diff --git a/meson.build b/meson.build index 042742aa07..f07a4bd0bf 100644 --- a/meson.build +++ b/meson.build @@ -85,8 +85,7 @@ sdl_ttf = '@0@_ttf'.format(sdl) sdl_image = '@0@_image'.format(sdl) if sdl_api == 3 - add_global_arguments('-DPG_SDL3=1', language: 'c') - add_global_arguments('-DSDL_ENABLE_OLD_NAMES=1', language: 'c') + add_global_arguments('-DPG_SDL3=1', '-DSDL_ENABLE_OLD_NAMES=1', language: 'c') endif pg_inc_dirs = [] diff --git a/src_c/font.c b/src_c/font.c index 5817e896f6..cae985f1cc 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -1174,15 +1174,19 @@ font_init(PyFontObject *self, PyObject *args, PyObject *kwds) if (fontsize <= 1) fontsize = 1; - if (rw->size(rw) <= 0) { + if (SDL_RWsize(rw) <= 0) { PyErr_Format(PyExc_ValueError, "Font file object has an invalid file size: %lld", - rw->size(rw)); + SDL_RWsize(rw)); goto error; } Py_BEGIN_ALLOW_THREADS; +#if SDL_VERSION_ATLEAST(3, 0, 0) + font = TTF_OpenFontIO(rw, 1, fontsize); +#else font = TTF_OpenFontRW(rw, 1, fontsize); +#endif Py_END_ALLOW_THREADS; Py_DECREF(obj); diff --git a/src_c/imageext.c b/src_c/imageext.c index 0d68d59070..d2823fcb00 100644 --- a/src_c/imageext.c +++ b/src_c/imageext.c @@ -117,10 +117,18 @@ image_load_ext(PyObject *self, PyObject *arg, PyObject *kwarg) SDL_UnlockMutex(_pg_img_mutex); */ +#if SDL_VERSION_ATLEAST(3, 0, 0) + surf = IMG_LoadTyped_IO(rw, 1, type); +#else surf = IMG_LoadTyped_RW(rw, 1, type); +#endif Py_END_ALLOW_THREADS; -#else /* ~WITH_THREAD */ +#else /* ~WITH_THREAD */ +#if SDL_VERSION_ATLEAST(3, 0, 0) + surf = IMG_LoadTyped_IO(rw, 1, type); +#else surf = IMG_LoadTyped_RW(rw, 1, type); +#endif #endif /* ~WITH_THREAD */ if (ext) { @@ -166,7 +174,11 @@ imageext_load_sized_svg(PyObject *self, PyObject *arg, PyObject *kwargs) } Py_BEGIN_ALLOW_THREADS; +#if SDL_VERSION_ATLEAST(3, 0, 0) + surf = IMG_LoadSizedSVG_IO(rw, width, height); +#else surf = IMG_LoadSizedSVG_RW(rw, width, height); +#endif SDL_RWclose(rw); Py_END_ALLOW_THREADS; if (surf == NULL) { @@ -231,7 +243,11 @@ image_save_ext(PyObject *self, PyObject *arg, PyObject *kwarg) char *ext = iext_find_extension(name); if (!strcasecmp(ext, "jpeg") || !strcasecmp(ext, "jpg")) { if (rw != NULL) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + result = IMG_SaveJPG_IO(surf, rw, 0, JPEG_QUALITY); +#else result = IMG_SaveJPG_RW(surf, rw, 0, JPEG_QUALITY); +#endif } else { result = IMG_SaveJPG(surf, name, JPEG_QUALITY); @@ -240,7 +256,11 @@ image_save_ext(PyObject *self, PyObject *arg, PyObject *kwarg) else if (!strcasecmp(ext, "png")) { /*Py_BEGIN_ALLOW_THREADS; */ if (rw != NULL) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + result = IMG_SavePNG_IO(surf, rw, 0); +#else result = IMG_SavePNG_RW(surf, rw, 0); +#endif } else { result = IMG_SavePNG(surf, name); diff --git a/src_c/meson.build b/src_c/meson.build index 9804e7cdfe..f2eb2a02d1 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -93,8 +93,6 @@ rect = py.extension_module( subdir: pg, ) -# TODO: support SDL3 -if sdl_api != 3 rwobject = py.extension_module( 'rwobject', 'rwobject.c', @@ -103,7 +101,6 @@ rwobject = py.extension_module( install: true, subdir: pg, ) -endif # TODO: support SDL3 if sdl_api != 3 diff --git a/src_c/mixer.c b/src_c/mixer.c index 0d3fa8f393..f342e18216 100644 --- a/src_c/mixer.c +++ b/src_c/mixer.c @@ -1875,7 +1875,11 @@ sound_init(PyObject *self, PyObject *arg, PyObject *kwarg) return -1; } Py_BEGIN_ALLOW_THREADS; +#if SDL_VERSION_ATLEAST(3, 0, 0) + chunk = Mix_LoadWAV_IO(rw, 1); +#else chunk = Mix_LoadWAV_RW(rw, 1); +#endif Py_END_ALLOW_THREADS; if (chunk == NULL) { PyErr_SetString(pgExc_SDLError, SDL_GetError()); diff --git a/src_c/music.c b/src_c/music.c index b6b733f90c..71bc776fb2 100644 --- a/src_c/music.c +++ b/src_c/music.c @@ -388,7 +388,11 @@ _load_music(PyObject *obj, char *namehint) } Py_BEGIN_ALLOW_THREADS; +#if SDL_VERSION_ATLEAST(3, 0, 0) + new_music = Mix_LoadMUSType_IO(rw, _get_type_from_hint(type), SDL_TRUE); +#else new_music = Mix_LoadMUSType_RW(rw, _get_type_from_hint(type), SDL_TRUE); +#endif Py_END_ALLOW_THREADS; if (ext) { diff --git a/src_c/rwobject.c b/src_c/rwobject.c index a88c2495b2..172702ebb3 100644 --- a/src_c/rwobject.c +++ b/src_c/rwobject.c @@ -46,6 +46,18 @@ static const char pg_default_errors[] = "backslashreplace"; static PyObject *os_module = NULL; +#if SDL_VERSION_ATLEAST(3, 0, 0) +static Sint64 +_pg_rw_size(void *); +static Sint64 +_pg_rw_seek(void *, Sint64, SDL_IOWhence); +static size_t +_pg_rw_read(void *, void *, size_t, SDL_IOStatus *); +static size_t +_pg_rw_write(void *, const void *, size_t, SDL_IOStatus *); +static bool +_pg_rw_close(void *); +#else static Sint64 _pg_rw_size(SDL_RWops *); static Sint64 @@ -56,6 +68,7 @@ static size_t _pg_rw_write(SDL_RWops *, const void *, size_t, size_t); static int _pg_rw_close(SDL_RWops *); +#endif /* Converter function used by PyArg_ParseTupleAndKeywords with the "O&" format. * @@ -291,13 +304,31 @@ pg_EncodeFilePath(PyObject *obj, PyObject *eclass) static int pgRWops_IsFileObject(SDL_RWops *rw) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_PropertiesID props = SDL_GetIOProperties(rw); + if (!props) { + // pgRWops_IsFileObject doesn't have any error checking facility + // so when in doubt let's say it isn't a file object. + return 0; + } + return SDL_GetBooleanProperty(props, "_pygame_is_file_object", 0); +#else return rw->close == _pg_rw_close; +#endif } +#if SDL_VERSION_ATLEAST(3, 0, 0) +static Sint64 +_pg_rw_size(void *userdata) +{ + pgRWHelper *helper = (pgRWHelper *)userdata; +#else static Sint64 _pg_rw_size(SDL_RWops *context) { pgRWHelper *helper = (pgRWHelper *)context->hidden.unknown.data1; +#endif + PyObject *pos = NULL; PyObject *tmp = NULL; Sint64 size; @@ -361,10 +392,19 @@ _pg_rw_size(SDL_RWops *context) return retval; } +#if SDL_VERSION_ATLEAST(3, 0, 0) +static size_t +_pg_rw_write(void *userdata, const void *ptr, size_t size, + SDL_IOStatus *status) +{ + pgRWHelper *helper = (pgRWHelper *)userdata; + size_t num = 1; +#else static size_t _pg_rw_write(SDL_RWops *context, const void *ptr, size_t size, size_t num) { pgRWHelper *helper = (pgRWHelper *)context->hidden.unknown.data1; +#endif PyObject *result; size_t retval; @@ -382,26 +422,42 @@ _pg_rw_write(SDL_RWops *context, const void *ptr, size_t size, size_t num) } Py_DECREF(result); +#if SDL_VERSION_ATLEAST(3, 0, 0) + retval = size; +#else retval = num; +#endif end: PyGILState_Release(state); return retval; } +#if SDL_VERSION_ATLEAST(3, 0, 0) +static bool +_pg_rw_close(void *userdata) +{ + pgRWHelper *helper = (pgRWHelper *)userdata; + bool retval = true; +#else static int _pg_rw_close(SDL_RWops *context) { pgRWHelper *helper = (pgRWHelper *)context->hidden.unknown.data1; - PyObject *result; int retval = 0; +#endif + PyObject *result; PyGILState_STATE state = PyGILState_Ensure(); if (helper->close) { result = PyObject_CallNoArgs(helper->close); if (!result) { PyErr_Print(); +#if SDL_VERSION_ATLEAST(3, 0, 0) + retval = false; +#else retval = -1; +#endif } Py_XDECREF(result); } @@ -414,7 +470,9 @@ _pg_rw_close(SDL_RWops *context) PyMem_Free(helper); PyGILState_Release(state); +#if !SDL_VERSION_ATLEAST(3, 0, 0) SDL_FreeRW(context); +#endif return retval; } @@ -437,6 +495,37 @@ pgRWops_FromFileObject(PyObject *obj) return NULL; } +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_IOStreamInterface iface; + iface.size = _pg_rw_size; + iface.seek = _pg_rw_seek; + iface.read = _pg_rw_read; + iface.write = _pg_rw_write; + iface.close = _pg_rw_close; + + // TODO: These should raise SDLError probably? + // rwobject.c hasn't required pygame.base before (the source of SDLError) + // so omitting that for now. + + rw = SDL_OpenIO(&iface, helper); + if (rw == NULL) { + iface.close(helper); + PyMem_Free(helper); + return (SDL_RWops *)RAISE(PyExc_IOError, SDL_GetError()); + } + + SDL_PropertiesID props = SDL_GetIOProperties(rw); + if (!props) { + PyMem_Free(helper); + return (SDL_RWops *)RAISE(PyExc_IOError, SDL_GetError()); + } + + if (!SDL_SetBooleanProperty(props, "_pygame_is_file_object", 1)) { + PyMem_Free(helper); + return (SDL_RWops *)RAISE(PyExc_IOError, SDL_GetError()); + } + +#else rw = SDL_AllocRW(); if (rw == NULL) { PyMem_Free(helper); @@ -450,14 +539,22 @@ pgRWops_FromFileObject(PyObject *obj) rw->read = _pg_rw_read; rw->write = _pg_rw_write; rw->close = _pg_rw_close; +#endif return rw; } +#if SDL_VERSION_ATLEAST(3, 0, 0) +static Sint64 +_pg_rw_seek(void *userdata, Sint64 offset, SDL_IOWhence whence) +{ + pgRWHelper *helper = (pgRWHelper *)userdata; +#else static Sint64 _pg_rw_seek(SDL_RWops *context, Sint64 offset, int whence) { pgRWHelper *helper = (pgRWHelper *)context->hidden.unknown.data1; +#endif PyObject *result; Sint64 retval; @@ -498,10 +595,18 @@ _pg_rw_seek(SDL_RWops *context, Sint64 offset, int whence) return retval; } +#if SDL_VERSION_ATLEAST(3, 0, 0) +static size_t +_pg_rw_read(void *userdata, void *ptr, size_t size, SDL_IOStatus *status) +{ + pgRWHelper *helper = (pgRWHelper *)userdata; + size_t maxnum = 1; +#else static size_t _pg_rw_read(SDL_RWops *context, void *ptr, size_t size, size_t maxnum) { pgRWHelper *helper = (pgRWHelper *)context->hidden.unknown.data1; +#endif PyObject *result; Py_ssize_t retval; @@ -527,7 +632,9 @@ _pg_rw_read(SDL_RWops *context, void *ptr, size_t size, size_t maxnum) retval = PyBytes_GET_SIZE(result); if (retval) { memcpy(ptr, PyBytes_AsString(result), retval); +#if !SDL_VERSION_ATLEAST(3, 0, 0) retval /= size; +#endif } Py_DECREF(result); @@ -581,7 +688,11 @@ _rwops_from_pystr(PyObject *obj, char **extptr) /* If out of memory, decref oencoded to be safe, and try * to close out `rw` as well. */ Py_DECREF(oencoded); +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (!SDL_RWclose(rw)) { +#else if (SDL_RWclose(rw) < 0) { +#endif PyErr_SetString(PyExc_IOError, SDL_GetError()); } return (SDL_RWops *)PyErr_NoMemory();