old data
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_RLEaccel_c_h_
|
||||
#define SDL_RLEaccel_c_h_
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
// Useful functions and variables from SDL_RLEaccel.c
|
||||
|
||||
extern bool SDL_RLESurface(SDL_Surface *surface);
|
||||
extern void SDL_UnRLESurface(SDL_Surface *surface, bool recode);
|
||||
|
||||
#endif // SDL_RLEaccel_c_h_
|
||||
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_sysvideo.h"
|
||||
#include "SDL_surface_c.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 bool SDLCALL SDL_SoftBlit(SDL_Surface *src, const SDL_Rect *srcrect,
|
||||
SDL_Surface *dst, const SDL_Rect *dstrect)
|
||||
{
|
||||
bool okay;
|
||||
int src_locked;
|
||||
int dst_locked;
|
||||
|
||||
// Everything is okay at the beginning...
|
||||
okay = true;
|
||||
|
||||
// Lock the destination if it's in hardware
|
||||
dst_locked = 0;
|
||||
if (SDL_MUSTLOCK(dst)) {
|
||||
if (!SDL_LockSurface(dst)) {
|
||||
okay = false;
|
||||
} else {
|
||||
dst_locked = 1;
|
||||
}
|
||||
}
|
||||
// Lock the source if it's in hardware
|
||||
src_locked = 0;
|
||||
if (SDL_MUSTLOCK(src)) {
|
||||
if (!SDL_LockSurface(src)) {
|
||||
okay = false;
|
||||
} else {
|
||||
src_locked = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up source and destination buffer pointers, and BLIT!
|
||||
if (okay) {
|
||||
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->bytes_per_pixel;
|
||||
info->src_w = srcrect->w;
|
||||
info->src_h = srcrect->h;
|
||||
info->src_pitch = src->pitch;
|
||||
info->src_skip =
|
||||
info->src_pitch - info->src_w * info->src_fmt->bytes_per_pixel;
|
||||
info->dst =
|
||||
(Uint8 *)dst->pixels + (Uint16)dstrect->y * dst->pitch +
|
||||
(Uint16)dstrect->x * info->dst_fmt->bytes_per_pixel;
|
||||
info->dst_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->bytes_per_pixel;
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef SDL_HAVE_BLIT_AUTO
|
||||
|
||||
#ifdef SDL_PLATFORM_MACOS
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
static 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 true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static bool SDL_UseAltivecPrefetch(void)
|
||||
{
|
||||
// Just guess G4
|
||||
return true;
|
||||
}
|
||||
#endif // SDL_PLATFORM_MACOS
|
||||
|
||||
static SDL_BlitFunc SDL_ChooseBlitFunc(SDL_PixelFormat src_format, SDL_PixelFormat dst_format, int flags,
|
||||
SDL_BlitFuncEntry *entries)
|
||||
{
|
||||
int i, flagcheck = (flags & (SDL_COPY_MODULATE_MASK | SDL_COPY_BLEND_MASK | SDL_COPY_COLORKEY | SDL_COPY_NEAREST));
|
||||
static unsigned int features = 0x7fffffff;
|
||||
|
||||
// Get the available CPU features
|
||||
if (features == 0x7fffffff) {
|
||||
features = SDL_CPU_ANY;
|
||||
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
|
||||
bool SDL_CalculateBlit(SDL_Surface *surface, SDL_Surface *dst)
|
||||
{
|
||||
SDL_BlitFunc blit = NULL;
|
||||
SDL_BlitMap *map = &surface->map;
|
||||
SDL_Colorspace src_colorspace = surface->colorspace;
|
||||
SDL_Colorspace dst_colorspace = dst->colorspace;
|
||||
|
||||
// We don't currently support blitting to < 8 bpp surfaces
|
||||
if (SDL_BITSPERPIXEL(dst->format) < 8) {
|
||||
SDL_InvalidateMap(map);
|
||||
return SDL_SetError("Blit combination not supported");
|
||||
}
|
||||
|
||||
#ifdef SDL_HAVE_RLE
|
||||
// Clean everything out to start
|
||||
if (surface->flags & SDL_INTERNAL_SURFACE_RLEACCEL) {
|
||||
SDL_UnRLESurface(surface, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
map->blit = SDL_SoftBlit;
|
||||
map->info.src_surface = surface;
|
||||
map->info.src_fmt = surface->fmt;
|
||||
map->info.src_pal = surface->palette;
|
||||
map->info.dst_surface = dst;
|
||||
map->info.dst_fmt = dst->fmt;
|
||||
map->info.dst_pal = dst->palette;
|
||||
|
||||
#ifdef SDL_HAVE_RLE
|
||||
// See if we can do RLE acceleration
|
||||
if (map->info.flags & SDL_COPY_RLE_DESIRED) {
|
||||
if (SDL_RLESurface(surface)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Choose a standard blit function
|
||||
if (!blit) {
|
||||
if (src_colorspace != dst_colorspace ||
|
||||
SDL_BYTESPERPIXEL(surface->format) > 4 ||
|
||||
SDL_BYTESPERPIXEL(dst->format) > 4) {
|
||||
blit = SDL_Blit_Slow_Float;
|
||||
}
|
||||
}
|
||||
if (!blit) {
|
||||
if (map->identity && !(map->info.flags & ~SDL_COPY_RLE_DESIRED)) {
|
||||
blit = SDL_BlitCopy;
|
||||
} else if (SDL_ISPIXELFORMAT_10BIT(surface->format) ||
|
||||
SDL_ISPIXELFORMAT_10BIT(dst->format)) {
|
||||
blit = SDL_Blit_Slow;
|
||||
}
|
||||
#ifdef SDL_HAVE_BLIT_0
|
||||
else if (SDL_BITSPERPIXEL(surface->format) < 8 &&
|
||||
SDL_ISPIXELFORMAT_INDEXED(surface->format)) {
|
||||
blit = SDL_CalculateBlit0(surface);
|
||||
}
|
||||
#endif
|
||||
#ifdef SDL_HAVE_BLIT_1
|
||||
else if (SDL_BYTESPERPIXEL(surface->format) == 1 &&
|
||||
SDL_ISPIXELFORMAT_INDEXED(surface->format)) {
|
||||
blit = SDL_CalculateBlit1(surface);
|
||||
}
|
||||
#endif
|
||||
#ifdef SDL_HAVE_BLIT_A
|
||||
else if (map->info.flags & SDL_COPY_BLEND) {
|
||||
blit = SDL_CalculateBlitA(surface);
|
||||
}
|
||||
#endif
|
||||
#ifdef SDL_HAVE_BLIT_N
|
||||
else {
|
||||
blit = SDL_CalculateBlitN(surface);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef SDL_HAVE_BLIT_AUTO
|
||||
if (!blit) {
|
||||
SDL_PixelFormat src_format = surface->format;
|
||||
SDL_PixelFormat dst_format = dst->format;
|
||||
|
||||
blit =
|
||||
SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags,
|
||||
SDL_GeneratedBlitFuncTable);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef TEST_SLOW_BLIT
|
||||
if (!blit)
|
||||
#endif
|
||||
{
|
||||
SDL_PixelFormat src_format = surface->format;
|
||||
SDL_PixelFormat dst_format = dst->format;
|
||||
|
||||
if ((!SDL_ISPIXELFORMAT_INDEXED(src_format) ||
|
||||
(src_format == SDL_PIXELFORMAT_INDEX8 && surface->palette)) &&
|
||||
!SDL_ISPIXELFORMAT_FOURCC(src_format) &&
|
||||
(!SDL_ISPIXELFORMAT_INDEXED(dst_format) ||
|
||||
(dst_format == SDL_PIXELFORMAT_INDEX8 && dst->palette)) &&
|
||||
!SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
|
||||
blit = SDL_Blit_Slow;
|
||||
}
|
||||
}
|
||||
map->data = (void *)blit;
|
||||
|
||||
// Make sure we have a blit function
|
||||
if (!blit) {
|
||||
SDL_InvalidateMap(map);
|
||||
return SDL_SetError("Blit combination not supported");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_blit_h_
|
||||
#define SDL_blit_h_
|
||||
|
||||
// Table to do pixel byte expansion
|
||||
extern const Uint8 *SDL_expand_byte[9];
|
||||
extern const Uint16 SDL_expand_byte_10[];
|
||||
|
||||
// SDL blit copy flags
|
||||
#define SDL_COPY_MODULATE_COLOR 0x00000001
|
||||
#define SDL_COPY_MODULATE_ALPHA 0x00000002
|
||||
#define SDL_COPY_MODULATE_MASK (SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA)
|
||||
#define SDL_COPY_BLEND 0x00000010
|
||||
#define SDL_COPY_BLEND_PREMULTIPLIED 0x00000020
|
||||
#define SDL_COPY_ADD 0x00000040
|
||||
#define SDL_COPY_ADD_PREMULTIPLIED 0x00000080
|
||||
#define SDL_COPY_MOD 0x00000100
|
||||
#define SDL_COPY_MUL 0x00000200
|
||||
#define SDL_COPY_BLEND_MASK (SDL_COPY_BLEND | SDL_COPY_BLEND_PREMULTIPLIED | SDL_COPY_ADD | SDL_COPY_ADD_PREMULTIPLIED | SDL_COPY_MOD | SDL_COPY_MUL)
|
||||
#define SDL_COPY_COLORKEY 0x00000400
|
||||
#define SDL_COPY_NEAREST 0x00000800
|
||||
#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
|
||||
{
|
||||
SDL_Surface *src_surface;
|
||||
Uint8 *src;
|
||||
int src_w, src_h;
|
||||
int src_pitch;
|
||||
int src_skip;
|
||||
SDL_Surface *dst_surface;
|
||||
Uint8 *dst;
|
||||
int dst_w, dst_h;
|
||||
int dst_pitch;
|
||||
int dst_skip;
|
||||
const SDL_PixelFormatDetails *src_fmt;
|
||||
const SDL_Palette *src_pal;
|
||||
const SDL_PixelFormatDetails *dst_fmt;
|
||||
const SDL_Palette *dst_pal;
|
||||
Uint8 *table;
|
||||
SDL_HashTable *palette_map;
|
||||
int flags;
|
||||
Uint32 colorkey;
|
||||
Uint8 r, g, b, a;
|
||||
} SDL_BlitInfo;
|
||||
|
||||
typedef void (*SDL_BlitFunc)(SDL_BlitInfo *info);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_PixelFormat src_format;
|
||||
SDL_PixelFormat dst_format;
|
||||
int flags;
|
||||
unsigned int cpu;
|
||||
SDL_BlitFunc func;
|
||||
} SDL_BlitFuncEntry;
|
||||
|
||||
typedef bool (SDLCALL *SDL_Blit) (struct SDL_Surface *src, const SDL_Rect *srcrect, struct SDL_Surface *dst, const SDL_Rect *dstrect);
|
||||
|
||||
// Blit mapping definition
|
||||
typedef struct SDL_BlitMap
|
||||
{
|
||||
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;
|
||||
} SDL_BlitMap;
|
||||
|
||||
// Functions found in SDL_blit.c
|
||||
extern bool SDL_CalculateBlit(SDL_Surface *surface, SDL_Surface *dst);
|
||||
|
||||
/* 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->Rbits][((Pixel & fmt->Rmask) >> fmt->Rshift)]; \
|
||||
g = SDL_expand_byte[fmt->Gbits][((Pixel & fmt->Gmask) >> fmt->Gshift)]; \
|
||||
b = SDL_expand_byte[fmt->Bbits][((Pixel & fmt->Bmask) >> fmt->Bshift)]; \
|
||||
}
|
||||
#define RGB_FROM_RGB565(Pixel, r, g, b) \
|
||||
{ \
|
||||
r = SDL_expand_byte[5][((Pixel & 0xF800) >> 11)]; \
|
||||
g = SDL_expand_byte[6][((Pixel & 0x07E0) >> 5)]; \
|
||||
b = SDL_expand_byte[5][(Pixel & 0x001F)]; \
|
||||
}
|
||||
#define RGB_FROM_RGB555(Pixel, r, g, b) \
|
||||
{ \
|
||||
r = SDL_expand_byte[5][((Pixel & 0x7C00) >> 10)]; \
|
||||
g = SDL_expand_byte[5][((Pixel & 0x03E0) >> 5)]; \
|
||||
b = SDL_expand_byte[5][(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 >> (8 - fmt->Rbits)) << fmt->Rshift) | \
|
||||
((g >> (8 - fmt->Gbits)) << fmt->Gshift) | \
|
||||
((b >> (8 - fmt->Bbits)) << fmt->Bshift) | \
|
||||
fmt->Amask; \
|
||||
}
|
||||
#define RGB332_FROM_RGB(Pixel, r, g, b) \
|
||||
{ \
|
||||
Pixel = (Uint8)(((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6)); \
|
||||
}
|
||||
#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 ARGB2101010_FROM_RGBAFLOAT(Pixel, r, g, b, a) \
|
||||
{ \
|
||||
r = SDL_clamp(r, 0.0f, 1.0f) * 1023.0f; \
|
||||
g = SDL_clamp(g, 0.0f, 1.0f) * 1023.0f; \
|
||||
b = SDL_clamp(b, 0.0f, 1.0f) * 1023.0f; \
|
||||
a = SDL_clamp(a, 0.0f, 1.0f) * 3.0f; \
|
||||
Pixel = (((Uint32)SDL_roundf(a)) << 30) | \
|
||||
(((Uint32)SDL_roundf(r)) << 20) | \
|
||||
(((Uint32)SDL_roundf(g)) << 10) | \
|
||||
(Uint32)SDL_roundf(b); \
|
||||
}
|
||||
#define ABGR2101010_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) | (b << 20) | (g << 10) | r; \
|
||||
}
|
||||
#define ABGR2101010_FROM_RGBAFLOAT(Pixel, r, g, b, a) \
|
||||
{ \
|
||||
r = SDL_clamp(r, 0.0f, 1.0f) * 1023.0f; \
|
||||
g = SDL_clamp(g, 0.0f, 1.0f) * 1023.0f; \
|
||||
b = SDL_clamp(b, 0.0f, 1.0f) * 1023.0f; \
|
||||
a = SDL_clamp(a, 0.0f, 1.0f) * 3.0f; \
|
||||
Pixel = (((Uint32)SDL_roundf(a)) << 30) | \
|
||||
(((Uint32)SDL_roundf(b)) << 20) | \
|
||||
(((Uint32)SDL_roundf(g)) << 10) | \
|
||||
(Uint32)SDL_roundf(r); \
|
||||
}
|
||||
#define ASSEMBLE_RGB(buf, bpp, fmt, r, g, b) \
|
||||
{ \
|
||||
switch (bpp) { \
|
||||
case 1: \
|
||||
{ \
|
||||
Uint8 _pixel; \
|
||||
\
|
||||
PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \
|
||||
*((Uint8 *)(buf)) = _pixel; \
|
||||
} break; \
|
||||
\
|
||||
case 2: \
|
||||
{ \
|
||||
Uint16 _pixel; \
|
||||
\
|
||||
PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \
|
||||
*((Uint16 *)(buf)) = _pixel; \
|
||||
} break; \
|
||||
\
|
||||
case 3: \
|
||||
{ \
|
||||
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
|
||||
*((buf) + fmt->Rshift / 8) = r; \
|
||||
*((buf) + fmt->Gshift / 8) = g; \
|
||||
*((buf) + fmt->Bshift / 8) = b; \
|
||||
} else { \
|
||||
*((buf) + 2 - fmt->Rshift / 8) = r; \
|
||||
*((buf) + 2 - fmt->Gshift / 8) = g; \
|
||||
*((buf) + 2 - fmt->Bshift / 8) = b; \
|
||||
} \
|
||||
} break; \
|
||||
\
|
||||
case 4: \
|
||||
{ \
|
||||
Uint32 _pixel; \
|
||||
\
|
||||
PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \
|
||||
*((Uint32 *)(buf)) = _pixel; \
|
||||
} break; \
|
||||
} \
|
||||
}
|
||||
|
||||
// FIXME: Should we rescale alpha into 0..255 here?
|
||||
#define RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a) \
|
||||
{ \
|
||||
r = SDL_expand_byte[fmt->Rbits][((Pixel & fmt->Rmask) >> fmt->Rshift)]; \
|
||||
g = SDL_expand_byte[fmt->Gbits][((Pixel & fmt->Gmask) >> fmt->Gshift)]; \
|
||||
b = SDL_expand_byte[fmt->Bbits][((Pixel & fmt->Bmask) >> fmt->Bshift)]; \
|
||||
a = SDL_expand_byte[fmt->Abits][((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[2][(Pixel >> 30)]; \
|
||||
}
|
||||
#define RGBAFLOAT_FROM_ARGB2101010(Pixel, r, g, b, a) \
|
||||
{ \
|
||||
r = (float)((Pixel >> 20) & 0x3FF) / 1023.0f; \
|
||||
g = (float)((Pixel >> 10) & 0x3FF) / 1023.0f; \
|
||||
b = (float)((Pixel >> 0) & 0x3FF) / 1023.0f; \
|
||||
a = (float)(Pixel >> 30) / 3.0f; \
|
||||
}
|
||||
#define RGBA_FROM_ABGR2101010(Pixel, r, g, b, a) \
|
||||
{ \
|
||||
r = ((Pixel >> 2) & 0xFF); \
|
||||
g = ((Pixel >> 12) & 0xFF); \
|
||||
b = ((Pixel >> 22) & 0xFF); \
|
||||
a = SDL_expand_byte[2][(Pixel >> 30)]; \
|
||||
}
|
||||
#define RGBAFLOAT_FROM_ABGR2101010(Pixel, r, g, b, a) \
|
||||
{ \
|
||||
r = (float)((Pixel >> 0) & 0x3FF) / 1023.0f; \
|
||||
g = (float)((Pixel >> 10) & 0x3FF) / 1023.0f; \
|
||||
b = (float)((Pixel >> 20) & 0x3FF) / 1023.0f; \
|
||||
a = (float)(Pixel >> 30) / 3.0f; \
|
||||
}
|
||||
#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 >> (8 - fmt->Rbits)) << fmt->Rshift) | \
|
||||
((g >> (8 - fmt->Gbits)) << fmt->Gshift) | \
|
||||
((b >> (8 - fmt->Bbits)) << fmt->Bshift) | \
|
||||
((a >> (8 - fmt->Abits)) << fmt->Ashift); \
|
||||
}
|
||||
#define ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a) \
|
||||
{ \
|
||||
switch (bpp) { \
|
||||
case 1: \
|
||||
{ \
|
||||
Uint8 _pixel; \
|
||||
\
|
||||
PIXEL_FROM_RGBA(_pixel, fmt, r, g, b, a); \
|
||||
*((Uint8 *)(buf)) = _pixel; \
|
||||
} break; \
|
||||
\
|
||||
case 2: \
|
||||
{ \
|
||||
Uint16 _pixel; \
|
||||
\
|
||||
PIXEL_FROM_RGBA(_pixel, fmt, r, g, b, a); \
|
||||
*((Uint16 *)(buf)) = _pixel; \
|
||||
} break; \
|
||||
\
|
||||
case 3: \
|
||||
{ \
|
||||
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
|
||||
*((buf) + fmt->Rshift / 8) = r; \
|
||||
*((buf) + fmt->Gshift / 8) = g; \
|
||||
*((buf) + fmt->Bshift / 8) = b; \
|
||||
} else { \
|
||||
*((buf) + 2 - fmt->Rshift / 8) = r; \
|
||||
*((buf) + 2 - fmt->Gshift / 8) = g; \
|
||||
*((buf) + 2 - fmt->Bshift / 8) = b; \
|
||||
} \
|
||||
} break; \
|
||||
\
|
||||
case 4: \
|
||||
{ \
|
||||
Uint32 _pixel; \
|
||||
\
|
||||
PIXEL_FROM_RGBA(_pixel, fmt, r, g, b, a); \
|
||||
*((Uint32 *)(buf)) = _pixel; \
|
||||
} break; \
|
||||
} \
|
||||
}
|
||||
|
||||
// Convert any 32-bit 4-bpp pixel to ARGB format
|
||||
#define PIXEL_TO_ARGB_PIXEL(src, srcfmt, dst) \
|
||||
do { \
|
||||
Uint8 a, r, g, b; \
|
||||
RGBA_FROM_PIXEL(src, srcfmt, r, g, b, a); \
|
||||
dst = a << 24 | r << 16 | g << 8 | b; \
|
||||
} while (0)
|
||||
// Blend a single color channel or alpha value
|
||||
/* dC = ((sC * sA) + (dC * (255 - sA))) / 255 */
|
||||
#define ALPHA_BLEND_CHANNEL(sC, dC, sA) \
|
||||
do { \
|
||||
Uint16 x; \
|
||||
x = ((sC - dC) * sA) + ((dC << 8) - dC); \
|
||||
x += 0x1U; \
|
||||
x += x >> 8; \
|
||||
dC = x >> 8; \
|
||||
} while (0)
|
||||
// Perform a division by 255 after a multiplication of two 8-bit color channels
|
||||
/* out = (sC * dC) / 255 */
|
||||
#define MULT_DIV_255(sC, dC, out) \
|
||||
do { \
|
||||
Uint16 x = sC * dC; \
|
||||
x += 0x1U; \
|
||||
x += x >> 8; \
|
||||
out = x >> 8; \
|
||||
} while (0)
|
||||
// Blend the RGB values of two pixels with an alpha value
|
||||
#define ALPHA_BLEND_RGB(sR, sG, sB, A, dR, dG, dB) \
|
||||
do { \
|
||||
ALPHA_BLEND_CHANNEL(sR, dR, A); \
|
||||
ALPHA_BLEND_CHANNEL(sG, dG, A); \
|
||||
ALPHA_BLEND_CHANNEL(sB, dB, A); \
|
||||
} while (0)
|
||||
|
||||
// Blend two 8888 pixels with the same format
|
||||
/* Calculates dst = ((src * factor) + (dst * (255 - factor))) / 255 */
|
||||
// FIXME: SDL_SIZE_MAX might not be an integer literal
|
||||
#if defined(SIZE_MAX) && (SIZE_MAX == 0xffffffffffffffff)
|
||||
#define FACTOR_BLEND_8888(src, dst, factor) \
|
||||
do { \
|
||||
Uint64 src64 = src; \
|
||||
src64 = (src64 | (src64 << 24)) & 0x00FF00FF00FF00FF; \
|
||||
\
|
||||
Uint64 dst64 = dst; \
|
||||
dst64 = (dst64 | (dst64 << 24)) & 0x00FF00FF00FF00FF; \
|
||||
\
|
||||
dst64 = ((src64 - dst64) * factor) + (dst64 << 8) - dst64; \
|
||||
dst64 += 0x0001000100010001; \
|
||||
dst64 += (dst64 >> 8) & 0x00FF00FF00FF00FF; \
|
||||
dst64 &= 0xFF00FF00FF00FF00; \
|
||||
\
|
||||
dst = (Uint32)((dst64 >> 8) | (dst64 >> 32)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define FACTOR_BLEND_8888(src, dst, factor) \
|
||||
do { \
|
||||
Uint32 src02 = src & 0x00FF00FF; \
|
||||
Uint32 dst02 = dst & 0x00FF00FF; \
|
||||
\
|
||||
Uint32 src13 = (src >> 8) & 0x00FF00FF; \
|
||||
Uint32 dst13 = (dst >> 8) & 0x00FF00FF; \
|
||||
\
|
||||
Uint32 res02 = ((src02 - dst02) * factor) + (dst02 << 8) - dst02; \
|
||||
res02 += 0x00010001; \
|
||||
res02 += (res02 >> 8) & 0x00FF00FF; \
|
||||
res02 = (res02 >> 8) & 0x00FF00FF; \
|
||||
\
|
||||
Uint32 res13 = ((src13 - dst13) * factor) + (dst13 << 8) - dst13; \
|
||||
res13 += 0x00010001; \
|
||||
res13 += (res13 >> 8) & 0x00FF00FF; \
|
||||
res13 &= 0xFF00FF00; \
|
||||
dst = res02 | res13; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
// Alpha blend two 8888 pixels with the same formats.
|
||||
#define ALPHA_BLEND_8888(src, dst, fmt) \
|
||||
do { \
|
||||
Uint32 srcA = (src >> fmt->Ashift) & 0xFF; \
|
||||
Uint32 tmp = src | fmt->Amask; \
|
||||
FACTOR_BLEND_8888(tmp, dst, srcA); \
|
||||
} while (0)
|
||||
|
||||
// Alpha blend two 8888 pixels with differing formats.
|
||||
#define ALPHA_BLEND_SWIZZLE_8888(src, dst, srcfmt, dstfmt) \
|
||||
do { \
|
||||
Uint32 srcA = (src >> srcfmt->Ashift) & 0xFF; \
|
||||
Uint32 tmp = (((src >> srcfmt->Rshift) & 0xFF) << dstfmt->Rshift) | \
|
||||
(((src >> srcfmt->Gshift) & 0xFF) << dstfmt->Gshift) | \
|
||||
(((src >> srcfmt->Bshift) & 0xFF) << dstfmt->Bshift) | \
|
||||
dstfmt->Amask; \
|
||||
FACTOR_BLEND_8888(tmp, dst, srcA); \
|
||||
} while (0)
|
||||
// Blend the RGBA values of two pixels
|
||||
#define ALPHA_BLEND_RGBA(sR, sG, sB, sA, dR, dG, dB, dA) \
|
||||
do { \
|
||||
ALPHA_BLEND_CHANNEL(sR, dR, sA); \
|
||||
ALPHA_BLEND_CHANNEL(sG, dG, sA); \
|
||||
ALPHA_BLEND_CHANNEL(sB, dB, sA); \
|
||||
ALPHA_BLEND_CHANNEL(255, dA, sA); \
|
||||
} 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
|
||||
|
||||
#define DUFFS_LOOP1(pixel_copy_increment, width) \
|
||||
{ \
|
||||
int n; \
|
||||
for (n = width; n > 0; --n) { \
|
||||
pixel_copy_increment; \
|
||||
} \
|
||||
}
|
||||
|
||||
#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); \
|
||||
} \
|
||||
}
|
||||
|
||||
// 2-times unrolled loop
|
||||
#define DUFFS_LOOP2(pixel_copy_increment, width) \
|
||||
{ \
|
||||
int n = (width + 1) / 2; \
|
||||
switch (width & 1) { \
|
||||
case 0: \
|
||||
do { \
|
||||
pixel_copy_increment; \
|
||||
SDL_FALLTHROUGH; \
|
||||
case 1: \
|
||||
pixel_copy_increment; \
|
||||
} while (--n > 0); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Use the 4-times version of the loop by default
|
||||
#define DUFFS_LOOP(pixel_copy_increment, width) \
|
||||
DUFFS_LOOP4(pixel_copy_increment, width)
|
||||
// Use the 8-times version of the loop for simple routines
|
||||
#define DUFFS_LOOP_TRIVIAL(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) \
|
||||
DUFFS_LOOP1(pixel_copy_increment, width)
|
||||
#define DUFFS_LOOP_TRIVIAL(pixel_copy_increment, width) \
|
||||
DUFFS_LOOP1(pixel_copy_increment, width)
|
||||
#define DUFFS_LOOP8(pixel_copy_increment, width) \
|
||||
DUFFS_LOOP1(pixel_copy_increment, width)
|
||||
#define DUFFS_LOOP4(pixel_copy_increment, width) \
|
||||
DUFFS_LOOP1(pixel_copy_increment, width)
|
||||
#define DUFFS_LOOP2(pixel_copy_increment, width) \
|
||||
DUFFS_LOOP1(pixel_copy_increment, width)
|
||||
#define DUFFS_LOOP_124(pixel_copy_increment1, \
|
||||
pixel_copy_increment2, \
|
||||
pixel_copy_increment4, width) \
|
||||
DUFFS_LOOP1(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_
|
||||
@@ -0,0 +1,972 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_HAVE_BLIT_0
|
||||
|
||||
#include "SDL_surface_c.h"
|
||||
|
||||
// Functions to blit from bitmaps to other surfaces
|
||||
|
||||
SDL_FORCE_INLINE void BlitBto1(SDL_BlitInfo *info, const Uint32 srcbpp)
|
||||
{
|
||||
const Uint32 mask = (1 << srcbpp) - 1;
|
||||
const Uint32 align = (8 / srcbpp) - 1;
|
||||
|
||||
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;
|
||||
|
||||
if (srcbpp == 4)
|
||||
srcskip += width - (width + 1) / 2;
|
||||
else if (srcbpp == 2)
|
||||
srcskip += width - (width + 3) / 4;
|
||||
else if (srcbpp == 1)
|
||||
srcskip += width - (width + 7) / 8;
|
||||
|
||||
if (map) {
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (1) {
|
||||
*dst = map[bit];
|
||||
}
|
||||
dst++;
|
||||
byte >>= srcbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (1) {
|
||||
*dst = map[bit];
|
||||
}
|
||||
dst++;
|
||||
byte <<= srcbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (1) {
|
||||
*dst = bit;
|
||||
}
|
||||
dst++;
|
||||
byte >>= srcbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (1) {
|
||||
*dst = bit;
|
||||
}
|
||||
dst++;
|
||||
byte <<= srcbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void BlitBto2(SDL_BlitInfo *info, const Uint32 srcbpp)
|
||||
{
|
||||
const Uint32 mask = (1 << srcbpp) - 1;
|
||||
const Uint32 align = (8 / srcbpp) - 1;
|
||||
|
||||
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;
|
||||
|
||||
if (srcbpp == 4)
|
||||
srcskip += width - (width + 1) / 2;
|
||||
else if (srcbpp == 2)
|
||||
srcskip += width - (width + 3) / 4;
|
||||
else if (srcbpp == 1)
|
||||
srcskip += width - (width + 7) / 8;
|
||||
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (1) {
|
||||
*dst = map[bit];
|
||||
}
|
||||
byte >>= srcbpp;
|
||||
dst++;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (1) {
|
||||
*dst = map[bit];
|
||||
}
|
||||
byte <<= srcbpp;
|
||||
dst++;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void BlitBto3(SDL_BlitInfo *info, const Uint32 srcbpp)
|
||||
{
|
||||
const Uint32 mask = (1 << srcbpp) - 1;
|
||||
const Uint32 align = (8 / srcbpp) - 1;
|
||||
|
||||
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;
|
||||
|
||||
if (srcbpp == 4)
|
||||
srcskip += width - (width + 1) / 2;
|
||||
else if (srcbpp == 2)
|
||||
srcskip += width - (width + 3) / 4;
|
||||
else if (srcbpp == 1)
|
||||
srcskip += width - (width + 7) / 8;
|
||||
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (1) {
|
||||
o = bit * 4;
|
||||
dst[0] = map[o++];
|
||||
dst[1] = map[o++];
|
||||
dst[2] = map[o++];
|
||||
}
|
||||
byte >>= srcbpp;
|
||||
dst += 3;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (1) {
|
||||
o = bit * 4;
|
||||
dst[0] = map[o++];
|
||||
dst[1] = map[o++];
|
||||
dst[2] = map[o++];
|
||||
}
|
||||
byte <<= srcbpp;
|
||||
dst += 3;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void BlitBto4(SDL_BlitInfo *info, const Uint32 srcbpp)
|
||||
{
|
||||
const Uint32 mask = (1 << srcbpp) - 1;
|
||||
const Uint32 align = (8 / srcbpp) - 1;
|
||||
|
||||
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;
|
||||
|
||||
if (srcbpp == 4)
|
||||
srcskip += width - (width + 1) / 2;
|
||||
else if (srcbpp == 2)
|
||||
srcskip += width - (width + 3) / 4;
|
||||
else if (srcbpp == 1)
|
||||
srcskip += width - (width + 7) / 8;
|
||||
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (1) {
|
||||
*dst = map[bit];
|
||||
}
|
||||
byte >>= srcbpp;
|
||||
dst++;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (1) {
|
||||
*dst = map[bit];
|
||||
}
|
||||
byte <<= srcbpp;
|
||||
dst++;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void BlitBto1Key(SDL_BlitInfo *info, const Uint32 srcbpp)
|
||||
{
|
||||
const Uint32 mask = (1 << srcbpp) - 1;
|
||||
const Uint32 align = (8 / srcbpp) - 1;
|
||||
|
||||
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
|
||||
if (srcbpp == 4)
|
||||
srcskip += width - (width + 1) / 2;
|
||||
else if (srcbpp == 2)
|
||||
srcskip += width - (width + 3) / 4;
|
||||
else if (srcbpp == 1)
|
||||
srcskip += width - (width + 7) / 8;
|
||||
|
||||
if (palmap) {
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (bit != ckey) {
|
||||
*dst = palmap[bit];
|
||||
}
|
||||
dst++;
|
||||
byte >>= srcbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (bit != ckey) {
|
||||
*dst = palmap[bit];
|
||||
}
|
||||
dst++;
|
||||
byte <<= srcbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (bit != ckey) {
|
||||
*dst = bit;
|
||||
}
|
||||
dst++;
|
||||
byte >>= srcbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (bit != ckey) {
|
||||
*dst = bit;
|
||||
}
|
||||
dst++;
|
||||
byte <<= srcbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void BlitBto2Key(SDL_BlitInfo *info, const Uint32 srcbpp)
|
||||
{
|
||||
const Uint32 mask = (1 << srcbpp) - 1;
|
||||
const Uint32 align = (8 / srcbpp) - 1;
|
||||
|
||||
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
|
||||
if (srcbpp == 4)
|
||||
srcskip += width - (width + 1) / 2;
|
||||
else if (srcbpp == 2)
|
||||
srcskip += width - (width + 3) / 4;
|
||||
else if (srcbpp == 1)
|
||||
srcskip += width - (width + 7) / 8;
|
||||
dstskip /= 2;
|
||||
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (bit != ckey) {
|
||||
*dstp = ((Uint16 *)palmap)[bit];
|
||||
}
|
||||
byte >>= srcbpp;
|
||||
dstp++;
|
||||
}
|
||||
src += srcskip;
|
||||
dstp += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (bit != ckey) {
|
||||
*dstp = ((Uint16 *)palmap)[bit];
|
||||
}
|
||||
byte <<= srcbpp;
|
||||
dstp++;
|
||||
}
|
||||
src += srcskip;
|
||||
dstp += dstskip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void BlitBto3Key(SDL_BlitInfo *info, const Uint32 srcbpp)
|
||||
{
|
||||
const Uint32 mask = (1 << srcbpp) - 1;
|
||||
const Uint32 align = (8 / srcbpp) - 1;
|
||||
|
||||
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
|
||||
if (srcbpp == 4)
|
||||
srcskip += width - (width + 1) / 2;
|
||||
else if (srcbpp == 2)
|
||||
srcskip += width - (width + 3) / 4;
|
||||
else if (srcbpp == 1)
|
||||
srcskip += width - (width + 7) / 8;
|
||||
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (bit != ckey) {
|
||||
SDL_memcpy(dst, &palmap[bit * 4], 3);
|
||||
}
|
||||
byte >>= srcbpp;
|
||||
dst += 3;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (bit != ckey) {
|
||||
SDL_memcpy(dst, &palmap[bit * 4], 3);
|
||||
}
|
||||
byte <<= srcbpp;
|
||||
dst += 3;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void BlitBto4Key(SDL_BlitInfo *info, const Uint32 srcbpp)
|
||||
{
|
||||
const Uint32 mask = (1 << srcbpp) - 1;
|
||||
const Uint32 align = (8 / srcbpp) - 1;
|
||||
|
||||
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
|
||||
if (srcbpp == 4)
|
||||
srcskip += width - (width + 1) / 2;
|
||||
else if (srcbpp == 2)
|
||||
srcskip += width - (width + 3) / 4;
|
||||
else if (srcbpp == 1)
|
||||
srcskip += width - (width + 7) / 8;
|
||||
dstskip /= 4;
|
||||
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (bit != ckey) {
|
||||
*dstp = ((Uint32 *)palmap)[bit];
|
||||
}
|
||||
byte >>= srcbpp;
|
||||
dstp++;
|
||||
}
|
||||
src += srcskip;
|
||||
dstp += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (bit != ckey) {
|
||||
*dstp = ((Uint32 *)palmap)[bit];
|
||||
}
|
||||
byte <<= srcbpp;
|
||||
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_pal->colors;
|
||||
const SDL_PixelFormatDetails *srcfmt = info->src_fmt;
|
||||
const SDL_PixelFormatDetails *dstfmt = info->dst_fmt;
|
||||
int srcbpp, dstbpp;
|
||||
int c;
|
||||
Uint32 pixelvalue, mask, align;
|
||||
unsigned sR, sG, sB;
|
||||
unsigned dR, dG, dB, dA;
|
||||
const unsigned A = info->a;
|
||||
|
||||
// Set up some basic variables
|
||||
srcbpp = srcfmt->bytes_per_pixel;
|
||||
dstbpp = dstfmt->bytes_per_pixel;
|
||||
if (srcbpp == 4)
|
||||
srcskip += width - (width + 1) / 2;
|
||||
else if (srcbpp == 2)
|
||||
srcskip += width - (width + 3) / 4;
|
||||
else if (srcbpp == 1)
|
||||
srcskip += width - (width + 7) / 8;
|
||||
mask = (1 << srcbpp) - 1;
|
||||
align = (8 / srcbpp) - 1;
|
||||
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (1) {
|
||||
sR = srcpal[bit].r;
|
||||
sG = srcpal[bit].g;
|
||||
sB = srcpal[bit].b;
|
||||
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
|
||||
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
|
||||
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
|
||||
}
|
||||
byte >>= srcbpp;
|
||||
dst += dstbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (1) {
|
||||
sR = srcpal[bit].r;
|
||||
sG = srcpal[bit].g;
|
||||
sB = srcpal[bit].b;
|
||||
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
|
||||
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
|
||||
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
|
||||
}
|
||||
byte <<= srcbpp;
|
||||
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;
|
||||
const SDL_PixelFormatDetails *srcfmt = info->src_fmt;
|
||||
const SDL_PixelFormatDetails *dstfmt = info->dst_fmt;
|
||||
const SDL_Color *srcpal = info->src_pal->colors;
|
||||
int srcbpp, dstbpp;
|
||||
int c;
|
||||
Uint32 pixelvalue, mask, align;
|
||||
unsigned sR, sG, sB;
|
||||
unsigned dR, dG, dB, dA;
|
||||
const unsigned A = info->a;
|
||||
Uint32 ckey = info->colorkey;
|
||||
|
||||
// Set up some basic variables
|
||||
srcbpp = srcfmt->bytes_per_pixel;
|
||||
dstbpp = dstfmt->bytes_per_pixel;
|
||||
if (srcbpp == 4)
|
||||
srcskip += width - (width + 1) / 2;
|
||||
else if (srcbpp == 2)
|
||||
srcskip += width - (width + 3) / 4;
|
||||
else if (srcbpp == 1)
|
||||
srcskip += width - (width + 7) / 8;
|
||||
mask = (1 << srcbpp) - 1;
|
||||
align = (8 / srcbpp) - 1;
|
||||
|
||||
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte & mask);
|
||||
if (bit != ckey) {
|
||||
sR = srcpal[bit].r;
|
||||
sG = srcpal[bit].g;
|
||||
sB = srcpal[bit].b;
|
||||
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
|
||||
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
|
||||
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
|
||||
}
|
||||
byte >>= srcbpp;
|
||||
dst += dstbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
} else {
|
||||
while (height--) {
|
||||
Uint8 byte = 0, bit;
|
||||
for (c = 0; c < width; ++c) {
|
||||
if (!(c & align)) {
|
||||
byte = *src++;
|
||||
}
|
||||
bit = (byte >> (8 - srcbpp)) & mask;
|
||||
if (bit != ckey) {
|
||||
sR = srcpal[bit].r;
|
||||
sG = srcpal[bit].g;
|
||||
sB = srcpal[bit].b;
|
||||
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
|
||||
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
|
||||
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
|
||||
}
|
||||
byte <<= srcbpp;
|
||||
dst += dstbpp;
|
||||
}
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void Blit1bto1(SDL_BlitInfo *info) {
|
||||
BlitBto1(info, 1);
|
||||
}
|
||||
|
||||
static void Blit1bto2(SDL_BlitInfo *info) {
|
||||
BlitBto2(info, 1);
|
||||
}
|
||||
|
||||
static void Blit1bto3(SDL_BlitInfo *info) {
|
||||
BlitBto3(info, 1);
|
||||
}
|
||||
|
||||
static void Blit1bto4(SDL_BlitInfo *info) {
|
||||
BlitBto4(info, 1);
|
||||
}
|
||||
|
||||
static const SDL_BlitFunc bitmap_blit_1b[] = {
|
||||
(SDL_BlitFunc)NULL, Blit1bto1, Blit1bto2, Blit1bto3, Blit1bto4
|
||||
};
|
||||
|
||||
static void Blit1bto1Key(SDL_BlitInfo *info) {
|
||||
BlitBto1Key(info, 1);
|
||||
}
|
||||
|
||||
static void Blit1bto2Key(SDL_BlitInfo *info) {
|
||||
BlitBto2Key(info, 1);
|
||||
}
|
||||
|
||||
static void Blit1bto3Key(SDL_BlitInfo *info) {
|
||||
BlitBto3Key(info, 1);
|
||||
}
|
||||
|
||||
static void Blit1bto4Key(SDL_BlitInfo *info) {
|
||||
BlitBto4Key(info, 1);
|
||||
}
|
||||
|
||||
static const SDL_BlitFunc colorkey_blit_1b[] = {
|
||||
(SDL_BlitFunc)NULL, Blit1bto1Key, Blit1bto2Key, Blit1bto3Key, Blit1bto4Key
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void Blit2bto1(SDL_BlitInfo *info) {
|
||||
BlitBto1(info, 2);
|
||||
}
|
||||
|
||||
static void Blit2bto2(SDL_BlitInfo *info) {
|
||||
BlitBto2(info, 2);
|
||||
}
|
||||
|
||||
static void Blit2bto3(SDL_BlitInfo *info) {
|
||||
BlitBto3(info, 2);
|
||||
}
|
||||
|
||||
static void Blit2bto4(SDL_BlitInfo *info) {
|
||||
BlitBto4(info, 2);
|
||||
}
|
||||
|
||||
static const SDL_BlitFunc bitmap_blit_2b[] = {
|
||||
(SDL_BlitFunc)NULL, Blit2bto1, Blit2bto2, Blit2bto3, Blit2bto4
|
||||
};
|
||||
|
||||
static void Blit2bto1Key(SDL_BlitInfo *info) {
|
||||
BlitBto1Key(info, 2);
|
||||
}
|
||||
|
||||
static void Blit2bto2Key(SDL_BlitInfo *info) {
|
||||
BlitBto2Key(info, 2);
|
||||
}
|
||||
|
||||
static void Blit2bto3Key(SDL_BlitInfo *info) {
|
||||
BlitBto3Key(info, 2);
|
||||
}
|
||||
|
||||
static void Blit2bto4Key(SDL_BlitInfo *info) {
|
||||
BlitBto4Key(info, 2);
|
||||
}
|
||||
|
||||
static const SDL_BlitFunc colorkey_blit_2b[] = {
|
||||
(SDL_BlitFunc)NULL, Blit2bto1Key, Blit2bto2Key, Blit2bto3Key, Blit2bto4Key
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void Blit4bto1(SDL_BlitInfo *info) {
|
||||
BlitBto1(info, 4);
|
||||
}
|
||||
|
||||
static void Blit4bto2(SDL_BlitInfo *info) {
|
||||
BlitBto2(info, 4);
|
||||
}
|
||||
|
||||
static void Blit4bto3(SDL_BlitInfo *info) {
|
||||
BlitBto3(info, 4);
|
||||
}
|
||||
|
||||
static void Blit4bto4(SDL_BlitInfo *info) {
|
||||
BlitBto4(info, 4);
|
||||
}
|
||||
|
||||
static const SDL_BlitFunc bitmap_blit_4b[] = {
|
||||
(SDL_BlitFunc)NULL, Blit4bto1, Blit4bto2, Blit4bto3, Blit4bto4
|
||||
};
|
||||
|
||||
static void Blit4bto1Key(SDL_BlitInfo *info) {
|
||||
BlitBto1Key(info, 4);
|
||||
}
|
||||
|
||||
static void Blit4bto2Key(SDL_BlitInfo *info) {
|
||||
BlitBto2Key(info, 4);
|
||||
}
|
||||
|
||||
static void Blit4bto3Key(SDL_BlitInfo *info) {
|
||||
BlitBto3Key(info, 4);
|
||||
}
|
||||
|
||||
static void Blit4bto4Key(SDL_BlitInfo *info) {
|
||||
BlitBto4Key(info, 4);
|
||||
}
|
||||
|
||||
static const SDL_BlitFunc colorkey_blit_4b[] = {
|
||||
(SDL_BlitFunc)NULL, Blit4bto1Key, Blit4bto2Key, Blit4bto3Key, Blit4bto4Key
|
||||
};
|
||||
|
||||
|
||||
|
||||
SDL_BlitFunc SDL_CalculateBlit0(SDL_Surface *surface)
|
||||
{
|
||||
int which;
|
||||
|
||||
if (SDL_BITSPERPIXEL(surface->map.info.dst_fmt->format) < 8) {
|
||||
which = 0;
|
||||
} else {
|
||||
which = SDL_BYTESPERPIXEL(surface->map.info.dst_fmt->format);
|
||||
}
|
||||
|
||||
if (SDL_PIXELTYPE(surface->format) == SDL_PIXELTYPE_INDEX1) {
|
||||
switch (surface->map.info.flags & ~SDL_COPY_RLE_MASK) {
|
||||
case 0:
|
||||
if (which < SDL_arraysize(bitmap_blit_1b)) {
|
||||
return bitmap_blit_1b[which];
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_COPY_COLORKEY:
|
||||
if (which < SDL_arraysize(colorkey_blit_1b)) {
|
||||
return colorkey_blit_1b[which];
|
||||
}
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (SDL_PIXELTYPE(surface->format) == SDL_PIXELTYPE_INDEX2) {
|
||||
switch (surface->map.info.flags & ~SDL_COPY_RLE_MASK) {
|
||||
case 0:
|
||||
if (which < SDL_arraysize(bitmap_blit_2b)) {
|
||||
return bitmap_blit_2b[which];
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_COPY_COLORKEY:
|
||||
if (which < SDL_arraysize(colorkey_blit_2b)) {
|
||||
return colorkey_blit_2b[which];
|
||||
}
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (SDL_PIXELTYPE(surface->format) == SDL_PIXELTYPE_INDEX4) {
|
||||
switch (surface->map.info.flags & ~SDL_COPY_RLE_MASK) {
|
||||
case 0:
|
||||
if (which < SDL_arraysize(bitmap_blit_4b)) {
|
||||
return bitmap_blit_4b[which];
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_COPY_COLORKEY:
|
||||
if (which < SDL_arraysize(colorkey_blit_4b)) {
|
||||
return colorkey_blit_4b[which];
|
||||
}
|
||||
break;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_HAVE_BLIT_1
|
||||
|
||||
#include "SDL_surface_c.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_TRIVIAL(
|
||||
{
|
||||
*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_TRIVIAL(
|
||||
{
|
||||
*(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_TRIVIAL(
|
||||
*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_TRIVIAL(
|
||||
{
|
||||
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_TRIVIAL(
|
||||
{
|
||||
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_TRIVIAL(
|
||||
{
|
||||
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_TRIVIAL(
|
||||
{
|
||||
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;
|
||||
const SDL_PixelFormatDetails *dstfmt = info->dst_fmt;
|
||||
const SDL_Color *srcpal = info->src_pal->colors;
|
||||
int dstbpp;
|
||||
Uint32 pixelvalue;
|
||||
unsigned sR, sG, sB, sA;
|
||||
unsigned dR, dG, dB, dA;
|
||||
const unsigned A = info->a;
|
||||
|
||||
// Set up some basic variables
|
||||
dstbpp = dstfmt->bytes_per_pixel;
|
||||
|
||||
while (height--) {
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
DUFFS_LOOP(
|
||||
{
|
||||
sR = srcpal[*src].r;
|
||||
sG = srcpal[*src].g;
|
||||
sB = srcpal[*src].b;
|
||||
sA = (srcpal[*src].a * A) / 255;
|
||||
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
|
||||
ALPHA_BLEND_RGBA(sR, sG, sB, sA, dR, dG, dB, dA);
|
||||
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
|
||||
src++;
|
||||
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;
|
||||
const SDL_PixelFormatDetails *dstfmt = info->dst_fmt;
|
||||
const SDL_Color *srcpal = info->src_pal->colors;
|
||||
Uint32 ckey = info->colorkey;
|
||||
int dstbpp;
|
||||
Uint32 pixelvalue;
|
||||
unsigned sR, sG, sB, sA;
|
||||
unsigned dR, dG, dB, dA;
|
||||
const unsigned A = info->a;
|
||||
|
||||
// Set up some basic variables
|
||||
dstbpp = dstfmt->bytes_per_pixel;
|
||||
|
||||
while (height--) {
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
DUFFS_LOOP(
|
||||
{
|
||||
if ( *src != ckey ) {
|
||||
sR = srcpal[*src].r;
|
||||
sG = srcpal[*src].g;
|
||||
sB = srcpal[*src].b;
|
||||
sA = (srcpal[*src].a * A) / 255;
|
||||
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
|
||||
ALPHA_BLEND_RGBA(sR, sG, sB, sA, dR, dG, dB, dA);
|
||||
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
|
||||
}
|
||||
src++;
|
||||
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;
|
||||
|
||||
if (SDL_BITSPERPIXEL(surface->map.info.dst_fmt->format) < 8) {
|
||||
which = 0;
|
||||
} else {
|
||||
which = SDL_BYTESPERPIXEL(surface->map.info.dst_fmt->format);
|
||||
}
|
||||
|
||||
switch (surface->map.info.flags & ~SDL_COPY_RLE_MASK) {
|
||||
case 0:
|
||||
if (which < SDL_arraysize(one_blit)) {
|
||||
return one_blit[which];
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_COPY_COLORKEY:
|
||||
if (which < SDL_arraysize(one_blitkey)) {
|
||||
return one_blitkey[which];
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_COPY_COLORKEY | SDL_COPY_BLEND: // this is not super-robust but handles a specific case we found sdl12-compat.
|
||||
if (surface->map.info.a == 255) {
|
||||
if (which < SDL_arraysize(one_blitkey)) {
|
||||
return one_blitkey[which];
|
||||
}
|
||||
} else {
|
||||
return which >= 2 ? Blit1toNAlphaKey : (SDL_BlitFunc)NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_COPY_BLEND:
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
// DO NOT EDIT! This file is generated by sdlgenblit.pl
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_HAVE_BLIT_AUTO
|
||||
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
|
||||
#include "SDL_blit.h"
|
||||
|
||||
extern SDL_BlitFuncEntry SDL_GeneratedBlitFuncTable[];
|
||||
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
|
||||
#endif // SDL_HAVE_BLIT_AUTO
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_surface_c.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
|
||||
|
||||
void SDL_BlitCopy(SDL_BlitInfo *info)
|
||||
{
|
||||
bool overlap;
|
||||
Uint8 *src, *dst;
|
||||
int w, h;
|
||||
int srcskip, dstskip;
|
||||
|
||||
w = info->dst_w * info->dst_fmt->bytes_per_pixel;
|
||||
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
|
||||
|
||||
while (h--) {
|
||||
SDL_memcpy(dst, src, w);
|
||||
src += srcskip;
|
||||
dst += dstskip;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_blit_copy_h_
|
||||
#define SDL_blit_copy_h_
|
||||
|
||||
void SDL_BlitCopy(SDL_BlitInfo *info);
|
||||
|
||||
#endif // SDL_blit_copy_h_
|
||||
@@ -0,0 +1,996 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_surface_c.h"
|
||||
#include "SDL_blit_slow.h"
|
||||
#include "SDL_pixels_c.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SlowBlitPixelAccess_Index8,
|
||||
SlowBlitPixelAccess_RGB,
|
||||
SlowBlitPixelAccess_RGBA,
|
||||
SlowBlitPixelAccess_10Bit,
|
||||
SlowBlitPixelAccess_Large,
|
||||
} SlowBlitPixelAccess;
|
||||
|
||||
static SlowBlitPixelAccess GetPixelAccessMethod(SDL_PixelFormat format)
|
||||
{
|
||||
if (SDL_BYTESPERPIXEL(format) > 4) {
|
||||
return SlowBlitPixelAccess_Large;
|
||||
} else if (SDL_ISPIXELFORMAT_10BIT(format)) {
|
||||
return SlowBlitPixelAccess_10Bit;
|
||||
} else if (format == SDL_PIXELFORMAT_INDEX8) {
|
||||
return SlowBlitPixelAccess_Index8;
|
||||
} else if (SDL_ISPIXELFORMAT_ALPHA(format)) {
|
||||
return SlowBlitPixelAccess_RGBA;
|
||||
} else {
|
||||
return SlowBlitPixelAccess_RGB;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 = 0;
|
||||
Uint32 srcR = 0, srcG = 0, srcB = 0, srcA = 0;
|
||||
Uint32 dstpixel = 0;
|
||||
Uint32 dstR = 0, dstG = 0, dstB = 0, dstA = 0;
|
||||
Uint64 srcy, srcx;
|
||||
Uint64 posy, posx;
|
||||
Uint64 incy, incx;
|
||||
const SDL_PixelFormatDetails *src_fmt = info->src_fmt;
|
||||
const SDL_Palette *src_pal = info->src_pal;
|
||||
const SDL_PixelFormatDetails *dst_fmt = info->dst_fmt;
|
||||
const SDL_Palette *dst_pal = info->dst_pal;
|
||||
SDL_HashTable *palette_map = info->palette_map;
|
||||
int srcbpp = src_fmt->bytes_per_pixel;
|
||||
int dstbpp = dst_fmt->bytes_per_pixel;
|
||||
SlowBlitPixelAccess src_access;
|
||||
SlowBlitPixelAccess dst_access;
|
||||
Uint32 rgbmask = ~src_fmt->Amask;
|
||||
Uint32 ckey = info->colorkey & rgbmask;
|
||||
Uint32 last_pixel = 0;
|
||||
Uint8 last_index = 0;
|
||||
|
||||
src_access = GetPixelAccessMethod(src_fmt->format);
|
||||
dst_access = GetPixelAccessMethod(dst_fmt->format);
|
||||
if (dst_access == SlowBlitPixelAccess_Index8) {
|
||||
last_index = SDL_LookupRGBAColor(palette_map, last_pixel, dst_pal);
|
||||
}
|
||||
|
||||
incy = ((Uint64)info->src_h << 16) / info->dst_h;
|
||||
incx = ((Uint64)info->src_w << 16) / info->dst_w;
|
||||
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));
|
||||
|
||||
switch (src_access) {
|
||||
case SlowBlitPixelAccess_Index8:
|
||||
srcpixel = *src;
|
||||
srcR = src_pal->colors[srcpixel].r;
|
||||
srcG = src_pal->colors[srcpixel].g;
|
||||
srcB = src_pal->colors[srcpixel].b;
|
||||
srcA = src_pal->colors[srcpixel].a;
|
||||
break;
|
||||
case SlowBlitPixelAccess_RGB:
|
||||
DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB);
|
||||
srcA = 0xFF;
|
||||
break;
|
||||
case SlowBlitPixelAccess_RGBA:
|
||||
DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB, srcA);
|
||||
break;
|
||||
case SlowBlitPixelAccess_10Bit:
|
||||
srcpixel = *((Uint32 *)(src));
|
||||
switch (src_fmt->format) {
|
||||
case SDL_PIXELFORMAT_XRGB2101010:
|
||||
RGBA_FROM_ARGB2101010(srcpixel, srcR, srcG, srcB, srcA);
|
||||
srcA = 0xFF;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_XBGR2101010:
|
||||
RGBA_FROM_ABGR2101010(srcpixel, srcR, srcG, srcB, srcA);
|
||||
srcA = 0xFF;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_ARGB2101010:
|
||||
RGBA_FROM_ARGB2101010(srcpixel, srcR, srcG, srcB, srcA);
|
||||
break;
|
||||
case SDL_PIXELFORMAT_ABGR2101010:
|
||||
RGBA_FROM_ABGR2101010(srcpixel, srcR, srcG, srcB, srcA);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SlowBlitPixelAccess_Large:
|
||||
// Handled in SDL_Blit_Slow_Float()
|
||||
break;
|
||||
}
|
||||
|
||||
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 (flags & SDL_COPY_BLEND_MASK) {
|
||||
switch (dst_access) {
|
||||
case SlowBlitPixelAccess_Index8:
|
||||
dstpixel = *dst;
|
||||
dstR = dst_pal->colors[dstpixel].r;
|
||||
dstG = dst_pal->colors[dstpixel].g;
|
||||
dstB = dst_pal->colors[dstpixel].b;
|
||||
dstA = dst_pal->colors[dstpixel].a;
|
||||
break;
|
||||
case SlowBlitPixelAccess_RGB:
|
||||
DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB);
|
||||
dstA = 0xFF;
|
||||
break;
|
||||
case SlowBlitPixelAccess_RGBA:
|
||||
DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA);
|
||||
break;
|
||||
case SlowBlitPixelAccess_10Bit:
|
||||
dstpixel = *((Uint32 *)(dst));
|
||||
switch (dst_fmt->format) {
|
||||
case SDL_PIXELFORMAT_XRGB2101010:
|
||||
RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA);
|
||||
dstA = 0xFF;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_XBGR2101010:
|
||||
RGBA_FROM_ABGR2101010(dstpixel, dstR, dstG, dstB, dstA);
|
||||
dstA = 0xFF;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_ARGB2101010:
|
||||
RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA);
|
||||
break;
|
||||
case SDL_PIXELFORMAT_ABGR2101010:
|
||||
RGBA_FROM_ABGR2101010(dstpixel, dstR, dstG, dstB, dstA);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SlowBlitPixelAccess_Large:
|
||||
// Handled in SDL_Blit_Slow_Float()
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// don't care
|
||||
}
|
||||
|
||||
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)) {
|
||||
if (srcA < 255) {
|
||||
srcR = (srcR * srcA) / 255;
|
||||
srcG = (srcG * srcA) / 255;
|
||||
srcB = (srcB * srcA) / 255;
|
||||
}
|
||||
}
|
||||
switch (flags & SDL_COPY_BLEND_MASK) {
|
||||
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_BLEND_PREMULTIPLIED:
|
||||
dstR = srcR + ((255 - srcA) * dstR) / 255;
|
||||
if (dstR > 255) {
|
||||
dstR = 255;
|
||||
}
|
||||
dstG = srcG + ((255 - srcA) * dstG) / 255;
|
||||
if (dstG > 255) {
|
||||
dstG = 255;
|
||||
}
|
||||
dstB = srcB + ((255 - srcA) * dstB) / 255;
|
||||
if (dstB > 255) {
|
||||
dstB = 255;
|
||||
}
|
||||
dstA = srcA + ((255 - srcA) * dstA) / 255;
|
||||
if (dstA > 255) {
|
||||
dstA = 255;
|
||||
}
|
||||
break;
|
||||
case SDL_COPY_ADD:
|
||||
case SDL_COPY_ADD_PREMULTIPLIED:
|
||||
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;
|
||||
}
|
||||
|
||||
switch (dst_access) {
|
||||
case SlowBlitPixelAccess_Index8:
|
||||
dstpixel = ((dstR << 24) | (dstG << 16) | (dstB << 8) | dstA);
|
||||
if (dstpixel != last_pixel) {
|
||||
last_pixel = dstpixel;
|
||||
last_index = SDL_LookupRGBAColor(palette_map, dstpixel, dst_pal);
|
||||
}
|
||||
*dst = last_index;
|
||||
break;
|
||||
case SlowBlitPixelAccess_RGB:
|
||||
ASSEMBLE_RGB(dst, dstbpp, dst_fmt, dstR, dstG, dstB);
|
||||
break;
|
||||
case SlowBlitPixelAccess_RGBA:
|
||||
ASSEMBLE_RGBA(dst, dstbpp, dst_fmt, dstR, dstG, dstB, dstA);
|
||||
break;
|
||||
case SlowBlitPixelAccess_10Bit:
|
||||
{
|
||||
Uint32 pixelvalue;
|
||||
switch (dst_fmt->format) {
|
||||
case SDL_PIXELFORMAT_XRGB2101010:
|
||||
dstA = 0xFF;
|
||||
SDL_FALLTHROUGH;
|
||||
case SDL_PIXELFORMAT_ARGB2101010:
|
||||
ARGB2101010_FROM_RGBA(pixelvalue, dstR, dstG, dstB, dstA);
|
||||
break;
|
||||
case SDL_PIXELFORMAT_XBGR2101010:
|
||||
dstA = 0xFF;
|
||||
SDL_FALLTHROUGH;
|
||||
case SDL_PIXELFORMAT_ABGR2101010:
|
||||
ABGR2101010_FROM_RGBA(pixelvalue, dstR, dstG, dstB, dstA);
|
||||
break;
|
||||
default:
|
||||
pixelvalue = 0;
|
||||
break;
|
||||
}
|
||||
*(Uint32 *)dst = pixelvalue;
|
||||
break;
|
||||
}
|
||||
case SlowBlitPixelAccess_Large:
|
||||
// Handled in SDL_Blit_Slow_Float()
|
||||
break;
|
||||
}
|
||||
|
||||
posx += incx;
|
||||
dst += dstbpp;
|
||||
}
|
||||
posy += incy;
|
||||
info->dst += info->dst_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert from F16 to float
|
||||
* Public domain implementation from https://gist.github.com/rygorous/2144712
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
Uint32 u;
|
||||
float f;
|
||||
struct
|
||||
{
|
||||
Uint32 Mantissa : 23;
|
||||
Uint32 Exponent : 8;
|
||||
Uint32 Sign : 1;
|
||||
} x;
|
||||
} FP32;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4214)
|
||||
#endif
|
||||
|
||||
typedef union
|
||||
{
|
||||
Uint16 u;
|
||||
struct
|
||||
{
|
||||
Uint16 Mantissa : 10;
|
||||
Uint16 Exponent : 5;
|
||||
Uint16 Sign : 1;
|
||||
} x;
|
||||
} FP16;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
static float half_to_float(Uint16 unValue)
|
||||
{
|
||||
static const FP32 magic = { (254 - 15) << 23 };
|
||||
static const FP32 was_infnan = { (127 + 16) << 23 };
|
||||
FP16 h;
|
||||
FP32 o;
|
||||
|
||||
h.u = unValue;
|
||||
o.u = (h.u & 0x7fff) << 13; // exponent/mantissa bits
|
||||
o.f *= magic.f; // exponent adjust
|
||||
if (o.f >= was_infnan.f) // make sure Inf/NaN survive
|
||||
o.u |= 255 << 23;
|
||||
o.u |= (h.u & 0x8000) << 16; // sign bit
|
||||
return o.f;
|
||||
}
|
||||
|
||||
/* Convert from float to F16
|
||||
* Public domain implementation from https://stackoverflow.com/questions/76799117/how-to-convert-a-float-to-a-half-type-and-the-other-way-around-in-c
|
||||
*/
|
||||
static Uint16 float_to_half(float a)
|
||||
{
|
||||
Uint32 ia;
|
||||
Uint16 ir;
|
||||
|
||||
SDL_memcpy(&ia, &a, sizeof(ia));
|
||||
|
||||
ir = (ia >> 16) & 0x8000;
|
||||
if ((ia & 0x7f800000) == 0x7f800000) {
|
||||
if ((ia & 0x7fffffff) == 0x7f800000) {
|
||||
ir |= 0x7c00; // infinity
|
||||
} else {
|
||||
ir |= 0x7e00 | ((ia >> (24 - 11)) & 0x1ff); // NaN, quietened
|
||||
}
|
||||
} else if ((ia & 0x7f800000) >= 0x33000000) {
|
||||
int shift = (int)((ia >> 23) & 0xff) - 127;
|
||||
if (shift > 15) {
|
||||
ir |= 0x7c00; // infinity
|
||||
} else {
|
||||
ia = (ia & 0x007fffff) | 0x00800000; // extract mantissa
|
||||
if (shift < -14) { // denormal
|
||||
ir |= ia >> (-1 - shift);
|
||||
ia = ia << (32 - (-1 - shift));
|
||||
} else { // normal
|
||||
ir |= ia >> (24 - 11);
|
||||
ia = ia << (32 - (24 - 11));
|
||||
ir = ir + ((14 + shift) << 10);
|
||||
}
|
||||
// IEEE-754 round to nearest of even
|
||||
if ((ia > 0x80000000) || ((ia == 0x80000000) && (ir & 1))) {
|
||||
ir++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ir;
|
||||
}
|
||||
|
||||
static void ReadFloatPixel(Uint8 *pixels, SlowBlitPixelAccess access, const SDL_PixelFormatDetails *fmt, const SDL_Palette *pal, SDL_Colorspace colorspace, float SDR_white_point,
|
||||
float *outR, float *outG, float *outB, float *outA)
|
||||
{
|
||||
Uint32 pixelvalue;
|
||||
Uint32 R, G, B, A;
|
||||
float fR = 0.0f, fG = 0.0f, fB = 0.0f, fA = 0.0f;
|
||||
float v[4];
|
||||
|
||||
switch (access) {
|
||||
case SlowBlitPixelAccess_Index8:
|
||||
pixelvalue = *pixels;
|
||||
fR = (float)pal->colors[pixelvalue].r / 255.0f;
|
||||
fG = (float)pal->colors[pixelvalue].g / 255.0f;
|
||||
fB = (float)pal->colors[pixelvalue].b / 255.0f;
|
||||
fA = (float)pal->colors[pixelvalue].a / 255.0f;
|
||||
break;
|
||||
case SlowBlitPixelAccess_RGB:
|
||||
DISEMBLE_RGB(pixels, fmt->bytes_per_pixel, fmt, pixelvalue, R, G, B);
|
||||
fR = (float)R / 255.0f;
|
||||
fG = (float)G / 255.0f;
|
||||
fB = (float)B / 255.0f;
|
||||
fA = 1.0f;
|
||||
break;
|
||||
case SlowBlitPixelAccess_RGBA:
|
||||
DISEMBLE_RGBA(pixels, fmt->bytes_per_pixel, fmt, pixelvalue, R, G, B, A);
|
||||
fR = (float)R / 255.0f;
|
||||
fG = (float)G / 255.0f;
|
||||
fB = (float)B / 255.0f;
|
||||
fA = (float)A / 255.0f;
|
||||
break;
|
||||
case SlowBlitPixelAccess_10Bit:
|
||||
pixelvalue = *((Uint32 *)pixels);
|
||||
switch (fmt->format) {
|
||||
case SDL_PIXELFORMAT_XRGB2101010:
|
||||
RGBAFLOAT_FROM_ARGB2101010(pixelvalue, fR, fG, fB, fA);
|
||||
fA = 1.0f;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_XBGR2101010:
|
||||
RGBAFLOAT_FROM_ABGR2101010(pixelvalue, fR, fG, fB, fA);
|
||||
fA = 1.0f;
|
||||
break;
|
||||
case SDL_PIXELFORMAT_ARGB2101010:
|
||||
RGBAFLOAT_FROM_ARGB2101010(pixelvalue, fR, fG, fB, fA);
|
||||
break;
|
||||
case SDL_PIXELFORMAT_ABGR2101010:
|
||||
RGBAFLOAT_FROM_ABGR2101010(pixelvalue, fR, fG, fB, fA);
|
||||
break;
|
||||
default:
|
||||
fR = fG = fB = fA = 0.0f;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SlowBlitPixelAccess_Large:
|
||||
switch (SDL_PIXELTYPE(fmt->format)) {
|
||||
case SDL_PIXELTYPE_ARRAYU16:
|
||||
v[0] = (float)(((Uint16 *)pixels)[0]) / SDL_MAX_UINT16;
|
||||
v[1] = (float)(((Uint16 *)pixels)[1]) / SDL_MAX_UINT16;
|
||||
v[2] = (float)(((Uint16 *)pixels)[2]) / SDL_MAX_UINT16;
|
||||
if (fmt->bytes_per_pixel == 8) {
|
||||
v[3] = (float)(((Uint16 *)pixels)[3]) / SDL_MAX_UINT16;
|
||||
} else {
|
||||
v[3] = 1.0f;
|
||||
}
|
||||
break;
|
||||
case SDL_PIXELTYPE_ARRAYF16:
|
||||
v[0] = half_to_float(((Uint16 *)pixels)[0]);
|
||||
v[1] = half_to_float(((Uint16 *)pixels)[1]);
|
||||
v[2] = half_to_float(((Uint16 *)pixels)[2]);
|
||||
if (fmt->bytes_per_pixel == 8) {
|
||||
v[3] = half_to_float(((Uint16 *)pixels)[3]);
|
||||
} else {
|
||||
v[3] = 1.0f;
|
||||
}
|
||||
break;
|
||||
case SDL_PIXELTYPE_ARRAYF32:
|
||||
v[0] = ((float *)pixels)[0];
|
||||
v[1] = ((float *)pixels)[1];
|
||||
v[2] = ((float *)pixels)[2];
|
||||
if (fmt->bytes_per_pixel == 16) {
|
||||
v[3] = ((float *)pixels)[3];
|
||||
} else {
|
||||
v[3] = 1.0f;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Unknown array type
|
||||
v[0] = v[1] = v[2] = v[3] = 0.0f;
|
||||
break;
|
||||
}
|
||||
switch (SDL_PIXELORDER(fmt->format)) {
|
||||
case SDL_ARRAYORDER_RGB:
|
||||
fR = v[0];
|
||||
fG = v[1];
|
||||
fB = v[2];
|
||||
fA = 1.0f;
|
||||
break;
|
||||
case SDL_ARRAYORDER_RGBA:
|
||||
fR = v[0];
|
||||
fG = v[1];
|
||||
fB = v[2];
|
||||
fA = v[3];
|
||||
break;
|
||||
case SDL_ARRAYORDER_ARGB:
|
||||
fA = v[0];
|
||||
fR = v[1];
|
||||
fG = v[2];
|
||||
fB = v[3];
|
||||
break;
|
||||
case SDL_ARRAYORDER_BGR:
|
||||
fB = v[0];
|
||||
fG = v[1];
|
||||
fR = v[2];
|
||||
fA = 1.0f;
|
||||
break;
|
||||
case SDL_ARRAYORDER_BGRA:
|
||||
fB = v[0];
|
||||
fG = v[1];
|
||||
fR = v[2];
|
||||
fA = v[3];
|
||||
break;
|
||||
case SDL_ARRAYORDER_ABGR:
|
||||
fA = v[0];
|
||||
fB = v[1];
|
||||
fG = v[2];
|
||||
fR = v[3];
|
||||
break;
|
||||
default:
|
||||
// Unknown array order
|
||||
fA = fR = fG = fB = 0.0f;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Convert to nits so src and dst are guaranteed to be linear and in the same units
|
||||
switch (SDL_COLORSPACETRANSFER(colorspace)) {
|
||||
case SDL_TRANSFER_CHARACTERISTICS_SRGB:
|
||||
fR = SDL_sRGBtoLinear(fR);
|
||||
fG = SDL_sRGBtoLinear(fG);
|
||||
fB = SDL_sRGBtoLinear(fB);
|
||||
break;
|
||||
case SDL_TRANSFER_CHARACTERISTICS_PQ:
|
||||
fR = SDL_PQtoNits(fR) / SDR_white_point;
|
||||
fG = SDL_PQtoNits(fG) / SDR_white_point;
|
||||
fB = SDL_PQtoNits(fB) / SDR_white_point;
|
||||
break;
|
||||
case SDL_TRANSFER_CHARACTERISTICS_LINEAR:
|
||||
fR /= SDR_white_point;
|
||||
fG /= SDR_white_point;
|
||||
fB /= SDR_white_point;
|
||||
break;
|
||||
default:
|
||||
// Unknown, leave it alone
|
||||
break;
|
||||
}
|
||||
|
||||
*outR = fR;
|
||||
*outG = fG;
|
||||
*outB = fB;
|
||||
*outA = fA;
|
||||
}
|
||||
|
||||
static void WriteFloatPixel(Uint8 *pixels, SlowBlitPixelAccess access, const SDL_PixelFormatDetails *fmt, SDL_Colorspace colorspace, float SDR_white_point,
|
||||
float fR, float fG, float fB, float fA)
|
||||
{
|
||||
Uint32 R, G, B, A;
|
||||
Uint32 pixelvalue;
|
||||
float v[4];
|
||||
|
||||
// We converted to nits so src and dst are guaranteed to be linear and in the same units
|
||||
switch (SDL_COLORSPACETRANSFER(colorspace)) {
|
||||
case SDL_TRANSFER_CHARACTERISTICS_SRGB:
|
||||
fR = SDL_sRGBfromLinear(fR);
|
||||
fG = SDL_sRGBfromLinear(fG);
|
||||
fB = SDL_sRGBfromLinear(fB);
|
||||
break;
|
||||
case SDL_TRANSFER_CHARACTERISTICS_PQ:
|
||||
fR = SDL_PQfromNits(fR * SDR_white_point);
|
||||
fG = SDL_PQfromNits(fG * SDR_white_point);
|
||||
fB = SDL_PQfromNits(fB * SDR_white_point);
|
||||
break;
|
||||
case SDL_TRANSFER_CHARACTERISTICS_LINEAR:
|
||||
fR *= SDR_white_point;
|
||||
fG *= SDR_white_point;
|
||||
fB *= SDR_white_point;
|
||||
break;
|
||||
default:
|
||||
// Unknown, leave it alone
|
||||
break;
|
||||
}
|
||||
|
||||
switch (access) {
|
||||
case SlowBlitPixelAccess_Index8:
|
||||
// This should never happen, checked before this call
|
||||
SDL_assert(0);
|
||||
break;
|
||||
case SlowBlitPixelAccess_RGB:
|
||||
R = (Uint8)SDL_roundf(SDL_clamp(fR, 0.0f, 1.0f) * 255.0f);
|
||||
G = (Uint8)SDL_roundf(SDL_clamp(fG, 0.0f, 1.0f) * 255.0f);
|
||||
B = (Uint8)SDL_roundf(SDL_clamp(fB, 0.0f, 1.0f) * 255.0f);
|
||||
ASSEMBLE_RGB(pixels, fmt->bytes_per_pixel, fmt, R, G, B);
|
||||
break;
|
||||
case SlowBlitPixelAccess_RGBA:
|
||||
R = (Uint8)SDL_roundf(SDL_clamp(fR, 0.0f, 1.0f) * 255.0f);
|
||||
G = (Uint8)SDL_roundf(SDL_clamp(fG, 0.0f, 1.0f) * 255.0f);
|
||||
B = (Uint8)SDL_roundf(SDL_clamp(fB, 0.0f, 1.0f) * 255.0f);
|
||||
A = (Uint8)SDL_roundf(SDL_clamp(fA, 0.0f, 1.0f) * 255.0f);
|
||||
ASSEMBLE_RGBA(pixels, fmt->bytes_per_pixel, fmt, R, G, B, A);
|
||||
break;
|
||||
case SlowBlitPixelAccess_10Bit:
|
||||
{
|
||||
switch (fmt->format) {
|
||||
case SDL_PIXELFORMAT_XRGB2101010:
|
||||
fA = 1.0f;
|
||||
SDL_FALLTHROUGH;
|
||||
case SDL_PIXELFORMAT_ARGB2101010:
|
||||
ARGB2101010_FROM_RGBAFLOAT(pixelvalue, fR, fG, fB, fA);
|
||||
break;
|
||||
case SDL_PIXELFORMAT_XBGR2101010:
|
||||
fA = 1.0f;
|
||||
SDL_FALLTHROUGH;
|
||||
case SDL_PIXELFORMAT_ABGR2101010:
|
||||
ABGR2101010_FROM_RGBAFLOAT(pixelvalue, fR, fG, fB, fA);
|
||||
break;
|
||||
default:
|
||||
pixelvalue = 0;
|
||||
break;
|
||||
}
|
||||
*(Uint32 *)pixels = pixelvalue;
|
||||
break;
|
||||
}
|
||||
case SlowBlitPixelAccess_Large:
|
||||
switch (SDL_PIXELORDER(fmt->format)) {
|
||||
case SDL_ARRAYORDER_RGB:
|
||||
v[0] = fR;
|
||||
v[1] = fG;
|
||||
v[2] = fB;
|
||||
v[3] = 1.0f;
|
||||
break;
|
||||
case SDL_ARRAYORDER_RGBA:
|
||||
v[0] = fR;
|
||||
v[1] = fG;
|
||||
v[2] = fB;
|
||||
v[3] = fA;
|
||||
break;
|
||||
case SDL_ARRAYORDER_ARGB:
|
||||
v[0] = fA;
|
||||
v[1] = fR;
|
||||
v[2] = fG;
|
||||
v[3] = fB;
|
||||
break;
|
||||
case SDL_ARRAYORDER_BGR:
|
||||
v[0] = fB;
|
||||
v[1] = fG;
|
||||
v[2] = fR;
|
||||
v[3] = 1.0f;
|
||||
break;
|
||||
case SDL_ARRAYORDER_BGRA:
|
||||
v[0] = fB;
|
||||
v[1] = fG;
|
||||
v[2] = fR;
|
||||
v[3] = fA;
|
||||
break;
|
||||
case SDL_ARRAYORDER_ABGR:
|
||||
v[0] = fA;
|
||||
v[1] = fB;
|
||||
v[2] = fG;
|
||||
v[3] = fR;
|
||||
break;
|
||||
default:
|
||||
// Unknown array order
|
||||
v[0] = v[1] = v[2] = v[3] = 0.0f;
|
||||
break;
|
||||
}
|
||||
switch (SDL_PIXELTYPE(fmt->format)) {
|
||||
case SDL_PIXELTYPE_ARRAYU16:
|
||||
((Uint16 *)pixels)[0] = (Uint16)SDL_roundf(SDL_clamp(v[0], 0.0f, 1.0f) * SDL_MAX_UINT16);
|
||||
((Uint16 *)pixels)[1] = (Uint16)SDL_roundf(SDL_clamp(v[1], 0.0f, 1.0f) * SDL_MAX_UINT16);
|
||||
((Uint16 *)pixels)[2] = (Uint16)SDL_roundf(SDL_clamp(v[2], 0.0f, 1.0f) * SDL_MAX_UINT16);
|
||||
if (fmt->bytes_per_pixel == 8) {
|
||||
((Uint16 *)pixels)[3] = (Uint16)SDL_roundf(SDL_clamp(v[3], 0.0f, 1.0f) * SDL_MAX_UINT16);
|
||||
}
|
||||
break;
|
||||
case SDL_PIXELTYPE_ARRAYF16:
|
||||
((Uint16 *)pixels)[0] = float_to_half(v[0]);
|
||||
((Uint16 *)pixels)[1] = float_to_half(v[1]);
|
||||
((Uint16 *)pixels)[2] = float_to_half(v[2]);
|
||||
if (fmt->bytes_per_pixel == 8) {
|
||||
((Uint16 *)pixels)[3] = float_to_half(v[3]);
|
||||
}
|
||||
break;
|
||||
case SDL_PIXELTYPE_ARRAYF32:
|
||||
((float *)pixels)[0] = v[0];
|
||||
((float *)pixels)[1] = v[1];
|
||||
((float *)pixels)[2] = v[2];
|
||||
if (fmt->bytes_per_pixel == 16) {
|
||||
((float *)pixels)[3] = v[3];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Unknown array type
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SDL_TONEMAP_NONE,
|
||||
SDL_TONEMAP_LINEAR,
|
||||
SDL_TONEMAP_CHROME
|
||||
} SDL_TonemapOperator;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_TonemapOperator op;
|
||||
|
||||
union {
|
||||
struct {
|
||||
float scale;
|
||||
} linear;
|
||||
|
||||
struct {
|
||||
float a;
|
||||
float b;
|
||||
const float *color_primaries_matrix;
|
||||
} chrome;
|
||||
|
||||
} data;
|
||||
|
||||
} SDL_TonemapContext;
|
||||
|
||||
static void TonemapLinear(float *r, float *g, float *b, float scale)
|
||||
{
|
||||
*r *= scale;
|
||||
*g *= scale;
|
||||
*b *= scale;
|
||||
}
|
||||
|
||||
/* This uses the same tonemapping algorithm developed by Google for Chrome:
|
||||
* https://colab.research.google.com/drive/1hI10nq6L6ru_UFvz7-f7xQaQp0qarz_K
|
||||
*
|
||||
* Essentially, you use the source headroom and the destination headroom
|
||||
* to calculate scaling factors:
|
||||
* tonemap_a = (dst_headroom / (src_headroom * src_headroom));
|
||||
* tonemap_b = (1.0f / dst_headroom);
|
||||
*
|
||||
* Then you normalize your source color by the HDR whitepoint,
|
||||
* and calculate a final scaling factor in BT.2020 colorspace.
|
||||
*/
|
||||
static void TonemapChrome(float *r, float *g, float *b, float tonemap_a, float tonemap_b)
|
||||
{
|
||||
float v1 = *r;
|
||||
float v2 = *g;
|
||||
float v3 = *b;
|
||||
float vmax = SDL_max(v1, SDL_max(v2, v3));
|
||||
|
||||
if (vmax > 0.0f) {
|
||||
float scale = (1.0f + tonemap_a * vmax) / (1.0f + tonemap_b * vmax);
|
||||
TonemapLinear(r, g, b, scale);
|
||||
}
|
||||
}
|
||||
|
||||
static void ApplyTonemap(SDL_TonemapContext *ctx, float *r, float *g, float *b)
|
||||
{
|
||||
switch (ctx->op) {
|
||||
case SDL_TONEMAP_LINEAR:
|
||||
TonemapLinear(r, g, b, ctx->data.linear.scale);
|
||||
break;
|
||||
case SDL_TONEMAP_CHROME:
|
||||
if (ctx->data.chrome.color_primaries_matrix) {
|
||||
SDL_ConvertColorPrimaries(r, g, b, ctx->data.chrome.color_primaries_matrix);
|
||||
}
|
||||
TonemapChrome(r, g, b, ctx->data.chrome.a, ctx->data.chrome.b);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The SECOND TRUE BLITTER
|
||||
* This one is even slower than the first, but also handles large pixel formats and colorspace conversion
|
||||
*/
|
||||
void SDL_Blit_Slow_Float(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;
|
||||
float srcR, srcG, srcB, srcA;
|
||||
float dstR, dstG, dstB, dstA;
|
||||
Uint64 srcy, srcx;
|
||||
Uint64 posy, posx;
|
||||
Uint64 incy, incx;
|
||||
const SDL_PixelFormatDetails *src_fmt = info->src_fmt;
|
||||
const SDL_Palette *src_pal = info->src_pal;
|
||||
const SDL_PixelFormatDetails *dst_fmt = info->dst_fmt;
|
||||
const SDL_Palette *dst_pal = info->dst_pal;
|
||||
SDL_HashTable *palette_map = info->palette_map;
|
||||
int srcbpp = src_fmt->bytes_per_pixel;
|
||||
int dstbpp = dst_fmt->bytes_per_pixel;
|
||||
SlowBlitPixelAccess src_access;
|
||||
SlowBlitPixelAccess dst_access;
|
||||
SDL_Colorspace src_colorspace;
|
||||
SDL_Colorspace dst_colorspace;
|
||||
SDL_ColorPrimaries src_primaries;
|
||||
SDL_ColorPrimaries dst_primaries;
|
||||
const float *color_primaries_matrix = NULL;
|
||||
float src_white_point;
|
||||
float dst_white_point;
|
||||
float dst_headroom;
|
||||
float src_headroom;
|
||||
SDL_TonemapContext tonemap;
|
||||
Uint32 last_pixel = 0;
|
||||
Uint8 last_index = 0;
|
||||
|
||||
src_colorspace = info->src_surface->colorspace;
|
||||
dst_colorspace = info->dst_surface->colorspace;
|
||||
src_primaries = SDL_COLORSPACEPRIMARIES(src_colorspace);
|
||||
dst_primaries = SDL_COLORSPACEPRIMARIES(dst_colorspace);
|
||||
|
||||
src_white_point = SDL_GetSurfaceSDRWhitePoint(info->src_surface, src_colorspace);
|
||||
dst_white_point = SDL_GetSurfaceSDRWhitePoint(info->dst_surface, dst_colorspace);
|
||||
src_headroom = SDL_GetSurfaceHDRHeadroom(info->src_surface, src_colorspace);
|
||||
dst_headroom = SDL_GetSurfaceHDRHeadroom(info->dst_surface, dst_colorspace);
|
||||
if (dst_headroom == 0.0f) {
|
||||
// The destination will have the same headroom as the source
|
||||
dst_headroom = src_headroom;
|
||||
SDL_SetFloatProperty(SDL_GetSurfaceProperties(info->dst_surface), SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT, dst_headroom);
|
||||
}
|
||||
|
||||
SDL_zero(tonemap);
|
||||
|
||||
if (src_headroom > dst_headroom) {
|
||||
const char *tonemap_operator = SDL_GetStringProperty(SDL_GetSurfaceProperties(info->src_surface), SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING, NULL);
|
||||
if (tonemap_operator) {
|
||||
if (SDL_strncmp(tonemap_operator, "*=", 2) == 0) {
|
||||
tonemap.op = SDL_TONEMAP_LINEAR;
|
||||
tonemap.data.linear.scale = (float)SDL_atof(tonemap_operator + 2);
|
||||
} else if (SDL_strcasecmp(tonemap_operator, "chrome") == 0) {
|
||||
tonemap.op = SDL_TONEMAP_CHROME;
|
||||
} else if (SDL_strcasecmp(tonemap_operator, "none") == 0) {
|
||||
tonemap.op = SDL_TONEMAP_NONE;
|
||||
}
|
||||
} else {
|
||||
tonemap.op = SDL_TONEMAP_CHROME;
|
||||
}
|
||||
if (tonemap.op == SDL_TONEMAP_CHROME) {
|
||||
tonemap.data.chrome.a = (dst_headroom / (src_headroom * src_headroom));
|
||||
tonemap.data.chrome.b = (1.0f / dst_headroom);
|
||||
|
||||
// We'll convert to BT.2020 primaries for the tonemap operation
|
||||
tonemap.data.chrome.color_primaries_matrix = SDL_GetColorPrimariesConversionMatrix(src_primaries, SDL_COLOR_PRIMARIES_BT2020);
|
||||
if (tonemap.data.chrome.color_primaries_matrix) {
|
||||
src_primaries = SDL_COLOR_PRIMARIES_BT2020;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (src_primaries != dst_primaries) {
|
||||
color_primaries_matrix = SDL_GetColorPrimariesConversionMatrix(src_primaries, dst_primaries);
|
||||
}
|
||||
|
||||
src_access = GetPixelAccessMethod(src_fmt->format);
|
||||
dst_access = GetPixelAccessMethod(dst_fmt->format);
|
||||
if (dst_access == SlowBlitPixelAccess_Index8) {
|
||||
last_index = SDL_LookupRGBAColor(palette_map, last_pixel, dst_pal);
|
||||
}
|
||||
|
||||
incy = ((Uint64)info->src_h << 16) / info->dst_h;
|
||||
incx = ((Uint64)info->src_w << 16) / info->dst_w;
|
||||
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));
|
||||
|
||||
ReadFloatPixel(src, src_access, src_fmt, src_pal, src_colorspace, src_white_point, &srcR, &srcG, &srcB, &srcA);
|
||||
|
||||
if (tonemap.op) {
|
||||
ApplyTonemap(&tonemap, &srcR, &srcG, &srcB);
|
||||
}
|
||||
|
||||
if (color_primaries_matrix) {
|
||||
SDL_ConvertColorPrimaries(&srcR, &srcG, &srcB, color_primaries_matrix);
|
||||
}
|
||||
|
||||
if (flags & SDL_COPY_COLORKEY) {
|
||||
// colorkey isn't supported
|
||||
}
|
||||
if ((flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL))) {
|
||||
ReadFloatPixel(dst, dst_access, dst_fmt, dst_pal, dst_colorspace, dst_white_point, &dstR, &dstG, &dstB, &dstA);
|
||||
} else {
|
||||
// don't care
|
||||
dstR = dstG = dstB = dstA = 0.0f;
|
||||
}
|
||||
|
||||
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)) {
|
||||
if (srcA < 1.0f) {
|
||||
srcR = (srcR * srcA);
|
||||
srcG = (srcG * srcA);
|
||||
srcB = (srcB * srcA);
|
||||
}
|
||||
}
|
||||
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 + ((1.0f - srcA) * dstR);
|
||||
dstG = srcG + ((1.0f - srcA) * dstG);
|
||||
dstB = srcB + ((1.0f - srcA) * dstB);
|
||||
dstA = srcA + ((1.0f - srcA) * dstA);
|
||||
break;
|
||||
case SDL_COPY_ADD:
|
||||
dstR = srcR + dstR;
|
||||
dstG = srcG + dstG;
|
||||
dstB = srcB + dstB;
|
||||
break;
|
||||
case SDL_COPY_MOD:
|
||||
dstR = (srcR * dstR);
|
||||
dstG = (srcG * dstG);
|
||||
dstB = (srcB * dstB);
|
||||
break;
|
||||
case SDL_COPY_MUL:
|
||||
dstR = ((srcR * dstR) + (dstR * (1.0f - srcA)));
|
||||
dstG = ((srcG * dstG) + (dstG * (1.0f - srcA)));
|
||||
dstB = ((srcB * dstB) + (dstB * (1.0f - srcA)));
|
||||
break;
|
||||
}
|
||||
|
||||
if (dst_access == SlowBlitPixelAccess_Index8) {
|
||||
Uint32 R = (Uint8)SDL_roundf(SDL_clamp(SDL_sRGBfromLinear(dstR), 0.0f, 1.0f) * 255.0f);
|
||||
Uint32 G = (Uint8)SDL_roundf(SDL_clamp(SDL_sRGBfromLinear(dstG), 0.0f, 1.0f) * 255.0f);
|
||||
Uint32 B = (Uint8)SDL_roundf(SDL_clamp(SDL_sRGBfromLinear(dstB), 0.0f, 1.0f) * 255.0f);
|
||||
Uint32 A = (Uint8)SDL_roundf(SDL_clamp(dstA, 0.0f, 1.0f) * 255.0f);
|
||||
Uint32 dstpixel = ((R << 24) | (G << 16) | (B << 8) | A);
|
||||
if (dstpixel != last_pixel) {
|
||||
last_pixel = dstpixel;
|
||||
last_index = SDL_LookupRGBAColor(palette_map, dstpixel, dst_pal);
|
||||
}
|
||||
*dst = last_index;
|
||||
} else {
|
||||
WriteFloatPixel(dst, dst_access, dst_fmt, dst_colorspace, dst_white_point, dstR, dstG, dstB, dstA);
|
||||
}
|
||||
|
||||
posx += incx;
|
||||
dst += dstbpp;
|
||||
}
|
||||
posy += incy;
|
||||
info->dst += info->dst_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_blit_slow_h_
|
||||
#define SDL_blit_slow_h_
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
extern void SDL_Blit_Slow(SDL_BlitInfo *info);
|
||||
extern void SDL_Blit_Slow_Float(SDL_BlitInfo *info);
|
||||
|
||||
#endif // SDL_blit_slow_h_
|
||||
@@ -0,0 +1,879 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
/*
|
||||
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"
|
||||
#include "SDL_surface_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
|
||||
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/eb4bbd50-b3ce-4917-895c-be31f214797f
|
||||
#ifndef LCS_WINDOWS_COLOR_SPACE
|
||||
// 0x57696E20 == "Win "
|
||||
#define LCS_WINDOWS_COLOR_SPACE 0x57696E20
|
||||
#endif
|
||||
|
||||
#ifndef LCS_sRGB
|
||||
// 0x73524742 == "sRGB"
|
||||
#define LCS_sRGB 0x73524742
|
||||
#endif
|
||||
|
||||
// Logical/physical color relationship
|
||||
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/9fec0834-607d-427d-abd5-ab240fb0db38
|
||||
#ifndef LCS_GM_GRAPHICS
|
||||
#define LCS_GM_GRAPHICS 0x00000002
|
||||
#endif
|
||||
|
||||
static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *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;
|
||||
const int pixels_per_byte = (isRle8 ? 1 : 2);
|
||||
|
||||
#define COPY_PIXEL(x) \
|
||||
spot = &bits[ofs++]; \
|
||||
if (spot >= start && spot < end) \
|
||||
*spot = (x)
|
||||
|
||||
for (;;) {
|
||||
if (!SDL_ReadU8(src, &ch)) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
| encoded mode starts with a run length, and then a byte
|
||||
| with two colour indexes to alternate between for the run
|
||||
*/
|
||||
if (ch) {
|
||||
Uint8 pixelvalue;
|
||||
if (!SDL_ReadU8(src, &pixelvalue)) {
|
||||
return false;
|
||||
}
|
||||
ch /= pixels_per_byte;
|
||||
do {
|
||||
COPY_PIXEL(pixelvalue);
|
||||
} while (--ch);
|
||||
} 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_ReadU8(src, &ch)) {
|
||||
return false;
|
||||
}
|
||||
switch (ch) {
|
||||
case 0: // end of line
|
||||
ofs = 0;
|
||||
bits -= pitch; // go to previous
|
||||
break;
|
||||
case 1: // end of bitmap
|
||||
return true; // success!
|
||||
case 2: // delta
|
||||
if (!SDL_ReadU8(src, &ch)) {
|
||||
return false;
|
||||
}
|
||||
ofs += ch / pixels_per_byte;
|
||||
|
||||
if (!SDL_ReadU8(src, &ch)) {
|
||||
return false;
|
||||
}
|
||||
bits -= ((ch / pixels_per_byte) * pitch);
|
||||
break;
|
||||
default: // no compression
|
||||
ch /= pixels_per_byte;
|
||||
needsPad = (ch & 1);
|
||||
do {
|
||||
Uint8 pixelvalue;
|
||||
if (!SDL_ReadU8(src, &pixelvalue)) {
|
||||
return false;
|
||||
}
|
||||
COPY_PIXEL(pixelvalue);
|
||||
} while (--ch);
|
||||
|
||||
// pad at even boundary
|
||||
if (needsPad && !SDL_ReadU8(src, &ch)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CorrectAlphaChannel(SDL_Surface *surface)
|
||||
{
|
||||
// Check to see if there is any alpha channel data
|
||||
bool hasAlpha = 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 = true;
|
||||
break;
|
||||
}
|
||||
alpha += 4;
|
||||
}
|
||||
|
||||
if (!hasAlpha) {
|
||||
alpha = ((Uint8 *)surface->pixels) + alphaChannelOffset;
|
||||
while (alpha < end) {
|
||||
*alpha = SDL_ALPHA_OPAQUE;
|
||||
alpha += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Surface *SDL_LoadBMP_IO(SDL_IOStream *src, bool closeio)
|
||||
{
|
||||
bool was_error = true;
|
||||
Sint64 fp_offset = 0;
|
||||
int i, pad;
|
||||
SDL_Surface *surface;
|
||||
Uint32 Rmask = 0;
|
||||
Uint32 Gmask = 0;
|
||||
Uint32 Bmask = 0;
|
||||
Uint32 Amask = 0;
|
||||
Uint8 *bits;
|
||||
Uint8 *top, *end;
|
||||
bool topDown;
|
||||
bool haveRGBMasks = false;
|
||||
bool haveAlphaMask = false;
|
||||
bool correctAlpha = 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;
|
||||
if (!src) {
|
||||
SDL_InvalidParamError("src");
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Read in the BMP file header
|
||||
fp_offset = SDL_TellIO(src);
|
||||
if (fp_offset < 0) {
|
||||
goto done;
|
||||
}
|
||||
SDL_ClearError();
|
||||
if (SDL_ReadIO(src, magic, 2) != 2) {
|
||||
goto done;
|
||||
}
|
||||
if (SDL_strncmp(magic, "BM", 2) != 0) {
|
||||
SDL_SetError("File is not a Windows BMP file");
|
||||
goto done;
|
||||
}
|
||||
if (!SDL_ReadU32LE(src, NULL /* bfSize */) ||
|
||||
!SDL_ReadU16LE(src, NULL /* bfReserved1 */) ||
|
||||
!SDL_ReadU16LE(src, NULL /* bfReserved2 */) ||
|
||||
!SDL_ReadU32LE(src, &bfOffBits)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Read the Win32 BITMAPINFOHEADER
|
||||
if (!SDL_ReadU32LE(src, &biSize)) {
|
||||
goto done;
|
||||
}
|
||||
if (biSize == 12) { // really old BITMAPCOREHEADER
|
||||
Uint16 biWidth16, biHeight16;
|
||||
if (!SDL_ReadU16LE(src, &biWidth16) ||
|
||||
!SDL_ReadU16LE(src, &biHeight16) ||
|
||||
!SDL_ReadU16LE(src, NULL /* biPlanes */) ||
|
||||
!SDL_ReadU16LE(src, &biBitCount)) {
|
||||
goto done;
|
||||
}
|
||||
biWidth = biWidth16;
|
||||
biHeight = biHeight16;
|
||||
biCompression = BI_RGB;
|
||||
// biSizeImage = 0;
|
||||
// biXPelsPerMeter = 0;
|
||||
// biYPelsPerMeter = 0;
|
||||
biClrUsed = 0;
|
||||
// biClrImportant = 0;
|
||||
} else if (biSize >= 40) { // some version of BITMAPINFOHEADER
|
||||
Uint32 headerSize;
|
||||
if (!SDL_ReadS32LE(src, &biWidth) ||
|
||||
!SDL_ReadS32LE(src, &biHeight) ||
|
||||
!SDL_ReadU16LE(src, NULL /* biPlanes */) ||
|
||||
!SDL_ReadU16LE(src, &biBitCount) ||
|
||||
!SDL_ReadU32LE(src, &biCompression) ||
|
||||
!SDL_ReadU32LE(src, NULL /* biSizeImage */) ||
|
||||
!SDL_ReadU32LE(src, NULL /* biXPelsPerMeter */) ||
|
||||
!SDL_ReadU32LE(src, NULL /* biYPelsPerMeter */) ||
|
||||
!SDL_ReadU32LE(src, &biClrUsed) ||
|
||||
!SDL_ReadU32LE(src, NULL /* biClrImportant */)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// 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 = true;
|
||||
if (!SDL_ReadU32LE(src, &Rmask) ||
|
||||
!SDL_ReadU32LE(src, &Gmask) ||
|
||||
!SDL_ReadU32LE(src, &Bmask)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// ...v3 adds an alpha mask.
|
||||
if (biSize >= 56) { // BITMAPV3INFOHEADER; adds alpha mask
|
||||
haveAlphaMask = true;
|
||||
if (!SDL_ReadU32LE(src, &Amask)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// the mask fields are ignored for v2+ headers if not BI_BITFIELD.
|
||||
if (biSize >= 52) { // BITMAPV2INFOHEADER; adds RGB masks
|
||||
if (!SDL_ReadU32LE(src, NULL /* Rmask */) ||
|
||||
!SDL_ReadU32LE(src, NULL /* Gmask */) ||
|
||||
!SDL_ReadU32LE(src, NULL /* Bmask */)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (biSize >= 56) { // BITMAPV3INFOHEADER; adds alpha mask
|
||||
if (!SDL_ReadU32LE(src, NULL /* Amask */)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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_TellIO(src) - (fp_offset + 14));
|
||||
if (biSize > headerSize) {
|
||||
if (SDL_SeekIO(src, (biSize - headerSize), SDL_IO_SEEK_CUR) < 0) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (biWidth <= 0 || biHeight == 0) {
|
||||
SDL_SetError("BMP file with bad dimensions (%" SDL_PRIs32 "x%" SDL_PRIs32 ")", biWidth, biHeight);
|
||||
goto done;
|
||||
}
|
||||
if (biHeight < 0) {
|
||||
topDown = true;
|
||||
biHeight = -biHeight;
|
||||
} else {
|
||||
topDown = false;
|
||||
}
|
||||
|
||||
// Check for read error
|
||||
if (SDL_strcmp(SDL_GetError(), "") != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Reject invalid bit depths
|
||||
switch (biBitCount) {
|
||||
case 0:
|
||||
case 3:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
SDL_SetError("%u bpp BMP images are not supported", biBitCount);
|
||||
goto done;
|
||||
default:
|
||||
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_XRGB1555 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 = 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
|
||||
{
|
||||
SDL_PixelFormat format;
|
||||
|
||||
// Get the pixel format
|
||||
format = SDL_GetPixelFormatForMasks(biBitCount, Rmask, Gmask, Bmask, Amask);
|
||||
surface = SDL_CreateSurface(biWidth, biHeight, format);
|
||||
|
||||
if (!surface) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the palette, if any
|
||||
if (SDL_ISPIXELFORMAT_INDEXED(surface->format)) {
|
||||
SDL_Palette *palette = SDL_CreateSurfacePalette(surface);
|
||||
if (!palette) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (SDL_SeekIO(src, fp_offset + 14 + biSize, SDL_IO_SEEK_SET) < 0) {
|
||||
SDL_SetError("Error seeking in datastream");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (biBitCount >= 32) { // we shift biClrUsed by this value later.
|
||||
SDL_SetError("Unsupported or incorrect biBitCount field");
|
||||
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");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
palette->ncolors = biClrUsed;
|
||||
|
||||
if (biSize == 12) {
|
||||
for (i = 0; i < palette->ncolors; ++i) {
|
||||
if (!SDL_ReadU8(src, &palette->colors[i].b) ||
|
||||
!SDL_ReadU8(src, &palette->colors[i].g) ||
|
||||
!SDL_ReadU8(src, &palette->colors[i].r)) {
|
||||
goto done;
|
||||
}
|
||||
palette->colors[i].a = SDL_ALPHA_OPAQUE;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < palette->ncolors; ++i) {
|
||||
if (!SDL_ReadU8(src, &palette->colors[i].b) ||
|
||||
!SDL_ReadU8(src, &palette->colors[i].g) ||
|
||||
!SDL_ReadU8(src, &palette->colors[i].r) ||
|
||||
!SDL_ReadU8(src, &palette->colors[i].a)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read the surface pixels. Note that the bmp image is upside down
|
||||
if (SDL_SeekIO(src, fp_offset + bfOffBits, SDL_IO_SEEK_SET) < 0) {
|
||||
SDL_SetError("Error seeking in datastream");
|
||||
goto done;
|
||||
}
|
||||
if ((biCompression == BI_RLE4) || (biCompression == BI_RLE8)) {
|
||||
if (!readRlePixels(surface, src, biCompression == BI_RLE8)) {
|
||||
SDL_SetError("Error reading from datastream");
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Success!
|
||||
was_error = false;
|
||||
goto done;
|
||||
}
|
||||
top = (Uint8 *)surface->pixels;
|
||||
end = (Uint8 *)surface->pixels + (surface->h * surface->pitch);
|
||||
pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0);
|
||||
if (topDown) {
|
||||
bits = top;
|
||||
} else {
|
||||
bits = end - surface->pitch;
|
||||
}
|
||||
while (bits >= top && bits < end) {
|
||||
if (SDL_ReadIO(src, bits, surface->pitch) != (size_t)surface->pitch) {
|
||||
goto done;
|
||||
}
|
||||
if (biBitCount == 8 && surface->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");
|
||||
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
|
||||
|
||||
// Skip padding bytes, ugh
|
||||
if (pad) {
|
||||
Uint8 padbyte;
|
||||
for (i = 0; i < pad; ++i) {
|
||||
if (!SDL_ReadU8(src, &padbyte)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (topDown) {
|
||||
bits += surface->pitch;
|
||||
} else {
|
||||
bits -= surface->pitch;
|
||||
}
|
||||
}
|
||||
if (correctAlpha) {
|
||||
CorrectAlphaChannel(surface);
|
||||
}
|
||||
|
||||
was_error = false;
|
||||
|
||||
done:
|
||||
if (was_error) {
|
||||
if (src) {
|
||||
SDL_SeekIO(src, fp_offset, SDL_IO_SEEK_SET);
|
||||
}
|
||||
SDL_DestroySurface(surface);
|
||||
surface = NULL;
|
||||
}
|
||||
if (closeio && src) {
|
||||
SDL_CloseIO(src);
|
||||
}
|
||||
return surface;
|
||||
}
|
||||
|
||||
SDL_Surface *SDL_LoadBMP(const char *file)
|
||||
{
|
||||
SDL_IOStream *stream = SDL_IOFromFile(file, "rb");
|
||||
if (!stream) {
|
||||
return NULL;
|
||||
}
|
||||
return SDL_LoadBMP_IO(stream, true);
|
||||
}
|
||||
|
||||
bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
|
||||
{
|
||||
bool was_error = true;
|
||||
Sint64 fp_offset, new_offset;
|
||||
int i, pad;
|
||||
SDL_Surface *intermediate_surface = NULL;
|
||||
Uint8 *bits;
|
||||
bool save32bit = false;
|
||||
bool saveLegacyBMP = false;
|
||||
|
||||
// The Win32 BMP file header (14 bytes)
|
||||
char magic[2] = { 'B', 'M' };
|
||||
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;
|
||||
|
||||
// The additional header members from the Win32 BITMAPV5HEADER struct (124 bytes in total)
|
||||
Uint32 bV5Intent = 0;
|
||||
Uint32 bV5ProfileData = 0;
|
||||
Uint32 bV5ProfileSize = 0;
|
||||
Uint32 bV5Reserved = 0;
|
||||
|
||||
// Make sure we have somewhere to save
|
||||
if (!SDL_SurfaceValid(surface)) {
|
||||
SDL_InvalidParamError("surface");
|
||||
goto done;
|
||||
}
|
||||
if (!dst) {
|
||||
SDL_InvalidParamError("dst");
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef SAVE_32BIT_BMP
|
||||
// We can save alpha information in a 32-bit BMP
|
||||
if (SDL_BITSPERPIXEL(surface->format) >= 8 &&
|
||||
(SDL_ISPIXELFORMAT_ALPHA(surface->format) ||
|
||||
surface->map.info.flags & SDL_COPY_COLORKEY)) {
|
||||
save32bit = true;
|
||||
}
|
||||
#endif // SAVE_32BIT_BMP
|
||||
|
||||
if (surface->palette && !save32bit) {
|
||||
if (SDL_BITSPERPIXEL(surface->format) == 8) {
|
||||
intermediate_surface = surface;
|
||||
} else {
|
||||
SDL_SetError("%u bpp BMP files not supported",
|
||||
SDL_BITSPERPIXEL(surface->format));
|
||||
goto done;
|
||||
}
|
||||
} else if ((surface->format == SDL_PIXELFORMAT_BGR24 && !save32bit) ||
|
||||
(surface->format == SDL_PIXELFORMAT_BGRA32 && save32bit)) {
|
||||
intermediate_surface = surface;
|
||||
} else {
|
||||
SDL_PixelFormat pixel_format;
|
||||
|
||||
/* If the surface has a colorkey or alpha channel we'll save a
|
||||
32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
|
||||
if (save32bit) {
|
||||
pixel_format = SDL_PIXELFORMAT_BGRA32;
|
||||
} else {
|
||||
pixel_format = SDL_PIXELFORMAT_BGR24;
|
||||
}
|
||||
intermediate_surface = SDL_ConvertSurface(surface, pixel_format);
|
||||
if (!intermediate_surface) {
|
||||
SDL_SetError("Couldn't convert image to %d bpp",
|
||||
(int)SDL_BITSPERPIXEL(pixel_format));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (save32bit) {
|
||||
saveLegacyBMP = SDL_GetHintBoolean(SDL_HINT_BMP_SAVE_LEGACY_FORMAT, false);
|
||||
}
|
||||
|
||||
if (SDL_LockSurface(intermediate_surface)) {
|
||||
const size_t bw = intermediate_surface->w * intermediate_surface->fmt->bytes_per_pixel;
|
||||
|
||||
// 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_TellIO(dst);
|
||||
if (fp_offset < 0) {
|
||||
goto done;
|
||||
}
|
||||
if (SDL_WriteIO(dst, magic, 2) != 2 ||
|
||||
!SDL_WriteU32LE(dst, bfSize) ||
|
||||
!SDL_WriteU16LE(dst, bfReserved1) ||
|
||||
!SDL_WriteU16LE(dst, bfReserved2) ||
|
||||
!SDL_WriteU32LE(dst, bfOffBits)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Set the BMP info values
|
||||
biSize = 40;
|
||||
biWidth = intermediate_surface->w;
|
||||
biHeight = intermediate_surface->h;
|
||||
biPlanes = 1;
|
||||
biBitCount = intermediate_surface->fmt->bits_per_pixel;
|
||||
biCompression = BI_RGB;
|
||||
biSizeImage = intermediate_surface->h * intermediate_surface->pitch;
|
||||
biXPelsPerMeter = 0;
|
||||
biYPelsPerMeter = 0;
|
||||
if (intermediate_surface->palette) {
|
||||
biClrUsed = intermediate_surface->palette->ncolors;
|
||||
} else {
|
||||
biClrUsed = 0;
|
||||
}
|
||||
biClrImportant = 0;
|
||||
|
||||
// Set the BMP info values
|
||||
if (save32bit && !saveLegacyBMP) {
|
||||
biSize = 124;
|
||||
// Version 4 values
|
||||
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_sRGB;
|
||||
bV4GammaRed = 0;
|
||||
bV4GammaGreen = 0;
|
||||
bV4GammaBlue = 0;
|
||||
// Version 5 values
|
||||
bV5Intent = LCS_GM_GRAPHICS;
|
||||
bV5ProfileData = 0;
|
||||
bV5ProfileSize = 0;
|
||||
bV5Reserved = 0;
|
||||
}
|
||||
|
||||
// Write the BMP info values
|
||||
if (!SDL_WriteU32LE(dst, biSize) ||
|
||||
!SDL_WriteS32LE(dst, biWidth) ||
|
||||
!SDL_WriteS32LE(dst, biHeight) ||
|
||||
!SDL_WriteU16LE(dst, biPlanes) ||
|
||||
!SDL_WriteU16LE(dst, biBitCount) ||
|
||||
!SDL_WriteU32LE(dst, biCompression) ||
|
||||
!SDL_WriteU32LE(dst, biSizeImage) ||
|
||||
!SDL_WriteU32LE(dst, biXPelsPerMeter) ||
|
||||
!SDL_WriteU32LE(dst, biYPelsPerMeter) ||
|
||||
!SDL_WriteU32LE(dst, biClrUsed) ||
|
||||
!SDL_WriteU32LE(dst, biClrImportant)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Write the BMP info values
|
||||
if (save32bit && !saveLegacyBMP) {
|
||||
// Version 4 values
|
||||
if (!SDL_WriteU32LE(dst, bV4RedMask) ||
|
||||
!SDL_WriteU32LE(dst, bV4GreenMask) ||
|
||||
!SDL_WriteU32LE(dst, bV4BlueMask) ||
|
||||
!SDL_WriteU32LE(dst, bV4AlphaMask) ||
|
||||
!SDL_WriteU32LE(dst, bV4CSType)) {
|
||||
goto done;
|
||||
}
|
||||
for (i = 0; i < 3 * 3; i++) {
|
||||
if (!SDL_WriteU32LE(dst, bV4Endpoints[i])) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (!SDL_WriteU32LE(dst, bV4GammaRed) ||
|
||||
!SDL_WriteU32LE(dst, bV4GammaGreen) ||
|
||||
!SDL_WriteU32LE(dst, bV4GammaBlue)) {
|
||||
goto done;
|
||||
}
|
||||
// Version 5 values
|
||||
if (!SDL_WriteU32LE(dst, bV5Intent) ||
|
||||
!SDL_WriteU32LE(dst, bV5ProfileData) ||
|
||||
!SDL_WriteU32LE(dst, bV5ProfileSize) ||
|
||||
!SDL_WriteU32LE(dst, bV5Reserved)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the palette (in BGR color order)
|
||||
if (intermediate_surface->palette) {
|
||||
SDL_Color *colors;
|
||||
int ncolors;
|
||||
|
||||
colors = intermediate_surface->palette->colors;
|
||||
ncolors = intermediate_surface->palette->ncolors;
|
||||
for (i = 0; i < ncolors; ++i) {
|
||||
if (!SDL_WriteU8(dst, colors[i].b) ||
|
||||
!SDL_WriteU8(dst, colors[i].g) ||
|
||||
!SDL_WriteU8(dst, colors[i].r) ||
|
||||
!SDL_WriteU8(dst, colors[i].a)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write the bitmap offset
|
||||
bfOffBits = (Uint32)(SDL_TellIO(dst) - fp_offset);
|
||||
if (SDL_SeekIO(dst, fp_offset + 10, SDL_IO_SEEK_SET) < 0) {
|
||||
goto done;
|
||||
}
|
||||
if (!SDL_WriteU32LE(dst, bfOffBits)) {
|
||||
goto done;
|
||||
}
|
||||
if (SDL_SeekIO(dst, fp_offset + bfOffBits, SDL_IO_SEEK_SET) < 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// 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_WriteIO(dst, bits, bw) != bw) {
|
||||
goto done;
|
||||
}
|
||||
if (pad) {
|
||||
const Uint8 padbyte = 0;
|
||||
for (i = 0; i < pad; ++i) {
|
||||
if (!SDL_WriteU8(dst, padbyte)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write the BMP file size
|
||||
new_offset = SDL_TellIO(dst);
|
||||
if (new_offset < 0) {
|
||||
goto done;
|
||||
}
|
||||
bfSize = (Uint32)(new_offset - fp_offset);
|
||||
if (SDL_SeekIO(dst, fp_offset + 2, SDL_IO_SEEK_SET) < 0) {
|
||||
goto done;
|
||||
}
|
||||
if (!SDL_WriteU32LE(dst, bfSize)) {
|
||||
goto done;
|
||||
}
|
||||
if (SDL_SeekIO(dst, fp_offset + bfSize, SDL_IO_SEEK_SET) < 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Close it up..
|
||||
SDL_UnlockSurface(intermediate_surface);
|
||||
|
||||
was_error = false;
|
||||
}
|
||||
|
||||
done:
|
||||
if (intermediate_surface && intermediate_surface != surface) {
|
||||
SDL_DestroySurface(intermediate_surface);
|
||||
}
|
||||
if (closeio && dst) {
|
||||
if (!SDL_CloseIO(dst)) {
|
||||
was_error = true;
|
||||
}
|
||||
}
|
||||
if (was_error) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_SaveBMP(SDL_Surface *surface, const char *file)
|
||||
{
|
||||
SDL_IOStream *stream = SDL_IOFromFile(file, "wb");
|
||||
if (!stream) {
|
||||
return false;
|
||||
}
|
||||
return SDL_SaveBMP_IO(surface, stream, true);
|
||||
}
|
||||
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_clipboard_c.h"
|
||||
#include "SDL_sysvideo.h"
|
||||
#include "../events/SDL_events_c.h"
|
||||
#include "../events/SDL_clipboardevents_c.h"
|
||||
|
||||
void SDL_FreeClipboardMimeTypes(SDL_VideoDevice *_this)
|
||||
{
|
||||
if (_this->clipboard_mime_types) {
|
||||
for (size_t 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SDL_CancelClipboardData(Uint32 sequence)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (!_this) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sequence && sequence != _this->clipboard_sequence) {
|
||||
// This clipboard data was already canceled
|
||||
return;
|
||||
}
|
||||
|
||||
if (_this->clipboard_cleanup) {
|
||||
_this->clipboard_cleanup(_this->clipboard_userdata);
|
||||
}
|
||||
|
||||
SDL_FreeClipboardMimeTypes(_this);
|
||||
|
||||
_this->clipboard_callback = NULL;
|
||||
_this->clipboard_cleanup = NULL;
|
||||
_this->clipboard_userdata = NULL;
|
||||
}
|
||||
|
||||
bool SDL_SaveClipboardMimeTypes(const char **mime_types, size_t num_mime_types)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (!_this) {
|
||||
return SDL_UninitializedVideo();
|
||||
}
|
||||
|
||||
SDL_FreeClipboardMimeTypes(_this);
|
||||
|
||||
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 (size_t 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_FreeClipboardMimeTypes(_this);
|
||||
return false;
|
||||
}
|
||||
_this->num_clipboard_mime_types = num_mime_types;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanupCallback cleanup, void *userdata, const char **mime_types, size_t num_mime_types)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (!_this) {
|
||||
return SDL_UninitializedVideo();
|
||||
}
|
||||
|
||||
// Parameter validation
|
||||
if (!((callback && mime_types && num_mime_types > 0) ||
|
||||
(!callback && !mime_types && num_mime_types == 0))) {
|
||||
return SDL_SetError("Invalid parameters");
|
||||
}
|
||||
|
||||
SDL_CancelClipboardData(0);
|
||||
|
||||
++_this->clipboard_sequence;
|
||||
if (!_this->clipboard_sequence) {
|
||||
_this->clipboard_sequence = 1;
|
||||
}
|
||||
_this->clipboard_callback = callback;
|
||||
_this->clipboard_cleanup = cleanup;
|
||||
_this->clipboard_userdata = userdata;
|
||||
|
||||
if (!SDL_SaveClipboardMimeTypes(mime_types, num_mime_types)) {
|
||||
SDL_ClearClipboardData();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_this->SetClipboardData) {
|
||||
if (!_this->SetClipboardData(_this)) {
|
||||
return false;
|
||||
}
|
||||
} else if (_this->SetClipboardText) {
|
||||
char *text = NULL;
|
||||
size_t size;
|
||||
|
||||
for (size_t 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)) {
|
||||
SDL_free(text);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (text) {
|
||||
SDL_free(text);
|
||||
} else {
|
||||
if (!_this->SetClipboardText(_this, "")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char **mime_types_copy = SDL_CopyClipboardMimeTypes(mime_types, num_mime_types, true);
|
||||
if (!mime_types_copy)
|
||||
return SDL_SetError("unable to copy current mime types");
|
||||
|
||||
SDL_SendClipboardUpdate(true, mime_types_copy, num_mime_types);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void *SDL_GetClipboardData(const char *mime_type, size_t *size)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
size_t unused;
|
||||
|
||||
if (!_this) {
|
||||
SDL_UninitializedVideo();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!mime_type) {
|
||||
SDL_InvalidParamError("mime_type");
|
||||
return NULL;
|
||||
}
|
||||
if (!size) {
|
||||
size = &unused;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
char *text = _this->GetClipboardText(_this);
|
||||
if (text) {
|
||||
if (*text == '\0') {
|
||||
SDL_free(text);
|
||||
text = NULL;
|
||||
} else {
|
||||
*size = SDL_strlen(text);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
} else {
|
||||
return SDL_GetInternalClipboardData(_this, mime_type, size);
|
||||
}
|
||||
}
|
||||
|
||||
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 true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SDL_HasClipboardData(const char *mime_type)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (!_this) {
|
||||
return SDL_UninitializedVideo();
|
||||
}
|
||||
|
||||
if (!mime_type) {
|
||||
return SDL_InvalidParamError("mime_type");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
char **SDL_CopyClipboardMimeTypes(const char **clipboard_mime_types, size_t num_mime_types, bool temporary)
|
||||
{
|
||||
size_t allocSize = sizeof(char *);
|
||||
for (size_t i = 0; i < num_mime_types; i++) {
|
||||
allocSize += sizeof(char *) + SDL_strlen(clipboard_mime_types[i]) + 1;
|
||||
}
|
||||
|
||||
char *ret;
|
||||
if (temporary)
|
||||
ret = (char *)SDL_AllocateTemporaryMemory(allocSize);
|
||||
else
|
||||
ret = (char *)SDL_malloc(allocSize);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **result = (char **)ret;
|
||||
ret += sizeof(char *) * (num_mime_types + 1);
|
||||
|
||||
for (size_t i = 0; i < num_mime_types; i++) {
|
||||
result[i] = ret;
|
||||
|
||||
const char *mime_type = clipboard_mime_types[i];
|
||||
// Copy the whole string including the terminating null char
|
||||
char c;
|
||||
do {
|
||||
c = *ret++ = *mime_type++;
|
||||
} while (c != '\0');
|
||||
}
|
||||
result[num_mime_types] = NULL;
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
char **SDL_GetClipboardMimeTypes(size_t *num_mime_types)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (num_mime_types) {
|
||||
*num_mime_types = 0;
|
||||
}
|
||||
|
||||
if (!_this) {
|
||||
SDL_UninitializedVideo();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (num_mime_types) {
|
||||
*num_mime_types = _this->num_clipboard_mime_types;
|
||||
}
|
||||
return SDL_CopyClipboardMimeTypes((const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types, false);
|
||||
}
|
||||
|
||||
// Clipboard text
|
||||
|
||||
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 * SDLCALL 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;
|
||||
}
|
||||
|
||||
bool SDL_SetClipboardText(const char *text)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
size_t num_mime_types;
|
||||
const char **text_mime_types;
|
||||
|
||||
if (!_this) {
|
||||
return SDL_UninitializedVideo();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
SDL_UninitializedVideo();
|
||||
return SDL_strdup("");
|
||||
}
|
||||
|
||||
text_mime_types = SDL_GetTextMimeTypes(_this, &num_mime_types);
|
||||
for (i = 0; i < num_mime_types; ++i) {
|
||||
void *clipdata = SDL_GetClipboardData(text_mime_types[i], &length);
|
||||
if (clipdata) {
|
||||
text = (char *)clipdata;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!text) {
|
||||
text = SDL_strdup("");
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
bool SDL_HasClipboardText(void)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
size_t i, num_mime_types;
|
||||
const char **text_mime_types;
|
||||
|
||||
if (!_this) {
|
||||
return SDL_UninitializedVideo();
|
||||
}
|
||||
|
||||
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 true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Primary selection text
|
||||
|
||||
bool SDL_SetPrimarySelectionText(const char *text)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (!_this) {
|
||||
return SDL_UninitializedVideo();
|
||||
}
|
||||
|
||||
if (!text) {
|
||||
text = "";
|
||||
}
|
||||
if (_this->SetPrimarySelectionText) {
|
||||
if (!_this->SetPrimarySelectionText(_this, text)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
SDL_free(_this->primary_selection_text);
|
||||
_this->primary_selection_text = SDL_strdup(text);
|
||||
}
|
||||
|
||||
char **mime_types = SDL_CopyClipboardMimeTypes((const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types, true);
|
||||
if (!mime_types)
|
||||
return SDL_SetError("unable to copy current mime types");
|
||||
|
||||
SDL_SendClipboardUpdate(true, mime_types, _this->num_clipboard_mime_types);
|
||||
return true;
|
||||
}
|
||||
|
||||
char *SDL_GetPrimarySelectionText(void)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (!_this) {
|
||||
SDL_UninitializedVideo();
|
||||
return SDL_strdup("");
|
||||
}
|
||||
|
||||
if (_this->GetPrimarySelectionText) {
|
||||
return _this->GetPrimarySelectionText(_this);
|
||||
} else {
|
||||
const char *text = _this->primary_selection_text;
|
||||
if (!text) {
|
||||
text = "";
|
||||
}
|
||||
return SDL_strdup(text);
|
||||
}
|
||||
}
|
||||
|
||||
bool SDL_HasPrimarySelectionText(void)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
||||
if (!_this) {
|
||||
return SDL_UninitializedVideo();
|
||||
}
|
||||
|
||||
if (_this->HasPrimarySelectionText) {
|
||||
return _this->HasPrimarySelectionText(_this);
|
||||
} else {
|
||||
if (_this->primary_selection_text && _this->primary_selection_text[0] != '\0') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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 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 bool SDL_HasInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type);
|
||||
|
||||
// General purpose clipboard text callback
|
||||
const void * SDLCALL SDL_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *size);
|
||||
|
||||
bool SDL_SaveClipboardMimeTypes(const char **mime_types, size_t num_mime_types);
|
||||
void SDL_FreeClipboardMimeTypes(SDL_VideoDevice *_this);
|
||||
char **SDL_CopyClipboardMimeTypes(const char **clipboard_mime_types, size_t num_mime_types, bool temporary);
|
||||
|
||||
#endif // SDL_clipboard_c_h_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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
|
||||
{
|
||||
SDL_SharedObject *opengl_dll_handle;
|
||||
SDL_SharedObject *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;
|
||||
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 bool SDL_EGL_HasExtension(SDL_VideoDevice *_this, SDL_EGL_ExtensionType type, const char *ext);
|
||||
|
||||
extern bool 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 bool SDL_EGL_LoadLibraryOnly(SDL_VideoDevice *_this, const char *path);
|
||||
extern bool 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 bool SDL_EGL_ChooseConfig(SDL_VideoDevice *_this);
|
||||
extern bool SDL_EGL_SetSwapInterval(SDL_VideoDevice *_this, int interval);
|
||||
extern bool SDL_EGL_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
|
||||
extern bool SDL_EGL_DestroyContext(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 bool 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 bool SDL_EGL_MakeCurrent(SDL_VideoDevice *_this, EGLSurface egl_surface, SDL_GLContext context);
|
||||
extern bool SDL_EGL_SwapBuffers(SDL_VideoDevice *_this, EGLSurface egl_surface);
|
||||
|
||||
// SDL Error-reporting
|
||||
extern bool 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) \
|
||||
bool BACKEND##_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) \
|
||||
{ \
|
||||
return SDL_EGL_SwapBuffers(_this, window->internal->egl_surface); \
|
||||
}
|
||||
|
||||
#define SDL_EGL_MakeCurrent_impl(BACKEND) \
|
||||
bool BACKEND##_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context) \
|
||||
{ \
|
||||
return SDL_EGL_MakeCurrent(_this, window ? window->internal->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->internal->egl_surface); \
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_OPENGL_EGL
|
||||
|
||||
#endif // SDL_egl_h_
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_surface_c.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; \
|
||||
\
|
||||
/* If the number of bytes per row is equal to the pitch, treat */ \
|
||||
/* all rows as one long continuous row (for better performance) */ \
|
||||
if ((w) * (bpp) == pitch) { \
|
||||
w = w * h; \
|
||||
h = 1; \
|
||||
} \
|
||||
\
|
||||
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'
|
||||
*/
|
||||
bool SDL_FillSurfaceRect(SDL_Surface *dst, const SDL_Rect *rect, Uint32 color)
|
||||
{
|
||||
if (!SDL_SurfaceValid(dst)) {
|
||||
return SDL_InvalidParamError("SDL_FillSurfaceRect(): dst");
|
||||
}
|
||||
|
||||
// If 'rect' == NULL, then fill the whole surface
|
||||
if (!rect) {
|
||||
rect = &dst->clip_rect;
|
||||
// Don't attempt to fill if the surface's clip_rect is empty
|
||||
if (SDL_RectEmpty(rect)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return SDL_FillSurfaceRects(dst, rect, 1, color);
|
||||
}
|
||||
|
||||
bool 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 (!SDL_SurfaceValid(dst)) {
|
||||
return SDL_InvalidParamError("SDL_FillSurfaceRects(): dst");
|
||||
}
|
||||
|
||||
// Nothing to do
|
||||
if (dst->w == 0 || dst->h == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Perform software fill
|
||||
if (!dst->pixels) {
|
||||
return SDL_SetError("SDL_FillSurfaceRects(): You must lock the surface");
|
||||
}
|
||||
|
||||
if (!rects) {
|
||||
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 (SDL_BITSPERPIXEL(dst->format) < 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 (SDL_BITSPERPIXEL(dst->format) == 4) {
|
||||
Uint8 b = (((Uint8)color << 4) | (Uint8)color);
|
||||
SDL_memset(dst->pixels, b, (size_t)dst->h * dst->pitch);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SDL_SetError("SDL_FillSurfaceRects(): Unsupported surface format");
|
||||
}
|
||||
|
||||
if (fill_function == NULL) {
|
||||
switch (SDL_BYTESPERPIXEL(dst->format)) {
|
||||
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 * SDL_BYTESPERPIXEL(dst->format);
|
||||
|
||||
fill_function(pixels, dst->pitch, color, rect->w, rect->h);
|
||||
}
|
||||
|
||||
// We're done!
|
||||
return true;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_pixels_c_h_
|
||||
#define SDL_pixels_c_h_
|
||||
|
||||
// Useful functions and variables from SDL_pixel.c
|
||||
|
||||
#include "SDL_blit.h"
|
||||
|
||||
|
||||
// Pixel format functions
|
||||
extern void SDL_Get8888AlphaMaskAndShift(const SDL_PixelFormatDetails *fmt, Uint32 *mask, Uint32 *shift);
|
||||
extern SDL_Colorspace SDL_GetDefaultColorspaceForFormat(SDL_PixelFormat pixel_format);
|
||||
extern void SDL_QuitPixelFormatDetails(void);
|
||||
|
||||
// Colorspace conversion functions
|
||||
extern float SDL_sRGBtoLinear(float v);
|
||||
extern float SDL_sRGBfromLinear(float v);
|
||||
extern float SDL_PQtoNits(float v);
|
||||
extern float SDL_PQfromNits(float v);
|
||||
extern const float *SDL_GetYCbCRtoRGBConversionMatrix(SDL_Colorspace colorspace, int w, int h, int bits_per_pixel);
|
||||
extern const float *SDL_GetColorPrimariesConversionMatrix(SDL_ColorPrimaries src, SDL_ColorPrimaries dst);
|
||||
extern void SDL_ConvertColorPrimaries(float *fR, float *fG, float *fB, const float *matrix);
|
||||
|
||||
// Blit mapping functions
|
||||
extern bool SDL_ValidateMap(SDL_Surface *src, SDL_Surface *dst);
|
||||
extern void SDL_InvalidateMap(SDL_BlitMap *map);
|
||||
extern bool SDL_MapSurface(SDL_Surface *src, SDL_Surface *dst);
|
||||
|
||||
// Miscellaneous functions
|
||||
extern void SDL_DitherPalette(SDL_Palette *palette);
|
||||
extern Uint8 SDL_FindColor(const SDL_Palette *pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||
extern Uint8 SDL_LookupRGBAColor(SDL_HashTable *palette_map, Uint32 pixelvalue, const SDL_Palette *pal);
|
||||
extern void SDL_DetectPalette(const SDL_Palette *pal, bool *is_opaque, bool *has_alpha_channel);
|
||||
extern SDL_Surface *SDL_DuplicatePixels(int width, int height, SDL_PixelFormat format, SDL_Colorspace colorspace, void *pixels, int pitch);
|
||||
|
||||
#endif // SDL_pixels_c_h_
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "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. */
|
||||
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 false;
|
||||
} else if (height < 1) {
|
||||
SDL_InvalidParamError("height");
|
||||
return false;
|
||||
} else if (!rects) {
|
||||
SDL_InvalidParamError("rects");
|
||||
return false;
|
||||
} else if (!span) {
|
||||
SDL_InvalidParamError("span");
|
||||
return false;
|
||||
} else if (numrects < 1) {
|
||||
SDL_InvalidParamError("numrects");
|
||||
return 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 true;
|
||||
}
|
||||
return 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 BIGSCALARTYPE Sint64
|
||||
#define COMPUTEOUTCODE ComputeOutCode
|
||||
#define ENCLOSEPOINTS_EPSILON 1
|
||||
#define SDL_RECT_CAN_OVERFLOW SDL_RectCanOverflow
|
||||
#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 BIGSCALARTYPE double
|
||||
#define COMPUTEOUTCODE ComputeOutCodeFloat
|
||||
#define ENCLOSEPOINTS_EPSILON 0.0f
|
||||
#define SDL_RECT_CAN_OVERFLOW SDL_RectCanOverflowFloat
|
||||
#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"
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_rect_c_h_
|
||||
#define SDL_rect_c_h_
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
extern bool SDL_GetSpanEnclosingRect(int width, int height, int numrects, const SDL_Rect *rects, SDL_Rect *span);
|
||||
|
||||
#endif // SDL_rect_c_h_
|
||||
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
// This file is #included twice to support int and float versions with the same code.
|
||||
|
||||
static bool SDL_RECT_CAN_OVERFLOW(const RECTTYPE *rect)
|
||||
{
|
||||
if (rect->x <= (SCALARTYPE)(SDL_MIN_SINT32 / 2) ||
|
||||
rect->x >= (SCALARTYPE)(SDL_MAX_SINT32 / 2) ||
|
||||
rect->y <= (SCALARTYPE)(SDL_MIN_SINT32 / 2) ||
|
||||
rect->y >= (SCALARTYPE)(SDL_MAX_SINT32 / 2) ||
|
||||
rect->w >= (SCALARTYPE)(SDL_MAX_SINT32 / 2) ||
|
||||
rect->h >= (SCALARTYPE)(SDL_MAX_SINT32 / 2)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SDL_HASINTERSECTION(const RECTTYPE *A, const RECTTYPE *B)
|
||||
{
|
||||
SCALARTYPE Amin, Amax, Bmin, Bmax;
|
||||
|
||||
if (!A) {
|
||||
SDL_InvalidParamError("A");
|
||||
return false;
|
||||
} else if (!B) {
|
||||
SDL_InvalidParamError("B");
|
||||
return false;
|
||||
} else if (SDL_RECT_CAN_OVERFLOW(A) ||
|
||||
SDL_RECT_CAN_OVERFLOW(B)) {
|
||||
SDL_SetError("Potential rect math overflow");
|
||||
return false;
|
||||
} else if (SDL_RECTEMPTY(A) || SDL_RECTEMPTY(B)) {
|
||||
return false; // Special cases for empty rects
|
||||
}
|
||||
|
||||
// Horizontal intersection
|
||||
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 - ENCLOSEPOINTS_EPSILON) < Amin) {
|
||||
return 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 - ENCLOSEPOINTS_EPSILON) < Amin) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_INTERSECTRECT(const RECTTYPE *A, const RECTTYPE *B, RECTTYPE *result)
|
||||
{
|
||||
SCALARTYPE Amin, Amax, Bmin, Bmax;
|
||||
|
||||
if (!A) {
|
||||
SDL_InvalidParamError("A");
|
||||
return false;
|
||||
} else if (!B) {
|
||||
SDL_InvalidParamError("B");
|
||||
return false;
|
||||
} else if (SDL_RECT_CAN_OVERFLOW(A) ||
|
||||
SDL_RECT_CAN_OVERFLOW(B)) {
|
||||
SDL_SetError("Potential rect math overflow");
|
||||
return false;
|
||||
} else if (!result) {
|
||||
SDL_InvalidParamError("result");
|
||||
return false;
|
||||
} else if (SDL_RECTEMPTY(A) || SDL_RECTEMPTY(B)) { // Special cases for empty rects
|
||||
result->w = 0;
|
||||
result->h = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Horizontal intersection
|
||||
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);
|
||||
}
|
||||
|
||||
bool SDL_UNIONRECT(const RECTTYPE *A, const RECTTYPE *B, RECTTYPE *result)
|
||||
{
|
||||
SCALARTYPE Amin, Amax, Bmin, Bmax;
|
||||
|
||||
if (!A) {
|
||||
return SDL_InvalidParamError("A");
|
||||
} else if (!B) {
|
||||
return SDL_InvalidParamError("B");
|
||||
} else if (SDL_RECT_CAN_OVERFLOW(A) ||
|
||||
SDL_RECT_CAN_OVERFLOW(B)) {
|
||||
return SDL_SetError("Potential rect math overflow");
|
||||
} else if (!result) {
|
||||
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 true;
|
||||
} else if (SDL_RECTEMPTY(B)) { // A not empty, B empty
|
||||
*result = *A;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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 true;
|
||||
}
|
||||
|
||||
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) {
|
||||
SDL_InvalidParamError("points");
|
||||
return false;
|
||||
} else if (count < 1) {
|
||||
SDL_InvalidParamError("count");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (clip) {
|
||||
bool added = false;
|
||||
const SCALARTYPE clip_minx = clip->x;
|
||||
const SCALARTYPE clip_miny = clip->y;
|
||||
const SCALARTYPE clip_maxx = clip->x + clip->w - ENCLOSEPOINTS_EPSILON;
|
||||
const SCALARTYPE clip_maxy = clip->y + clip->h - ENCLOSEPOINTS_EPSILON;
|
||||
|
||||
// Special case for empty rectangle
|
||||
if (SDL_RECTEMPTY(clip)) {
|
||||
return 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) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// First point added
|
||||
minx = maxx = x;
|
||||
miny = maxy = y;
|
||||
added = 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 false;
|
||||
}
|
||||
} else {
|
||||
// Special case: if no result was requested, we are done
|
||||
if (!result) {
|
||||
return 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) + ENCLOSEPOINTS_EPSILON;
|
||||
result->h = (maxy - miny) + ENCLOSEPOINTS_EPSILON;
|
||||
}
|
||||
return 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 - ENCLOSEPOINTS_EPSILON)) {
|
||||
code |= CODE_BOTTOM;
|
||||
}
|
||||
if (x < rect->x) {
|
||||
code |= CODE_LEFT;
|
||||
} else if (x > (rect->x + rect->w - ENCLOSEPOINTS_EPSILON)) {
|
||||
code |= CODE_RIGHT;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
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) {
|
||||
SDL_InvalidParamError("rect");
|
||||
return false;
|
||||
} else if (SDL_RECT_CAN_OVERFLOW(rect)) {
|
||||
SDL_SetError("Potential rect math overflow");
|
||||
return false;
|
||||
} else if (!X1) {
|
||||
SDL_InvalidParamError("X1");
|
||||
return false;
|
||||
} else if (!Y1) {
|
||||
SDL_InvalidParamError("Y1");
|
||||
return false;
|
||||
} else if (!X2) {
|
||||
SDL_InvalidParamError("X2");
|
||||
return false;
|
||||
} else if (!Y2) {
|
||||
SDL_InvalidParamError("Y2");
|
||||
return false;
|
||||
} else if (SDL_RECTEMPTY(rect)) {
|
||||
return 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 - ENCLOSEPOINTS_EPSILON;
|
||||
recty2 = rect->y + rect->h - ENCLOSEPOINTS_EPSILON;
|
||||
|
||||
// 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 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 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 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 true;
|
||||
}
|
||||
|
||||
// More complicated Cohen-Sutherland algorithm
|
||||
outcode1 = COMPUTEOUTCODE(rect, x1, y1);
|
||||
outcode2 = COMPUTEOUTCODE(rect, x2, y2);
|
||||
while (outcode1 || outcode2) {
|
||||
if (outcode1 & outcode2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outcode1) {
|
||||
if (outcode1 & CODE_TOP) {
|
||||
y = recty1;
|
||||
x = (SCALARTYPE) (x1 + ((BIGSCALARTYPE)(x2 - x1) * (y - y1)) / (y2 - y1));
|
||||
} else if (outcode1 & CODE_BOTTOM) {
|
||||
y = recty2;
|
||||
x = (SCALARTYPE) (x1 + ((BIGSCALARTYPE)(x2 - x1) * (y - y1)) / (y2 - y1));
|
||||
} else if (outcode1 & CODE_LEFT) {
|
||||
x = rectx1;
|
||||
y = (SCALARTYPE) (y1 + ((BIGSCALARTYPE)(y2 - y1) * (x - x1)) / (x2 - x1));
|
||||
} else if (outcode1 & CODE_RIGHT) {
|
||||
x = rectx2;
|
||||
y = (SCALARTYPE) (y1 + ((BIGSCALARTYPE)(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 = (SCALARTYPE) (x1 + ((BIGSCALARTYPE)(x2 - x1) * (y - y1)) / (y2 - y1));
|
||||
} else if (outcode2 & CODE_BOTTOM) {
|
||||
SDL_assert(y2 != y1); // if equal: division by zero.
|
||||
y = recty2;
|
||||
x = (SCALARTYPE) (x1 + ((BIGSCALARTYPE)(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 = (SCALARTYPE) (y1 + ((BIGSCALARTYPE)(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 = (SCALARTYPE) (y1 + ((BIGSCALARTYPE)(y2 - y1) * (x - x1)) / (x2 - x1));
|
||||
}
|
||||
x2 = x;
|
||||
y2 = y;
|
||||
outcode2 = COMPUTEOUTCODE(rect, x, y);
|
||||
}
|
||||
}
|
||||
*X1 = x1;
|
||||
*Y1 = y1;
|
||||
*X2 = x2;
|
||||
*Y2 = y2;
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef RECTTYPE
|
||||
#undef POINTTYPE
|
||||
#undef SCALARTYPE
|
||||
#undef BIGSCALARTYPE
|
||||
#undef COMPUTEOUTCODE
|
||||
#undef ENCLOSEPOINTS_EPSILON
|
||||
#undef SDL_RECT_CAN_OVERFLOW
|
||||
#undef SDL_HASINTERSECTION
|
||||
#undef SDL_INTERSECTRECT
|
||||
#undef SDL_RECTEMPTY
|
||||
#undef SDL_UNIONRECT
|
||||
#undef SDL_ENCLOSEPOINTS
|
||||
#undef SDL_INTERSECTRECTANDLINE
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_stb_c.h"
|
||||
|
||||
|
||||
// We currently only support JPEG, but we could add other image formats if we wanted
|
||||
#ifdef SDL_HAVE_STB
|
||||
#define malloc SDL_malloc
|
||||
#define realloc SDL_realloc
|
||||
#define free SDL_free
|
||||
#undef memcpy
|
||||
#define memcpy SDL_memcpy
|
||||
#undef memset
|
||||
#define memset SDL_memset
|
||||
#undef strcmp
|
||||
#define strcmp SDL_strcmp
|
||||
#undef strncmp
|
||||
#define strncmp SDL_strncmp
|
||||
#define strtol SDL_strtol
|
||||
|
||||
#define abs SDL_abs
|
||||
#define pow SDL_pow
|
||||
#define ldexp SDL_scalbn
|
||||
|
||||
#define STB_IMAGE_STATIC
|
||||
#define STBI_NO_THREAD_LOCALS
|
||||
#define STBI_FAILURE_USERMSG
|
||||
#if defined(SDL_NEON_INTRINSICS)
|
||||
#define STBI_NEON
|
||||
#endif
|
||||
#define STBI_ONLY_JPEG
|
||||
#define STBI_NO_GIF
|
||||
#define STBI_NO_PNG
|
||||
#define STBI_NO_HDR
|
||||
#define STBI_NO_LINEAR
|
||||
#define STBI_NO_ZLIB
|
||||
#define STBI_NO_STDIO
|
||||
#define STBI_ASSERT SDL_assert
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#undef memset
|
||||
#endif
|
||||
|
||||
#ifdef SDL_HAVE_STB
|
||||
static bool SDL_ConvertPixels_MJPG_to_NV12(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch)
|
||||
{
|
||||
int w = 0, h = 0, format = 0;
|
||||
stbi__context s;
|
||||
stbi__start_mem(&s, src, src_pitch);
|
||||
|
||||
stbi__result_info ri;
|
||||
SDL_zero(ri);
|
||||
ri.bits_per_channel = 8;
|
||||
ri.channel_order = STBI_ORDER_RGB;
|
||||
ri.num_channels = 0;
|
||||
|
||||
stbi__nv12 nv12;
|
||||
nv12.w = width;
|
||||
nv12.h = height;
|
||||
nv12.pitch = dst_pitch;
|
||||
nv12.y = (stbi_uc *)dst;
|
||||
nv12.uv = nv12.y + (nv12.h * nv12.pitch);
|
||||
|
||||
void *pixels = stbi__jpeg_load(&s, &w, &h, &format, 4, &nv12, &ri);
|
||||
if (!pixels) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // SDL_HAVE_STB
|
||||
|
||||
bool SDL_ConvertPixels_STB(int width, int height,
|
||||
SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch,
|
||||
SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch)
|
||||
{
|
||||
#ifdef SDL_HAVE_STB
|
||||
if (src_format == SDL_PIXELFORMAT_MJPG && dst_format == SDL_PIXELFORMAT_NV12) {
|
||||
return SDL_ConvertPixels_MJPG_to_NV12(width, height, src, src_pitch, dst, dst_pitch);
|
||||
}
|
||||
|
||||
bool result;
|
||||
int w = 0, h = 0, format = 0;
|
||||
int len = (src_format == SDL_PIXELFORMAT_MJPG) ? src_pitch : (height * src_pitch);
|
||||
void *pixels = stbi_load_from_memory(src, len, &w, &h, &format, 4);
|
||||
if (!pixels) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (w == width && h == height) {
|
||||
result = SDL_ConvertPixelsAndColorspace(w, h, SDL_PIXELFORMAT_RGBA32, SDL_COLORSPACE_SRGB, 0, pixels, width * 4, dst_format, dst_colorspace, dst_properties, dst, dst_pitch);
|
||||
} else {
|
||||
result = SDL_SetError("Expected image size %dx%d, actual size %dx%d", width, height, w, h);
|
||||
}
|
||||
stbi_image_free(pixels);
|
||||
|
||||
return result;
|
||||
#else
|
||||
return SDL_SetError("SDL not built with STB image support");
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_stb_c_h_
|
||||
#define SDL_stb_c_h_
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
// Image conversion functions
|
||||
|
||||
extern bool SDL_ConvertPixels_STB(int width, int height, SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch);
|
||||
|
||||
#endif // SDL_stb_c_h_
|
||||
@@ -0,0 +1,982 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_surface_c.h"
|
||||
|
||||
static bool SDL_StretchSurfaceUncheckedNearest(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect);
|
||||
static bool SDL_StretchSurfaceUncheckedLinear(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect);
|
||||
|
||||
bool SDL_StretchSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode)
|
||||
{
|
||||
bool result;
|
||||
int src_locked;
|
||||
int dst_locked;
|
||||
SDL_Rect full_src;
|
||||
SDL_Rect full_dst;
|
||||
|
||||
if (!src) {
|
||||
return SDL_InvalidParamError("src");
|
||||
}
|
||||
if (!dst) {
|
||||
return SDL_InvalidParamError("dst");
|
||||
}
|
||||
|
||||
if (src->format != dst->format) {
|
||||
// Slow!
|
||||
SDL_Surface *src_tmp = SDL_ConvertSurfaceAndColorspace(src, dst->format, dst->palette, dst->colorspace, dst->props);
|
||||
if (!src_tmp) {
|
||||
return false;
|
||||
}
|
||||
result = SDL_StretchSurface(src_tmp, srcrect, dst, dstrect, scaleMode);
|
||||
SDL_DestroySurface(src_tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (SDL_ISPIXELFORMAT_FOURCC(src->format)) {
|
||||
// Slow!
|
||||
if (!dstrect) {
|
||||
full_dst.x = 0;
|
||||
full_dst.y = 0;
|
||||
full_dst.w = dst->w;
|
||||
full_dst.h = dst->h;
|
||||
dstrect = &full_dst;
|
||||
}
|
||||
|
||||
SDL_Surface *src_tmp = SDL_ConvertSurface(src, SDL_PIXELFORMAT_XRGB8888);
|
||||
SDL_Surface *dst_tmp = SDL_CreateSurface(dstrect->w, dstrect->h, SDL_PIXELFORMAT_XRGB8888);
|
||||
if (src_tmp && dst_tmp) {
|
||||
result = SDL_StretchSurface(src_tmp, srcrect, dst_tmp, NULL, scaleMode);
|
||||
if (result) {
|
||||
result = SDL_ConvertPixelsAndColorspace(dstrect->w, dstrect->h,
|
||||
dst_tmp->format, SDL_COLORSPACE_SRGB, 0,
|
||||
dst_tmp->pixels, dst_tmp->pitch,
|
||||
dst->format, dst->colorspace, SDL_GetSurfaceProperties(dst),
|
||||
(Uint8 *)dst->pixels + dstrect->y * dst->pitch + dstrect->x * SDL_BYTESPERPIXEL(dst->format), dst->pitch);
|
||||
}
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
SDL_DestroySurface(src_tmp);
|
||||
SDL_DestroySurface(dst_tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (scaleMode) {
|
||||
case SDL_SCALEMODE_NEAREST:
|
||||
break;
|
||||
case SDL_SCALEMODE_LINEAR:
|
||||
break;
|
||||
case SDL_SCALEMODE_PIXELART:
|
||||
scaleMode = SDL_SCALEMODE_NEAREST;
|
||||
break;
|
||||
default:
|
||||
return SDL_InvalidParamError("scaleMode");
|
||||
}
|
||||
|
||||
if (scaleMode == SDL_SCALEMODE_LINEAR) {
|
||||
if (SDL_BYTESPERPIXEL(src->format) != 4 || src->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 true;
|
||||
}
|
||||
|
||||
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)) {
|
||||
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)) {
|
||||
if (dst_locked) {
|
||||
SDL_UnlockSurface(dst);
|
||||
}
|
||||
return SDL_SetError("Unable to lock source surface");
|
||||
}
|
||||
src_locked = 1;
|
||||
}
|
||||
|
||||
if (scaleMode == SDL_SCALEMODE_NEAREST) {
|
||||
result = SDL_StretchSurfaceUncheckedNearest(src, srcrect, dst, dstrect);
|
||||
} else {
|
||||
result = SDL_StretchSurfaceUncheckedLinear(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 result;
|
||||
}
|
||||
|
||||
/* 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; \
|
||||
Sint64 fp_sum_h; \
|
||||
int fp_step_h, left_pad_h, right_pad_h; \
|
||||
Sint64 fp_sum_w; \
|
||||
int fp_step_w, left_pad_w, right_pad_w; \
|
||||
Sint64 fp_sum_w_init; \
|
||||
int 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; \
|
||||
Uint64 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 = (Uint64)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, Sint64 *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
|
||||
Sint64 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 bool 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 true;
|
||||
}
|
||||
|
||||
#ifdef SDL_NEON_INTRINSICS
|
||||
#define CAST_uint8x8_t (uint8x8_t)
|
||||
#define CAST_uint32x2_t (uint32x2_t)
|
||||
#endif
|
||||
|
||||
#if 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 bool 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 true;
|
||||
}
|
||||
#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 bool 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 true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool SDL_StretchSurfaceUncheckedLinear(SDL_Surface *s, const SDL_Rect *srcrect, SDL_Surface *d, const SDL_Rect *dstrect)
|
||||
{
|
||||
bool result = false;
|
||||
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 (!result && hasNEON()) {
|
||||
result = scale_mat_NEON(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SDL_SSE2_INTRINSICS
|
||||
if (!result && hasSSE2()) {
|
||||
result = scale_mat_SSE(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!result) {
|
||||
result = scale_mat(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define SDL_SCALE_NEAREST__START \
|
||||
int i; \
|
||||
Uint64 posy, incy; \
|
||||
Uint64 posx, incx; \
|
||||
Uint64 srcy, srcx; \
|
||||
int dst_gap, n; \
|
||||
const Uint32 *src_h0; \
|
||||
incy = ((Uint64)src_h << 16) / dst_h; \
|
||||
incx = ((Uint64)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 bool 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;
|
||||
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 true;
|
||||
}
|
||||
|
||||
static bool 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;
|
||||
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 true;
|
||||
}
|
||||
|
||||
static bool 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;
|
||||
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 true;
|
||||
}
|
||||
|
||||
static bool 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;
|
||||
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 true;
|
||||
}
|
||||
|
||||
bool SDL_StretchSurfaceUncheckedNearest(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;
|
||||
int bpp = SDL_BYTESPERPIXEL(d->format);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_surface_c_h_
|
||||
#define SDL_surface_c_h_
|
||||
|
||||
// Useful functions and variables from SDL_surface.c
|
||||
|
||||
#include "SDL_blit.h"
|
||||
|
||||
// Surface internal flags
|
||||
typedef Uint32 SDL_SurfaceDataFlags;
|
||||
|
||||
#define SDL_INTERNAL_SURFACE_DONTFREE 0x00000001u /**< Surface is referenced internally */
|
||||
#define SDL_INTERNAL_SURFACE_STACK 0x00000002u /**< Surface is allocated on the stack */
|
||||
#define SDL_INTERNAL_SURFACE_RLEACCEL 0x00000004u /**< Surface is RLE encoded */
|
||||
|
||||
// Surface internal data definition
|
||||
struct SDL_Surface
|
||||
{
|
||||
// Public API definition
|
||||
SDL_SurfaceFlags flags; /**< The flags of the surface, read-only */
|
||||
SDL_PixelFormat format; /**< The format of the surface, read-only */
|
||||
int w; /**< The width of the surface, read-only. */
|
||||
int h; /**< The height of the surface, read-only. */
|
||||
int pitch; /**< The distance in bytes between rows of pixels, read-only */
|
||||
void *pixels; /**< A pointer to the pixels of the surface, the pixels are writeable if non-NULL */
|
||||
|
||||
int refcount; /**< Application reference count, used when freeing surface */
|
||||
|
||||
void *reserved; /**< Reserved for internal use */
|
||||
|
||||
// Private API definition
|
||||
|
||||
/** flags for this surface */
|
||||
SDL_SurfaceDataFlags internal_flags;
|
||||
|
||||
/** properties for this surface */
|
||||
SDL_PropertiesID props;
|
||||
|
||||
/** detailed format for this surface */
|
||||
const SDL_PixelFormatDetails *fmt;
|
||||
|
||||
/** Pixel colorspace */
|
||||
SDL_Colorspace colorspace;
|
||||
|
||||
/** palette for indexed surfaces */
|
||||
SDL_Palette *palette;
|
||||
|
||||
/** Alternate representation of images */
|
||||
int num_images;
|
||||
SDL_Surface **images;
|
||||
|
||||
/** information needed for surfaces requiring locks */
|
||||
int locked;
|
||||
|
||||
/** clipping information */
|
||||
SDL_Rect clip_rect;
|
||||
|
||||
/** info for fast blit mapping to other surfaces */
|
||||
SDL_BlitMap map;
|
||||
};
|
||||
|
||||
// Surface functions
|
||||
extern bool SDL_SurfaceValid(SDL_Surface *surface);
|
||||
extern void SDL_UpdateSurfaceLockFlag(SDL_Surface *surface);
|
||||
extern bool SDL_CalculateSurfaceSize(SDL_PixelFormat format, int width, int height, size_t *size, size_t *pitch, bool minimalPitch);
|
||||
extern float SDL_GetDefaultSDRWhitePoint(SDL_Colorspace colorspace);
|
||||
extern float SDL_GetSurfaceSDRWhitePoint(SDL_Surface *surface, SDL_Colorspace colorspace);
|
||||
extern float SDL_GetDefaultHDRHeadroom(SDL_Colorspace colorspace);
|
||||
extern float SDL_GetSurfaceHDRHeadroom(SDL_Surface *surface, SDL_Colorspace colorspace);
|
||||
extern SDL_Surface *SDL_GetSurfaceImage(SDL_Surface *surface, float display_scale);
|
||||
|
||||
#endif // SDL_surface_c_h_
|
||||
@@ -0,0 +1,613 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_sysvideo_h_
|
||||
#define SDL_sysvideo_h_
|
||||
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
|
||||
#include "SDL_surface_c.h"
|
||||
|
||||
// The SDL video driver
|
||||
|
||||
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_WindowData SDL_WindowData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float SDR_white_level;
|
||||
float HDR_headroom;
|
||||
} SDL_HDROutputProperties;
|
||||
|
||||
// Define the SDL window structure, corresponding to toplevel windows
|
||||
struct SDL_Window
|
||||
{
|
||||
SDL_WindowID id;
|
||||
char *title;
|
||||
SDL_Surface *icon;
|
||||
int x, y;
|
||||
int w, h;
|
||||
int min_w, min_h;
|
||||
int max_w, max_h;
|
||||
float min_aspect;
|
||||
float max_aspect;
|
||||
int last_pixel_w, last_pixel_h;
|
||||
SDL_WindowFlags flags;
|
||||
SDL_WindowFlags pending_flags;
|
||||
float display_scale;
|
||||
bool external_graphics_context;
|
||||
bool fullscreen_exclusive; // The window is currently fullscreen exclusive
|
||||
SDL_DisplayID last_fullscreen_exclusive_display; // The last fullscreen_exclusive display
|
||||
SDL_DisplayID last_displayID;
|
||||
|
||||
/* Stored position and size for the window in the non-fullscreen state,
|
||||
* including when the window is maximized or tiled.
|
||||
*
|
||||
* This is the size and position to which the window should return when
|
||||
* leaving the fullscreen state.
|
||||
*/
|
||||
SDL_Rect windowed;
|
||||
|
||||
/* Stored position and size for the window in the base 'floating' state;
|
||||
* when not fullscreen, nor in a state such as maximized or tiled.
|
||||
*
|
||||
* This is the size and position to which the window should return when
|
||||
* it's maximized and SDL_RestoreWindow() is called.
|
||||
*/
|
||||
SDL_Rect floating;
|
||||
|
||||
// The last client requested size and position for the window.
|
||||
SDL_Rect pending;
|
||||
|
||||
/* Toggle for drivers to indicate that the current window state is tiled,
|
||||
* and sizes set non-programmatically shouldn't be cached.
|
||||
*/
|
||||
bool tiled;
|
||||
|
||||
// Whether or not the initial position was defined
|
||||
bool undefined_x;
|
||||
bool undefined_y;
|
||||
|
||||
SDL_DisplayMode requested_fullscreen_mode;
|
||||
SDL_DisplayMode current_fullscreen_mode;
|
||||
SDL_HDROutputProperties HDR;
|
||||
|
||||
float opacity;
|
||||
|
||||
SDL_Surface *surface;
|
||||
bool surface_valid;
|
||||
|
||||
bool is_hiding;
|
||||
bool restore_on_show; // Child was hidden recursively by the parent, restore when shown.
|
||||
bool last_position_pending; // This should NOT be cleared by the backend, as it is used for fullscreen positioning.
|
||||
bool last_size_pending; // This should be cleared by the backend if the new size cannot be applied.
|
||||
bool update_fullscreen_on_display_changed;
|
||||
bool constrain_popup;
|
||||
bool is_destroying;
|
||||
bool is_dropping; // drag/drop in progress, expecting SDL_SendDropComplete().
|
||||
|
||||
int safe_inset_left;
|
||||
int safe_inset_right;
|
||||
int safe_inset_top;
|
||||
int safe_inset_bottom;
|
||||
SDL_Rect safe_rect;
|
||||
|
||||
SDL_PropertiesID text_input_props;
|
||||
bool text_input_active;
|
||||
SDL_Rect text_input_rect;
|
||||
int text_input_cursor;
|
||||
|
||||
SDL_Rect mouse_rect;
|
||||
|
||||
SDL_HitTest hit_test;
|
||||
void *hit_test_data;
|
||||
|
||||
SDL_ProgressState progress_state;
|
||||
float progress_value;
|
||||
|
||||
SDL_PropertiesID props;
|
||||
|
||||
int num_renderers;
|
||||
SDL_Renderer **renderers;
|
||||
|
||||
SDL_WindowData *internal;
|
||||
|
||||
// If a toplevel window, holds the current keyboard focus for grabbing popups.
|
||||
SDL_Window *keyboard_focus;
|
||||
|
||||
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 | 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_HDROutputProperties HDR;
|
||||
|
||||
// This is true if we are fullscreen or fullscreen is pending
|
||||
bool fullscreen_active;
|
||||
SDL_Window *fullscreen_window;
|
||||
|
||||
SDL_VideoDevice *device;
|
||||
|
||||
SDL_PropertiesID props;
|
||||
|
||||
SDL_DisplayData *internal;
|
||||
};
|
||||
|
||||
// Video device flags
|
||||
typedef enum
|
||||
{
|
||||
VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED = 0x01,
|
||||
VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT = 0x02,
|
||||
VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS = 0x04,
|
||||
VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY = 0x08,
|
||||
VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES = 0x10,
|
||||
VIDEO_DEVICE_CAPS_DISABLE_MOUSE_WARP_ON_FULLSCREEN_TRANSITIONS = 0x20,
|
||||
VIDEO_DEVICE_CAPS_SENDS_HDR_CHANGES = 0x40
|
||||
} DeviceCaps;
|
||||
|
||||
// Fullscreen operations
|
||||
typedef enum
|
||||
{
|
||||
SDL_FULLSCREEN_OP_LEAVE = 0,
|
||||
SDL_FULLSCREEN_OP_ENTER,
|
||||
SDL_FULLSCREEN_OP_UPDATE
|
||||
} SDL_FullscreenOp;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SDL_FULLSCREEN_FAILED,
|
||||
SDL_FULLSCREEN_SUCCEEDED,
|
||||
SDL_FULLSCREEN_PENDING
|
||||
} SDL_FullscreenResult;
|
||||
|
||||
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 true (success) or false (error).
|
||||
*/
|
||||
bool (*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
|
||||
*/
|
||||
bool (*GetDisplayBounds)(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
|
||||
|
||||
/*
|
||||
* Get the usable bounds of a display (bounds minus menubar or whatever)
|
||||
*/
|
||||
bool (*GetDisplayUsableBounds)(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
|
||||
|
||||
/*
|
||||
* Get a list of the available display modes for a display.
|
||||
*/
|
||||
bool (*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.
|
||||
*/
|
||||
bool (*SetDisplayMode)(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
|
||||
|
||||
/* * * */
|
||||
/*
|
||||
* Window functions
|
||||
*/
|
||||
bool (*CreateSDLWindow)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
|
||||
void (*SetWindowTitle)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*SetWindowIcon)(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
|
||||
bool (*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);
|
||||
void (*SetWindowAspectRatio)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*GetWindowBordersSize)(SDL_VideoDevice *_this, SDL_Window *window, int *top, int *left, int *bottom, int *right);
|
||||
float (*GetWindowContentScale)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
void (*GetWindowSizeInPixels)(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
|
||||
bool (*SetWindowOpacity)(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
|
||||
bool (*SetWindowParent)(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent);
|
||||
bool (*SetWindowModal)(SDL_VideoDevice *_this, SDL_Window *window, bool modal);
|
||||
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, bool bordered);
|
||||
void (*SetWindowResizable)(SDL_VideoDevice *_this, SDL_Window *window, bool resizable);
|
||||
void (*SetWindowAlwaysOnTop)(SDL_VideoDevice *_this, SDL_Window *window, bool on_top);
|
||||
SDL_FullscreenResult (*SetWindowFullscreen)(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen);
|
||||
void *(*GetWindowICCProfile)(SDL_VideoDevice *_this, SDL_Window *window, size_t *size);
|
||||
SDL_DisplayID (*GetDisplayForWindow)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*SetWindowMouseRect)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*SetWindowMouseGrab)(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed);
|
||||
bool (*SetWindowKeyboardGrab)(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed);
|
||||
void (*DestroyWindow)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*CreateWindowFramebuffer)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PixelFormat *format, void **pixels, int *pitch);
|
||||
bool (*SetWindowFramebufferVSync)(SDL_VideoDevice *_this, SDL_Window *window, int vsync);
|
||||
bool (*GetWindowFramebufferVSync)(SDL_VideoDevice *_this, SDL_Window *window, int *vsync);
|
||||
bool (*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);
|
||||
bool (*UpdateWindowShape)(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *shape);
|
||||
bool (*FlashWindow)(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||
bool (*ApplyWindowProgress)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*SetWindowFocusable)(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
|
||||
bool (*SyncWindow)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
/* * * */
|
||||
/*
|
||||
* OpenGL support
|
||||
*/
|
||||
bool (*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);
|
||||
bool (*GL_MakeCurrent)(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
|
||||
SDL_EGLSurface (*GL_GetEGLSurface)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*GL_SetSwapInterval)(SDL_VideoDevice *_this, int interval);
|
||||
bool (*GL_GetSwapInterval)(SDL_VideoDevice *_this, int *interval);
|
||||
bool (*GL_SwapWindow)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*GL_DestroyContext)(SDL_VideoDevice *_this, SDL_GLContext context);
|
||||
void (*GL_DefaultProfileConfig)(SDL_VideoDevice *_this, int *mask, int *major, int *minor);
|
||||
|
||||
/* * * */
|
||||
/*
|
||||
* Vulkan support
|
||||
*/
|
||||
bool (*Vulkan_LoadLibrary)(SDL_VideoDevice *_this, const char *path);
|
||||
void (*Vulkan_UnloadLibrary)(SDL_VideoDevice *_this);
|
||||
char const * const *(*Vulkan_GetInstanceExtensions)(SDL_VideoDevice *_this, Uint32 *count);
|
||||
bool (*Vulkan_CreateSurface)(SDL_VideoDevice *_this, SDL_Window *window, VkInstance instance, const struct VkAllocationCallbacks *allocator, VkSurfaceKHR *surface);
|
||||
void (*Vulkan_DestroySurface)(SDL_VideoDevice *_this, VkInstance instance, VkSurfaceKHR surface, const struct VkAllocationCallbacks *allocator);
|
||||
bool (*Vulkan_GetPresentationSupport)(SDL_VideoDevice *_this, VkInstance instance, VkPhysicalDevice physicalDevice, Uint32 queueFamilyIndex);
|
||||
|
||||
/* * * */
|
||||
/*
|
||||
* 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/resume the screensaver
|
||||
bool (*SuspendScreenSaver)(SDL_VideoDevice *_this);
|
||||
|
||||
// Text input
|
||||
bool (*StartTextInput)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
bool (*StopTextInput)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*UpdateTextInputArea)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*ClearComposition)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
// Screen keyboard
|
||||
bool (*HasScreenKeyboardSupport)(SDL_VideoDevice *_this);
|
||||
void (*ShowScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
void (*HideScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
void (*SetTextInputProperties)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
bool (*IsScreenKeyboardShown)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
// Clipboard
|
||||
const char **(*GetTextMimeTypes)(SDL_VideoDevice *_this, size_t *num_mime_types);
|
||||
bool (*SetClipboardData)(SDL_VideoDevice *_this);
|
||||
void *(*GetClipboardData)(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
|
||||
bool (*HasClipboardData)(SDL_VideoDevice *_this, const char *mime_type);
|
||||
/* If you implement *ClipboardData, you don't need to implement *ClipboardText */
|
||||
bool (*SetClipboardText)(SDL_VideoDevice *_this, const char *text);
|
||||
char *(*GetClipboardText)(SDL_VideoDevice *_this);
|
||||
bool (*HasClipboardText)(SDL_VideoDevice *_this);
|
||||
// These functions are only needed if the platform has a separate primary selection buffer
|
||||
bool (*SetPrimarySelectionText)(SDL_VideoDevice *_this, const char *text);
|
||||
char *(*GetPrimarySelectionText)(SDL_VideoDevice *_this);
|
||||
bool (*HasPrimarySelectionText)(SDL_VideoDevice *_this);
|
||||
|
||||
// MessageBox
|
||||
bool (*ShowMessageBox)(SDL_VideoDevice *_this, const SDL_MessageBoxData *messageboxdata, int *buttonID);
|
||||
|
||||
// Hit-testing
|
||||
bool (*SetWindowHitTest)(SDL_Window *window, bool enabled);
|
||||
|
||||
// Tell window that app enabled drag'n'drop events
|
||||
void (*AcceptDragAndDrop)(SDL_Window *window, bool accept);
|
||||
|
||||
// Display the system-level window menu
|
||||
void (*ShowWindowSystemMenu)(SDL_Window *window, int x, int y);
|
||||
|
||||
/* * * */
|
||||
// Data common to all drivers
|
||||
SDL_ThreadID thread;
|
||||
bool checked_texture_framebuffer;
|
||||
bool is_dummy;
|
||||
bool suspend_screensaver;
|
||||
void *wakeup_window;
|
||||
int num_displays;
|
||||
SDL_VideoDisplay **displays;
|
||||
SDL_Rect desktop_bounds;
|
||||
SDL_Window *windows;
|
||||
SDL_Window *grabbed_window;
|
||||
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;
|
||||
bool setting_display_mode;
|
||||
Uint32 device_caps;
|
||||
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];
|
||||
SDL_SharedObject *dll_handle;
|
||||
} gl_config;
|
||||
|
||||
SDL_EGLAttribArrayCallback egl_platformattrib_callback;
|
||||
SDL_EGLIntArrayCallback egl_surfaceattrib_callback;
|
||||
SDL_EGLIntArrayCallback egl_contextattrib_callback;
|
||||
void *egl_attrib_callback_userdata;
|
||||
|
||||
/* * * */
|
||||
// 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.) */
|
||||
bool gl_allow_no_surface;
|
||||
|
||||
/* * * */
|
||||
// Data used by the Vulkan drivers
|
||||
struct
|
||||
{
|
||||
SDL_FunctionPointer vkGetInstanceProcAddr;
|
||||
SDL_FunctionPointer vkEnumerateInstanceExtensionProperties;
|
||||
int loader_loaded;
|
||||
char loader_path[256];
|
||||
SDL_SharedObject *loader_handle;
|
||||
} vulkan_config;
|
||||
|
||||
/* * * */
|
||||
// Data private to this driver
|
||||
SDL_VideoData *internal;
|
||||
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);
|
||||
bool (*ShowMessageBox)(const SDL_MessageBoxData *messageboxdata, int *buttonID); // can be done without initializing backend!
|
||||
bool is_preferred;
|
||||
} VideoBootStrap;
|
||||
|
||||
// Not all of these are available in a given build. Use #ifdefs, etc.
|
||||
extern VideoBootStrap PRIVATE_bootstrap;
|
||||
extern VideoBootStrap COCOA_bootstrap;
|
||||
extern VideoBootStrap X11_bootstrap;
|
||||
extern VideoBootStrap WINDOWS_bootstrap;
|
||||
extern VideoBootStrap HAIKU_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 NGAGE_bootstrap;
|
||||
extern VideoBootStrap RPI_bootstrap;
|
||||
extern VideoBootStrap KMSDRM_bootstrap;
|
||||
extern VideoBootStrap DUMMY_bootstrap;
|
||||
extern VideoBootStrap DUMMY_evdev_bootstrap;
|
||||
extern VideoBootStrap Wayland_preferred_bootstrap;
|
||||
extern VideoBootStrap Wayland_bootstrap;
|
||||
extern VideoBootStrap VIVANTE_bootstrap;
|
||||
extern VideoBootStrap Emscripten_bootstrap;
|
||||
extern VideoBootStrap OFFSCREEN_bootstrap;
|
||||
extern VideoBootStrap QNX_bootstrap;
|
||||
extern VideoBootStrap OPENVR_bootstrap;
|
||||
|
||||
extern bool SDL_UninitializedVideo(void);
|
||||
// Use SDL_OnVideoThread() sparingly, to avoid regressions in use cases that currently happen to work
|
||||
extern bool SDL_OnVideoThread(void);
|
||||
extern SDL_VideoDevice *SDL_GetVideoDevice(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, bool send_event);
|
||||
extern void SDL_DelVideoDisplay(SDL_DisplayID display, bool send_event);
|
||||
extern 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 void SDL_SetDisplayHDRProperties(SDL_VideoDisplay *display, const SDL_HDROutputProperties *HDR);
|
||||
extern bool SDL_SetDisplayModeForDisplay(SDL_VideoDisplay *display, SDL_DisplayMode *mode);
|
||||
extern SDL_VideoDisplay *SDL_GetVideoDisplay(SDL_DisplayID display);
|
||||
extern SDL_DisplayID SDL_GetDisplayForWindowPosition(SDL_Window *window);
|
||||
extern SDL_VideoDisplay *SDL_GetVideoDisplayForWindow(SDL_Window *window);
|
||||
extern SDL_VideoDisplay *SDL_GetVideoDisplayForFullscreenWindow(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_SetWindowHDRProperties(SDL_Window *window, const SDL_HDROutputProperties *HDR, bool send_event);
|
||||
extern void SDL_SetWindowSafeAreaInsets(SDL_Window *window, int left, int right, int top, int bottom);
|
||||
|
||||
extern void SDL_GL_DeduceMaxSupportedESProfile(int *major, int *minor);
|
||||
|
||||
extern bool SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags);
|
||||
extern bool SDL_HasWindows(void);
|
||||
extern void SDL_RelativeToGlobalForWindow(SDL_Window *window, int rel_x, int rel_y, int *abs_x, int *abs_y);
|
||||
extern void SDL_GlobalToRelativeForWindow(SDL_Window *window, int abs_x, int abs_y, int *rel_x, int *rel_y);
|
||||
extern bool SDL_ShouldFocusPopup(SDL_Window *window);
|
||||
extern bool SDL_ShouldRelinquishPopupFocus(SDL_Window *window, SDL_Window **new_focus);
|
||||
|
||||
extern void SDL_OnDisplayAdded(SDL_VideoDisplay *display);
|
||||
extern void SDL_OnDisplayMoved(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_OnWindowLiveResizeUpdate(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 bool SDL_UpdateFullscreenMode(SDL_Window *window, SDL_FullscreenOp fullscreen, bool commit);
|
||||
extern SDL_Window *SDL_GetToplevelForKeyboardFocus(void);
|
||||
|
||||
extern bool SDL_ShouldAllowTopmost(void);
|
||||
|
||||
extern void SDL_ToggleDragAndDropSupport(void);
|
||||
|
||||
extern void SDL_UpdateDesktopBounds(void);
|
||||
|
||||
extern SDL_TextInputType SDL_GetTextInputType(SDL_PropertiesID props);
|
||||
extern SDL_Capitalization SDL_GetTextInputCapitalization(SDL_PropertiesID props);
|
||||
extern bool SDL_GetTextInputAutocorrect(SDL_PropertiesID props);
|
||||
extern bool SDL_GetTextInputMultiline(SDL_PropertiesID props);
|
||||
|
||||
#endif // SDL_sysvideo_h_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_video_c_h_
|
||||
#define SDL_video_c_h_
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
struct SDL_VideoDevice;
|
||||
|
||||
/**
|
||||
* 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 true on success or false on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*/
|
||||
extern bool 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 bool SDL_SetWindowTextureVSync(struct SDL_VideoDevice *_this, SDL_Window *window, int vsync);
|
||||
|
||||
#if defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND) || defined(SDL_VIDEO_DRIVER_EMSCRIPTEN)
|
||||
const char *SDL_GetCSSCursorName(SDL_SystemCursor id, const char **fallback_name);
|
||||
#endif
|
||||
|
||||
extern bool SDL_AddWindowRenderer(SDL_Window *window, SDL_Renderer *renderer);
|
||||
extern void SDL_RemoveWindowRenderer(SDL_Window *window, SDL_Renderer *renderer);
|
||||
|
||||
#endif // SDL_video_c_h_
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_VIDEO_DRIVER_WINDOWS
|
||||
|
||||
#if defined(SDL_PLATFORM_WINDOWS)
|
||||
|
||||
bool SDL_RegisterApp(const char *name, Uint32 style, void *hInst)
|
||||
{
|
||||
(void)name;
|
||||
(void)style;
|
||||
(void)hInst;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDL_UnregisterApp(void)
|
||||
{
|
||||
}
|
||||
|
||||
void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // defined(SDL_PLATFORM_WINDOWS)
|
||||
|
||||
SDL_DECLSPEC bool SDLCALL SDL_GetDXGIOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *outputIndex);
|
||||
bool SDL_GetDXGIOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *outputIndex)
|
||||
{
|
||||
(void)displayID;
|
||||
(void)adapterIndex;
|
||||
(void)outputIndex;
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
SDL_DECLSPEC int SDLCALL SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID);
|
||||
int SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID)
|
||||
{
|
||||
(void)displayID;
|
||||
SDL_Unsupported();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#elif defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
SDL_DECLSPEC int SDLCALL SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID);
|
||||
int SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID)
|
||||
{
|
||||
(void)displayID;
|
||||
SDL_Unsupported();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // !SDL_VIDEO_DRIVER_WINDOWS
|
||||
|
||||
#ifndef SDL_PLATFORM_GDK
|
||||
|
||||
SDL_DECLSPEC bool SDLCALL SDL_GetGDKTaskQueue(void *outTaskQueue);
|
||||
bool SDL_GetGDKTaskQueue(void *outTaskQueue)
|
||||
{
|
||||
(void)outTaskQueue;
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef SDL_VIDEO_DRIVER_UIKIT
|
||||
|
||||
SDL_DECLSPEC void SDLCALL SDL_OnApplicationDidChangeStatusBarOrientation(void);
|
||||
void SDL_OnApplicationDidChangeStatusBarOrientation(void)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef SDL_VIDEO_DRIVER_UIKIT
|
||||
|
||||
typedef void (SDLCALL *SDL_iOSAnimationCallback)(void *userdata);
|
||||
SDL_DECLSPEC bool SDLCALL SDL_SetiOSAnimationCallback(SDL_Window *window, int interval, SDL_iOSAnimationCallback callback, void *callbackParam);
|
||||
bool SDL_SetiOSAnimationCallback(SDL_Window *window, int interval, SDL_iOSAnimationCallback callback, void *callbackParam)
|
||||
{
|
||||
(void)window;
|
||||
(void)interval;
|
||||
(void)callback;
|
||||
(void)callbackParam;
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
SDL_DECLSPEC void SDLCALL SDL_SetiOSEventPump(bool enabled);
|
||||
void SDL_SetiOSEventPump(bool enabled)
|
||||
{
|
||||
(void)enabled;
|
||||
SDL_Unsupported();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#ifndef SDL_vulkan_internal_h_
|
||||
#define SDL_vulkan_internal_h_
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_VULKAN
|
||||
#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
|
||||
|
||||
/* 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 bool SDL_Vulkan_Display_CreateSurface(void *vkGetInstanceProcAddr,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
VkSurfaceKHR *surface);
|
||||
|
||||
/* Platform independent base function for destroying the Vulkan surface. Unlike surface
|
||||
* creation, surface destruction doesn't require platform specific extensions like
|
||||
* VK_KHR_wayland_surface, VK_KHR_android_surface or VK_EXT_metal_surface. The only
|
||||
* necessary extension is cross platform VK_KHR_surface, which is a dependency to all
|
||||
* WSI platform extensions, so we can handle surface destruction in an platform-independent
|
||||
* manner. */
|
||||
extern void SDL_Vulkan_DestroySurface_Internal(void *vkGetInstanceProcAddr,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR surface,
|
||||
const struct VkAllocationCallbacks *allocator);
|
||||
#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_
|
||||
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "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 rc = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
|
||||
VkExtensionProperties *result;
|
||||
|
||||
if (rc == 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(rc),
|
||||
(int)rc);
|
||||
return NULL;
|
||||
} else if (rc != VK_SUCCESS) {
|
||||
SDL_SetError(
|
||||
"Getting Vulkan extensions failed: vkEnumerateInstanceExtensionProperties returned "
|
||||
"%s(%d)",
|
||||
SDL_Vulkan_GetResultString(rc),
|
||||
(int)rc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
result = (VkExtensionProperties *)SDL_calloc(1, sizeof(VkExtensionProperties)); // so we can return non-null
|
||||
} else {
|
||||
result = (VkExtensionProperties *)SDL_calloc(count, sizeof(VkExtensionProperties));
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = vkEnumerateInstanceExtensionProperties(NULL, &count, result);
|
||||
if (rc != VK_SUCCESS) {
|
||||
SDL_SetError(
|
||||
"Getting Vulkan extensions failed: vkEnumerateInstanceExtensionProperties returned "
|
||||
"%s(%d)",
|
||||
SDL_Vulkan_GetResultString(rc),
|
||||
(int)rc);
|
||||
SDL_free(result);
|
||||
return NULL;
|
||||
}
|
||||
*extensionCount = count;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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,
|
||||
};
|
||||
|
||||
bool SDL_Vulkan_Display_CreateSurface(void *vkGetInstanceProcAddr_,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
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 rc;
|
||||
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_GetHint(SDL_HINT_VULKAN_DISPLAY);
|
||||
if (chosenDisplayId) {
|
||||
displayId = SDL_atoi(chosenDisplayId);
|
||||
}
|
||||
|
||||
// Enumerate physical devices
|
||||
rc = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
|
||||
if (rc != VK_SUCCESS) {
|
||||
SDL_SetError("Could not enumerate Vulkan physical devices");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (physicalDeviceCount == 0) {
|
||||
SDL_SetError("No Vulkan physical devices");
|
||||
goto error;
|
||||
}
|
||||
|
||||
physicalDevices = (VkPhysicalDevice *)SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
|
||||
if (!physicalDevices) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
|
||||
if (rc != 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
|
||||
rc = vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertiesCount, NULL);
|
||||
if (rc != 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 = (VkDisplayPropertiesKHR *)SDL_malloc(sizeof(VkDisplayPropertiesKHR) * displayPropertiesCount);
|
||||
if (!displayProperties) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertiesCount, displayProperties);
|
||||
if (rc != 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
|
||||
rc = vkGetDisplayModePropertiesKHR(physicalDevice, display, &displayModePropertiesCount, NULL);
|
||||
if (rc != 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 = (VkDisplayModePropertiesKHR *)SDL_malloc(sizeof(VkDisplayModePropertiesKHR) * displayModePropertiesCount);
|
||||
if (!displayModeProperties) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = vkGetDisplayModePropertiesKHR(physicalDevice, display, &displayModePropertiesCount, displayModeProperties);
|
||||
if (rc != 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
|
||||
rc = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &displayPlanePropertiesCount, NULL);
|
||||
if (rc != 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 = (VkDisplayPlanePropertiesKHR *)SDL_malloc(sizeof(VkDisplayPlanePropertiesKHR) * displayPlanePropertiesCount);
|
||||
if (!displayPlaneProperties) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &displayPlanePropertiesCount, displayPlaneProperties);
|
||||
if (rc != 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.
|
||||
rc = vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, i, &planeSupportedDisplaysCount, NULL);
|
||||
if (rc != 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 = (VkDisplayKHR *)SDL_malloc(sizeof(VkDisplayKHR) * planeSupportedDisplaysCount);
|
||||
if (!planeSupportedDisplays) {
|
||||
SDL_free(displayPlaneProperties);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, i, &planeSupportedDisplaysCount, planeSupportedDisplays);
|
||||
if (rc != 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;
|
||||
}
|
||||
|
||||
rc = vkGetDisplayPlaneCapabilitiesKHR(physicalDevice, createInfo.displayMode, i, &planeCaps);
|
||||
if (rc != 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 %u, minimum extent %ux%u maximum extent %ux%u", 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");
|
||||
goto error;
|
||||
}
|
||||
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
|
||||
createInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
createInfo.globalAlpha = 1.0f;
|
||||
|
||||
rc = vkCreateDisplayPlaneSurfaceKHR(instance, &createInfo, allocator, surface);
|
||||
if (rc != VK_SUCCESS) {
|
||||
SDL_SetError("vkCreateDisplayPlaneSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(rc));
|
||||
goto error;
|
||||
}
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Created surface");
|
||||
return true;
|
||||
|
||||
error:
|
||||
SDL_free(physicalDevices);
|
||||
return false;
|
||||
}
|
||||
|
||||
void SDL_Vulkan_DestroySurface_Internal(void *vkGetInstanceProcAddr_,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR surface,
|
||||
const struct VkAllocationCallbacks *allocator)
|
||||
{
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
|
||||
(PFN_vkGetInstanceProcAddr)vkGetInstanceProcAddr_;
|
||||
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR =
|
||||
(PFN_vkDestroySurfaceKHR)vkGetInstanceProcAddr(
|
||||
instance,
|
||||
"vkDestroySurfaceKHR");
|
||||
|
||||
if (vkDestroySurfaceKHR) {
|
||||
vkDestroySurfaceKHR(instance, surface, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_yuv_c_h_
|
||||
#define SDL_yuv_c_h_
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
// YUV conversion functions
|
||||
|
||||
extern bool SDL_ConvertPixels_YUV_to_RGB(int width, int height, SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch);
|
||||
extern bool SDL_ConvertPixels_RGB_to_YUV(int width, int height, SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch);
|
||||
extern bool SDL_ConvertPixels_YUV_to_YUV(int width, int height, SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch);
|
||||
|
||||
|
||||
extern bool SDL_CalculateYUVSize(SDL_PixelFormat format, int w, int h, size_t *size, size_t *pitch);
|
||||
|
||||
#endif // SDL_yuv_c_h_
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
||||
|
||||
#include "SDL_androidvideo.h"
|
||||
#include "SDL_androidclipboard.h"
|
||||
#include "../../core/android/SDL_android.h"
|
||||
|
||||
bool Android_SetClipboardText(SDL_VideoDevice *_this, const char *text)
|
||||
{
|
||||
return Android_JNI_SetClipboardText(text);
|
||||
}
|
||||
|
||||
char *Android_GetClipboardText(SDL_VideoDevice *_this)
|
||||
{
|
||||
return Android_JNI_GetClipboardText();
|
||||
}
|
||||
|
||||
bool Android_HasClipboardText(SDL_VideoDevice *_this)
|
||||
{
|
||||
return Android_JNI_HasClipboardText();
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_androidclipboard_h_
|
||||
#define SDL_androidclipboard_h_
|
||||
|
||||
extern bool Android_SetClipboardText(SDL_VideoDevice *_this, const char *text);
|
||||
extern char *Android_GetClipboardText(SDL_VideoDevice *_this);
|
||||
extern bool Android_HasClipboardText(SDL_VideoDevice *_this);
|
||||
|
||||
#endif // SDL_androidclipboard_h_
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_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/aaudio/SDL_aaudio.h"
|
||||
#include "../../audio/openslES/SDL_openslES.h"
|
||||
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
static void android_egl_context_restore(SDL_Window *window)
|
||||
{
|
||||
if (window) {
|
||||
SDL_WindowData *data = window->internal;
|
||||
SDL_GL_MakeCurrent(window, NULL);
|
||||
if (!SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context)) {
|
||||
// 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);
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = SDL_EVENT_RENDER_DEVICE_RESET;
|
||||
event.render.windowID = SDL_GetWindowID(window);
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
data->backup_done = false;
|
||||
|
||||
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->internal;
|
||||
data->egl_context = SDL_GL_GetCurrentContext();
|
||||
|
||||
// Save/Restore the swap interval / vsync
|
||||
if (SDL_GL_GetSwapInterval(&interval)) {
|
||||
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 = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume
|
||||
*/
|
||||
static bool Android_EventsInitialized;
|
||||
static bool Android_BlockOnPause = true;
|
||||
static bool Android_Paused;
|
||||
static bool Android_PausedAudio;
|
||||
static bool Android_Destroyed;
|
||||
|
||||
void Android_InitEvents(void)
|
||||
{
|
||||
if (!Android_EventsInitialized) {
|
||||
Android_BlockOnPause = SDL_GetHintBoolean(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, true);
|
||||
Android_Paused = false;
|
||||
Android_Destroyed = false;
|
||||
Android_EventsInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void Android_PauseAudio(void)
|
||||
{
|
||||
OPENSLES_PauseDevices();
|
||||
AAUDIO_PauseDevices();
|
||||
Android_PausedAudio = true;
|
||||
}
|
||||
|
||||
static void Android_ResumeAudio(void)
|
||||
{
|
||||
if (Android_PausedAudio) {
|
||||
OPENSLES_ResumeDevices();
|
||||
AAUDIO_ResumeDevices();
|
||||
Android_PausedAudio = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void Android_OnPause(void)
|
||||
{
|
||||
SDL_OnApplicationWillEnterBackground();
|
||||
SDL_OnApplicationDidEnterBackground();
|
||||
|
||||
/* The semantics are that as soon as the enter background event
|
||||
* has been queued, the app will block. The application should
|
||||
* do any life cycle handling in an event filter while the event
|
||||
* was being queued.
|
||||
*/
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
if (Android_Window && !Android_Window->external_graphics_context) {
|
||||
Android_LockActivityMutex();
|
||||
android_egl_context_backup(Android_Window);
|
||||
Android_UnlockActivityMutex();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Android_BlockOnPause) {
|
||||
// We're blocking, also pause audio
|
||||
Android_PauseAudio();
|
||||
}
|
||||
|
||||
Android_Paused = true;
|
||||
}
|
||||
|
||||
static void Android_OnResume(void)
|
||||
{
|
||||
Android_Paused = false;
|
||||
|
||||
SDL_OnApplicationWillEnterForeground();
|
||||
|
||||
Android_ResumeAudio();
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
// Restore the GL Context from here, as this operation is thread dependent
|
||||
if (Android_Window && !Android_Window->external_graphics_context && !SDL_HasEvent(SDL_EVENT_QUIT)) {
|
||||
Android_LockActivityMutex();
|
||||
android_egl_context_restore(Android_Window);
|
||||
Android_UnlockActivityMutex();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Make sure SW Keyboard is restored when an app becomes foreground
|
||||
if (Android_Window) {
|
||||
Android_RestoreScreenKeyboardOnResume(SDL_GetVideoDevice(), Android_Window);
|
||||
}
|
||||
|
||||
SDL_OnApplicationDidEnterForeground();
|
||||
}
|
||||
|
||||
static void Android_OnLowMemory(void)
|
||||
{
|
||||
SDL_SendAppEvent(SDL_EVENT_LOW_MEMORY);
|
||||
}
|
||||
|
||||
static void Android_OnDestroy(void)
|
||||
{
|
||||
// Make sure we unblock any audio processing before we quit
|
||||
Android_ResumeAudio();
|
||||
|
||||
/* Discard previous events. The user should have handled state storage
|
||||
* in SDL_EVENT_WILL_ENTER_BACKGROUND. After nativeSendQuit() is called, no
|
||||
* events other than SDL_EVENT_QUIT and SDL_EVENT_TERMINATING should fire */
|
||||
SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST);
|
||||
SDL_SendQuit();
|
||||
SDL_SendAppEvent(SDL_EVENT_TERMINATING);
|
||||
|
||||
Android_Destroyed = true;
|
||||
}
|
||||
|
||||
static void Android_HandleLifecycleEvent(SDL_AndroidLifecycleEvent event)
|
||||
{
|
||||
switch (event) {
|
||||
case SDL_ANDROID_LIFECYCLE_WAKE:
|
||||
// Nothing to do, just return
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_PAUSE:
|
||||
Android_OnPause();
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_RESUME:
|
||||
Android_OnResume();
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_LOWMEMORY:
|
||||
Android_OnLowMemory();
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_DESTROY:
|
||||
Android_OnDestroy();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static Sint64 GetLifecycleEventTimeout(bool paused, Sint64 timeoutNS)
|
||||
{
|
||||
if (Android_Paused) {
|
||||
if (Android_BlockOnPause) {
|
||||
timeoutNS = -1;
|
||||
} else if (timeoutNS == 0) {
|
||||
timeoutNS = SDL_MS_TO_NS(100);
|
||||
}
|
||||
}
|
||||
return timeoutNS;
|
||||
}
|
||||
|
||||
void Android_PumpEvents(Sint64 timeoutNS)
|
||||
{
|
||||
SDL_AndroidLifecycleEvent event;
|
||||
bool paused = Android_Paused;
|
||||
|
||||
while (!Android_Destroyed &&
|
||||
Android_WaitLifecycleEvent(&event, GetLifecycleEventTimeout(paused, timeoutNS))) {
|
||||
Android_HandleLifecycleEvent(event);
|
||||
|
||||
switch (event) {
|
||||
case SDL_ANDROID_LIFECYCLE_WAKE:
|
||||
// Finish handling events quickly if we're not paused
|
||||
timeoutNS = 0;
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_PAUSE:
|
||||
// Finish handling events at the current timeout and return to process events one more time before blocking.
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_RESUME:
|
||||
// Finish handling events at the resume state timeout
|
||||
paused = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Android_WaitActiveAndLockActivity(void)
|
||||
{
|
||||
while (Android_Paused && !Android_Destroyed) {
|
||||
Android_PumpEvents(-1);
|
||||
}
|
||||
|
||||
if (Android_Destroyed) {
|
||||
SDL_SetError("Android activity has been destroyed");
|
||||
return false;
|
||||
}
|
||||
|
||||
Android_LockActivityMutex();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Android_QuitEvents(void)
|
||||
{
|
||||
Android_EventsInitialized = false;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
extern void Android_InitEvents(void);
|
||||
extern void Android_PumpEvents(Sint64 timeoutNS);
|
||||
extern bool Android_WaitActiveAndLockActivity(void);
|
||||
extern void Android_QuitEvents(void);
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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_androidevents.h"
|
||||
#include "SDL_androidgl.h"
|
||||
#include "../../core/android/SDL_android.h"
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
bool Android_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
|
||||
{
|
||||
if (window && context) {
|
||||
return SDL_EGL_MakeCurrent(_this, window->internal->egl_surface, context);
|
||||
} else {
|
||||
return SDL_EGL_MakeCurrent(_this, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_GLContext Android_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_GLContext result;
|
||||
|
||||
if (!Android_WaitActiveAndLockActivity()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = SDL_EGL_CreateContext(_this, window->internal->egl_surface);
|
||||
|
||||
Android_UnlockActivityMutex();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Android_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
bool result;
|
||||
|
||||
Android_LockActivityMutex();
|
||||
|
||||
/* 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();*/
|
||||
result = SDL_EGL_SwapBuffers(_this, window->internal->egl_surface);
|
||||
|
||||
Android_UnlockActivityMutex();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Android_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
|
||||
{
|
||||
return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType)0, 0);
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_androidgl_h_
|
||||
#define SDL_androidgl_h_
|
||||
|
||||
extern SDL_GLContext Android_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Android_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
|
||||
extern bool Android_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Android_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
|
||||
#endif // SDL_androidgl_h_
|
||||
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#include "SDL_androidkeyboard.h"
|
||||
|
||||
#include "../../core/android/SDL_android.h"
|
||||
|
||||
#define TYPE_CLASS_TEXT 0x00000001
|
||||
#define TYPE_CLASS_NUMBER 0x00000002
|
||||
#define TYPE_CLASS_PHONE 0x00000003
|
||||
#define TYPE_CLASS_DATETIME 0x00000004
|
||||
|
||||
#define TYPE_DATETIME_VARIATION_NORMAL 0x00000000
|
||||
#define TYPE_DATETIME_VARIATION_DATE 0x00000010
|
||||
#define TYPE_DATETIME_VARIATION_TIME 0x00000020
|
||||
|
||||
#define TYPE_NUMBER_VARIATION_NORMAL 0x00000000
|
||||
#define TYPE_NUMBER_VARIATION_PASSWORD 0x00000010
|
||||
#define TYPE_NUMBER_FLAG_SIGNED 0x00001000
|
||||
#define TYPE_NUMBER_FLAG_DECIMAL 0x00002000
|
||||
|
||||
#define TYPE_TEXT_FLAG_CAP_CHARACTERS 0x00001000
|
||||
#define TYPE_TEXT_FLAG_CAP_WORDS 0x00002000
|
||||
#define TYPE_TEXT_FLAG_CAP_SENTENCES 0x00004000
|
||||
#define TYPE_TEXT_FLAG_AUTO_CORRECT 0x00008000
|
||||
#define TYPE_TEXT_FLAG_AUTO_COMPLETE 0x00010000
|
||||
#define TYPE_TEXT_FLAG_MULTI_LINE 0x00020000
|
||||
#define TYPE_TEXT_FLAG_IME_MULTI_LINE 0x00040000
|
||||
#define TYPE_TEXT_FLAG_NO_SUGGESTIONS 0x00080000
|
||||
|
||||
#define TYPE_TEXT_VARIATION_NORMAL 0x00000000
|
||||
#define TYPE_TEXT_VARIATION_URI 0x00000010
|
||||
#define TYPE_TEXT_VARIATION_EMAIL_ADDRESS 0x00000020
|
||||
#define TYPE_TEXT_VARIATION_EMAIL_SUBJECT 0x00000030
|
||||
#define TYPE_TEXT_VARIATION_SHORT_MESSAGE 0x00000040
|
||||
#define TYPE_TEXT_VARIATION_LONG_MESSAGE 0x00000050
|
||||
#define TYPE_TEXT_VARIATION_PERSON_NAME 0x00000060
|
||||
#define TYPE_TEXT_VARIATION_POSTAL_ADDRESS 0x00000070
|
||||
#define TYPE_TEXT_VARIATION_PASSWORD 0x00000080
|
||||
#define TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 0x00000090
|
||||
#define TYPE_TEXT_VARIATION_WEB_EDIT_TEXT 0x000000a0
|
||||
#define TYPE_TEXT_VARIATION_FILTER 0x000000b0
|
||||
#define TYPE_TEXT_VARIATION_PHONETIC 0x000000c0
|
||||
#define TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS 0x000000d0
|
||||
#define TYPE_TEXT_VARIATION_WEB_PASSWORD 0x000000e0
|
||||
|
||||
|
||||
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_UNKNOWN, // AKEYCODE_EXPLORER
|
||||
SDL_SCANCODE_UNKNOWN, // 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_MEDIA_PLAY_PAUSE, // AKEYCODE_MEDIA_PLAY_PAUSE
|
||||
SDL_SCANCODE_MEDIA_STOP, // AKEYCODE_MEDIA_STOP
|
||||
SDL_SCANCODE_MEDIA_NEXT_TRACK, // AKEYCODE_MEDIA_NEXT
|
||||
SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, // AKEYCODE_MEDIA_PREVIOUS
|
||||
SDL_SCANCODE_MEDIA_REWIND, // AKEYCODE_MEDIA_REWIND
|
||||
SDL_SCANCODE_MEDIA_FAST_FORWARD, // 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_MEDIA_PLAY, // AKEYCODE_MEDIA_PLAY
|
||||
SDL_SCANCODE_MEDIA_PAUSE, // AKEYCODE_MEDIA_PAUSE
|
||||
SDL_SCANCODE_UNKNOWN, // AKEYCODE_MEDIA_CLOSE
|
||||
SDL_SCANCODE_MEDIA_EJECT, // AKEYCODE_MEDIA_EJECT
|
||||
SDL_SCANCODE_MEDIA_RECORD, // 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_NUMLOCKCLEAR, // 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_CHANNEL_INCREMENT, // AKEYCODE_CHANNEL_UP
|
||||
SDL_SCANCODE_CHANNEL_INCREMENT, // 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_UNKNOWN, // 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_UNKNOWN, // AKEYCODE_BRIGHTNESS_DOWN
|
||||
SDL_SCANCODE_UNKNOWN, // 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 bool SDL_screen_keyboard_shown;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void Android_OnKeyDown(int keycode)
|
||||
{
|
||||
SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, keycode, TranslateKeycode(keycode), true);
|
||||
}
|
||||
|
||||
void Android_OnKeyUp(int keycode)
|
||||
{
|
||||
SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, keycode, TranslateKeycode(keycode), false);
|
||||
}
|
||||
|
||||
bool Android_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Android_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
|
||||
{
|
||||
int input_type = 0;
|
||||
if (SDL_HasProperty(props, SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER)) {
|
||||
input_type = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER, 0);
|
||||
} else {
|
||||
switch (SDL_GetTextInputType(props)) {
|
||||
default:
|
||||
case SDL_TEXTINPUT_TYPE_TEXT:
|
||||
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_NORMAL);
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
|
||||
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PERSON_NAME);
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
|
||||
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
|
||||
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_NORMAL);
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
|
||||
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
|
||||
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER:
|
||||
input_type = (TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_NORMAL);
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
|
||||
input_type = (TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_PASSWORD);
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
|
||||
input_type = (TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_NORMAL);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (SDL_GetTextInputCapitalization(props)) {
|
||||
default:
|
||||
case SDL_CAPITALIZE_NONE:
|
||||
break;
|
||||
case SDL_CAPITALIZE_LETTERS:
|
||||
input_type |= TYPE_TEXT_FLAG_CAP_CHARACTERS;
|
||||
break;
|
||||
case SDL_CAPITALIZE_WORDS:
|
||||
input_type |= TYPE_TEXT_FLAG_CAP_WORDS;
|
||||
break;
|
||||
case SDL_CAPITALIZE_SENTENCES:
|
||||
input_type |= TYPE_TEXT_FLAG_CAP_SENTENCES;
|
||||
break;
|
||||
}
|
||||
|
||||
if (SDL_GetTextInputAutocorrect(props)) {
|
||||
input_type |= (TYPE_TEXT_FLAG_AUTO_CORRECT | TYPE_TEXT_FLAG_AUTO_COMPLETE);
|
||||
}
|
||||
|
||||
if (SDL_GetTextInputMultiline(props)) {
|
||||
input_type |= TYPE_TEXT_FLAG_MULTI_LINE;
|
||||
}
|
||||
}
|
||||
Android_JNI_ShowScreenKeyboard(input_type, &window->text_input_rect);
|
||||
SDL_screen_keyboard_shown = true;
|
||||
}
|
||||
|
||||
void Android_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
Android_JNI_HideScreenKeyboard();
|
||||
SDL_screen_keyboard_shown = false;
|
||||
}
|
||||
|
||||
void Android_RestoreScreenKeyboardOnResume(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
if (SDL_screen_keyboard_shown) {
|
||||
Android_ShowScreenKeyboard(_this, window, window->text_input_props);
|
||||
}
|
||||
}
|
||||
|
||||
bool Android_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
return Android_JNI_IsScreenKeyboardShown();
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_androidvideo.h"
|
||||
|
||||
extern void Android_OnKeyDown(int keycode);
|
||||
extern void Android_OnKeyUp(int keycode);
|
||||
|
||||
extern bool Android_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
|
||||
extern void Android_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
extern void Android_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Android_RestoreScreenKeyboardOnResume(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Android_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
||||
|
||||
#include "SDL_androidmessagebox.h"
|
||||
#include "../../core/android/SDL_android.h"
|
||||
|
||||
bool Android_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
|
||||
{
|
||||
return Android_JNI_ShowMessageBox(messageboxdata, buttonID);
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
||||
|
||||
extern bool Android_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID);
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_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
|
||||
|
||||
struct SDL_CursorData
|
||||
{
|
||||
int custom_cursor;
|
||||
int system_cursor;
|
||||
};
|
||||
|
||||
// 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_CursorData *data = (SDL_CursorData *)SDL_calloc(1, sizeof(*data));
|
||||
if (data) {
|
||||
data->custom_cursor = custom_cursor;
|
||||
data->system_cursor = system_cursor;
|
||||
cursor->internal = data;
|
||||
} else {
|
||||
SDL_free(cursor);
|
||||
cursor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static SDL_Cursor *Android_CreateDefaultCursor(void)
|
||||
{
|
||||
SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
|
||||
return Android_WrapCursor(0, id);
|
||||
}
|
||||
|
||||
static SDL_Cursor *Android_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
|
||||
{
|
||||
int custom_cursor;
|
||||
SDL_Surface *converted;
|
||||
|
||||
converted = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ARGB8888);
|
||||
if (!converted) {
|
||||
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_CursorData *data = cursor->internal;
|
||||
if (data->custom_cursor != 0) {
|
||||
Android_JNI_DestroyCustomCursor(data->custom_cursor);
|
||||
}
|
||||
SDL_free(cursor->internal);
|
||||
SDL_free(cursor);
|
||||
}
|
||||
|
||||
static SDL_Cursor *Android_CreateEmptyCursor(void)
|
||||
{
|
||||
if (!empty_cursor) {
|
||||
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(void)
|
||||
{
|
||||
if (empty_cursor) {
|
||||
Android_FreeCursor(empty_cursor);
|
||||
empty_cursor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool Android_ShowCursor(SDL_Cursor *cursor)
|
||||
{
|
||||
if (!cursor) {
|
||||
cursor = Android_CreateEmptyCursor();
|
||||
}
|
||||
if (cursor) {
|
||||
SDL_CursorData *data = cursor->internal;
|
||||
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 true;
|
||||
} else {
|
||||
// SDL error set inside Android_CreateEmptyCursor()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool Android_SetRelativeMouseMode(bool enabled)
|
||||
{
|
||||
if (!Android_JNI_SupportsRelativeMouse()) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
if (!Android_JNI_SetRelativeMouseEnabled(enabled)) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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, bool relative)
|
||||
{
|
||||
int changes;
|
||||
Uint8 button;
|
||||
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case ACTION_DOWN:
|
||||
changes = state & ~last_state;
|
||||
button = TranslateButton(changes);
|
||||
last_state = state;
|
||||
SDL_SendMouseMotion(0, window, SDL_DEFAULT_MOUSE_ID, relative, x, y);
|
||||
SDL_SendMouseButton(0, window, SDL_DEFAULT_MOUSE_ID, button, true);
|
||||
break;
|
||||
|
||||
case ACTION_UP:
|
||||
changes = last_state & ~state;
|
||||
button = TranslateButton(changes);
|
||||
last_state = state;
|
||||
SDL_SendMouseMotion(0, window, SDL_DEFAULT_MOUSE_ID, relative, x, y);
|
||||
SDL_SendMouseButton(0, window, SDL_DEFAULT_MOUSE_ID, button, false);
|
||||
break;
|
||||
|
||||
case ACTION_MOVE:
|
||||
case ACTION_HOVER_MOVE:
|
||||
SDL_SendMouseMotion(0, window, SDL_DEFAULT_MOUSE_ID, relative, x, y);
|
||||
break;
|
||||
|
||||
case ACTION_SCROLL:
|
||||
SDL_SendMouseWheel(0, window, SDL_DEFAULT_MOUSE_ID, x, y, SDL_MOUSEWHEEL_NORMAL);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_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, bool relative);
|
||||
extern void Android_QuitMouse(void);
|
||||
|
||||
#endif // SDL_androidmouse_h_
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
||||
|
||||
#include "SDL_androidpen.h"
|
||||
#include "../../events/SDL_pen_c.h"
|
||||
#include "../../core/android/SDL_android.h"
|
||||
|
||||
#define ACTION_DOWN 0
|
||||
#define ACTION_UP 1
|
||||
#define ACTION_CANCEL 3
|
||||
#define ACTION_POINTER_DOWN 5
|
||||
#define ACTION_POINTER_UP 6
|
||||
#define ACTION_HOVER_EXIT 10
|
||||
|
||||
void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, float x, float y, float p)
|
||||
{
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
// pointer index starts from zero.
|
||||
pen_id_in++;
|
||||
|
||||
SDL_PenID pen = SDL_FindPenByHandle((void *) (size_t) pen_id_in);
|
||||
if (!pen) {
|
||||
// TODO: Query JNI for pen device info
|
||||
SDL_PenInfo peninfo;
|
||||
SDL_zero(peninfo);
|
||||
peninfo.capabilities = SDL_PEN_CAPABILITY_PRESSURE | SDL_PEN_CAPABILITY_ERASER;
|
||||
peninfo.num_buttons = 2;
|
||||
peninfo.subtype = SDL_PEN_TYPE_PEN;
|
||||
pen = SDL_AddPenDevice(0, NULL, &peninfo, (void *) (size_t) pen_id_in);
|
||||
if (!pen) {
|
||||
SDL_Log("error: can't add a pen device %d", pen_id_in);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SendPenMotion(0, pen, window, x, y);
|
||||
SDL_SendPenAxis(0, pen, window, SDL_PEN_AXIS_PRESSURE, p);
|
||||
// TODO: add more axis
|
||||
|
||||
SDL_PenInputFlags current = SDL_GetPenStatus(pen, NULL, 0);
|
||||
int diff = current ^ button;
|
||||
if (diff != 0) {
|
||||
// Android only exposes BUTTON_STYLUS_PRIMARY and BUTTON_STYLUS_SECONDARY
|
||||
if (diff & SDL_PEN_INPUT_BUTTON_1)
|
||||
SDL_SendPenButton(0, pen, window, 1, (button & SDL_PEN_INPUT_BUTTON_1) != 0);
|
||||
|
||||
if (diff & SDL_PEN_INPUT_BUTTON_2)
|
||||
SDL_SendPenButton(0, pen, window, 2, (button & SDL_PEN_INPUT_BUTTON_2) != 0);
|
||||
}
|
||||
|
||||
// button contains DOWN/ERASER_TIP on DOWN/UP regardless of pressed state, use action to distinguish
|
||||
// we don't compare tip flags above because MotionEvent.getButtonState doesn't return stylus tip/eraser state.
|
||||
switch (action) {
|
||||
case ACTION_CANCEL:
|
||||
case ACTION_HOVER_EXIT:
|
||||
SDL_RemovePenDevice(0, pen);
|
||||
break;
|
||||
|
||||
case ACTION_DOWN:
|
||||
case ACTION_POINTER_DOWN:
|
||||
SDL_SendPenTouch(0, pen, window, (button & SDL_PEN_INPUT_ERASER_TIP) != 0, true);
|
||||
break;
|
||||
|
||||
case ACTION_UP:
|
||||
case ACTION_POINTER_UP:
|
||||
SDL_SendPenTouch(0, pen, window, (button & SDL_PEN_INPUT_ERASER_TIP) != 0, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_androidvideo.h"
|
||||
|
||||
extern void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, float x, float y, float p);
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_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) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Touch device -1 appears when using Android emulator, eg:
|
||||
* adb shell input mouse tap 100 100
|
||||
* adb shell input touchscreen tap 100 100
|
||||
*/
|
||||
touchDeviceId = (SDL_TouchID)(touch_device_id_in + 2);
|
||||
|
||||
// Finger ID should be greater than 0
|
||||
fingerId = (SDL_FingerID)(pointer_finger_id_in + 1);
|
||||
|
||||
if (SDL_AddTouch(touchDeviceId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) {
|
||||
SDL_Log("error: can't add touch %s, %d", __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case ACTION_DOWN:
|
||||
case ACTION_POINTER_DOWN:
|
||||
SDL_SendTouch(0, touchDeviceId, fingerId, window, SDL_EVENT_FINGER_DOWN, 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_EVENT_FINGER_UP, x, y, p);
|
||||
break;
|
||||
|
||||
case ACTION_CANCEL:
|
||||
SDL_SendTouch(0, touchDeviceId, fingerId, window, SDL_EVENT_FINGER_CANCELED, x, y, p);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#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);
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_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"
|
||||
#include "SDL_androidmessagebox.h"
|
||||
|
||||
#define ANDROID_VID_DRIVER_NAME "android"
|
||||
|
||||
// Initialization/Query functions
|
||||
static bool 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_DestroyContext SDL_EGL_DestroyContext
|
||||
|
||||
// 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;
|
||||
static SDL_DisplayOrientation Android_ScreenOrientation = SDL_ORIENTATION_UNKNOWN;
|
||||
int Android_SafeInsetLeft = 0;
|
||||
int Android_SafeInsetRight = 0;
|
||||
int Android_SafeInsetTop = 0;
|
||||
int Android_SafeInsetBottom = 0;
|
||||
static SDL_SystemTheme Android_SystemTheme;
|
||||
|
||||
static bool Android_SuspendScreenSaver(SDL_VideoDevice *_this)
|
||||
{
|
||||
return Android_JNI_SuspendScreenSaver(_this->suspend_screensaver);
|
||||
}
|
||||
|
||||
static void Android_DeleteDevice(SDL_VideoDevice *device)
|
||||
{
|
||||
SDL_free(device->internal);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_VideoDevice *Android_CreateDevice(void)
|
||||
{
|
||||
SDL_VideoDevice *device;
|
||||
SDL_VideoData *data;
|
||||
|
||||
// Initialize all variables that we clean on shutdown
|
||||
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
|
||||
if (!device) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
|
||||
if (!data) {
|
||||
SDL_free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device->internal = data;
|
||||
device->system_theme = Android_SystemTheme;
|
||||
|
||||
// Set the function pointers
|
||||
device->VideoInit = Android_VideoInit;
|
||||
device->VideoQuit = Android_VideoQuit;
|
||||
|
||||
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->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_DestroyContext = Android_GLES_DestroyContext;
|
||||
#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;
|
||||
device->Vulkan_DestroySurface = Android_Vulkan_DestroySurface;
|
||||
#endif
|
||||
|
||||
// Screensaver
|
||||
device->SuspendScreenSaver = Android_SuspendScreenSaver;
|
||||
|
||||
// Screen keyboard
|
||||
device->HasScreenKeyboardSupport = Android_HasScreenKeyboardSupport;
|
||||
device->ShowScreenKeyboard = Android_ShowScreenKeyboard;
|
||||
device->HideScreenKeyboard = Android_HideScreenKeyboard;
|
||||
device->IsScreenKeyboardShown = Android_IsScreenKeyboardShown;
|
||||
|
||||
// Clipboard
|
||||
device->SetClipboardText = Android_SetClipboardText;
|
||||
device->GetClipboardText = Android_GetClipboardText;
|
||||
device->HasClipboardText = Android_HasClipboardText;
|
||||
|
||||
device->device_caps = VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
VideoBootStrap Android_bootstrap = {
|
||||
ANDROID_VID_DRIVER_NAME, "SDL Android video driver",
|
||||
Android_CreateDevice,
|
||||
Android_ShowMessageBox,
|
||||
false
|
||||
};
|
||||
|
||||
bool Android_VideoInit(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
SDL_DisplayID displayID;
|
||||
SDL_VideoDisplay *display;
|
||||
SDL_DisplayMode mode;
|
||||
|
||||
videodata->isPaused = false;
|
||||
videodata->isPausing = false;
|
||||
|
||||
SDL_zero(mode);
|
||||
mode.format = Android_ScreenFormat;
|
||||
mode.w = Android_DeviceWidth;
|
||||
mode.h = Android_DeviceHeight;
|
||||
mode.refresh_rate = Android_ScreenRate;
|
||||
|
||||
displayID = SDL_AddBasicVideoDisplay(&mode);
|
||||
if (displayID == 0) {
|
||||
return false;
|
||||
}
|
||||
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 true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void Android_SendOrientationUpdate(void)
|
||||
{
|
||||
/* If we've received a compatible resize event, update the
|
||||
* orientation immediately, otherwise wait for the display
|
||||
* resize event.
|
||||
*/
|
||||
SDL_VideoDevice *device = SDL_GetVideoDevice();
|
||||
if (device && device->num_displays > 0) {
|
||||
SDL_VideoDisplay *display = device->displays[0];
|
||||
bool mode_landscape = (display->desktop_mode.w > display->desktop_mode.h);
|
||||
bool sensor_landscape = (Android_ScreenOrientation == SDL_ORIENTATION_LANDSCAPE || Android_ScreenOrientation == SDL_ORIENTATION_LANDSCAPE_FLIPPED);
|
||||
if (sensor_landscape == mode_landscape) {
|
||||
SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_ORIENTATION, Android_ScreenOrientation, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Android_SetOrientation(SDL_DisplayOrientation orientation)
|
||||
{
|
||||
Android_ScreenOrientation = orientation;
|
||||
Android_SendOrientationUpdate();
|
||||
}
|
||||
|
||||
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);
|
||||
Android_SendOrientationUpdate();
|
||||
}
|
||||
|
||||
if (window) {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, Android_SurfaceWidth, Android_SurfaceHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void Android_SetWindowSafeAreaInsets(int left, int right, int top, int bottom)
|
||||
{
|
||||
Android_SafeInsetLeft = left;
|
||||
Android_SafeInsetRight = right;
|
||||
Android_SafeInsetTop = top;
|
||||
Android_SafeInsetBottom = bottom;
|
||||
|
||||
if (Android_Window) {
|
||||
SDL_SetWindowSafeAreaInsets(Android_Window, left, right, top, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
void Android_SetDarkMode(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
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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_SetOrientation(SDL_DisplayOrientation orientation);
|
||||
extern void Android_SendResize(SDL_Window *window);
|
||||
extern void Android_SetWindowSafeAreaInsets(int left, int right, int top, int bottom);
|
||||
extern void Android_SetDarkMode(bool enabled);
|
||||
|
||||
// Private display data
|
||||
|
||||
struct SDL_VideoData
|
||||
{
|
||||
int isPaused;
|
||||
int isPausing;
|
||||
};
|
||||
|
||||
extern int Android_SurfaceWidth;
|
||||
extern int Android_SurfaceHeight;
|
||||
extern float Android_ScreenDensity;
|
||||
extern int Android_SafeInsetLeft;
|
||||
extern int Android_SafeInsetRight;
|
||||
extern int Android_SafeInsetTop;
|
||||
extern int Android_SafeInsetBottom;
|
||||
|
||||
#endif // SDL_androidvideo_h_
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @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_vulkan_internal.h"
|
||||
|
||||
#include "SDL_androidvideo.h"
|
||||
#include "SDL_androidwindow.h"
|
||||
|
||||
#include "SDL_androidvulkan.h"
|
||||
|
||||
|
||||
bool Android_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
|
||||
{
|
||||
VkExtensionProperties *extensions = NULL;
|
||||
Uint32 i, extensionCount = 0;
|
||||
bool hasSurfaceExtension = false;
|
||||
bool hasAndroidSurfaceExtension = false;
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
|
||||
if (_this->vulkan_config.loader_handle) {
|
||||
return SDL_SetError("Vulkan already loaded");
|
||||
}
|
||||
|
||||
// Load the Vulkan loader library
|
||||
if (!path) {
|
||||
path = SDL_GetHint(SDL_HINT_VULKAN_LIBRARY);
|
||||
}
|
||||
if (!path) {
|
||||
path = "libvulkan.so";
|
||||
}
|
||||
_this->vulkan_config.loader_handle = SDL_LoadObject(path);
|
||||
if (!_this->vulkan_config.loader_handle) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
goto fail;
|
||||
}
|
||||
for (i = 0; i < extensionCount; i++) {
|
||||
if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
|
||||
hasSurfaceExtension = true;
|
||||
} else if (SDL_strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
|
||||
hasAndroidSurfaceExtension = 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 true;
|
||||
|
||||
fail:
|
||||
SDL_UnloadObject(_this->vulkan_config.loader_handle);
|
||||
_this->vulkan_config.loader_handle = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
char const * const *Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count)
|
||||
{
|
||||
static const char *const extensionsForAndroid[] = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
|
||||
};
|
||||
if (count) {
|
||||
*count = SDL_arraysize(extensionsForAndroid);
|
||||
}
|
||||
return extensionsForAndroid;
|
||||
}
|
||||
|
||||
bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
VkSurfaceKHR *surface)
|
||||
{
|
||||
SDL_WindowData *windowData = window->internal;
|
||||
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) {
|
||||
return SDL_SetError("Vulkan is not loaded");
|
||||
}
|
||||
|
||||
if (!vkCreateAndroidSurfaceKHR) {
|
||||
return SDL_SetError(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
|
||||
" extension is not enabled in the Vulkan instance.");
|
||||
}
|
||||
SDL_zero(createInfo);
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
|
||||
createInfo.pNext = NULL;
|
||||
createInfo.flags = 0;
|
||||
createInfo.window = windowData->native_window;
|
||||
result = vkCreateAndroidSurfaceKHR(instance, &createInfo, allocator, surface);
|
||||
if (result != VK_SUCCESS) {
|
||||
return SDL_SetError("vkCreateAndroidSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Android_Vulkan_DestroySurface(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR surface,
|
||||
const struct VkAllocationCallbacks *allocator)
|
||||
{
|
||||
if (_this->vulkan_config.loader_handle) {
|
||||
SDL_Vulkan_DestroySurface_Internal(_this->vulkan_config.vkGetInstanceProcAddr, instance, surface, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @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)
|
||||
|
||||
extern bool Android_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
extern void Android_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
|
||||
extern char const * const *Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count);
|
||||
extern bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
VkSurfaceKHR *surface);
|
||||
extern void Android_Vulkan_DestroySurface(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR surface,
|
||||
const struct VkAllocationCallbacks *allocator);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SDL_androidvulkan_h_
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_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_androidevents.h"
|
||||
#include "SDL_androidwindow.h"
|
||||
|
||||
|
||||
// Currently only one window
|
||||
SDL_Window *Android_Window = NULL;
|
||||
|
||||
bool Android_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
bool result = true;
|
||||
|
||||
if (!Android_WaitActiveAndLockActivity()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Android_Window) {
|
||||
result = 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) {
|
||||
result = false;
|
||||
goto endfunction;
|
||||
}
|
||||
|
||||
data->native_window = Android_JNI_GetNativeWindow();
|
||||
if (!data->native_window) {
|
||||
SDL_free(data);
|
||||
result = SDL_SetError("Could not fetch native window");
|
||||
goto endfunction;
|
||||
}
|
||||
SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER, data->native_window);
|
||||
|
||||
/* 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);
|
||||
result = false;
|
||||
goto endfunction;
|
||||
}
|
||||
}
|
||||
SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_ANDROID_SURFACE_POINTER, data->egl_surface);
|
||||
#endif
|
||||
|
||||
SDL_SetWindowSafeAreaInsets(window, Android_SafeInsetLeft, Android_SafeInsetRight, Android_SafeInsetTop, Android_SafeInsetBottom);
|
||||
|
||||
window->internal = data;
|
||||
Android_Window = window;
|
||||
|
||||
endfunction:
|
||||
|
||||
Android_UnlockActivityMutex();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Android_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
Android_JNI_SetActivityTitle(window->title);
|
||||
}
|
||||
|
||||
SDL_FullscreenResult Android_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen)
|
||||
{
|
||||
Android_LockActivityMutex();
|
||||
|
||||
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->internal;
|
||||
if (!data || !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:
|
||||
|
||||
Android_UnlockActivityMutex();
|
||||
|
||||
return SDL_FULLSCREEN_SUCCEEDED;
|
||||
}
|
||||
|
||||
void Android_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
Android_JNI_MinizeWindow();
|
||||
}
|
||||
|
||||
void Android_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, 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)
|
||||
{
|
||||
Android_LockActivityMutex();
|
||||
|
||||
if (window == Android_Window) {
|
||||
Android_Window = NULL;
|
||||
|
||||
if (window->internal) {
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
#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->internal);
|
||||
window->internal = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Android_UnlockActivityMutex();
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_androidwindow_h_
|
||||
#define SDL_androidwindow_h_
|
||||
|
||||
#include "../../core/android/SDL_android.h"
|
||||
#include "../SDL_egl_c.h"
|
||||
|
||||
extern bool Android_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
|
||||
extern void Android_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern SDL_FullscreenResult Android_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen);
|
||||
extern void Android_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Android_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable);
|
||||
|
||||
extern void Android_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
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
|
||||
bool backup_done;
|
||||
ANativeWindow *native_window;
|
||||
|
||||
};
|
||||
|
||||
#endif // SDL_androidwindow_h_
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_cocoaclipboard_h_
|
||||
#define SDL_cocoaclipboard_h_
|
||||
|
||||
// Forward declaration
|
||||
@class SDL_CocoaVideoData;
|
||||
|
||||
extern void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data);
|
||||
extern bool Cocoa_SetClipboardData(SDL_VideoDevice *_this);
|
||||
extern void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
|
||||
extern bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
|
||||
|
||||
#endif // SDL_cocoaclipboard_h_
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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 bool Cocoa_SuspendScreenSaver(SDL_VideoDevice *_this);
|
||||
|
||||
#endif // SDL_cocoaevents_h_
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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 bool Cocoa_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
extern bool Cocoa_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Cocoa_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
extern bool Cocoa_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed);
|
||||
|
||||
#endif // SDL_cocoakeyboard_h_
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_COCOA
|
||||
|
||||
extern bool Cocoa_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID);
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_COCOA
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
/*
|
||||
* @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 SDL3_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_
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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 void Cocoa_UpdateDisplays(SDL_VideoDevice *_this);
|
||||
extern bool Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
|
||||
extern bool Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
|
||||
extern bool Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
|
||||
extern bool Cocoa_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
|
||||
extern void Cocoa_QuitModes(SDL_VideoDevice *_this);
|
||||
extern SDL_VideoDisplay *Cocoa_FindSDLDisplayByCGDirectDisplayID(SDL_VideoDevice *_this, CGDirectDisplayID displayid);
|
||||
|
||||
#endif // SDL_cocoamodes_h_
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_cocoamouse_h_
|
||||
#define SDL_cocoamouse_h_
|
||||
|
||||
#include "SDL_cocoavideo.h"
|
||||
|
||||
extern bool Cocoa_InitMouse(SDL_VideoDevice *_this);
|
||||
extern NSWindow *Cocoa_GetMouseFocus();
|
||||
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.
|
||||
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_
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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 SDL3OpenGLContext : 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 bool 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 bool Cocoa_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
|
||||
extern bool Cocoa_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval);
|
||||
extern bool Cocoa_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
|
||||
extern bool Cocoa_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Cocoa_GL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context);
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // SDL_VIDEO_OPENGL_CGL
|
||||
|
||||
#endif // SDL_cocoaopengl_h_
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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 bool Cocoa_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
extern SDL_GLContext Cocoa_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Cocoa_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Cocoa_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
|
||||
extern bool Cocoa_GLES_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context);
|
||||
extern bool 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_
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_cocoapen_h_
|
||||
#define SDL_cocoapenm_h_
|
||||
|
||||
#include "SDL_cocoavideo.h"
|
||||
|
||||
extern bool Cocoa_InitPen(SDL_VideoDevice *_this);
|
||||
extern bool Cocoa_HandlePenEvent(SDL_CocoaWindowData *_data, NSEvent *event); // return false if we didn't handle this event.
|
||||
extern void Cocoa_QuitPen(SDL_VideoDevice *_this);
|
||||
|
||||
#endif // SDL_cocoapen_h_
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_cocoashape_h_
|
||||
#define SDL_cocoashape_h_
|
||||
|
||||
extern bool Cocoa_UpdateWindowShape(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *shape);
|
||||
|
||||
#endif // SDL_cocoashape_h_
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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"
|
||||
#include "SDL_cocoapen.h"
|
||||
|
||||
// Private display data
|
||||
|
||||
@class SDL3TranslatorResponder;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OptionAsAltNone,
|
||||
OptionAsAltOnlyLeft,
|
||||
OptionAsAltOnlyRight,
|
||||
OptionAsAltBoth,
|
||||
} OptionAsAlt;
|
||||
|
||||
@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) SDL3TranslatorResponder *fieldEdit;
|
||||
@property(nonatomic) NSInteger clipboard_count;
|
||||
@property(nonatomic) IOPMAssertionID screensaver_assertion;
|
||||
@property(nonatomic) SDL_Mutex *swaplock;
|
||||
@property(nonatomic) OptionAsAlt option_as_alt;
|
||||
@end
|
||||
|
||||
// Utility functions
|
||||
extern SDL_SystemTheme Cocoa_GetSystemTheme(void);
|
||||
extern NSImage *Cocoa_CreateImage(SDL_Surface *surface);
|
||||
|
||||
#endif // SDL_cocoavideo_h_
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @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)
|
||||
|
||||
extern bool Cocoa_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
extern void Cocoa_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
|
||||
extern char const * const *Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count);
|
||||
extern bool Cocoa_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
VkSurfaceKHR *surface);
|
||||
extern void Cocoa_Vulkan_DestroySurface(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR surface,
|
||||
const struct VkAllocationCallbacks *allocator);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SDL_cocoavulkan_h_
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_cocoawindow_h_
|
||||
#define SDL_cocoawindow_h_
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
#include "../SDL_egl_c.h"
|
||||
#endif
|
||||
|
||||
#define SDL_METALVIEW_TAG 255
|
||||
|
||||
@class SDL_CocoaWindowData;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PENDING_OPERATION_NONE = 0x00,
|
||||
PENDING_OPERATION_ENTER_FULLSCREEN = 0x01,
|
||||
PENDING_OPERATION_LEAVE_FULLSCREEN = 0x02,
|
||||
PENDING_OPERATION_MINIMIZE = 0x04,
|
||||
PENDING_OPERATION_ZOOM = 0x08
|
||||
} PendingWindowOperation;
|
||||
|
||||
@interface SDL3Cocoa_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;
|
||||
BOOL isMiniaturizing;
|
||||
NSInteger focusClickPending;
|
||||
float pendingWindowWarpX, pendingWindowWarpY;
|
||||
BOOL isDragAreaRunning;
|
||||
NSTimer *liveResizeTimer;
|
||||
}
|
||||
|
||||
- (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)updateIgnoreMouseState:(NSEvent *)theEvent;
|
||||
- (void)setPendingMoveX:(float)x Y:(float)y;
|
||||
- (void)windowDidFinishMoving;
|
||||
- (void)onMovingOrFocusClickPendingStateCleared;
|
||||
|
||||
// Window delegate functionality
|
||||
- (BOOL)windowShouldClose:(id)sender;
|
||||
- (void)windowDidExpose:(NSNotification *)aNotification;
|
||||
- (void)windowDidChangeOcclusionState:(NSNotification *)aNotification;
|
||||
- (void)windowWillStartLiveResize:(NSNotification *)aNotification;
|
||||
- (void)windowDidEndLiveResize:(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.
|
||||
- (void)updateHitTest;
|
||||
- (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;
|
||||
|
||||
// Tablet event handling (but these also come through on mouse events sometimes!)
|
||||
- (void)tabletProximity:(NSEvent *)theEvent;
|
||||
- (void)tabletPoint:(NSEvent *)theEvent;
|
||||
|
||||
@end
|
||||
/* *INDENT-ON* */
|
||||
|
||||
@class SDL3OpenGLContext;
|
||||
@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) BOOL in_blocking_transition;
|
||||
@property(nonatomic) BOOL fullscreen_space_requested;
|
||||
@property(nonatomic) BOOL was_zoomed;
|
||||
@property(nonatomic) NSInteger window_number;
|
||||
@property(nonatomic) NSInteger flash_request;
|
||||
@property(nonatomic) SDL3Cocoa_WindowListener *listener;
|
||||
@property(nonatomic) NSModalSession modal_session;
|
||||
@property(nonatomic) SDL_CocoaVideoData *videodata;
|
||||
@property(nonatomic) bool pending_size;
|
||||
@property(nonatomic) bool pending_position;
|
||||
@property(nonatomic) bool border_toggled;
|
||||
@property(nonatomic) bool has_modal_dialog;
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
@property(nonatomic) EGLSurface egl_surface;
|
||||
#endif
|
||||
@end
|
||||
|
||||
extern bool b_inModeTransition;
|
||||
|
||||
extern bool Cocoa_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
|
||||
extern void Cocoa_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Cocoa_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
|
||||
extern bool 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_SetWindowAspectRatio(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Cocoa_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
|
||||
extern bool 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, bool bordered);
|
||||
extern void Cocoa_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable);
|
||||
extern void Cocoa_SetWindowAlwaysOnTop(SDL_VideoDevice *_this, SDL_Window *window, bool on_top);
|
||||
extern SDL_FullscreenResult Cocoa_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp 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 bool Cocoa_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Cocoa_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed);
|
||||
extern void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Cocoa_SetWindowHitTest(SDL_Window *window, bool enabled);
|
||||
extern void Cocoa_AcceptDragAndDrop(SDL_Window *window, bool accept);
|
||||
extern bool Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||
extern bool Cocoa_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
|
||||
extern bool Cocoa_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal);
|
||||
extern bool Cocoa_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent);
|
||||
extern bool Cocoa_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
extern void Cocoa_MenuVisibilityCallback(void *userdata, const char *name, const char *oldValue, const char *newValue);
|
||||
|
||||
#endif // SDL_cocoawindow_h_
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_D3D12_H
|
||||
#define SDL_D3D12_H
|
||||
|
||||
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
|
||||
|
||||
/* From the DirectX-Headers build system:
|
||||
* "MinGW has RPC headers which define old versions, and complain if D3D
|
||||
* headers are included before the RPC headers, since D3D headers were
|
||||
* generated with new MIDL and "require" new RPC headers."
|
||||
*/
|
||||
#define __REQUIRED_RPCNDR_H_VERSION__ 475
|
||||
|
||||
// May not be defined in winapifamily.h, can safely be ignored
|
||||
#ifndef WINAPI_PARTITION_GAMES
|
||||
#define WINAPI_PARTITION_GAMES 0
|
||||
#endif // WINAPI_PARTITION_GAMES
|
||||
|
||||
#define COBJMACROS
|
||||
#include "d3d12.h"
|
||||
#include <dxgi1_6.h>
|
||||
#include <dxgidebug.h>
|
||||
|
||||
#define D3D_GUID(X) &(X)
|
||||
|
||||
#define D3D_SAFE_RELEASE(X) \
|
||||
if (X) { \
|
||||
(X)->lpVtbl->Release(X); \
|
||||
X = NULL; \
|
||||
}
|
||||
|
||||
/* Some D3D12 calls are mismatched between Windows/Xbox, so we need to wrap the
|
||||
* C function ourselves :(
|
||||
*/
|
||||
#define D3D_CALL_RET(THIS, FUNC, ...) (THIS)->lpVtbl->FUNC((THIS), ##__VA_ARGS__)
|
||||
|
||||
#else // !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
|
||||
|
||||
#if defined(SDL_PLATFORM_XBOXONE)
|
||||
#include <d3d12_x.h>
|
||||
#else // SDL_PLATFORM_XBOXSERIES
|
||||
#include <d3d12_xs.h>
|
||||
#endif
|
||||
|
||||
#define D3D_GUID(X) (X)
|
||||
|
||||
#define D3D_SAFE_RELEASE(X) \
|
||||
if (X) { \
|
||||
(X)->Release(); \
|
||||
X = NULL; \
|
||||
}
|
||||
|
||||
// Older versions of the Xbox GDK may not have this defined
|
||||
#ifndef D3D12_TEXTURE_DATA_PITCH_ALIGNMENT
|
||||
#define D3D12_TEXTURE_DATA_PITCH_ALIGNMENT 256
|
||||
#endif
|
||||
#ifndef D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE
|
||||
#define D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE ((D3D12_RESOURCE_STATES) (0x40 | 0x80))
|
||||
#endif
|
||||
#ifndef D3D12_HEAP_TYPE_GPU_UPLOAD
|
||||
#define D3D12_HEAP_TYPE_GPU_UPLOAD ((D3D12_HEAP_TYPE) 5)
|
||||
#endif
|
||||
|
||||
// DXGI_PRESENT flags are removed on Xbox
|
||||
#define DXGI_PRESENT_ALLOW_TEARING 0
|
||||
|
||||
// Xbox D3D12 does not define the COBJMACROS, so we need to define them ourselves
|
||||
#include "SDL_d3d12_xbox_cmacros.h"
|
||||
|
||||
// They don't even define the CMACROS for ID3DBlob, come on man
|
||||
#define ID3D10Blob_GetBufferPointer(blob) blob->GetBufferPointer()
|
||||
#define ID3D10Blob_GetBufferSize(blob) blob->GetBufferSize()
|
||||
#define ID3D10Blob_Release(blob) blob->Release()
|
||||
|
||||
/* Xbox's D3D12 ABI actually varies from Windows, if a function does not exist
|
||||
* in the above header then you need to use this instead :(
|
||||
*/
|
||||
#define D3D_CALL_RET(THIS, FUNC, RETVAL, ...) *(RETVAL) = (THIS)->FUNC(__VA_ARGS__)
|
||||
|
||||
#endif // !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
|
||||
|
||||
#endif // SDL_D3D12_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
// Build and run this any time you update d3d12.h/d3d12sdklayers.h!
|
||||
|
||||
using System.IO;
|
||||
|
||||
class Program
|
||||
{
|
||||
static void GenMacros(string[] input, StreamWriter output)
|
||||
{
|
||||
for (int i = 0; i < input.Length; i += 1)
|
||||
{
|
||||
if (input[i].StartsWith("#define I"))
|
||||
{
|
||||
// Strip out the bad ABI calls, use D3D_CALL_RET instead!
|
||||
if (input[i].Contains("_GetDesc(") ||
|
||||
input[i].Contains("_GetDesc1(") ||
|
||||
input[i].Contains("_GetCPUDescriptorHandleForHeapStart(") ||
|
||||
input[i].Contains("_GetGPUDescriptorHandleForHeapStart(") ||
|
||||
input[i].Contains("_GetResourceAllocationInfo(") ||
|
||||
input[i].Contains("_GetResourceAllocationInfo1(") ||
|
||||
input[i].Contains("_GetResourceAllocationInfo2(") ||
|
||||
input[i].Contains("_GetResourceAllocationInfo3(") ||
|
||||
input[i].Contains("_GetCustomHeapProperties(") ||
|
||||
input[i].Contains("_GetAdapterLuid(") ||
|
||||
input[i].Contains("_GetLUID(") ||
|
||||
input[i].Contains("_GetProgramIdentifier(") ||
|
||||
input[i].Contains("_GetNodeID(") ||
|
||||
input[i].Contains("_GetEntrypointID("))
|
||||
{
|
||||
// May as well skip the next line...
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The first line is fine as-is.
|
||||
output.WriteLine(input[i]);
|
||||
|
||||
// The second line, however...
|
||||
i += 1;
|
||||
|
||||
string notThis;
|
||||
if (input[i].LastIndexOf("This,") > -1)
|
||||
{
|
||||
// Function with arguments
|
||||
notThis = "This,";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Function with no arguments
|
||||
notThis = "This";
|
||||
}
|
||||
|
||||
int lastNotThis = input[i].LastIndexOf(notThis);
|
||||
string alias = input[i].Substring(0, lastNotThis).Replace("lpVtbl -> ", "");
|
||||
string definition = input[i].Substring(lastNotThis).Replace(notThis, "");
|
||||
output.WriteLine(alias + definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
using (FileStream SDL_d3d12_xbox_cmacros_h = File.OpenWrite("SDL_d3d12_xbox_cmacros.h"))
|
||||
using (StreamWriter output = new StreamWriter(SDL_d3d12_xbox_cmacros_h))
|
||||
{
|
||||
output.WriteLine("/* This file is autogenerated, DO NOT MODIFY */");
|
||||
GenMacros(File.ReadAllLines("d3d12.h"), output);
|
||||
GenMacros(File.ReadAllLines("d3d12sdklayers.h"), output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_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
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_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_
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_DUMMY
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../../SDL_properties_c.h"
|
||||
#include "SDL_nullframebuffer_c.h"
|
||||
|
||||
#define DUMMY_SURFACE "SDL.internal.window.surface"
|
||||
|
||||
|
||||
bool SDL_DUMMY_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, SDL_PixelFormat *format, void **pixels, int *pitch)
|
||||
{
|
||||
SDL_Surface *surface;
|
||||
const SDL_PixelFormat surface_format = SDL_PIXELFORMAT_XRGB8888;
|
||||
int w, h;
|
||||
|
||||
// Create a new framebuffer
|
||||
SDL_GetWindowSizeInPixels(window, &w, &h);
|
||||
surface = SDL_CreateSurface(w, h, surface_format);
|
||||
if (!surface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the info and return!
|
||||
SDL_SetSurfaceProperty(SDL_GetWindowProperties(window), DUMMY_SURFACE, surface);
|
||||
*format = surface_format;
|
||||
*pixels = surface->pixels;
|
||||
*pitch = surface->pitch;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool 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_GetPointerProperty(SDL_GetWindowProperties(window), DUMMY_SURFACE, NULL);
|
||||
if (!surface) {
|
||||
return SDL_SetError("Couldn't find dummy surface for window");
|
||||
}
|
||||
|
||||
// Send the data to the display
|
||||
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DUMMY_SAVE_FRAMES, false)) {
|
||||
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 true;
|
||||
}
|
||||
|
||||
void SDL_DUMMY_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_ClearProperty(SDL_GetWindowProperties(window), DUMMY_SURFACE);
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_DUMMY
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_nullframebuffer_c_h_
|
||||
#define SDL_nullframebuffer_c_h_
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
extern bool SDL_DUMMY_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, SDL_PixelFormat *format, void **pixels, int *pitch);
|
||||
extern bool 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_
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_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 bool DUMMY_VideoInit(SDL_VideoDevice *_this);
|
||||
static void DUMMY_VideoQuit(SDL_VideoDevice *_this);
|
||||
|
||||
static bool DUMMY_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, window->pending.x, window->pending.y);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DUMMY_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, window->pending.w, window->pending.h);
|
||||
}
|
||||
|
||||
// DUMMY driver bootstrap functions
|
||||
|
||||
static bool 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 true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
// Initialize all variables that we clean on shutdown
|
||||
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
|
||||
if (!device) {
|
||||
return NULL;
|
||||
}
|
||||
device->is_dummy = true;
|
||||
|
||||
// Set the function pointers
|
||||
device->VideoInit = DUMMY_VideoInit;
|
||||
device->VideoQuit = DUMMY_VideoQuit;
|
||||
device->PumpEvents = DUMMY_PumpEvents;
|
||||
device->SetWindowSize = DUMMY_SetWindowSize;
|
||||
device->SetWindowPosition = DUMMY_SetWindowPosition;
|
||||
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,
|
||||
NULL, // no ShowMessageBox implementation
|
||||
false
|
||||
};
|
||||
|
||||
#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,
|
||||
NULL, // no ShowMessageBox implementation
|
||||
false
|
||||
};
|
||||
|
||||
#endif // SDL_INPUT_LINUXEV
|
||||
|
||||
bool 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 false;
|
||||
}
|
||||
|
||||
#ifdef SDL_INPUT_LINUXEV
|
||||
SDL_EVDEV_Init();
|
||||
#endif
|
||||
|
||||
// We're done!
|
||||
return true;
|
||||
}
|
||||
|
||||
void DUMMY_VideoQuit(SDL_VideoDevice *_this)
|
||||
{
|
||||
#ifdef SDL_INPUT_LINUXEV
|
||||
SDL_EVDEV_Quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_DUMMY
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#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
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_emscriptenevents_h_
|
||||
#define SDL_emscriptenevents_h_
|
||||
|
||||
#include "SDL_emscriptenvideo.h"
|
||||
|
||||
extern void Emscripten_RegisterGlobalEventHandlers(SDL_VideoDevice *device);
|
||||
extern void Emscripten_UnregisterGlobalEventHandlers(SDL_VideoDevice *device);
|
||||
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_
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include "SDL_emscriptenvideo.h"
|
||||
#include "SDL_emscriptenframebuffer.h"
|
||||
|
||||
#include <emscripten/threading.h>
|
||||
|
||||
bool Emscripten_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, SDL_PixelFormat *format, void **pixels, int *pitch)
|
||||
{
|
||||
SDL_Surface *surface;
|
||||
const SDL_PixelFormat surface_format = SDL_PIXELFORMAT_XBGR8888;
|
||||
int w, h;
|
||||
|
||||
// Free the old framebuffer surface
|
||||
SDL_WindowData *data = window->internal;
|
||||
surface = data->surface;
|
||||
SDL_DestroySurface(surface);
|
||||
|
||||
// Create a new one
|
||||
SDL_GetWindowSizeInPixels(window, &w, &h);
|
||||
|
||||
surface = SDL_CreateSurface(w, h, surface_format);
|
||||
if (!surface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the info and return!
|
||||
data->surface = surface;
|
||||
*format = surface_format;
|
||||
*pixels = surface->pixels;
|
||||
*pitch = surface->pitch;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Emscripten_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects)
|
||||
{
|
||||
SDL_Surface *surface;
|
||||
|
||||
SDL_WindowData *data = window->internal;
|
||||
surface = data->surface;
|
||||
if (!surface) {
|
||||
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 = Browser.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 / 4;
|
||||
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, true)) {
|
||||
// give back control to browser for screen refresh
|
||||
emscripten_sleep(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Emscripten_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
SDL_DestroySurface(data->surface);
|
||||
data->surface = NULL;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_emscriptenframebuffer_h_
|
||||
#define SDL_emscriptenframebuffer_h_
|
||||
|
||||
extern bool Emscripten_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, SDL_PixelFormat *format, void **pixels, int *pitch);
|
||||
extern bool 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_
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
#include <emscripten/threading.h>
|
||||
|
||||
#include "SDL_emscriptenmouse.h"
|
||||
#include "SDL_emscriptenvideo.h"
|
||||
|
||||
#include "../SDL_video_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
|
||||
// older Emscriptens don't have this, but we need to for wasm64 compatibility.
|
||||
#ifndef MAIN_THREAD_EM_ASM_PTR
|
||||
#ifdef __wasm64__
|
||||
#error You need to upgrade your Emscripten compiler to support wasm64
|
||||
#else
|
||||
#define MAIN_THREAD_EM_ASM_PTR MAIN_THREAD_EM_ASM_INT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static SDL_Cursor *Emscripten_CreateCursorFromString(const char *cursor_str, bool is_custom)
|
||||
{
|
||||
SDL_CursorData *curdata;
|
||||
SDL_Cursor *cursor = SDL_calloc(1, sizeof(SDL_Cursor));
|
||||
if (cursor) {
|
||||
curdata = (SDL_CursorData *)SDL_calloc(1, sizeof(*curdata));
|
||||
if (!curdata) {
|
||||
SDL_free(cursor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
curdata->system_cursor = cursor_str;
|
||||
curdata->is_custom = is_custom;
|
||||
cursor->internal = curdata;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static SDL_Cursor *Emscripten_CreateDefaultCursor(void)
|
||||
{
|
||||
SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
|
||||
const char *cursor_name = SDL_GetCSSCursorName(id, NULL);
|
||||
return Emscripten_CreateCursorFromString(cursor_name, 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_ConvertSurface(surface, SDL_PIXELFORMAT_ABGR8888);
|
||||
|
||||
if (!conv_surf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
cursor_url = (const char *)MAIN_THREAD_EM_ASM_PTR({
|
||||
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 / 4;
|
||||
|
||||
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 = _SDL_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, true);
|
||||
}
|
||||
|
||||
static SDL_Cursor *Emscripten_CreateSystemCursor(SDL_SystemCursor id)
|
||||
{
|
||||
const char *cursor_name = SDL_GetCSSCursorName(id, NULL);
|
||||
|
||||
return Emscripten_CreateCursorFromString(cursor_name, false);
|
||||
}
|
||||
|
||||
static void Emscripten_FreeCursor(SDL_Cursor *cursor)
|
||||
{
|
||||
SDL_CursorData *curdata;
|
||||
if (cursor) {
|
||||
curdata = cursor->internal;
|
||||
|
||||
if (curdata) {
|
||||
if (curdata->is_custom) {
|
||||
SDL_free((char *)curdata->system_cursor);
|
||||
}
|
||||
SDL_free(cursor->internal);
|
||||
}
|
||||
|
||||
SDL_free(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
static bool Emscripten_ShowCursor(SDL_Cursor *cursor)
|
||||
{
|
||||
SDL_CursorData *curdata;
|
||||
if (SDL_GetMouseFocus() != NULL) {
|
||||
if (cursor && cursor->internal) {
|
||||
curdata = cursor->internal;
|
||||
|
||||
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 true;
|
||||
}
|
||||
|
||||
static bool Emscripten_SetRelativeMouseMode(bool enabled)
|
||||
{
|
||||
SDL_Window *window;
|
||||
SDL_WindowData *window_data;
|
||||
|
||||
// TODO: pointer lock isn't actually enabled yet
|
||||
if (enabled) {
|
||||
window = SDL_GetMouseFocus();
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
window_data = window->internal;
|
||||
|
||||
if (emscripten_request_pointerlock(window_data->canvas_id, 1) >= EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (emscripten_exit_pointerlock() >= EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static SDL_MouseButtonFlags Emscripten_GetGlobalMouseState(float *x, float *y)
|
||||
{
|
||||
*x = MAIN_THREAD_EM_ASM_DOUBLE({
|
||||
return Module['SDL3']['mouse_x'];
|
||||
});
|
||||
*y = MAIN_THREAD_EM_ASM_DOUBLE({
|
||||
return Module['SDL3']['mouse_y'];
|
||||
});
|
||||
SDL_MouseButtonFlags flags = 0;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
const bool button_down = MAIN_THREAD_EM_ASM_INT({
|
||||
return Module['SDL3']['mouse_buttons'][$0];
|
||||
}, i);
|
||||
if (button_down) {
|
||||
flags |= 1 << i;
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
void Emscripten_InitMouse(void)
|
||||
{
|
||||
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;
|
||||
|
||||
// Add event listeners to track mouse events on the document
|
||||
MAIN_THREAD_EM_ASM({
|
||||
if (!Module['SDL3']) {
|
||||
Module['SDL3'] = {};
|
||||
}
|
||||
var SDL3 = Module['SDL3'];
|
||||
SDL3['mouse_x'] = 0;
|
||||
SDL3['mouse_y'] = 0;
|
||||
/*
|
||||
Based on https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
|
||||
Possible value for button in the event object is [0, 5)
|
||||
NOTE: Some browsers do not allow handling the forwards and backwards buttons
|
||||
*/
|
||||
SDL3['mouse_buttons'] = [];
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
SDL3['mouse_buttons'][i] = false;
|
||||
}
|
||||
document.addEventListener('mousemove', function(e) {
|
||||
// Reacquire from object in case it changed for some reason
|
||||
var SDL3 = Module['SDL3'];
|
||||
SDL3['mouse_x'] = e.clientX;
|
||||
SDL3['mouse_y'] = e.clientY;
|
||||
});
|
||||
document.addEventListener('mousedown', function(e) {
|
||||
// Reacquire from object in case it changed for some reason
|
||||
var SDL3 = Module['SDL3'];
|
||||
if (0 <= e.button && e.button < SDL3['mouse_buttons'].length) {
|
||||
SDL3['mouse_buttons'][e.button] = true;
|
||||
}
|
||||
});
|
||||
document.addEventListener('mouseup', function(e) {
|
||||
// Reacquire from object in case it changed for some reason
|
||||
var SDL3 = Module['SDL3'];
|
||||
if (0 <= e.button && e.button < SDL3['mouse_buttons'].length) {
|
||||
SDL3['mouse_buttons'][e.button] = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
mouse->GetGlobalMouseState = Emscripten_GetGlobalMouseState;
|
||||
|
||||
SDL_SetDefaultCursor(Emscripten_CreateDefaultCursor());
|
||||
}
|
||||
|
||||
void Emscripten_QuitMouse(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_emscriptenmouse_h_
|
||||
#define SDL_emscriptenmouse_h_
|
||||
|
||||
struct SDL_CursorData
|
||||
{
|
||||
const char *system_cursor;
|
||||
bool is_custom;
|
||||
};
|
||||
|
||||
extern void Emscripten_InitMouse(void);
|
||||
extern void Emscripten_QuitMouse(void);
|
||||
|
||||
#endif // SDL_emscriptenmouse_h_
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/html5_webgl.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include "SDL_emscriptenvideo.h"
|
||||
#include "SDL_emscriptenopengles.h"
|
||||
#include "../../main/SDL_main_callbacks.h"
|
||||
|
||||
bool Emscripten_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool Emscripten_GLES_SetSwapInterval(SDL_VideoDevice *_this, int interval)
|
||||
{
|
||||
if (interval < 0) {
|
||||
return SDL_SetError("Late swap tearing currently unsupported");
|
||||
}
|
||||
|
||||
if (Emscripten_ShouldSetSwapInterval(interval)) {
|
||||
// don't change the mainloop timing if the app is also driving a main callback with this hint,
|
||||
// as we assume that was the more deliberate action.
|
||||
if (!SDL_HasMainCallbacks() || !SDL_GetHint(SDL_HINT_MAIN_CALLBACK_RATE)) {
|
||||
if (interval == 0) {
|
||||
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, 0);
|
||||
} else {
|
||||
emscripten_set_main_loop_timing(EM_TIMING_RAF, interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool 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 true;
|
||||
} else {
|
||||
*interval = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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->internal;
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
bool Emscripten_GLES_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context)
|
||||
{
|
||||
SDL_Window *window;
|
||||
|
||||
// remove the context from its window
|
||||
for (window = _this->windows; window; window = window->next) {
|
||||
SDL_WindowData *window_data = window->internal;
|
||||
|
||||
if (window_data->gl_context == context) {
|
||||
window_data->gl_context = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
emscripten_webgl_destroy_context((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Emscripten_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, true)) {
|
||||
// give back control to browser for screen refresh
|
||||
emscripten_sleep(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool 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->internal;
|
||||
|
||||
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 true;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_emscriptenopengles_h_
|
||||
#define SDL_emscriptenopengles_h_
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
// OpenGLES functions
|
||||
extern bool Emscripten_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
extern void Emscripten_GLES_UnloadLibrary(SDL_VideoDevice *_this);
|
||||
extern SDL_FunctionPointer Emscripten_GLES_GetProcAddress(SDL_VideoDevice *_this, const char *proc);
|
||||
extern bool Emscripten_GLES_SetSwapInterval(SDL_VideoDevice *_this, int interval);
|
||||
extern bool Emscripten_GLES_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
|
||||
extern SDL_GLContext Emscripten_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Emscripten_GLES_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context);
|
||||
extern bool Emscripten_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Emscripten_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#endif // SDL_emscriptenopengles_h_
|
||||
@@ -0,0 +1,644 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../SDL_pixels_c.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#include "SDL_emscriptenvideo.h"
|
||||
#include "SDL_emscriptenopengles.h"
|
||||
#include "SDL_emscriptenframebuffer.h"
|
||||
#include "SDL_emscriptenevents.h"
|
||||
#include "SDL_emscriptenmouse.h"
|
||||
|
||||
#define EMSCRIPTENVID_DRIVER_NAME "emscripten"
|
||||
|
||||
// Initialization/Query functions
|
||||
static bool Emscripten_VideoInit(SDL_VideoDevice *_this);
|
||||
static bool Emscripten_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
|
||||
static void Emscripten_VideoQuit(SDL_VideoDevice *_this);
|
||||
static bool Emscripten_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
|
||||
|
||||
static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
|
||||
static void Emscripten_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
static void Emscripten_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
|
||||
static void Emscripten_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
static SDL_FullscreenResult Emscripten_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen);
|
||||
static void Emscripten_PumpEvents(SDL_VideoDevice *_this);
|
||||
static void Emscripten_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
static bool pumpevents_has_run = false;
|
||||
static int pending_swap_interval = -1;
|
||||
|
||||
|
||||
// Emscripten driver bootstrap functions
|
||||
|
||||
static void Emscripten_DeleteDevice(SDL_VideoDevice *device)
|
||||
{
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_SystemTheme Emscripten_GetSystemTheme(void)
|
||||
{
|
||||
/* Technically, light theme can mean explicit light theme or no preference.
|
||||
https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme#syntax */
|
||||
|
||||
int theme_code = MAIN_THREAD_EM_ASM_INT({
|
||||
if (!window.matchMedia) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (window.matchMedia('(prefers-color-scheme: light)').matches) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
});
|
||||
|
||||
switch (theme_code) {
|
||||
case 0:
|
||||
return SDL_SYSTEM_THEME_LIGHT;
|
||||
|
||||
case 1:
|
||||
return SDL_SYSTEM_THEME_DARK;
|
||||
|
||||
default:
|
||||
return SDL_SYSTEM_THEME_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void Emscripten_ListenSystemTheme(void)
|
||||
{
|
||||
MAIN_THREAD_EM_ASM({
|
||||
if (window.matchMedia) {
|
||||
if (typeof(Module['SDL3']) === 'undefined') {
|
||||
Module['SDL3'] = {};
|
||||
}
|
||||
|
||||
var SDL3 = Module['SDL3'];
|
||||
|
||||
SDL3.eventHandlerThemeChanged = function(event) {
|
||||
_Emscripten_SendSystemThemeChangedEvent();
|
||||
};
|
||||
|
||||
SDL3.themeChangedMatchMedia = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
SDL3.themeChangedMatchMedia.addEventListener('change', SDL3.eventHandlerThemeChanged);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void Emscripten_UnlistenSystemTheme(void)
|
||||
{
|
||||
MAIN_THREAD_EM_ASM({
|
||||
if (typeof(Module['SDL3']) !== 'undefined') {
|
||||
var SDL3 = Module['SDL3'];
|
||||
|
||||
SDL3.themeChangedMatchMedia.removeEventListener('change', SDL3.eventHandlerThemeChanged);
|
||||
SDL3.themeChangedMatchMedia = undefined;
|
||||
SDL3.eventHandlerThemeChanged = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Emscripten_SendSystemThemeChangedEvent(void)
|
||||
{
|
||||
SDL_SetSystemTheme(Emscripten_GetSystemTheme());
|
||||
}
|
||||
|
||||
static SDL_VideoDevice *Emscripten_CreateDevice(void)
|
||||
{
|
||||
SDL_VideoDevice *device;
|
||||
|
||||
// Initialize all variables that we clean on shutdown
|
||||
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
|
||||
if (!device) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Firefox sends blur event which would otherwise prevent full screen
|
||||
* when the user clicks to allow full screen.
|
||||
* See https://bugzilla.mozilla.org/show_bug.cgi?id=1144964
|
||||
*/
|
||||
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
|
||||
|
||||
// Set the function pointers
|
||||
device->VideoInit = Emscripten_VideoInit;
|
||||
device->VideoQuit = Emscripten_VideoQuit;
|
||||
device->GetDisplayUsableBounds = Emscripten_GetDisplayUsableBounds;
|
||||
device->SetDisplayMode = Emscripten_SetDisplayMode;
|
||||
|
||||
device->PumpEvents = Emscripten_PumpEvents;
|
||||
|
||||
device->CreateSDLWindow = Emscripten_CreateWindow;
|
||||
device->SetWindowTitle = Emscripten_SetWindowTitle;
|
||||
/*device->SetWindowIcon = Emscripten_SetWindowIcon;
|
||||
device->SetWindowPosition = Emscripten_SetWindowPosition;*/
|
||||
device->SetWindowSize = Emscripten_SetWindowSize;
|
||||
/*device->ShowWindow = Emscripten_ShowWindow;
|
||||
device->HideWindow = Emscripten_HideWindow;
|
||||
device->RaiseWindow = Emscripten_RaiseWindow;
|
||||
device->MaximizeWindow = Emscripten_MaximizeWindow;
|
||||
device->MinimizeWindow = Emscripten_MinimizeWindow;
|
||||
device->RestoreWindow = Emscripten_RestoreWindow;
|
||||
device->SetWindowMouseGrab = Emscripten_SetWindowMouseGrab;*/
|
||||
device->GetWindowSizeInPixels = Emscripten_GetWindowSizeInPixels;
|
||||
device->DestroyWindow = Emscripten_DestroyWindow;
|
||||
device->SetWindowFullscreen = Emscripten_SetWindowFullscreen;
|
||||
|
||||
device->CreateWindowFramebuffer = Emscripten_CreateWindowFramebuffer;
|
||||
device->UpdateWindowFramebuffer = Emscripten_UpdateWindowFramebuffer;
|
||||
device->DestroyWindowFramebuffer = Emscripten_DestroyWindowFramebuffer;
|
||||
|
||||
device->GL_LoadLibrary = Emscripten_GLES_LoadLibrary;
|
||||
device->GL_GetProcAddress = Emscripten_GLES_GetProcAddress;
|
||||
device->GL_UnloadLibrary = Emscripten_GLES_UnloadLibrary;
|
||||
device->GL_CreateContext = Emscripten_GLES_CreateContext;
|
||||
device->GL_MakeCurrent = Emscripten_GLES_MakeCurrent;
|
||||
device->GL_SetSwapInterval = Emscripten_GLES_SetSwapInterval;
|
||||
device->GL_GetSwapInterval = Emscripten_GLES_GetSwapInterval;
|
||||
device->GL_SwapWindow = Emscripten_GLES_SwapWindow;
|
||||
device->GL_DestroyContext = Emscripten_GLES_DestroyContext;
|
||||
|
||||
device->free = Emscripten_DeleteDevice;
|
||||
|
||||
Emscripten_ListenSystemTheme();
|
||||
device->system_theme = Emscripten_GetSystemTheme();
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static bool Emscripten_ShowMessagebox(const SDL_MessageBoxData *messageboxdata, int *buttonID) {
|
||||
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, true)) {
|
||||
char dialog_background[32];
|
||||
char dialog_color[32];
|
||||
char button_border[32];
|
||||
char button_background[32];
|
||||
char button_hovered[32];
|
||||
|
||||
if (messageboxdata->colorScheme) {
|
||||
SDL_MessageBoxColor color = messageboxdata->colorScheme->colors[SDL_MESSAGEBOX_COLOR_BACKGROUND];
|
||||
SDL_snprintf(dialog_background, sizeof(dialog_background), "rgb(%u, %u, %u)", color.r, color.g, color.b);
|
||||
|
||||
color = messageboxdata->colorScheme->colors[SDL_MESSAGEBOX_COLOR_TEXT];
|
||||
SDL_snprintf(dialog_color, sizeof(dialog_color), "rgb(%u, %u, %u)", color.r, color.g, color.b);
|
||||
|
||||
color = messageboxdata->colorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER];
|
||||
SDL_snprintf(button_border, sizeof(button_border), "rgb(%u, %u, %u)", color.r, color.g, color.b);
|
||||
|
||||
color = messageboxdata->colorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND];
|
||||
SDL_snprintf(button_background, sizeof(button_background), "rgb(%u, %u, %u)", color.r, color.g, color.b);
|
||||
|
||||
color = messageboxdata->colorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED];
|
||||
SDL_snprintf(button_hovered, sizeof(button_hovered), "rgb(%u, %u, %u)", color.r, color.g, color.b);
|
||||
} else {
|
||||
SDL_zero(dialog_background);
|
||||
SDL_zero(dialog_color);
|
||||
SDL_zero(button_border);
|
||||
SDL_zero(button_background);
|
||||
SDL_zero(button_hovered);
|
||||
}
|
||||
|
||||
// TODO: Handle parent window when multiple windows can be added in Emscripten builds
|
||||
char dialog_id[64];
|
||||
SDL_snprintf(dialog_id, sizeof(dialog_id), "SDL3_messagebox_%u", SDL_rand_bits());
|
||||
EM_ASM({
|
||||
var title = UTF8ToString($0);
|
||||
var message = UTF8ToString($1);
|
||||
var background = UTF8ToString($2);
|
||||
var color = UTF8ToString($3);
|
||||
var id = UTF8ToString($4);
|
||||
|
||||
// Dialogs are always put in the front of the DOM
|
||||
var dialog = document.createElement("dialog");
|
||||
// Set class to allow for CSS selectors
|
||||
dialog.classList.add("SDL3_messagebox");
|
||||
dialog.id = id;
|
||||
dialog.style.color = color;
|
||||
dialog.style.backgroundColor = background;
|
||||
document.body.append(dialog);
|
||||
|
||||
var h1 = document.createElement("h1");
|
||||
h1.innerText = title;
|
||||
dialog.append(h1);
|
||||
|
||||
var p = document.createElement("p");
|
||||
p.innerText = message;
|
||||
dialog.append(p);
|
||||
|
||||
dialog.showModal();
|
||||
}, messageboxdata->title, messageboxdata->message, dialog_background, dialog_color, dialog_id);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < messageboxdata->numbuttons; ++i) {
|
||||
SDL_MessageBoxButtonData button = messageboxdata->buttons[i];
|
||||
|
||||
const int created = EM_ASM_INT({
|
||||
var dialog_id = UTF8ToString($0);
|
||||
var text = UTF8ToString($1);
|
||||
var responseId = $2;
|
||||
var clickOnReturn = $3;
|
||||
var clickOnEscape = $4;
|
||||
var border = UTF8ToString($5);
|
||||
var background = UTF8ToString($6);
|
||||
var hovered = UTF8ToString($7);
|
||||
|
||||
var dialog = document.getElementById(dialog_id);
|
||||
if (!dialog) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerText = text;
|
||||
button.style.borderColor = border;
|
||||
button.style.backgroundColor = background;
|
||||
|
||||
dialog.addEventListener('keydown', function(e) {
|
||||
if (clickOnReturn && e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
button.click();
|
||||
} else if (clickOnEscape && e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
button.click();
|
||||
}
|
||||
});
|
||||
dialog.addEventListener('cancel', function(e){
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
button.onmouseenter = function(e){
|
||||
button.style.backgroundColor = hovered;
|
||||
};
|
||||
button.onmouseleave = function(e){
|
||||
button.style.backgroundColor = background;
|
||||
};
|
||||
button.onclick = function(e) {
|
||||
dialog.close(responseId);
|
||||
};
|
||||
|
||||
dialog.append(button);
|
||||
return true;
|
||||
},
|
||||
dialog_id,
|
||||
button.text,
|
||||
button.buttonID,
|
||||
button.flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
|
||||
button.flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
|
||||
button_border,
|
||||
button_background,
|
||||
button_hovered
|
||||
);
|
||||
|
||||
if (!created) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// give back control to browser for screen refresh
|
||||
emscripten_sleep(0);
|
||||
|
||||
const int dialog_open = EM_ASM_INT({
|
||||
var dialog_id = UTF8ToString($0);
|
||||
|
||||
var dialog = document.getElementById(dialog_id);
|
||||
if (!dialog) {
|
||||
return false;
|
||||
}
|
||||
return dialog.open;
|
||||
}, dialog_id);
|
||||
|
||||
if (dialog_open) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*buttonID = EM_ASM_INT({
|
||||
var dialog_id = UTF8ToString($0);
|
||||
var dialog = document.getElementById(dialog_id);
|
||||
if (!dialog) {
|
||||
return 0;
|
||||
}
|
||||
try
|
||||
{
|
||||
return parseInt(dialog.returnValue);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}, dialog_id);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Cannot add elements to DOM and block without Asyncify. So, fall back to the alert function.
|
||||
EM_ASM({
|
||||
alert(UTF8ToString($0) + "\n\n" + UTF8ToString($1));
|
||||
}, messageboxdata->title, messageboxdata->message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
VideoBootStrap Emscripten_bootstrap = {
|
||||
EMSCRIPTENVID_DRIVER_NAME, "SDL emscripten video driver",
|
||||
Emscripten_CreateDevice,
|
||||
Emscripten_ShowMessagebox,
|
||||
false
|
||||
};
|
||||
|
||||
bool Emscripten_VideoInit(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_DisplayMode mode;
|
||||
|
||||
// Use a fake 32-bpp desktop mode
|
||||
SDL_zero(mode);
|
||||
mode.format = SDL_PIXELFORMAT_XRGB8888;
|
||||
emscripten_get_screen_size(&mode.w, &mode.h);
|
||||
mode.pixel_density = emscripten_get_device_pixel_ratio();
|
||||
|
||||
if (SDL_AddBasicVideoDisplay(&mode) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Emscripten_InitMouse();
|
||||
|
||||
// Assume we have a mouse and keyboard
|
||||
SDL_AddKeyboard(SDL_DEFAULT_KEYBOARD_ID, NULL, false);
|
||||
SDL_AddMouse(SDL_DEFAULT_MOUSE_ID, NULL, false);
|
||||
|
||||
Emscripten_RegisterGlobalEventHandlers(_this);
|
||||
|
||||
// We're done!
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Emscripten_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
|
||||
{
|
||||
// can't do this
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Emscripten_VideoQuit(SDL_VideoDevice *_this)
|
||||
{
|
||||
Emscripten_UnregisterGlobalEventHandlers(_this);
|
||||
Emscripten_QuitMouse();
|
||||
Emscripten_UnlistenSystemTheme();
|
||||
pumpevents_has_run = false;
|
||||
pending_swap_interval = -1;
|
||||
}
|
||||
|
||||
static bool Emscripten_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
|
||||
{
|
||||
if (rect) {
|
||||
rect->x = 0;
|
||||
rect->y = 0;
|
||||
rect->w = MAIN_THREAD_EM_ASM_INT({
|
||||
return window.innerWidth;
|
||||
});
|
||||
rect->h = MAIN_THREAD_EM_ASM_INT({
|
||||
return window.innerHeight;
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Emscripten_ShouldSetSwapInterval(int interval)
|
||||
{
|
||||
if (!pumpevents_has_run) {
|
||||
pending_swap_interval = interval;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Emscripten_PumpEvents(SDL_VideoDevice *_this)
|
||||
{
|
||||
if (!pumpevents_has_run) {
|
||||
// we assume you've set a mainloop by the time you've called pumpevents, so we delay initial SetInterval changes until then.
|
||||
// otherwise you'll get a warning on the javascript console.
|
||||
pumpevents_has_run = true;
|
||||
if (pending_swap_interval >= 0) {
|
||||
Emscripten_GLES_SetSwapInterval(_this, pending_swap_interval);
|
||||
pending_swap_interval = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void requestFullscreenThroughSDL(SDL_Window *window)
|
||||
{
|
||||
SDL_SetWindowFullscreen(window, true);
|
||||
}
|
||||
|
||||
static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
|
||||
{
|
||||
SDL_WindowData *wdata;
|
||||
double scaled_w, scaled_h;
|
||||
double css_w, css_h;
|
||||
const char *selector;
|
||||
|
||||
// Allocate window internal data
|
||||
wdata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
|
||||
if (!wdata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
selector = SDL_GetHint(SDL_HINT_EMSCRIPTEN_CANVAS_SELECTOR);
|
||||
if (!selector || !*selector) {
|
||||
selector = SDL_GetStringProperty(props, SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING, "#canvas");
|
||||
}
|
||||
wdata->canvas_id = SDL_strdup(selector);
|
||||
|
||||
selector = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
|
||||
if (!selector || !*selector) {
|
||||
selector = SDL_GetStringProperty(props, SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING, "#window");
|
||||
}
|
||||
wdata->keyboard_element = SDL_strdup(selector);
|
||||
|
||||
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
|
||||
wdata->pixel_ratio = emscripten_get_device_pixel_ratio();
|
||||
} else {
|
||||
wdata->pixel_ratio = 1.0f;
|
||||
}
|
||||
|
||||
scaled_w = SDL_floor(window->w * wdata->pixel_ratio);
|
||||
scaled_h = SDL_floor(window->h * wdata->pixel_ratio);
|
||||
|
||||
// set a fake size to check if there is any CSS sizing the canvas
|
||||
emscripten_set_canvas_element_size(wdata->canvas_id, 1, 1);
|
||||
emscripten_get_element_css_size(wdata->canvas_id, &css_w, &css_h);
|
||||
|
||||
wdata->external_size = SDL_floor(css_w) != 1 || SDL_floor(css_h) != 1;
|
||||
|
||||
if ((window->flags & SDL_WINDOW_RESIZABLE) && wdata->external_size) {
|
||||
// external css has resized us
|
||||
scaled_w = css_w * wdata->pixel_ratio;
|
||||
scaled_h = css_h * wdata->pixel_ratio;
|
||||
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, SDL_lroundf(css_w), SDL_lroundf(css_h));
|
||||
}
|
||||
emscripten_set_canvas_element_size(wdata->canvas_id, SDL_lroundf(scaled_w), SDL_lroundf(scaled_h));
|
||||
|
||||
// if the size is not being controlled by css, we need to scale down for hidpi
|
||||
if (!wdata->external_size) {
|
||||
if (wdata->pixel_ratio != 1.0f) {
|
||||
// scale canvas down
|
||||
emscripten_set_element_css_size(wdata->canvas_id, window->w, window->h);
|
||||
}
|
||||
}
|
||||
|
||||
wdata->window = window;
|
||||
|
||||
// Setup driver data for this window
|
||||
window->internal = wdata;
|
||||
|
||||
// One window, it always has focus
|
||||
SDL_SetMouseFocus(window);
|
||||
SDL_SetKeyboardFocus(window);
|
||||
|
||||
Emscripten_RegisterEventHandlers(wdata);
|
||||
|
||||
// disable the emscripten "fullscreen" button.
|
||||
MAIN_THREAD_EM_ASM({
|
||||
Module['requestFullscreen'] = function(lockPointer, resizeCanvas) {
|
||||
_requestFullscreenThroughSDL($0);
|
||||
};
|
||||
}, window);
|
||||
|
||||
// Ensure canvas_id and keyboard_element are added to the window's properties
|
||||
SDL_SetStringProperty(window->props, SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING, wdata->canvas_id);
|
||||
SDL_SetStringProperty(window->props, SDL_PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING, wdata->keyboard_element);
|
||||
|
||||
// Window has been successfully created
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Emscripten_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
|
||||
if (window->internal) {
|
||||
data = window->internal;
|
||||
// update pixel ratio
|
||||
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
|
||||
data->pixel_ratio = emscripten_get_device_pixel_ratio();
|
||||
}
|
||||
emscripten_set_canvas_element_size(data->canvas_id, SDL_lroundf(window->pending.w * data->pixel_ratio), SDL_lroundf(window->pending.h * data->pixel_ratio));
|
||||
|
||||
// scale canvas down
|
||||
if (!data->external_size && data->pixel_ratio != 1.0f) {
|
||||
emscripten_set_element_css_size(data->canvas_id, window->pending.w, window->pending.h);
|
||||
}
|
||||
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, window->pending.w, window->pending.h);
|
||||
}
|
||||
}
|
||||
|
||||
static void Emscripten_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
if (window->internal) {
|
||||
data = window->internal;
|
||||
*w = SDL_lroundf(window->w * data->pixel_ratio);
|
||||
*h = SDL_lroundf(window->h * data->pixel_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
static void Emscripten_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
|
||||
if (window->internal) {
|
||||
data = window->internal;
|
||||
|
||||
Emscripten_UnregisterEventHandlers(data);
|
||||
|
||||
// We can't destroy the canvas, so resize it to zero instead
|
||||
emscripten_set_canvas_element_size(data->canvas_id, 0, 0);
|
||||
SDL_free(data->canvas_id);
|
||||
|
||||
SDL_free(data->keyboard_element);
|
||||
|
||||
SDL_free(window->internal);
|
||||
window->internal = NULL;
|
||||
}
|
||||
|
||||
// just ignore clicks on the fullscreen button while there's no SDL window.
|
||||
MAIN_THREAD_EM_ASM({ Module['requestFullscreen'] = function(lockPointer, resizeCanvas) {}; });
|
||||
}
|
||||
|
||||
static SDL_FullscreenResult Emscripten_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
int res = -1;
|
||||
|
||||
if (window->internal) {
|
||||
data = window->internal;
|
||||
|
||||
if (fullscreen) {
|
||||
EmscriptenFullscreenStrategy strategy;
|
||||
bool is_fullscreen_desktop = !window->fullscreen_exclusive;
|
||||
|
||||
SDL_zero(strategy);
|
||||
strategy.scaleMode = is_fullscreen_desktop ? EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH : EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT;
|
||||
|
||||
if (!is_fullscreen_desktop) {
|
||||
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE;
|
||||
} else if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
|
||||
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
|
||||
} else {
|
||||
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
|
||||
}
|
||||
|
||||
strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
|
||||
|
||||
strategy.canvasResizedCallback = Emscripten_HandleCanvasResize;
|
||||
strategy.canvasResizedCallbackUserData = data;
|
||||
|
||||
data->fullscreen_mode_flags = (window->flags & SDL_WINDOW_FULLSCREEN);
|
||||
data->fullscreen_resize = is_fullscreen_desktop;
|
||||
|
||||
res = emscripten_request_fullscreen_strategy(data->canvas_id, 1, &strategy);
|
||||
} else {
|
||||
res = emscripten_exit_fullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
if (res == EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
return SDL_FULLSCREEN_SUCCEEDED;
|
||||
} else if (res == EMSCRIPTEN_RESULT_DEFERRED) {
|
||||
return SDL_FULLSCREEN_PENDING;
|
||||
} else {
|
||||
return SDL_FULLSCREEN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
static void Emscripten_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
emscripten_set_window_title(window->title);
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_emscriptenvideo_h_
|
||||
#define SDL_emscriptenvideo_h_
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../../events/SDL_touch_c.h"
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
|
||||
struct SDL_WindowData
|
||||
{
|
||||
SDL_Window *window;
|
||||
SDL_Surface *surface;
|
||||
|
||||
SDL_GLContext gl_context;
|
||||
|
||||
char *canvas_id;
|
||||
char *keyboard_element;
|
||||
|
||||
float pixel_ratio;
|
||||
|
||||
bool external_size;
|
||||
|
||||
Uint32 fullscreen_mode_flags;
|
||||
bool fullscreen_resize;
|
||||
|
||||
bool has_pointer_lock;
|
||||
|
||||
bool mouse_focus_loss_pending;
|
||||
};
|
||||
|
||||
bool Emscripten_ShouldSetSwapInterval(int interval);
|
||||
|
||||
#endif // SDL_emscriptenvideo_h_
|
||||
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
/*
|
||||
Screen keyboard and text input backend
|
||||
for GDK platforms.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
#include "SDL_gdktextinput.h"
|
||||
|
||||
#ifdef SDL_GDK_TEXTINPUT
|
||||
|
||||
// GDK headers are weird here
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#include <XGameUI.h>
|
||||
#include <XUser.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include "../windows/SDL_windowsvideo.h"
|
||||
|
||||
// TODO: Have a separate task queue for text input perhaps?
|
||||
static XTaskQueueHandle g_TextTaskQueue = NULL;
|
||||
// Global because there can be only one text entry shown at once.
|
||||
static XAsyncBlock *g_TextBlock = NULL;
|
||||
|
||||
// Creation parameters
|
||||
static bool g_DidRegisterHints = false;
|
||||
static char *g_TitleText = NULL;
|
||||
static char *g_DescriptionText = NULL;
|
||||
static char *g_DefaultText = NULL;
|
||||
static const Sint32 g_DefaultTextInputScope = (Sint32)XGameUiTextEntryInputScope::Default;
|
||||
static Sint32 g_TextInputScope = g_DefaultTextInputScope;
|
||||
static const Sint32 g_DefaultMaxTextLength = 1024; // as per doc: maximum allowed amount on consoles
|
||||
static Sint32 g_MaxTextLength = g_DefaultMaxTextLength;
|
||||
|
||||
static void SDLCALL GDK_InternalHintCallback(
|
||||
void *userdata,
|
||||
const char *name,
|
||||
const char *oldValue,
|
||||
const char *newValue)
|
||||
{
|
||||
if (!userdata) {
|
||||
return;
|
||||
}
|
||||
|
||||
// oldValue is ignored because we store it ourselves.
|
||||
// name is ignored because we deduce it from userdata
|
||||
|
||||
if (userdata == &g_TextInputScope || userdata == &g_MaxTextLength) {
|
||||
// int32 hint
|
||||
Sint32 intValue = (!newValue || newValue[0] == '\0') ? 0 : SDL_atoi(newValue);
|
||||
if (userdata == &g_MaxTextLength && intValue <= 0) {
|
||||
intValue = g_DefaultMaxTextLength;
|
||||
} else if (userdata == &g_TextInputScope && intValue < 0) {
|
||||
intValue = g_DefaultTextInputScope;
|
||||
}
|
||||
|
||||
*(Sint32 *)userdata = intValue;
|
||||
} else {
|
||||
// string hint
|
||||
if (!newValue || newValue[0] == '\0') {
|
||||
// treat empty or NULL strings as just NULL for this impl
|
||||
SDL_free(*(char **)userdata);
|
||||
*(char **)userdata = NULL;
|
||||
} else {
|
||||
char *newString = SDL_strdup(newValue);
|
||||
if (newString) {
|
||||
// free previous value and write the new one
|
||||
SDL_free(*(char **)userdata);
|
||||
*(char **)userdata = newString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool GDK_InternalEnsureTaskQueue(void)
|
||||
{
|
||||
if (!g_TextTaskQueue) {
|
||||
if (!SDL_GetGDKTaskQueue(&g_TextTaskQueue)) {
|
||||
// SetError will be done for us.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void CALLBACK GDK_InternalTextEntryCallback(XAsyncBlock *asyncBlock)
|
||||
{
|
||||
HRESULT hR = S_OK;
|
||||
Uint32 resultSize = 0;
|
||||
Uint32 resultUsed = 0;
|
||||
char *resultBuffer = NULL;
|
||||
|
||||
// The keyboard will be already hidden when we reach this code
|
||||
|
||||
if (FAILED(hR = XGameUiShowTextEntryResultSize(
|
||||
asyncBlock,
|
||||
&resultSize))) {
|
||||
SDL_SetError("XGameUiShowTextEntryResultSize failure with HRESULT of %08X", hR);
|
||||
} else if (resultSize > 0) {
|
||||
// +1 to be super sure that the buffer will be null terminated
|
||||
resultBuffer = (char *)SDL_calloc(1 + (size_t)resultSize, sizeof(*resultBuffer));
|
||||
if (resultBuffer) {
|
||||
// still pass the original size that we got from ResultSize
|
||||
if (FAILED(hR = XGameUiShowTextEntryResult(
|
||||
asyncBlock,
|
||||
resultSize,
|
||||
resultBuffer,
|
||||
&resultUsed))) {
|
||||
SDL_SetError("XGameUiShowTextEntryResult failure with HRESULT of %08X", hR);
|
||||
}
|
||||
// check that we have some text and that we weren't cancelled
|
||||
else if (resultUsed > 0 && resultBuffer[0] != '\0') {
|
||||
// it's null terminated so it's fine
|
||||
SDL_SendKeyboardText(resultBuffer);
|
||||
}
|
||||
// we're done with the buffer
|
||||
SDL_free(resultBuffer);
|
||||
resultBuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// free the async block after we're done
|
||||
SDL_free(asyncBlock);
|
||||
asyncBlock = NULL;
|
||||
g_TextBlock = NULL; // once we do this we're fully done with the keyboard
|
||||
}
|
||||
|
||||
void GDK_EnsureHints(void)
|
||||
{
|
||||
if (g_DidRegisterHints == false) {
|
||||
SDL_AddHintCallback(
|
||||
SDL_HINT_GDK_TEXTINPUT_TITLE,
|
||||
GDK_InternalHintCallback,
|
||||
&g_TitleText);
|
||||
SDL_AddHintCallback(
|
||||
SDL_HINT_GDK_TEXTINPUT_DESCRIPTION,
|
||||
GDK_InternalHintCallback,
|
||||
&g_DescriptionText);
|
||||
SDL_AddHintCallback(
|
||||
SDL_HINT_GDK_TEXTINPUT_DEFAULT_TEXT,
|
||||
GDK_InternalHintCallback,
|
||||
&g_DefaultText);
|
||||
SDL_AddHintCallback(
|
||||
SDL_HINT_GDK_TEXTINPUT_SCOPE,
|
||||
GDK_InternalHintCallback,
|
||||
&g_TextInputScope);
|
||||
SDL_AddHintCallback(
|
||||
SDL_HINT_GDK_TEXTINPUT_MAX_LENGTH,
|
||||
GDK_InternalHintCallback,
|
||||
&g_MaxTextLength);
|
||||
g_DidRegisterHints = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool GDK_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
|
||||
{
|
||||
/*
|
||||
* Currently a stub, since all input is handled by the virtual keyboard,
|
||||
* but perhaps when implementing XGameUiTextEntryOpen in the future
|
||||
* you will need this.
|
||||
*
|
||||
* Also XGameUiTextEntryOpen docs say that it is
|
||||
* "not implemented on desktop" so... no thanks.
|
||||
*
|
||||
* Right now this function isn't implemented on Desktop
|
||||
* and seems to be present only in the docs? So I didn't bother.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GDK_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
// See notice in GDK_StartTextInput
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GDK_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
/*
|
||||
* XGameUiShowTextEntryAsync does not allow you to set
|
||||
* the position of the virtual keyboard window.
|
||||
*
|
||||
* However, XGameUiTextEntryOpen seems to allow that,
|
||||
* but again, see notice in GDK_StartTextInput.
|
||||
*
|
||||
* Right now it's a stub which may be useful later.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GDK_ClearComposition(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
// See notice in GDK_StartTextInput
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GDK_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
|
||||
{
|
||||
// Currently always true for this input method
|
||||
return true;
|
||||
}
|
||||
|
||||
void GDK_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
|
||||
{
|
||||
/*
|
||||
* There is XGameUiTextEntryOpen but it's only in online docs,
|
||||
* My October Update 1 GDKX installation does not have this function defined
|
||||
* and as such I decided not to use it at all, since some folks might use even older GDKs.
|
||||
*
|
||||
* That means the only text input option for us is a simple virtual keyboard widget.
|
||||
*/
|
||||
|
||||
HRESULT hR = S_OK;
|
||||
|
||||
if (g_TextBlock) {
|
||||
// already showing the keyboard
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GDK_InternalEnsureTaskQueue()) {
|
||||
// unable to obtain the SDL GDK queue
|
||||
return;
|
||||
}
|
||||
|
||||
g_TextBlock = (XAsyncBlock *)SDL_calloc(1, sizeof(*g_TextBlock));
|
||||
if (!g_TextBlock) {
|
||||
return;
|
||||
}
|
||||
|
||||
XGameUiTextEntryInputScope scope;
|
||||
switch (SDL_GetTextInputType(props)) {
|
||||
default:
|
||||
case SDL_TEXTINPUT_TYPE_TEXT:
|
||||
scope = (XGameUiTextEntryInputScope)g_TextInputScope;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
|
||||
scope = XGameUiTextEntryInputScope::Default;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
|
||||
scope = XGameUiTextEntryInputScope::EmailSmtpAddress;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
|
||||
scope = XGameUiTextEntryInputScope::Default;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
|
||||
scope = XGameUiTextEntryInputScope::Password;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
|
||||
scope = XGameUiTextEntryInputScope::Default;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER:
|
||||
scope = XGameUiTextEntryInputScope::Number;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
|
||||
// FIXME: Password or number scope?
|
||||
scope = XGameUiTextEntryInputScope::Number;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
|
||||
scope = XGameUiTextEntryInputScope::Number;
|
||||
break;
|
||||
}
|
||||
|
||||
g_TextBlock->queue = g_TextTaskQueue;
|
||||
g_TextBlock->context = _this;
|
||||
g_TextBlock->callback = GDK_InternalTextEntryCallback;
|
||||
if (FAILED(hR = XGameUiShowTextEntryAsync(
|
||||
g_TextBlock,
|
||||
g_TitleText,
|
||||
g_DescriptionText,
|
||||
g_DefaultText,
|
||||
scope,
|
||||
(uint32_t)g_MaxTextLength))) {
|
||||
SDL_free(g_TextBlock);
|
||||
g_TextBlock = NULL;
|
||||
SDL_SetError("XGameUiShowTextEntryAsync failure with HRESULT of %08X", hR);
|
||||
}
|
||||
}
|
||||
|
||||
void GDK_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
if (g_TextBlock) {
|
||||
XAsyncCancel(g_TextBlock);
|
||||
// the completion callback will free the block
|
||||
}
|
||||
}
|
||||
|
||||
bool GDK_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
return (g_TextBlock != NULL);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_gdktextinput_h_
|
||||
#define SDL_gdktextinput_h_
|
||||
|
||||
#ifdef SDL_GDK_TEXTINPUT
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
void GDK_EnsureHints(void);
|
||||
|
||||
bool GDK_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
bool GDK_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool GDK_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool GDK_ClearComposition(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
bool GDK_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
|
||||
void GDK_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
void GDK_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool GDK_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,755 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_BWin_h_
|
||||
#define SDL_BWin_h_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "SDL_internal.h"
|
||||
#include "SDL_bframebuffer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <AppKit.h>
|
||||
#include <Cursor.h>
|
||||
#include <InterfaceKit.h>
|
||||
#ifdef SDL_VIDEO_OPENGL
|
||||
#include <opengl/GLView.h>
|
||||
#endif
|
||||
#include "../../core/haiku/SDL_BApp.h"
|
||||
|
||||
enum WinCommands
|
||||
{
|
||||
BWIN_MOVE_WINDOW,
|
||||
BWIN_RESIZE_WINDOW,
|
||||
BWIN_SHOW_WINDOW,
|
||||
BWIN_HIDE_WINDOW,
|
||||
BWIN_MAXIMIZE_WINDOW,
|
||||
BWIN_MINIMIZE_WINDOW,
|
||||
BWIN_RESTORE_WINDOW,
|
||||
BWIN_SET_TITLE,
|
||||
BWIN_SET_BORDERED,
|
||||
BWIN_SET_RESIZABLE,
|
||||
BWIN_FULLSCREEN,
|
||||
BWIN_UPDATE_FRAMEBUFFER,
|
||||
BWIN_MINIMUM_SIZE_WINDOW
|
||||
};
|
||||
|
||||
// non-OpenGL framebuffer view
|
||||
class SDL_BView : public BView
|
||||
{
|
||||
public:
|
||||
SDL_BView(BRect frame, const char *name, uint32 resizingMode)
|
||||
: BView(frame, name, resizingMode, B_WILL_DRAW),
|
||||
fBitmap(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void Draw(BRect dirty)
|
||||
{
|
||||
if (fBitmap != NULL)
|
||||
DrawBitmap(fBitmap, B_ORIGIN);
|
||||
}
|
||||
|
||||
void SetBitmap(BBitmap *bitmap)
|
||||
{
|
||||
fBitmap = bitmap;
|
||||
}
|
||||
|
||||
private:
|
||||
BBitmap *fBitmap;
|
||||
};
|
||||
|
||||
class SDL_BWin : public BWindow
|
||||
{
|
||||
public:
|
||||
// Constructor/Destructor
|
||||
SDL_BWin(BRect bounds, window_look look, uint32 flags)
|
||||
: BWindow(bounds, "Untitled", look, B_NORMAL_WINDOW_FEEL, flags)
|
||||
{
|
||||
_last_buttons = 0;
|
||||
|
||||
_cur_view = NULL;
|
||||
_SDL_View = NULL;
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL
|
||||
_SDL_GLView = NULL;
|
||||
_gl_type = 0;
|
||||
#endif
|
||||
_shown = false;
|
||||
_inhibit_resize = false;
|
||||
_mouse_focused = false;
|
||||
_prev_frame = NULL;
|
||||
_fullscreen = NULL;
|
||||
|
||||
// Handle framebuffer stuff
|
||||
_buffer_locker = new BLocker();
|
||||
_bitmap = NULL;
|
||||
}
|
||||
|
||||
virtual ~SDL_BWin()
|
||||
{
|
||||
Lock();
|
||||
|
||||
if (_SDL_View != NULL && _SDL_View != _cur_view) {
|
||||
delete _SDL_View;
|
||||
_SDL_View = NULL;
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL
|
||||
if (_SDL_GLView) {
|
||||
if (SDL_Looper->GetCurrentContext() == _SDL_GLView)
|
||||
SDL_Looper->SetCurrentContext(NULL);
|
||||
if (_SDL_GLView == _cur_view)
|
||||
RemoveChild(_SDL_GLView);
|
||||
_SDL_GLView = NULL;
|
||||
// _SDL_GLView deleted by HAIKU_GL_DestroyContext
|
||||
}
|
||||
|
||||
#endif
|
||||
Unlock();
|
||||
|
||||
delete _prev_frame;
|
||||
|
||||
// Clean up framebuffer stuff
|
||||
_buffer_locker->Lock();
|
||||
delete _buffer_locker;
|
||||
}
|
||||
|
||||
void SetCurrentView(BView *view)
|
||||
{
|
||||
if (_cur_view != view) {
|
||||
if (_cur_view != NULL)
|
||||
RemoveChild(_cur_view);
|
||||
_cur_view = view;
|
||||
if (_cur_view != NULL)
|
||||
AddChild(_cur_view);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateCurrentView()
|
||||
{
|
||||
#ifdef SDL_VIDEO_OPENGL
|
||||
if (_SDL_GLView != NULL) {
|
||||
SetCurrentView(_SDL_GLView);
|
||||
} else
|
||||
#endif
|
||||
if (_SDL_View != NULL) {
|
||||
SetCurrentView(_SDL_View);
|
||||
} else {
|
||||
SetCurrentView(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_BView *CreateView()
|
||||
{
|
||||
Lock();
|
||||
if (_SDL_View == NULL) {
|
||||
_SDL_View = new SDL_BView(Bounds(), "SDL View", B_FOLLOW_ALL_SIDES);
|
||||
UpdateCurrentView();
|
||||
}
|
||||
Unlock();
|
||||
return _SDL_View;
|
||||
}
|
||||
|
||||
void RemoveView()
|
||||
{
|
||||
Lock();
|
||||
if (_SDL_View != NULL) {
|
||||
SDL_BView *oldView = _SDL_View;
|
||||
_SDL_View = NULL;
|
||||
UpdateCurrentView();
|
||||
delete oldView;
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
|
||||
/* * * * * OpenGL functionality * * * * */
|
||||
#ifdef SDL_VIDEO_OPENGL
|
||||
BGLView *CreateGLView(Uint32 gl_flags)
|
||||
{
|
||||
Lock();
|
||||
if (_SDL_GLView == NULL) {
|
||||
_SDL_GLView = new BGLView(Bounds(), "SDL GLView",
|
||||
B_FOLLOW_ALL_SIDES,
|
||||
(B_WILL_DRAW | B_FRAME_EVENTS),
|
||||
gl_flags);
|
||||
_gl_type = gl_flags;
|
||||
UpdateCurrentView();
|
||||
}
|
||||
Unlock();
|
||||
return _SDL_GLView;
|
||||
}
|
||||
|
||||
void RemoveGLView()
|
||||
{
|
||||
Lock();
|
||||
if (_SDL_GLView != NULL) {
|
||||
if (SDL_Looper->GetCurrentContext() == _SDL_GLView)
|
||||
SDL_Looper->SetCurrentContext(NULL);
|
||||
_SDL_GLView = NULL;
|
||||
UpdateCurrentView();
|
||||
// _SDL_GLView deleted by HAIKU_GL_DestroyContext
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
|
||||
void SwapBuffers(void)
|
||||
{
|
||||
_SDL_GLView->SwapBuffers();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* * * * * Event sending * * * * */
|
||||
// Hook functions
|
||||
virtual void FrameMoved(BPoint origin)
|
||||
{
|
||||
// Post a message to the BApp so that it can handle the window event
|
||||
BMessage msg(BAPP_WINDOW_MOVED);
|
||||
msg.AddInt32("window-x", (int)origin.x);
|
||||
msg.AddInt32("window-y", (int)origin.y);
|
||||
_PostWindowEvent(msg);
|
||||
|
||||
// Perform normal hook operations
|
||||
BWindow::FrameMoved(origin);
|
||||
}
|
||||
|
||||
void FrameResized(float width, float height)
|
||||
{
|
||||
// Post a message to the BApp so that it can handle the window event
|
||||
BMessage msg(BAPP_WINDOW_RESIZED);
|
||||
|
||||
msg.AddInt32("window-w", (int)width + 1);
|
||||
msg.AddInt32("window-h", (int)height + 1);
|
||||
_PostWindowEvent(msg);
|
||||
|
||||
// Perform normal hook operations
|
||||
BWindow::FrameResized(width, height);
|
||||
}
|
||||
|
||||
bool QuitRequested()
|
||||
{
|
||||
BMessage msg(BAPP_WINDOW_CLOSE_REQUESTED);
|
||||
_PostWindowEvent(msg);
|
||||
|
||||
// We won't allow a quit unless asked by DestroyWindow()
|
||||
return false;
|
||||
}
|
||||
|
||||
void WindowActivated(bool active)
|
||||
{
|
||||
BMessage msg(BAPP_KEYBOARD_FOCUS); // Mouse focus sold separately
|
||||
msg.AddBool("focusGained", active);
|
||||
_PostWindowEvent(msg);
|
||||
}
|
||||
|
||||
void Zoom(BPoint origin,
|
||||
float width,
|
||||
float height)
|
||||
{
|
||||
BMessage msg(BAPP_MAXIMIZE); // Closest thing to maximization Haiku has
|
||||
_PostWindowEvent(msg);
|
||||
|
||||
// Before the window zooms, record its size
|
||||
if (!_prev_frame)
|
||||
_prev_frame = new BRect(Frame());
|
||||
|
||||
// Perform normal hook operations
|
||||
BWindow::Zoom(origin, width, height);
|
||||
}
|
||||
|
||||
// Member functions
|
||||
void Show()
|
||||
{
|
||||
while (IsHidden()) {
|
||||
BWindow::Show();
|
||||
}
|
||||
_shown = true;
|
||||
|
||||
BMessage msg(BAPP_SHOW);
|
||||
_PostWindowEvent(msg);
|
||||
}
|
||||
|
||||
void Hide()
|
||||
{
|
||||
BWindow::Hide();
|
||||
_shown = false;
|
||||
|
||||
BMessage msg(BAPP_HIDE);
|
||||
_PostWindowEvent(msg);
|
||||
}
|
||||
|
||||
void Minimize(bool minimize)
|
||||
{
|
||||
BWindow::Minimize(minimize);
|
||||
int32 minState = (minimize ? BAPP_MINIMIZE : BAPP_RESTORE);
|
||||
|
||||
BMessage msg(minState);
|
||||
_PostWindowEvent(msg);
|
||||
}
|
||||
|
||||
void ScreenChanged(BRect screenFrame, color_space depth)
|
||||
{
|
||||
if (_fullscreen) {
|
||||
MoveTo(screenFrame.left, screenFrame.top);
|
||||
ResizeTo(screenFrame.Width(), screenFrame.Height());
|
||||
}
|
||||
}
|
||||
|
||||
// BView message interruption
|
||||
void DispatchMessage(BMessage *msg, BHandler *target)
|
||||
{
|
||||
BPoint where; // Used by mouse moved
|
||||
int32 buttons; // Used for mouse button events
|
||||
int32 key; // Used for key events
|
||||
|
||||
switch (msg->what) {
|
||||
case B_MOUSE_MOVED:
|
||||
int32 transit;
|
||||
if (msg->FindPoint("where", &where) == B_OK && msg->FindInt32("be:transit", &transit) == B_OK) {
|
||||
_MouseMotionEvent(where, transit);
|
||||
}
|
||||
break;
|
||||
|
||||
case B_MOUSE_DOWN:
|
||||
if (msg->FindInt32("buttons", &buttons) == B_OK) {
|
||||
_MouseButtonEvent(buttons, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case B_MOUSE_UP:
|
||||
if (msg->FindInt32("buttons", &buttons) == B_OK) {
|
||||
_MouseButtonEvent(buttons, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case B_MOUSE_WHEEL_CHANGED:
|
||||
float x, y;
|
||||
if (msg->FindFloat("be:wheel_delta_x", &x) == B_OK && msg->FindFloat("be:wheel_delta_y", &y) == B_OK) {
|
||||
_MouseWheelEvent((int)x, (int)y);
|
||||
}
|
||||
break;
|
||||
|
||||
case B_KEY_DOWN:
|
||||
{
|
||||
int32 i = 0;
|
||||
int8 byte;
|
||||
int8 bytes[4] = { 0, 0, 0, 0 };
|
||||
while (i < 4 && msg->FindInt8("byte", i, &byte) == B_OK) {
|
||||
bytes[i] = byte;
|
||||
i++;
|
||||
}
|
||||
if (msg->FindInt32("key", &key) == B_OK) {
|
||||
_KeyEvent((SDL_Scancode)key, &bytes[0], i, true);
|
||||
}
|
||||
} break;
|
||||
|
||||
case B_UNMAPPED_KEY_DOWN: // modifier keys are unmapped
|
||||
if (msg->FindInt32("key", &key) == B_OK) {
|
||||
_KeyEvent((SDL_Scancode)key, NULL, 0, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case B_KEY_UP:
|
||||
case B_UNMAPPED_KEY_UP: // modifier keys are unmapped
|
||||
if (msg->FindInt32("key", &key) == B_OK) {
|
||||
_KeyEvent(key, NULL, 0, false);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* move it after switch{} so it's always handled
|
||||
that way we keep Haiku features like:
|
||||
- CTRL+Q to close window (and other shortcuts)
|
||||
- PrintScreen to make screenshot into /boot/home
|
||||
- etc.. */
|
||||
// BWindow::DispatchMessage(msg, target);
|
||||
break;
|
||||
}
|
||||
|
||||
BWindow::DispatchMessage(msg, target);
|
||||
}
|
||||
|
||||
// Handle command messages
|
||||
void MessageReceived(BMessage *message)
|
||||
{
|
||||
switch (message->what) {
|
||||
// Handle commands from SDL
|
||||
case BWIN_SET_TITLE:
|
||||
_SetTitle(message);
|
||||
break;
|
||||
case BWIN_MOVE_WINDOW:
|
||||
_MoveTo(message);
|
||||
break;
|
||||
case BWIN_RESIZE_WINDOW:
|
||||
_ResizeTo(message);
|
||||
break;
|
||||
case BWIN_SET_BORDERED:
|
||||
{
|
||||
bool bEnabled;
|
||||
if (message->FindBool("window-border", &bEnabled) == B_OK)
|
||||
_SetBordered(bEnabled);
|
||||
break;
|
||||
}
|
||||
case BWIN_SET_RESIZABLE:
|
||||
{
|
||||
bool bEnabled;
|
||||
if (message->FindBool("window-resizable", &bEnabled) == B_OK)
|
||||
_SetResizable(bEnabled);
|
||||
break;
|
||||
}
|
||||
case BWIN_SHOW_WINDOW:
|
||||
Show();
|
||||
break;
|
||||
case BWIN_HIDE_WINDOW:
|
||||
Hide();
|
||||
break;
|
||||
case BWIN_MAXIMIZE_WINDOW:
|
||||
BWindow::Zoom();
|
||||
break;
|
||||
case BWIN_MINIMIZE_WINDOW:
|
||||
Minimize(true);
|
||||
break;
|
||||
case BWIN_RESTORE_WINDOW:
|
||||
_Restore();
|
||||
break;
|
||||
case BWIN_FULLSCREEN:
|
||||
{
|
||||
bool fullscreen;
|
||||
if (message->FindBool("fullscreen", &fullscreen) == B_OK)
|
||||
_SetFullScreen(fullscreen);
|
||||
break;
|
||||
}
|
||||
case BWIN_MINIMUM_SIZE_WINDOW:
|
||||
_SetMinimumSize(message);
|
||||
break;
|
||||
case BWIN_UPDATE_FRAMEBUFFER:
|
||||
{
|
||||
BMessage *pendingMessage;
|
||||
while ((pendingMessage = MessageQueue()->FindMessage(BWIN_UPDATE_FRAMEBUFFER, 0))) {
|
||||
MessageQueue()->RemoveMessage(pendingMessage);
|
||||
delete pendingMessage;
|
||||
}
|
||||
if (_bitmap != NULL) {
|
||||
#ifdef SDL_VIDEO_OPENGL
|
||||
if (_SDL_GLView != NULL && _cur_view == _SDL_GLView) {
|
||||
_SDL_GLView->CopyPixelsIn(_bitmap, B_ORIGIN);
|
||||
} else
|
||||
#endif
|
||||
if (_SDL_View != NULL && _cur_view == _SDL_View) {
|
||||
_SDL_View->Draw(Bounds());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Perform normal message handling
|
||||
BWindow::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Accessor methods
|
||||
bool IsShown() { return _shown; }
|
||||
int32 GetID() { return _id; }
|
||||
BBitmap *GetBitmap() { return _bitmap; }
|
||||
BView *GetCurView() { return _cur_view; }
|
||||
SDL_BView *GetView() { return _SDL_View; }
|
||||
#ifdef SDL_VIDEO_OPENGL
|
||||
BGLView *GetGLView()
|
||||
{
|
||||
return _SDL_GLView;
|
||||
}
|
||||
Uint32 GetGLType() { return _gl_type; }
|
||||
#endif
|
||||
|
||||
// Setter methods
|
||||
void SetID(int32 id) { _id = id; }
|
||||
void LockBuffer() { _buffer_locker->Lock(); }
|
||||
void UnlockBuffer() { _buffer_locker->Unlock(); }
|
||||
void SetBitmap(BBitmap *bitmap)
|
||||
{
|
||||
_bitmap = bitmap;
|
||||
if (_SDL_View != NULL)
|
||||
_SDL_View->SetBitmap(bitmap);
|
||||
}
|
||||
|
||||
private:
|
||||
// Event redirection
|
||||
void _MouseMotionEvent(BPoint &where, int32 transit)
|
||||
{
|
||||
if (transit == B_EXITED_VIEW) {
|
||||
// Change mouse focus
|
||||
if (_mouse_focused) {
|
||||
_MouseFocusEvent(false);
|
||||
}
|
||||
} else {
|
||||
// Change mouse focus
|
||||
if (!_mouse_focused) {
|
||||
_MouseFocusEvent(true);
|
||||
}
|
||||
BMessage msg(BAPP_MOUSE_MOVED);
|
||||
msg.AddInt32("x", (int)where.x);
|
||||
msg.AddInt32("y", (int)where.y);
|
||||
|
||||
_PostWindowEvent(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void _MouseFocusEvent(bool focusGained)
|
||||
{
|
||||
_mouse_focused = focusGained;
|
||||
BMessage msg(BAPP_MOUSE_FOCUS);
|
||||
msg.AddBool("focusGained", focusGained);
|
||||
_PostWindowEvent(msg);
|
||||
|
||||
/* FIXME: Why were these here?
|
||||
if false: be_app->SetCursor(B_HAND_CURSOR);
|
||||
if true: SDL_SetCursor(NULL); */
|
||||
}
|
||||
|
||||
void _MouseButtonEvent(int32 buttons, bool down)
|
||||
{
|
||||
int32 buttonStateChange = buttons ^ _last_buttons;
|
||||
|
||||
if (buttonStateChange & B_PRIMARY_MOUSE_BUTTON) {
|
||||
_SendMouseButton(SDL_BUTTON_LEFT, down);
|
||||
}
|
||||
if (buttonStateChange & B_SECONDARY_MOUSE_BUTTON) {
|
||||
_SendMouseButton(SDL_BUTTON_RIGHT, down);
|
||||
}
|
||||
if (buttonStateChange & B_TERTIARY_MOUSE_BUTTON) {
|
||||
_SendMouseButton(SDL_BUTTON_MIDDLE, down);
|
||||
}
|
||||
|
||||
_last_buttons = buttons;
|
||||
}
|
||||
|
||||
void _SendMouseButton(int32 button, bool down)
|
||||
{
|
||||
BMessage msg(BAPP_MOUSE_BUTTON);
|
||||
msg.AddInt32("button-id", button);
|
||||
msg.AddBool("button-down", down);
|
||||
_PostWindowEvent(msg);
|
||||
}
|
||||
|
||||
void _MouseWheelEvent(int32 x, int32 y)
|
||||
{
|
||||
// Create a message to pass along to the BeApp thread
|
||||
BMessage msg(BAPP_MOUSE_WHEEL);
|
||||
msg.AddInt32("xticks", x);
|
||||
msg.AddInt32("yticks", y);
|
||||
_PostWindowEvent(msg);
|
||||
}
|
||||
|
||||
void _KeyEvent(int32 keyCode, const int8 *keyUtf8, const ssize_t &len, bool down)
|
||||
{
|
||||
// Create a message to pass along to the BeApp thread
|
||||
BMessage msg(BAPP_KEY);
|
||||
msg.AddInt32("key-scancode", keyCode);
|
||||
if (keyUtf8 != NULL) {
|
||||
msg.AddData("key-utf8", B_INT8_TYPE, (const void *)keyUtf8, len);
|
||||
}
|
||||
msg.AddBool("key-down", down);
|
||||
SDL_Looper->PostMessage(&msg);
|
||||
}
|
||||
|
||||
void _RepaintEvent()
|
||||
{
|
||||
// Force a repaint: Call the SDL exposed event
|
||||
BMessage msg(BAPP_REPAINT);
|
||||
_PostWindowEvent(msg);
|
||||
}
|
||||
void _PostWindowEvent(BMessage &msg)
|
||||
{
|
||||
msg.AddInt32("window-id", _id);
|
||||
SDL_Looper->PostMessage(&msg);
|
||||
}
|
||||
|
||||
// Command methods (functions called upon by SDL)
|
||||
void _SetTitle(BMessage *msg)
|
||||
{
|
||||
const char *title;
|
||||
if (
|
||||
msg->FindString("window-title", &title) != B_OK) {
|
||||
return;
|
||||
}
|
||||
SetTitle(title);
|
||||
}
|
||||
|
||||
void _MoveTo(BMessage *msg)
|
||||
{
|
||||
int32 x, y;
|
||||
if (
|
||||
msg->FindInt32("window-x", &x) != B_OK ||
|
||||
msg->FindInt32("window-y", &y) != B_OK) {
|
||||
return;
|
||||
}
|
||||
if (_fullscreen)
|
||||
_non_fullscreen_frame.OffsetTo(x, y);
|
||||
else
|
||||
MoveTo(x, y);
|
||||
}
|
||||
|
||||
void _ResizeTo(BMessage *msg)
|
||||
{
|
||||
int32 w, h;
|
||||
if (
|
||||
msg->FindInt32("window-w", &w) != B_OK ||
|
||||
msg->FindInt32("window-h", &h) != B_OK) {
|
||||
return;
|
||||
}
|
||||
if (_fullscreen) {
|
||||
_non_fullscreen_frame.right = _non_fullscreen_frame.left + w;
|
||||
_non_fullscreen_frame.bottom = _non_fullscreen_frame.top + h;
|
||||
} else
|
||||
ResizeTo(w, h);
|
||||
}
|
||||
|
||||
void _SetBordered(bool bEnabled)
|
||||
{
|
||||
if (_fullscreen)
|
||||
_bordered = bEnabled;
|
||||
else
|
||||
SetLook(bEnabled ? B_TITLED_WINDOW_LOOK : B_NO_BORDER_WINDOW_LOOK);
|
||||
}
|
||||
|
||||
void _SetResizable(bool bEnabled)
|
||||
{
|
||||
if (_fullscreen)
|
||||
_resizable = bEnabled;
|
||||
else {
|
||||
if (bEnabled) {
|
||||
SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_ZOOMABLE));
|
||||
} else {
|
||||
SetFlags(Flags() | (B_NOT_RESIZABLE | B_NOT_ZOOMABLE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _SetMinimumSize(BMessage *msg)
|
||||
{
|
||||
float maxHeight;
|
||||
float maxWidth;
|
||||
float _;
|
||||
int32 minHeight;
|
||||
int32 minWidth;
|
||||
|
||||
// This is a bit convoluted, we only want to set the minimum not the maximum
|
||||
// But there is no direct call to do that, so store the maximum size beforehand
|
||||
GetSizeLimits(&_, &maxWidth, &_, &maxHeight);
|
||||
if (msg->FindInt32("window-w", &minWidth) != B_OK)
|
||||
return;
|
||||
if (msg->FindInt32("window-h", &minHeight) != B_OK)
|
||||
return;
|
||||
SetSizeLimits((float)minWidth, maxWidth, (float)minHeight, maxHeight);
|
||||
UpdateSizeLimits();
|
||||
}
|
||||
|
||||
void _Restore()
|
||||
{
|
||||
if (IsMinimized()) {
|
||||
Minimize(false);
|
||||
} else if (IsHidden()) {
|
||||
Show();
|
||||
} else if (_fullscreen) {
|
||||
|
||||
} else if (_prev_frame != NULL) { // Zoomed
|
||||
MoveTo(_prev_frame->left, _prev_frame->top);
|
||||
ResizeTo(_prev_frame->Width(), _prev_frame->Height());
|
||||
}
|
||||
}
|
||||
|
||||
void _SetFullScreen(bool fullscreen)
|
||||
{
|
||||
if (fullscreen != _fullscreen) {
|
||||
if (fullscreen) {
|
||||
BScreen screen(this);
|
||||
BRect screenFrame = screen.Frame();
|
||||
printf("screen frame: ");
|
||||
screenFrame.PrintToStream();
|
||||
printf("\n");
|
||||
_bordered = Look() != B_NO_BORDER_WINDOW_LOOK;
|
||||
_resizable = !(Flags() & B_NOT_RESIZABLE);
|
||||
_non_fullscreen_frame = Frame();
|
||||
_SetBordered(false);
|
||||
_SetResizable(false);
|
||||
MoveTo(screenFrame.left, screenFrame.top);
|
||||
ResizeTo(screenFrame.Width(), screenFrame.Height());
|
||||
_fullscreen = fullscreen;
|
||||
} else {
|
||||
_fullscreen = fullscreen;
|
||||
MoveTo(_non_fullscreen_frame.left, _non_fullscreen_frame.top);
|
||||
ResizeTo(_non_fullscreen_frame.Width(), _non_fullscreen_frame.Height());
|
||||
_SetBordered(_bordered);
|
||||
_SetResizable(_resizable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Members
|
||||
|
||||
BView *_cur_view;
|
||||
SDL_BView *_SDL_View;
|
||||
#ifdef SDL_VIDEO_OPENGL
|
||||
BGLView *_SDL_GLView;
|
||||
Uint32 _gl_type;
|
||||
#endif
|
||||
|
||||
int32 _last_buttons;
|
||||
int32 _id; // Window id used by SDL_BApp
|
||||
bool _mouse_focused; // Does this window have mouse focus?
|
||||
bool _shown;
|
||||
bool _inhibit_resize;
|
||||
|
||||
BRect *_prev_frame; // Previous position and size of the window
|
||||
bool _fullscreen;
|
||||
// valid only if fullscreen
|
||||
BRect _non_fullscreen_frame;
|
||||
bool _bordered;
|
||||
bool _resizable;
|
||||
|
||||
// Framebuffer members
|
||||
BLocker *_buffer_locker;
|
||||
BBitmap *_bitmap;
|
||||
};
|
||||
|
||||
/* FIXME:
|
||||
* An explanation of framebuffer flags.
|
||||
*
|
||||
* _connected - Original variable used to let the drawing thread know
|
||||
* when changes are being made to the other framebuffer
|
||||
* members.
|
||||
* _connection_disabled - Used to signal to the drawing thread that the window
|
||||
* is closing, and the thread should exit.
|
||||
* _buffer_created - True if the current buffer is valid
|
||||
* _buffer_dirty - True if the window should be redrawn.
|
||||
* _trash_window_buffer - True if the window buffer needs to be trashed partway
|
||||
* through a draw cycle. Occurs when the previous
|
||||
* buffer provided by DirectConnected() is invalidated.
|
||||
*/
|
||||
#endif // SDL_BWin_h_
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_BCLIPBOARD_H
|
||||
#define SDL_BCLIPBOARD_H
|
||||
|
||||
extern bool HAIKU_SetClipboardText(SDL_VideoDevice *_this, const char *text);
|
||||
extern char *HAIKU_GetClipboardText(SDL_VideoDevice *_this);
|
||||
extern bool HAIKU_HasClipboardText(SDL_VideoDevice *_this);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_BEVENTS_H
|
||||
#define SDL_BEVENTS_H
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void HAIKU_PumpEvents(SDL_VideoDevice *_this);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user