From 5a8d38a4221ace8be48d0cad9def6d09226f06f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Tue, 28 Jan 2025 12:44:09 +0100 Subject: [PATCH 01/22] Add interface for _sdl2.video classes --- buildconfig/Setup.Android.SDL2.in | 3 + buildconfig/Setup.Emscripten.SDL2.in | 3 + buildconfig/Setup.SDL2.in | 3 + src_c/_pygame.h | 3 + src_c/include/_pygame.h | 61 ++++++++++++++++++++ src_c/renderer.c | 83 ++++++++++++++++++++++++++++ src_c/static.c | 15 +++++ src_c/texture.c | 83 ++++++++++++++++++++++++++++ src_c/video_image.c | 83 ++++++++++++++++++++++++++++ 9 files changed, 337 insertions(+) create mode 100644 src_c/renderer.c create mode 100644 src_c/texture.c create mode 100644 src_c/video_image.c diff --git a/buildconfig/Setup.Android.SDL2.in b/buildconfig/Setup.Android.SDL2.in index fc556ad024..f107f84b55 100644 --- a/buildconfig/Setup.Android.SDL2.in +++ b/buildconfig/Setup.Android.SDL2.in @@ -62,4 +62,7 @@ math src_c/math.c $(SDL) $(DEBUG) pixelcopy src_c/pixelcopy.c $(SDL) $(DEBUG) newbuffer src_c/newbuffer.c $(SDL) $(DEBUG) window src_c/window.c $(SDL) $(DEBUG) +_renderer src_c/renderer.c $(SDL) $(DEBUG) +_texture src_c/texture.c $(SDL) $(DEBUG) +_image src_c/video_image.c $(SDL) $(DEBUG) geometry src_c/geometry.c $(SDL) $(DEBUG) diff --git a/buildconfig/Setup.Emscripten.SDL2.in b/buildconfig/Setup.Emscripten.SDL2.in index 28e86f1e42..6bae799663 100644 --- a/buildconfig/Setup.Emscripten.SDL2.in +++ b/buildconfig/Setup.Emscripten.SDL2.in @@ -64,6 +64,9 @@ rect src_c/void.c rwobject src_c/void.c system src_c/void.c window src_c/void.c +_renderer src_c/void.c +_texture src_c/void.c +_image src_c/void.c geometry src_c/void.c #_sdl2.controller src_c/_sdl2/controller.c $(SDL) $(DEBUG) -Isrc_c diff --git a/buildconfig/Setup.SDL2.in b/buildconfig/Setup.SDL2.in index 011b8d1404..d7d2389802 100644 --- a/buildconfig/Setup.SDL2.in +++ b/buildconfig/Setup.SDL2.in @@ -75,3 +75,6 @@ newbuffer src_c/newbuffer.c $(SDL) $(DEBUG) system src_c/system.c $(SDL) $(DEBUG) geometry src_c/geometry.c $(SDL) $(DEBUG) window src_c/window.c $(SDL) $(DEBUG) +_renderer src_c/renderer.c $(SDL) $(DEBUG) +_texture src_c/texture.c $(SDL) $(DEBUG) +_image src_c/video_image.c $(SDL) $(DEBUG) diff --git a/src_c/_pygame.h b/src_c/_pygame.h index 77fcd2cb50..fb16708fc6 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -616,6 +616,9 @@ typedef enum { #define PYGAMEAPI_BASE_NUMSLOTS 30 #define PYGAMEAPI_EVENT_NUMSLOTS 10 #define PYGAMEAPI_WINDOW_NUMSLOTS 1 +#define PYGAMEAPI_RENDERER_NUMSLOTS 1 +#define PYGAMEAPI_TEXTURE_NUMSLOTS 1 +#define PYGAMEAPI_IMAGE_NUMSLOTS 1 #define PYGAMEAPI_GEOMETRY_NUMSLOTS 2 #endif /* _PYGAME_INTERNAL_H */ diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index 41c186eddb..880b8a4481 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -520,6 +520,61 @@ typedef struct { #define import_pygame_window() IMPORT_PYGAME_MODULE(window) #endif +typedef struct pgTextureObject pgTextureObject; + +/* + * Renderer module + */ +typedef struct { + PyObject_HEAD SDL_Renderer *renderer; + pgWindowObject *window; + pgTextureObject *target; + SDL_bool _is_borrowed; +} pgRendererObject; +#ifndef PYGAMEAPI_RENDERER_INTERNAL +#define pgRenderer_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_renderer, 0)) +#define pgRenderer_Check(x) \ + (PyObject_IsInstance((x), (PyObject *)&pgRenderer_Type)) +#define import_pygame_renderer() IMPORT_PYGAME_MODULE(_renderer) +#endif + +/* + * Texture module + */ +struct pgTextureObject { + PyObject_HEAD SDL_Texture *texture; + pgRendererObject *renderer; + int width; + int height; +}; +#ifndef PYGAMEAPI_TEXTURE_INTERNAL +#define pgTexture_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_texture, 0)) +#define pgTexture_Check(x) \ + (PyObject_IsInstance((x), (PyObject *)&pgTexture_Type)) +#define import_pygame_texture() IMPORT_PYGAME_MODULE(_texture) +#endif + +/* + * Image module + */ +typedef struct { + PyObject_HEAD pgTextureObject *texture; + pgRectObject *srcrect; + pgColorObject* color; + float angle; + float alpha; + SDL_Point origin; + SDL_bool flip_x; + SDL_bool flip_y; + SDL_BlendMode blend_mode; +} pgImageObject; +#ifndef PYGAMEAPI_IMAGE_INTERNAL +#define pgImage_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_image, 0)) +#define pgImage_Check(x) \ + (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) +#define import_pygame_image() IMPORT_PYGAME_MODULE(_image) +#endif + #define IMPORT_PYGAME_MODULE _IMPORT_PYGAME_MODULE /* @@ -539,6 +594,9 @@ PYGAMEAPI_DEFINE_SLOTS(pixelarray); PYGAMEAPI_DEFINE_SLOTS(color); PYGAMEAPI_DEFINE_SLOTS(math); PYGAMEAPI_DEFINE_SLOTS(window); +PYGAMEAPI_DEFINE_SLOTS(_renderer); +PYGAMEAPI_DEFINE_SLOTS(_texture); +PYGAMEAPI_DEFINE_SLOTS(_image); PYGAMEAPI_DEFINE_SLOTS(geometry); #else /* ~PYGAME_H */ PYGAMEAPI_EXTERN_SLOTS(base); @@ -553,6 +611,9 @@ PYGAMEAPI_EXTERN_SLOTS(pixelarray); PYGAMEAPI_EXTERN_SLOTS(color); PYGAMEAPI_EXTERN_SLOTS(math); PYGAMEAPI_EXTERN_SLOTS(window); +PYGAMEAPI_EXTERN_SLOTS(_renderer); +PYGAMEAPI_EXTERN_SLOTS(_texture); +PYGAMEAPI_EXTERN_SLOTS(_image); PYGAMEAPI_EXTERN_SLOTS(geometry); #endif /* ~PYGAME_H */ diff --git a/src_c/renderer.c b/src_c/renderer.c new file mode 100644 index 0000000000..0d6efd84a8 --- /dev/null +++ b/src_c/renderer.c @@ -0,0 +1,83 @@ +#define PYGAMEAPI_RENDERER_INTERNAL + +#include "pygame.h" + +#include "pgcompat.h" + +#include "doc/sdl2_video_doc.h" + +static PyTypeObject pgRenderer_Type; + +static PyMethodDef renderer_methods[] = { + {NULL, NULL, 0, NULL} +}; + +static PyGetSetDef renderer_getset[] = { + {NULL, 0, NULL, NULL, NULL} +}; + +static PyTypeObject pgRenderer_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Renderer", + .tp_basicsize = sizeof(pgRendererObject), + //.tp_dealloc = (destructor)renderer_dealloc, + .tp_doc = DOC_SDL2_VIDEO_RENDERER, + .tp_methods = renderer_methods, + //.tp_init = (initproc)renderer_init, + .tp_new = PyType_GenericNew, + .tp_getset = renderer_getset +}; + +static PyMethodDef _renderer_methods[] = { + {NULL, NULL, 0, NULL} +}; + +MODINIT_DEFINE(_renderer) +{ + PyObject *module, *apiobj; + static void *c_api[PYGAMEAPI_RENDERER_NUMSLOTS]; + + static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT, + "_renderer", + "docs_needed", + -1, + _renderer_methods, + NULL, + NULL, + NULL, + NULL}; + + /* imported needed apis; Do this first so if there is an error + the module is not loaded. + */ + import_pygame_base(); + if (PyErr_Occurred()) { + return NULL; + } + + if (PyType_Ready(&pgRenderer_Type) < 0) { + return NULL; + } + + /* create the module */ + module = PyModule_Create(&_module); + if (module == 0) { + return NULL; + } + + Py_INCREF(&pgRenderer_Type); + if (PyModule_AddObject(module, "Renderer", (PyObject *)&pgRenderer_Type)) { + Py_DECREF(&pgRenderer_Type); + Py_DECREF(module); + return NULL; + } + + c_api[0] = &pgRenderer_Type; + apiobj = encapsulate_api(c_api, "_renderer"); + if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { + Py_XDECREF(apiobj); + Py_DECREF(module); + return NULL; + } + + return module; +} diff --git a/src_c/static.c b/src_c/static.c index 97229dd633..697cf473f6 100644 --- a/src_c/static.c +++ b/src_c/static.c @@ -187,6 +187,15 @@ PyInit_pixelarray(void); PyMODINIT_FUNC PyInit_window(void); +PyMODINIT_FUNC +PyInit__renderer(void); + +PyMODINIT_FUNC +PyInit__image(void); + +PyMODINIT_FUNC +PyInit__texture(void); + // pygame_static module void @@ -320,6 +329,9 @@ PyInit_pygame_static() load_submodule("pygame.mixer", PyInit_mixer_music(), "music"); load_submodule("pygame", PyInit_window(), "window"); + load_submodule("pygame", PyInit__renderer(), "_renderer"); + load_submodule("pygame", PyInit__texture(), "_texture"); + load_submodule("pygame", PyInit__image(), "_image"); load_submodule("pygame", PyInit_pixelarray(), "pixelarray"); @@ -364,6 +376,9 @@ PyInit_pygame_static() #include "simd_blitters_sse2.c" #include "window.c" +#include "renderer.c" +#include "texture.c" +#include "video_image.c" #undef pgVidInfo_Type #undef pgVidInfo_New diff --git a/src_c/texture.c b/src_c/texture.c new file mode 100644 index 0000000000..4edba997ed --- /dev/null +++ b/src_c/texture.c @@ -0,0 +1,83 @@ +#define PYGAMEAPI_TEXTURE_INTERNAL + +#include "pygame.h" + +#include "pgcompat.h" + +#include "doc/sdl2_video_doc.h" + +static PyTypeObject pgTexture_Type; + +static PyMethodDef texture_methods[] = { + {NULL, NULL, 0, NULL} +}; + +static PyGetSetDef texture_getset[] = { + {NULL, 0, NULL, NULL, NULL} +}; + +static PyTypeObject pgTexture_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._texture.Texture", + .tp_basicsize = sizeof(pgTextureObject), + //.tp_dealloc = (destructor)texture_dealloc, + .tp_doc = DOC_SDL2_VIDEO_TEXTURE, + .tp_methods = texture_methods, + //.tp_init = (initproc)texture_init, + .tp_new = PyType_GenericNew, + .tp_getset = texture_getset +}; + +static PyMethodDef _texture_methods[] = { + {NULL, NULL, 0, NULL} +}; + +MODINIT_DEFINE(_texture) +{ + PyObject *module, *apiobj; + static void *c_api[PYGAMEAPI_TEXTURE_NUMSLOTS]; + + static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT, + "_texture", + "docs_needed", + -1, + _texture_methods, + NULL, + NULL, + NULL, + NULL}; + + /* imported needed apis; Do this first so if there is an error + the module is not loaded. + */ + import_pygame_base(); + if (PyErr_Occurred()) { + return NULL; + } + + if (PyType_Ready(&pgTexture_Type) < 0) { + return NULL; + } + + /* create the module */ + module = PyModule_Create(&_module); + if (module == 0) { + return NULL; + } + + Py_INCREF(&pgTexture_Type); + if (PyModule_AddObject(module, "Texture", (PyObject *)&pgTexture_Type)) { + Py_DECREF(&pgTexture_Type); + Py_DECREF(module); + return NULL; + } + + c_api[0] = &pgTexture_Type; + apiobj = encapsulate_api(c_api, "_texture"); + if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { + Py_XDECREF(apiobj); + Py_DECREF(module); + return NULL; + } + + return module; +} diff --git a/src_c/video_image.c b/src_c/video_image.c new file mode 100644 index 0000000000..69b7770989 --- /dev/null +++ b/src_c/video_image.c @@ -0,0 +1,83 @@ +#define PYGAMEAPI_IMAGE_INTERNAL + +#include "pygame.h" + +#include "pgcompat.h" + +#include "doc/sdl2_video_doc.h" + +static PyTypeObject pgImage_Type; + +static PyMethodDef image_methods[] = { + {NULL, NULL, 0, NULL} +}; + +static PyGetSetDef image_getset[] = { + {NULL, 0, NULL, NULL, NULL} +}; + +static PyTypeObject pgImage_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._image.Image", + .tp_basicsize = sizeof(pgImageObject), + //.tp_dealloc = (destructor)image_dealloc, + .tp_doc = DOC_SDL2_VIDEO_IMAGE, + .tp_methods = image_methods, + //.tp_init = (initproc)image_init, + .tp_new = PyType_GenericNew, + .tp_getset = image_getset +}; + +static PyMethodDef _image_methods[] = { + {NULL, NULL, 0, NULL} +}; + +MODINIT_DEFINE(_image) +{ + PyObject *module, *apiobj; + static void *c_api[PYGAMEAPI_IMAGE_NUMSLOTS]; + + static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT, + "_image", + "docs_needed", + -1, + _image_methods, + NULL, + NULL, + NULL, + NULL}; + + /* imported needed apis; Do this first so if there is an error + the module is not loaded. + */ + import_pygame_base(); + if (PyErr_Occurred()) { + return NULL; + } + + if (PyType_Ready(&pgImage_Type) < 0) { + return NULL; + } + + /* create the module */ + module = PyModule_Create(&_module); + if (module == 0) { + return NULL; + } + + Py_INCREF(&pgImage_Type); + if (PyModule_AddObject(module, "Image", (PyObject *)&pgImage_Type)) { + Py_DECREF(&pgImage_Type); + Py_DECREF(module); + return NULL; + } + + c_api[0] = &pgImage_Type; + apiobj = encapsulate_api(c_api, "_image"); + if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { + Py_XDECREF(apiobj); + Py_DECREF(module); + return NULL; + } + + return module; +} From 1d2b1861b01fa11799035538b51c719f6669f8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Tue, 28 Jan 2025 12:59:17 +0100 Subject: [PATCH 02/22] Add interface for _sdl2.video classes --- src_c/include/_pygame.h | 5 ++--- src_c/renderer.c | 19 +++++-------------- src_c/texture.c | 19 +++++-------------- src_c/video_image.c | 21 ++++++--------------- 4 files changed, 18 insertions(+), 46 deletions(-) diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index 880b8a4481..e278fbf072 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -560,7 +560,7 @@ struct pgTextureObject { typedef struct { PyObject_HEAD pgTextureObject *texture; pgRectObject *srcrect; - pgColorObject* color; + pgColorObject *color; float angle; float alpha; SDL_Point origin; @@ -570,8 +570,7 @@ typedef struct { } pgImageObject; #ifndef PYGAMEAPI_IMAGE_INTERNAL #define pgImage_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_image, 0)) -#define pgImage_Check(x) \ - (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) +#define pgImage_Check(x) (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) #define import_pygame_image() IMPORT_PYGAME_MODULE(_image) #endif diff --git a/src_c/renderer.c b/src_c/renderer.c index 0d6efd84a8..3b37f10c57 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -8,28 +8,19 @@ static PyTypeObject pgRenderer_Type; -static PyMethodDef renderer_methods[] = { - {NULL, NULL, 0, NULL} -}; +static PyMethodDef renderer_methods[] = {{NULL, NULL, 0, NULL}}; -static PyGetSetDef renderer_getset[] = { - {NULL, 0, NULL, NULL, NULL} -}; +static PyGetSetDef renderer_getset[] = {{NULL, 0, NULL, NULL, NULL}}; static PyTypeObject pgRenderer_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Renderer", .tp_basicsize = sizeof(pgRendererObject), //.tp_dealloc = (destructor)renderer_dealloc, - .tp_doc = DOC_SDL2_VIDEO_RENDERER, - .tp_methods = renderer_methods, + .tp_doc = DOC_SDL2_VIDEO_RENDERER, .tp_methods = renderer_methods, //.tp_init = (initproc)renderer_init, - .tp_new = PyType_GenericNew, - .tp_getset = renderer_getset -}; + .tp_new = PyType_GenericNew, .tp_getset = renderer_getset}; -static PyMethodDef _renderer_methods[] = { - {NULL, NULL, 0, NULL} -}; +static PyMethodDef _renderer_methods[] = {{NULL, NULL, 0, NULL}}; MODINIT_DEFINE(_renderer) { diff --git a/src_c/texture.c b/src_c/texture.c index 4edba997ed..add029f8b8 100644 --- a/src_c/texture.c +++ b/src_c/texture.c @@ -8,28 +8,19 @@ static PyTypeObject pgTexture_Type; -static PyMethodDef texture_methods[] = { - {NULL, NULL, 0, NULL} -}; +static PyMethodDef texture_methods[] = {{NULL, NULL, 0, NULL}}; -static PyGetSetDef texture_getset[] = { - {NULL, 0, NULL, NULL, NULL} -}; +static PyGetSetDef texture_getset[] = {{NULL, 0, NULL, NULL, NULL}}; static PyTypeObject pgTexture_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._texture.Texture", .tp_basicsize = sizeof(pgTextureObject), //.tp_dealloc = (destructor)texture_dealloc, - .tp_doc = DOC_SDL2_VIDEO_TEXTURE, - .tp_methods = texture_methods, + .tp_doc = DOC_SDL2_VIDEO_TEXTURE, .tp_methods = texture_methods, //.tp_init = (initproc)texture_init, - .tp_new = PyType_GenericNew, - .tp_getset = texture_getset -}; + .tp_new = PyType_GenericNew, .tp_getset = texture_getset}; -static PyMethodDef _texture_methods[] = { - {NULL, NULL, 0, NULL} -}; +static PyMethodDef _texture_methods[] = {{NULL, NULL, 0, NULL}}; MODINIT_DEFINE(_texture) { diff --git a/src_c/video_image.c b/src_c/video_image.c index 69b7770989..7763fe3c6a 100644 --- a/src_c/video_image.c +++ b/src_c/video_image.c @@ -8,28 +8,19 @@ static PyTypeObject pgImage_Type; -static PyMethodDef image_methods[] = { - {NULL, NULL, 0, NULL} -}; +static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; -static PyGetSetDef image_getset[] = { - {NULL, 0, NULL, NULL, NULL} -}; +static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; static PyTypeObject pgImage_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._image.Image", .tp_basicsize = sizeof(pgImageObject), //.tp_dealloc = (destructor)image_dealloc, - .tp_doc = DOC_SDL2_VIDEO_IMAGE, - .tp_methods = image_methods, + .tp_doc = DOC_SDL2_VIDEO_IMAGE, .tp_methods = image_methods, //.tp_init = (initproc)image_init, - .tp_new = PyType_GenericNew, - .tp_getset = image_getset -}; + .tp_new = PyType_GenericNew, .tp_getset = image_getset}; -static PyMethodDef _image_methods[] = { - {NULL, NULL, 0, NULL} -}; +static PyMethodDef _image_methods[] = {{NULL, NULL, 0, NULL}}; MODINIT_DEFINE(_image) { @@ -45,7 +36,7 @@ MODINIT_DEFINE(_image) NULL, NULL, NULL}; - + /* imported needed apis; Do this first so if there is an error the module is not loaded. */ From 789818485e2f37440a3771a3efb3c1053877315b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Tue, 28 Jan 2025 13:35:05 +0100 Subject: [PATCH 03/22] Add interface for _sdl2.video classes --- src_c/meson.build | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src_c/meson.build b/src_c/meson.build index d56d6b014d..117707d14a 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -316,6 +316,42 @@ window = py.extension_module( subdir: pg, ) +# TODO: support SDL3 +if sdl_api != 3 +_renderer = py.extension_module( + '_renderer', + 'renderer.c', + c_args: warnings_error, + dependencies: pg_base_deps, + install: true, + subdir: pg, +) +endif + +# TODO: support SDL3 +if sdl_api != 3 +_texture = py.extension_module( + '_texture', + 'texture.c', + c_args: warnings_error, + dependencies: pg_base_deps, + install: true, + subdir: pg, +) +endif + +# TODO: support SDL3 +if sdl_api != 3 +_image = py.extension_module( + '_image', + 'video_image.c', + c_args: warnings_error, + dependencies: pg_base_deps, + install: true, + subdir: pg, +) +endif + # TODO: support SDL3 if sdl_api != 3 gfxdraw = py.extension_module( From 3d2baa69ccc57cf70bf796ea27a12535b42f1c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Tue, 28 Jan 2025 15:12:54 +0100 Subject: [PATCH 04/22] Add interface for _sdl2.video classes --- src_c/static.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src_c/static.c b/src_c/static.c index 697cf473f6..5fe9c63d2e 100644 --- a/src_c/static.c +++ b/src_c/static.c @@ -8,6 +8,9 @@ #define PYGAMEAPI_BASE_INTERNAL #define PYGAMEAPI_SURFACE_INTERNAL #define PYGAMEAPI_WINDOW_INTERNAL +#define PYGAMEAPI_RENDERER_INTERNAL +#define PYGAMEAPI_TEXTURE_INTERNAL +#define PYGAMEAPI_IMAGE_INTERNAL #define pgSurface_New(surface) (pgSurfaceObject *)pgSurface_New2((surface), 1) #define pgSurface_NewNoOwn(surface) \ From a3cb1f9dcb463f8d11149286331257dd8e557329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Tue, 28 Jan 2025 15:36:39 +0100 Subject: [PATCH 05/22] Add interface for _sdl2.video classes --- src_c/video_image.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src_c/video_image.c b/src_c/video_image.c index 7763fe3c6a..a98f6e78cb 100644 --- a/src_c/video_image.c +++ b/src_c/video_image.c @@ -20,7 +20,7 @@ static PyTypeObject pgImage_Type = { //.tp_init = (initproc)image_init, .tp_new = PyType_GenericNew, .tp_getset = image_getset}; -static PyMethodDef _image_methods[] = {{NULL, NULL, 0, NULL}}; +static PyMethodDef video_image_methods[] = {{NULL, NULL, 0, NULL}}; MODINIT_DEFINE(_image) { @@ -31,7 +31,7 @@ MODINIT_DEFINE(_image) "_image", "docs_needed", -1, - _image_methods, + video_image_methods, NULL, NULL, NULL, From b15938eb8737df19b2af9a71f670ee31be172590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Wed, 29 Jan 2025 15:25:10 +0100 Subject: [PATCH 06/22] Add interface for _sdl2.video classes --- buildconfig/Setup.Android.SDL2.in | 2 - buildconfig/Setup.Emscripten.SDL2.in | 2 - buildconfig/Setup.SDL2.in | 2 - src_c/_pygame.h | 4 +- src_c/include/_pygame.h | 38 +++++--------- src_c/meson.build | 24 --------- src_c/renderer.c | 32 ++++++++++-- src_c/renderer_image.c | 24 +++++++++ src_c/static.c | 12 ----- src_c/texture.c | 68 ++++--------------------- src_c/video_image.c | 74 ---------------------------- 11 files changed, 73 insertions(+), 209 deletions(-) create mode 100644 src_c/renderer_image.c delete mode 100644 src_c/video_image.c diff --git a/buildconfig/Setup.Android.SDL2.in b/buildconfig/Setup.Android.SDL2.in index f107f84b55..b50f41cc5d 100644 --- a/buildconfig/Setup.Android.SDL2.in +++ b/buildconfig/Setup.Android.SDL2.in @@ -63,6 +63,4 @@ pixelcopy src_c/pixelcopy.c $(SDL) $(DEBUG) newbuffer src_c/newbuffer.c $(SDL) $(DEBUG) window src_c/window.c $(SDL) $(DEBUG) _renderer src_c/renderer.c $(SDL) $(DEBUG) -_texture src_c/texture.c $(SDL) $(DEBUG) -_image src_c/video_image.c $(SDL) $(DEBUG) geometry src_c/geometry.c $(SDL) $(DEBUG) diff --git a/buildconfig/Setup.Emscripten.SDL2.in b/buildconfig/Setup.Emscripten.SDL2.in index 6bae799663..33e25bbbb6 100644 --- a/buildconfig/Setup.Emscripten.SDL2.in +++ b/buildconfig/Setup.Emscripten.SDL2.in @@ -65,8 +65,6 @@ rwobject src_c/void.c system src_c/void.c window src_c/void.c _renderer src_c/void.c -_texture src_c/void.c -_image src_c/void.c geometry src_c/void.c #_sdl2.controller src_c/_sdl2/controller.c $(SDL) $(DEBUG) -Isrc_c diff --git a/buildconfig/Setup.SDL2.in b/buildconfig/Setup.SDL2.in index d7d2389802..d6e4e39eb7 100644 --- a/buildconfig/Setup.SDL2.in +++ b/buildconfig/Setup.SDL2.in @@ -76,5 +76,3 @@ system src_c/system.c $(SDL) $(DEBUG) geometry src_c/geometry.c $(SDL) $(DEBUG) window src_c/window.c $(SDL) $(DEBUG) _renderer src_c/renderer.c $(SDL) $(DEBUG) -_texture src_c/texture.c $(SDL) $(DEBUG) -_image src_c/video_image.c $(SDL) $(DEBUG) diff --git a/src_c/_pygame.h b/src_c/_pygame.h index fb16708fc6..c6ab80db0a 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -616,9 +616,7 @@ typedef enum { #define PYGAMEAPI_BASE_NUMSLOTS 30 #define PYGAMEAPI_EVENT_NUMSLOTS 10 #define PYGAMEAPI_WINDOW_NUMSLOTS 1 -#define PYGAMEAPI_RENDERER_NUMSLOTS 1 -#define PYGAMEAPI_TEXTURE_NUMSLOTS 1 -#define PYGAMEAPI_IMAGE_NUMSLOTS 1 +#define PYGAMEAPI_RENDERER_NUMSLOTS 3 #define PYGAMEAPI_GEOMETRY_NUMSLOTS 2 #endif /* _PYGAME_INTERNAL_H */ diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index e278fbf072..d7a6f292f9 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -531,32 +531,14 @@ typedef struct { pgTextureObject *target; SDL_bool _is_borrowed; } pgRendererObject; -#ifndef PYGAMEAPI_RENDERER_INTERNAL -#define pgRenderer_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_renderer, 0)) -#define pgRenderer_Check(x) \ - (PyObject_IsInstance((x), (PyObject *)&pgRenderer_Type)) -#define import_pygame_renderer() IMPORT_PYGAME_MODULE(_renderer) -#endif -/* - * Texture module - */ struct pgTextureObject { PyObject_HEAD SDL_Texture *texture; pgRendererObject *renderer; int width; int height; }; -#ifndef PYGAMEAPI_TEXTURE_INTERNAL -#define pgTexture_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_texture, 0)) -#define pgTexture_Check(x) \ - (PyObject_IsInstance((x), (PyObject *)&pgTexture_Type)) -#define import_pygame_texture() IMPORT_PYGAME_MODULE(_texture) -#endif -/* - * Image module - */ typedef struct { PyObject_HEAD pgTextureObject *texture; pgRectObject *srcrect; @@ -568,10 +550,18 @@ typedef struct { SDL_bool flip_y; SDL_BlendMode blend_mode; } pgImageObject; -#ifndef PYGAMEAPI_IMAGE_INTERNAL -#define pgImage_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_image, 0)) -#define pgImage_Check(x) (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) -#define import_pygame_image() IMPORT_PYGAME_MODULE(_image) + +#ifndef PYGAMEAPI_RENDERER_INTERNAL +#define pgRenderer_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_renderer, 0)) +#define pgTexture_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_renderer, 1)) +#define pgImage_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_renderer, 2)) +#define pgRenderer_Check(x) \ + (PyObject_IsInstance((x), (PyObject *)&pgRenderer_Type)) +#define pgTexture_Check(x) \ + (PyObject_IsInstance((x), (PyObject *)&pgTexture_Type)) +#define pgImage_Check(x) \ + (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) +#define import_pygame_renderer() IMPORT_PYGAME_MODULE(_renderer) #endif #define IMPORT_PYGAME_MODULE _IMPORT_PYGAME_MODULE @@ -594,8 +584,6 @@ PYGAMEAPI_DEFINE_SLOTS(color); PYGAMEAPI_DEFINE_SLOTS(math); PYGAMEAPI_DEFINE_SLOTS(window); PYGAMEAPI_DEFINE_SLOTS(_renderer); -PYGAMEAPI_DEFINE_SLOTS(_texture); -PYGAMEAPI_DEFINE_SLOTS(_image); PYGAMEAPI_DEFINE_SLOTS(geometry); #else /* ~PYGAME_H */ PYGAMEAPI_EXTERN_SLOTS(base); @@ -611,8 +599,6 @@ PYGAMEAPI_EXTERN_SLOTS(color); PYGAMEAPI_EXTERN_SLOTS(math); PYGAMEAPI_EXTERN_SLOTS(window); PYGAMEAPI_EXTERN_SLOTS(_renderer); -PYGAMEAPI_EXTERN_SLOTS(_texture); -PYGAMEAPI_EXTERN_SLOTS(_image); PYGAMEAPI_EXTERN_SLOTS(geometry); #endif /* ~PYGAME_H */ diff --git a/src_c/meson.build b/src_c/meson.build index 117707d14a..59a0320583 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -328,30 +328,6 @@ _renderer = py.extension_module( ) endif -# TODO: support SDL3 -if sdl_api != 3 -_texture = py.extension_module( - '_texture', - 'texture.c', - c_args: warnings_error, - dependencies: pg_base_deps, - install: true, - subdir: pg, -) -endif - -# TODO: support SDL3 -if sdl_api != 3 -_image = py.extension_module( - '_image', - 'video_image.c', - c_args: warnings_error, - dependencies: pg_base_deps, - install: true, - subdir: pg, -) -endif - # TODO: support SDL3 if sdl_api != 3 gfxdraw = py.extension_module( diff --git a/src_c/renderer.c b/src_c/renderer.c index 3b37f10c57..fc963e765b 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -6,6 +6,9 @@ #include "doc/sdl2_video_doc.h" +#include "texture.c" +#include "renderer_image.c" + static PyTypeObject pgRenderer_Type; static PyMethodDef renderer_methods[] = {{NULL, NULL, 0, NULL}}; @@ -14,11 +17,14 @@ static PyGetSetDef renderer_getset[] = {{NULL, 0, NULL, NULL, NULL}}; static PyTypeObject pgRenderer_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Renderer", - .tp_basicsize = sizeof(pgRendererObject), - //.tp_dealloc = (destructor)renderer_dealloc, - .tp_doc = DOC_SDL2_VIDEO_RENDERER, .tp_methods = renderer_methods, - //.tp_init = (initproc)renderer_init, - .tp_new = PyType_GenericNew, .tp_getset = renderer_getset}; + .tp_basicsize = sizeof(pgRendererObject), + //.tp_dealloc = (destructor)renderer_dealloc, + .tp_doc = DOC_SDL2_VIDEO_RENDERER, + .tp_methods = renderer_methods, + //.tp_init = (initproc)renderer_init, + .tp_new = PyType_GenericNew, + .tp_getset = renderer_getset +}; static PyMethodDef _renderer_methods[] = {{NULL, NULL, 0, NULL}}; @@ -62,7 +68,23 @@ MODINIT_DEFINE(_renderer) return NULL; } + Py_INCREF(&pgTexture_Type); + if (PyModule_AddObject(module, "Texture", (PyObject *)&pgTexture_Type)) { + Py_DECREF(&pgTexture_Type); + Py_DECREF(module); + return NULL; + } + + Py_INCREF(&pgImage_Type); + if (PyModule_AddObject(module, "Image", (PyObject *)&pgImage_Type)) { + Py_DECREF(&pgImage_Type); + Py_DECREF(module); + return NULL; + } + c_api[0] = &pgRenderer_Type; + c_api[1] = &pgTexture_Type; + c_api[2] = &pgImage_Type; apiobj = encapsulate_api(c_api, "_renderer"); if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { Py_XDECREF(apiobj); diff --git a/src_c/renderer_image.c b/src_c/renderer_image.c new file mode 100644 index 0000000000..15d2bbea46 --- /dev/null +++ b/src_c/renderer_image.c @@ -0,0 +1,24 @@ +#include "pygame.h" + +#include "pgcompat.h" + +#include "doc/sdl2_video_doc.h" + +static PyTypeObject pgImage_Type; + +static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; + +static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; + +static PyTypeObject pgImage_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Image", + .tp_basicsize = sizeof(pgImageObject), + //.tp_dealloc = (destructor)image_dealloc, + .tp_doc = DOC_SDL2_VIDEO_IMAGE, + .tp_methods = image_methods, + //.tp_init = (initproc)image_init, + .tp_new = PyType_GenericNew, + .tp_getset = image_getset +}; + +static PyMethodDef _image_methods[] = {{NULL, NULL, 0, NULL}}; diff --git a/src_c/static.c b/src_c/static.c index 5fe9c63d2e..50ce5315eb 100644 --- a/src_c/static.c +++ b/src_c/static.c @@ -9,8 +9,6 @@ #define PYGAMEAPI_SURFACE_INTERNAL #define PYGAMEAPI_WINDOW_INTERNAL #define PYGAMEAPI_RENDERER_INTERNAL -#define PYGAMEAPI_TEXTURE_INTERNAL -#define PYGAMEAPI_IMAGE_INTERNAL #define pgSurface_New(surface) (pgSurfaceObject *)pgSurface_New2((surface), 1) #define pgSurface_NewNoOwn(surface) \ @@ -193,12 +191,6 @@ PyInit_window(void); PyMODINIT_FUNC PyInit__renderer(void); -PyMODINIT_FUNC -PyInit__image(void); - -PyMODINIT_FUNC -PyInit__texture(void); - // pygame_static module void @@ -333,8 +325,6 @@ PyInit_pygame_static() load_submodule("pygame", PyInit_window(), "window"); load_submodule("pygame", PyInit__renderer(), "_renderer"); - load_submodule("pygame", PyInit__texture(), "_texture"); - load_submodule("pygame", PyInit__image(), "_image"); load_submodule("pygame", PyInit_pixelarray(), "pixelarray"); @@ -380,8 +370,6 @@ PyInit_pygame_static() #include "window.c" #include "renderer.c" -#include "texture.c" -#include "video_image.c" #undef pgVidInfo_Type #undef pgVidInfo_New diff --git a/src_c/texture.c b/src_c/texture.c index add029f8b8..48d1775497 100644 --- a/src_c/texture.c +++ b/src_c/texture.c @@ -1,5 +1,3 @@ -#define PYGAMEAPI_TEXTURE_INTERNAL - #include "pygame.h" #include "pgcompat.h" @@ -13,62 +11,14 @@ static PyMethodDef texture_methods[] = {{NULL, NULL, 0, NULL}}; static PyGetSetDef texture_getset[] = {{NULL, 0, NULL, NULL, NULL}}; static PyTypeObject pgTexture_Type = { - PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._texture.Texture", - .tp_basicsize = sizeof(pgTextureObject), - //.tp_dealloc = (destructor)texture_dealloc, - .tp_doc = DOC_SDL2_VIDEO_TEXTURE, .tp_methods = texture_methods, - //.tp_init = (initproc)texture_init, - .tp_new = PyType_GenericNew, .tp_getset = texture_getset}; + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Texture", + .tp_basicsize = sizeof(pgTextureObject), + //.tp_dealloc = (destructor)texture_dealloc, + .tp_doc = DOC_SDL2_VIDEO_TEXTURE, + .tp_methods = texture_methods, + //.tp_init = (initproc)texture_init, + .tp_new = PyType_GenericNew, + .tp_getset = texture_getset +}; static PyMethodDef _texture_methods[] = {{NULL, NULL, 0, NULL}}; - -MODINIT_DEFINE(_texture) -{ - PyObject *module, *apiobj; - static void *c_api[PYGAMEAPI_TEXTURE_NUMSLOTS]; - - static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT, - "_texture", - "docs_needed", - -1, - _texture_methods, - NULL, - NULL, - NULL, - NULL}; - - /* imported needed apis; Do this first so if there is an error - the module is not loaded. - */ - import_pygame_base(); - if (PyErr_Occurred()) { - return NULL; - } - - if (PyType_Ready(&pgTexture_Type) < 0) { - return NULL; - } - - /* create the module */ - module = PyModule_Create(&_module); - if (module == 0) { - return NULL; - } - - Py_INCREF(&pgTexture_Type); - if (PyModule_AddObject(module, "Texture", (PyObject *)&pgTexture_Type)) { - Py_DECREF(&pgTexture_Type); - Py_DECREF(module); - return NULL; - } - - c_api[0] = &pgTexture_Type; - apiobj = encapsulate_api(c_api, "_texture"); - if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { - Py_XDECREF(apiobj); - Py_DECREF(module); - return NULL; - } - - return module; -} diff --git a/src_c/video_image.c b/src_c/video_image.c deleted file mode 100644 index a98f6e78cb..0000000000 --- a/src_c/video_image.c +++ /dev/null @@ -1,74 +0,0 @@ -#define PYGAMEAPI_IMAGE_INTERNAL - -#include "pygame.h" - -#include "pgcompat.h" - -#include "doc/sdl2_video_doc.h" - -static PyTypeObject pgImage_Type; - -static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; - -static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; - -static PyTypeObject pgImage_Type = { - PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._image.Image", - .tp_basicsize = sizeof(pgImageObject), - //.tp_dealloc = (destructor)image_dealloc, - .tp_doc = DOC_SDL2_VIDEO_IMAGE, .tp_methods = image_methods, - //.tp_init = (initproc)image_init, - .tp_new = PyType_GenericNew, .tp_getset = image_getset}; - -static PyMethodDef video_image_methods[] = {{NULL, NULL, 0, NULL}}; - -MODINIT_DEFINE(_image) -{ - PyObject *module, *apiobj; - static void *c_api[PYGAMEAPI_IMAGE_NUMSLOTS]; - - static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT, - "_image", - "docs_needed", - -1, - video_image_methods, - NULL, - NULL, - NULL, - NULL}; - - /* imported needed apis; Do this first so if there is an error - the module is not loaded. - */ - import_pygame_base(); - if (PyErr_Occurred()) { - return NULL; - } - - if (PyType_Ready(&pgImage_Type) < 0) { - return NULL; - } - - /* create the module */ - module = PyModule_Create(&_module); - if (module == 0) { - return NULL; - } - - Py_INCREF(&pgImage_Type); - if (PyModule_AddObject(module, "Image", (PyObject *)&pgImage_Type)) { - Py_DECREF(&pgImage_Type); - Py_DECREF(module); - return NULL; - } - - c_api[0] = &pgImage_Type; - apiobj = encapsulate_api(c_api, "_image"); - if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { - Py_XDECREF(apiobj); - Py_DECREF(module); - return NULL; - } - - return module; -} From ef1c27d7be98b61729c0240916b0075d72781301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Wed, 29 Jan 2025 15:33:20 +0100 Subject: [PATCH 07/22] Add interface for _sdl2.video classes --- src_c/renderer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src_c/renderer.c b/src_c/renderer.c index fc963e765b..92c381d1ac 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -55,6 +55,14 @@ MODINIT_DEFINE(_renderer) return NULL; } + if (PyType_Ready(&pgTexture_Type) < 0) { + return NULL; + } + + if (PyType_Ready(&pgImage_Type) < 0) { + return NULL; + } + /* create the module */ module = PyModule_Create(&_module); if (module == 0) { From 363a1931695e9dee405e4e9b0042f88207f55179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Wed, 29 Jan 2025 15:38:01 +0100 Subject: [PATCH 08/22] Add interface for _sdl2.video classes --- src_c/include/_pygame.h | 3 +-- src_c/renderer.c | 13 +++++-------- src_c/renderer_image.c | 13 +++++-------- src_c/texture.c | 13 +++++-------- 4 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index d7a6f292f9..6858f270f7 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -559,8 +559,7 @@ typedef struct { (PyObject_IsInstance((x), (PyObject *)&pgRenderer_Type)) #define pgTexture_Check(x) \ (PyObject_IsInstance((x), (PyObject *)&pgTexture_Type)) -#define pgImage_Check(x) \ - (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) +#define pgImage_Check(x) (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) #define import_pygame_renderer() IMPORT_PYGAME_MODULE(_renderer) #endif diff --git a/src_c/renderer.c b/src_c/renderer.c index 92c381d1ac..0ea397427f 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -17,14 +17,11 @@ static PyGetSetDef renderer_getset[] = {{NULL, 0, NULL, NULL, NULL}}; static PyTypeObject pgRenderer_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Renderer", - .tp_basicsize = sizeof(pgRendererObject), - //.tp_dealloc = (destructor)renderer_dealloc, - .tp_doc = DOC_SDL2_VIDEO_RENDERER, - .tp_methods = renderer_methods, - //.tp_init = (initproc)renderer_init, - .tp_new = PyType_GenericNew, - .tp_getset = renderer_getset -}; + .tp_basicsize = sizeof(pgRendererObject), + //.tp_dealloc = (destructor)renderer_dealloc, + .tp_doc = DOC_SDL2_VIDEO_RENDERER, .tp_methods = renderer_methods, + //.tp_init = (initproc)renderer_init, + .tp_new = PyType_GenericNew, .tp_getset = renderer_getset}; static PyMethodDef _renderer_methods[] = {{NULL, NULL, 0, NULL}}; diff --git a/src_c/renderer_image.c b/src_c/renderer_image.c index 15d2bbea46..af2ac4ff7c 100644 --- a/src_c/renderer_image.c +++ b/src_c/renderer_image.c @@ -12,13 +12,10 @@ static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; static PyTypeObject pgImage_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Image", - .tp_basicsize = sizeof(pgImageObject), - //.tp_dealloc = (destructor)image_dealloc, - .tp_doc = DOC_SDL2_VIDEO_IMAGE, - .tp_methods = image_methods, - //.tp_init = (initproc)image_init, - .tp_new = PyType_GenericNew, - .tp_getset = image_getset -}; + .tp_basicsize = sizeof(pgImageObject), + //.tp_dealloc = (destructor)image_dealloc, + .tp_doc = DOC_SDL2_VIDEO_IMAGE, .tp_methods = image_methods, + //.tp_init = (initproc)image_init, + .tp_new = PyType_GenericNew, .tp_getset = image_getset}; static PyMethodDef _image_methods[] = {{NULL, NULL, 0, NULL}}; diff --git a/src_c/texture.c b/src_c/texture.c index 48d1775497..3ea5bc3d4b 100644 --- a/src_c/texture.c +++ b/src_c/texture.c @@ -12,13 +12,10 @@ static PyGetSetDef texture_getset[] = {{NULL, 0, NULL, NULL, NULL}}; static PyTypeObject pgTexture_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Texture", - .tp_basicsize = sizeof(pgTextureObject), - //.tp_dealloc = (destructor)texture_dealloc, - .tp_doc = DOC_SDL2_VIDEO_TEXTURE, - .tp_methods = texture_methods, - //.tp_init = (initproc)texture_init, - .tp_new = PyType_GenericNew, - .tp_getset = texture_getset -}; + .tp_basicsize = sizeof(pgTextureObject), + //.tp_dealloc = (destructor)texture_dealloc, + .tp_doc = DOC_SDL2_VIDEO_TEXTURE, .tp_methods = texture_methods, + //.tp_init = (initproc)texture_init, + .tp_new = PyType_GenericNew, .tp_getset = texture_getset}; static PyMethodDef _texture_methods[] = {{NULL, NULL, 0, NULL}}; From 363fa59ebcc87969fcc882391fbfe1e712b59490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Wed, 29 Jan 2025 15:43:45 +0100 Subject: [PATCH 09/22] Add interface for _sdl2.video classes --- src_c/renderer_image.c | 2 -- src_c/texture.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/src_c/renderer_image.c b/src_c/renderer_image.c index af2ac4ff7c..49831fec2a 100644 --- a/src_c/renderer_image.c +++ b/src_c/renderer_image.c @@ -17,5 +17,3 @@ static PyTypeObject pgImage_Type = { .tp_doc = DOC_SDL2_VIDEO_IMAGE, .tp_methods = image_methods, //.tp_init = (initproc)image_init, .tp_new = PyType_GenericNew, .tp_getset = image_getset}; - -static PyMethodDef _image_methods[] = {{NULL, NULL, 0, NULL}}; diff --git a/src_c/texture.c b/src_c/texture.c index 3ea5bc3d4b..a8a82c2cf3 100644 --- a/src_c/texture.c +++ b/src_c/texture.c @@ -17,5 +17,3 @@ static PyTypeObject pgTexture_Type = { .tp_doc = DOC_SDL2_VIDEO_TEXTURE, .tp_methods = texture_methods, //.tp_init = (initproc)texture_init, .tp_new = PyType_GenericNew, .tp_getset = texture_getset}; - -static PyMethodDef _texture_methods[] = {{NULL, NULL, 0, NULL}}; From afccd4b0e52f780068a0a16c36526aefc3514b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Mon, 3 Feb 2025 12:48:13 +0100 Subject: [PATCH 10/22] Add interface for _sdl2.video classes --- src_c/renderer.c | 31 ++++++++++++++++++++++++++++--- src_c/renderer_image.c | 19 ------------------- src_c/texture.c | 19 ------------------- 3 files changed, 28 insertions(+), 41 deletions(-) delete mode 100644 src_c/renderer_image.c delete mode 100644 src_c/texture.c diff --git a/src_c/renderer.c b/src_c/renderer.c index 0ea397427f..8b0c0072e0 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -6,15 +6,24 @@ #include "doc/sdl2_video_doc.h" -#include "texture.c" -#include "renderer_image.c" - static PyTypeObject pgRenderer_Type; +static PyTypeObject pgTexture_Type; + +static PyTypeObject pgImage_Type; + static PyMethodDef renderer_methods[] = {{NULL, NULL, 0, NULL}}; static PyGetSetDef renderer_getset[] = {{NULL, 0, NULL, NULL, NULL}}; +static PyMethodDef texture_methods[] = {{NULL, NULL, 0, NULL}}; + +static PyGetSetDef texture_getset[] = {{NULL, 0, NULL, NULL, NULL}}; + +static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; + +static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; + static PyTypeObject pgRenderer_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Renderer", .tp_basicsize = sizeof(pgRendererObject), @@ -23,6 +32,22 @@ static PyTypeObject pgRenderer_Type = { //.tp_init = (initproc)renderer_init, .tp_new = PyType_GenericNew, .tp_getset = renderer_getset}; +static PyTypeObject pgTexture_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Texture", + .tp_basicsize = sizeof(pgTextureObject), + //.tp_dealloc = (destructor)texture_dealloc, + .tp_doc = DOC_SDL2_VIDEO_TEXTURE, .tp_methods = texture_methods, + //.tp_init = (initproc)texture_init, + .tp_new = PyType_GenericNew, .tp_getset = texture_getset}; + +static PyTypeObject pgImage_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Image", + .tp_basicsize = sizeof(pgImageObject), + //.tp_dealloc = (destructor)image_dealloc, + .tp_doc = DOC_SDL2_VIDEO_IMAGE, .tp_methods = image_methods, + //.tp_init = (initproc)image_init, + .tp_new = PyType_GenericNew, .tp_getset = image_getset}; + static PyMethodDef _renderer_methods[] = {{NULL, NULL, 0, NULL}}; MODINIT_DEFINE(_renderer) diff --git a/src_c/renderer_image.c b/src_c/renderer_image.c deleted file mode 100644 index 49831fec2a..0000000000 --- a/src_c/renderer_image.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "pygame.h" - -#include "pgcompat.h" - -#include "doc/sdl2_video_doc.h" - -static PyTypeObject pgImage_Type; - -static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; - -static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; - -static PyTypeObject pgImage_Type = { - PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Image", - .tp_basicsize = sizeof(pgImageObject), - //.tp_dealloc = (destructor)image_dealloc, - .tp_doc = DOC_SDL2_VIDEO_IMAGE, .tp_methods = image_methods, - //.tp_init = (initproc)image_init, - .tp_new = PyType_GenericNew, .tp_getset = image_getset}; diff --git a/src_c/texture.c b/src_c/texture.c deleted file mode 100644 index a8a82c2cf3..0000000000 --- a/src_c/texture.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "pygame.h" - -#include "pgcompat.h" - -#include "doc/sdl2_video_doc.h" - -static PyTypeObject pgTexture_Type; - -static PyMethodDef texture_methods[] = {{NULL, NULL, 0, NULL}}; - -static PyGetSetDef texture_getset[] = {{NULL, 0, NULL, NULL, NULL}}; - -static PyTypeObject pgTexture_Type = { - PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Texture", - .tp_basicsize = sizeof(pgTextureObject), - //.tp_dealloc = (destructor)texture_dealloc, - .tp_doc = DOC_SDL2_VIDEO_TEXTURE, .tp_methods = texture_methods, - //.tp_init = (initproc)texture_init, - .tp_new = PyType_GenericNew, .tp_getset = texture_getset}; From c6ba34d2b7f2f949ac7f71e6027956268eea5d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Wed, 29 Jan 2025 15:49:01 +0100 Subject: [PATCH 11/22] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 813f3848e07d268892a4081a9939bb9ab0895a23 Author: Josip Komljenović Date: Wed Jan 29 15:43:45 2025 +0100 Add interface for _sdl2.video classes commit 702958c883149d4321fe96eab6de2ecbbae5cf31 Author: Josip Komljenović Date: Wed Jan 29 15:38:01 2025 +0100 Add interface for _sdl2.video classes commit 081b032255cbcc5ce32c39bebe0a5187765c5d04 Author: Josip Komljenović Date: Wed Jan 29 15:33:20 2025 +0100 Add interface for _sdl2.video classes commit c9ffd1c5517cdd61d3ac00f82d50930d7965cdb3 Author: Josip Komljenović Date: Wed Jan 29 15:25:10 2025 +0100 Add interface for _sdl2.video classes --- src_c/renderer.c | 3 +++ src_c/renderer_image.c | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src_c/renderer_image.c diff --git a/src_c/renderer.c b/src_c/renderer.c index 8b0c0072e0..00b0186e8a 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -6,6 +6,9 @@ #include "doc/sdl2_video_doc.h" +#include "texture.c" +#include "renderer_image.c" + static PyTypeObject pgRenderer_Type; static PyTypeObject pgTexture_Type; diff --git a/src_c/renderer_image.c b/src_c/renderer_image.c new file mode 100644 index 0000000000..49831fec2a --- /dev/null +++ b/src_c/renderer_image.c @@ -0,0 +1,19 @@ +#include "pygame.h" + +#include "pgcompat.h" + +#include "doc/sdl2_video_doc.h" + +static PyTypeObject pgImage_Type; + +static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; + +static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; + +static PyTypeObject pgImage_Type = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Image", + .tp_basicsize = sizeof(pgImageObject), + //.tp_dealloc = (destructor)image_dealloc, + .tp_doc = DOC_SDL2_VIDEO_IMAGE, .tp_methods = image_methods, + //.tp_init = (initproc)image_init, + .tp_new = PyType_GenericNew, .tp_getset = image_getset}; From 8bc95e5f10e54988416cdab5bd4756e8de2bcf0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Thu, 30 Jan 2025 14:57:14 +0100 Subject: [PATCH 12/22] Port Renderer to C code --- src_c/include/_pygame.h | 2 +- src_c/renderer.c | 715 +++++++++++++++++++++++++++++++++++++++- src_c/renderer_image.c | 8 + 3 files changed, 722 insertions(+), 3 deletions(-) diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index 6858f270f7..6e0fc30bde 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -561,7 +561,7 @@ typedef struct { (PyObject_IsInstance((x), (PyObject *)&pgTexture_Type)) #define pgImage_Check(x) (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) #define import_pygame_renderer() IMPORT_PYGAME_MODULE(_renderer) -#endif +#endif /* PYGAMEAPI_RENDERER_INTERNAL */ #define IMPORT_PYGAME_MODULE _IMPORT_PYGAME_MODULE diff --git a/src_c/renderer.c b/src_c/renderer.c index 00b0186e8a..362d1fe63e 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -15,9 +15,705 @@ static PyTypeObject pgTexture_Type; static PyTypeObject pgImage_Type; -static PyMethodDef renderer_methods[] = {{NULL, NULL, 0, NULL}}; +#define RENDERER_ERROR_CHECK(x) \ + if (x < 0) { \ + return RAISE(pgExc_SDLError, SDL_GetError()); \ + } + +#define RENDERER_PROPERTY_ERROR_CHECK(x) \ + if (x < 0) { \ + RAISE(pgExc_SDLError, SDL_GetError()); \ + return -1; \ + } + +static PyObject * +from_window(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +{ + PyObject *window; + static char *keywords[] = {"window", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &window)) { + return NULL; + } + if (pgWindow_Check(window)) { + pgRendererObject *self = + (pgRendererObject *)(cls->tp_new(cls, NULL, NULL)); + self->window = (pgWindowObject *)window; + if (self->window->_is_borrowed) { + self->_is_borrowed = SDL_TRUE; + } + else { + return RAISE(pgExc_SDLError, + "Window is not created from display module"); + } + self->renderer = SDL_GetRenderer(self->window->_win); + if (!self->renderer) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + self->target = NULL; + return (PyObject *)self; + } + else { + return RAISE(PyExc_TypeError, "Invalid window argument"); + } +} + +static PyObject * +renderer_draw_point(pgRendererObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *point; + float x, y; + static char *keywords[] = {"point", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &point)) { + return NULL; + } + if (!pg_TwoFloatsFromObj(point, &x, &y)) { + return RAISE(PyExc_TypeError, "invalid point"); + } + RENDERER_ERROR_CHECK(SDL_RenderDrawPointF(self->renderer, x, y)) + Py_RETURN_NONE; +} + +static PyObject * +renderer_draw_line(pgRendererObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *start, *end; + float startx, starty, endx, endy; + static char *keywords[] = {"p1", "p2", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", keywords, &start, + &end)) { + return NULL; + } + if (!pg_TwoFloatsFromObj(start, &startx, &starty)) { + return RAISE(PyExc_TypeError, "invalid p1 argument"); + } + if (!pg_TwoFloatsFromObj(end, &endx, &endy)) { + return RAISE(PyExc_TypeError, "invalid p2 argument"); + } + RENDERER_ERROR_CHECK( + SDL_RenderDrawLineF(self->renderer, startx, starty, endx, endy)) + Py_RETURN_NONE; +} + +static PyObject * +renderer_draw_rect(pgRendererObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *rectobj; + SDL_FRect *rect = NULL, temp; + static char *keywords[] = {"rect", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &rectobj)) { + return NULL; + } + if (!(rect = pgFRect_FromObject(rectobj, &temp))) { + return RAISE(PyExc_TypeError, "rect argument is invalid"); + } + RENDERER_ERROR_CHECK(SDL_RenderDrawRectF(self->renderer, rect)) + Py_RETURN_NONE; +} + +static PyObject * +renderer_fill_rect(pgRendererObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *rectobj; + SDL_FRect *rect = NULL, temp; + static char *keywords[] = {"rect", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &rectobj)) { + return NULL; + } + if (!(rect = pgFRect_FromObject(rectobj, &temp))) { + return RAISE(PyExc_TypeError, "rect argument is invalid"); + } + RENDERER_ERROR_CHECK(SDL_RenderFillRectF(self->renderer, rect)) + Py_RETURN_NONE; +} + +static PyObject * +renderer_draw_triangle(pgRendererObject *self, PyObject *args, + PyObject *kwargs) +{ + PyObject *p1, *p2, *p3; + float p1x, p1y, p2x, p2y, p3x, p3y; + SDL_FPoint points[4]; + static char *keywords[] = {"p1", "p2", "p3", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOO", keywords, &p1, &p2, + &p3)) { + return NULL; + } + if (!pg_TwoFloatsFromObj(p1, &p1x, &p1y)) { + return RAISE(PyExc_TypeError, "invalid p1 argument"); + } + if (!pg_TwoFloatsFromObj(p2, &p2x, &p2y)) { + return RAISE(PyExc_TypeError, "invalid p2 argument"); + } + if (!pg_TwoFloatsFromObj(p3, &p3x, &p3y)) { + return RAISE(PyExc_TypeError, "invalid p3 argument"); + } + points[0].x = p1x; + points[0].y = p1y; + points[1].x = p2x; + points[1].y = p2y; + points[2].x = p3x; + points[2].y = p3y; + points[3].x = p1x; + points[3].y = p1y; + RENDERER_ERROR_CHECK(SDL_RenderDrawLinesF(self->renderer, points, 4)) + Py_RETURN_NONE; +} + +static PyObject * +renderer_fill_triangle(pgRendererObject *self, PyObject *args, + PyObject *kwargs) +{ +#if SDL_VERSION_ATLEAST(2, 0, 18) + Uint8 rgba[4]; + PyObject *p1, *p2, *p3; + float p1x, p1y, p2x, p2y, p3x, p3y; + SDL_Vertex vertices[3]; + static char *keywords[] = {"p1", "p2", "p3", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOO", keywords, &p1, &p2, + &p3)) { + return NULL; + } + if (!pg_TwoFloatsFromObj(p1, &p1x, &p1y)) { + return RAISE(PyExc_TypeError, "invalid p1 argument"); + } + if (!pg_TwoFloatsFromObj(p2, &p2x, &p2y)) { + return RAISE(PyExc_TypeError, "invalid p2 argument"); + } + if (!pg_TwoFloatsFromObj(p3, &p3x, &p3y)) { + return RAISE(PyExc_TypeError, "invalid p3 argument"); + } + RENDERER_ERROR_CHECK(SDL_GetRenderDrawColor(self->renderer, &rgba[0], + &rgba[1], &rgba[2], &rgba[3])) + vertices[0].position.x = p1x; + vertices[0].position.y = p1y; + vertices[0].color.r = rgba[0]; + vertices[0].color.g = rgba[1]; + vertices[0].color.b = rgba[2]; + vertices[0].color.a = rgba[3]; + vertices[1].position.x = p2x; + vertices[1].position.y = p2y; + vertices[1].color.r = rgba[0]; + vertices[1].color.g = rgba[1]; + vertices[1].color.b = rgba[2]; + vertices[1].color.a = rgba[3]; + vertices[2].position.x = p3x; + vertices[2].position.y = p3y; + vertices[2].color.r = rgba[0]; + vertices[2].color.g = rgba[1]; + vertices[2].color.b = rgba[2]; + vertices[2].color.a = rgba[3]; + RENDERER_ERROR_CHECK( + SDL_RenderGeometry(self->renderer, NULL, vertices, 3, NULL, 0)) + Py_RETURN_NONE; +#else + RAISE(PyExc_TypeError, "fill_triangle() requires SDL 2.0.18 or newer"); + Py_RETURN_NONE; +#endif +} + +static PyObject * +renderer_draw_quad(pgRendererObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *p1, *p2, *p3, *p4; + float p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y; + SDL_FPoint points[5]; + static char *keywords[] = {"p1", "p2", "p3", "p4", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOOO", keywords, &p1, &p2, + &p3, &p4)) { + return NULL; + } + if (!pg_TwoFloatsFromObj(p1, &p1x, &p1y)) { + return RAISE(PyExc_TypeError, "invalid p1 argument"); + } + if (!pg_TwoFloatsFromObj(p2, &p2x, &p2y)) { + return RAISE(PyExc_TypeError, "invalid p2 argument"); + } + if (!pg_TwoFloatsFromObj(p3, &p3x, &p3y)) { + return RAISE(PyExc_TypeError, "invalid p3 argument"); + } + if (!pg_TwoFloatsFromObj(p4, &p4x, &p4y)) { + return RAISE(PyExc_TypeError, "invalid p4 argument"); + } + points[0].x = p1x; + points[0].y = p1y; + points[1].x = p2x; + points[1].y = p2y; + points[2].x = p3x; + points[2].y = p3y; + points[3].x = p4x; + points[3].y = p4y; + points[4].x = p1x; + points[4].y = p1y; + RENDERER_ERROR_CHECK(SDL_RenderDrawLinesF(self->renderer, points, 5)) + Py_RETURN_NONE; +} + +static PyObject * +renderer_fill_quad(pgRendererObject *self, PyObject *args, PyObject *kwargs) +{ +#if SDL_VERSION_ATLEAST(2, 0, 18) + Uint8 rgba[4]; + PyObject *p1, *p2, *p3, *p4; + float p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y; + SDL_Vertex vertices[6]; + static char *keywords[] = {"p1", "p2", "p3", "p4", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOOO", keywords, &p1, &p2, + &p3, &p4)) { + return NULL; + } + if (!pg_TwoFloatsFromObj(p1, &p1x, &p1y)) { + return RAISE(PyExc_TypeError, "invalid p1 argument"); + } + if (!pg_TwoFloatsFromObj(p2, &p2x, &p2y)) { + return RAISE(PyExc_TypeError, "invalid p2 argument"); + } + if (!pg_TwoFloatsFromObj(p3, &p3x, &p3y)) { + return RAISE(PyExc_TypeError, "invalid p3 argument"); + } + if (!pg_TwoFloatsFromObj(p4, &p4x, &p4y)) { + return RAISE(PyExc_TypeError, "invalid p4 argument"); + } + RENDERER_ERROR_CHECK(SDL_GetRenderDrawColor(self->renderer, &rgba[0], + &rgba[1], &rgba[2], &rgba[3])) + vertices[0].position.x = p1x; + vertices[0].position.y = p1y; + vertices[0].color.r = rgba[0]; + vertices[0].color.g = rgba[1]; + vertices[0].color.b = rgba[2]; + vertices[0].color.a = rgba[3]; + vertices[1].position.x = p2x; + vertices[1].position.y = p2y; + vertices[1].color.r = rgba[0]; + vertices[1].color.g = rgba[1]; + vertices[1].color.b = rgba[2]; + vertices[1].color.a = rgba[3]; + vertices[2].position.x = p3x; + vertices[2].position.y = p3y; + vertices[2].color.r = rgba[0]; + vertices[2].color.g = rgba[1]; + vertices[2].color.b = rgba[2]; + vertices[2].color.a = rgba[3]; + vertices[3].position.x = p3x; + vertices[3].position.y = p3y; + vertices[3].color.r = rgba[0]; + vertices[3].color.g = rgba[1]; + vertices[3].color.b = rgba[2]; + vertices[3].color.a = rgba[3]; + vertices[4].position.x = p4x; + vertices[4].position.y = p4y; + vertices[4].color.r = rgba[0]; + vertices[4].color.g = rgba[1]; + vertices[4].color.b = rgba[2]; + vertices[4].color.a = rgba[3]; + vertices[5].position.x = p1x; + vertices[5].position.y = p1y; + vertices[5].color.r = rgba[0]; + vertices[5].color.g = rgba[1]; + vertices[5].color.b = rgba[2]; + vertices[5].color.a = rgba[3]; + RENDERER_ERROR_CHECK( + SDL_RenderGeometry(self->renderer, NULL, vertices, 6, NULL, 0)) + Py_RETURN_NONE; +#else + RAISE(PyExc_TypeError, "fill_quad() requires SDL 2.0.18 or newer"); + Py_RETURN_NONE; +#endif +} + +static PyObject * +renderer_present(pgRendererObject *self, PyObject *_null) +{ + SDL_RenderPresent(self->renderer); + Py_RETURN_NONE; +} + +static PyObject * +renderer_clear(pgRendererObject *self, PyObject *_null) +{ + RENDERER_ERROR_CHECK(SDL_RenderClear(self->renderer)) + Py_RETURN_NONE; +} + +static PyObject * +renderer_get_viewport(pgRendererObject *self, PyObject *_null) +{ + SDL_Rect rect; + SDL_RenderGetViewport(self->renderer, &rect); + return pgRect_New(&rect); +} -static PyGetSetDef renderer_getset[] = {{NULL, 0, NULL, NULL, NULL}}; +static PyObject * +renderer_set_viewport(pgRendererObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *rectobj = Py_None; + SDL_Rect rect; + static char *keywords[] = {"area", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", keywords, &rectobj)) { + return NULL; + } + if (rectobj == Py_None) { + RENDERER_ERROR_CHECK(SDL_RenderSetViewport(self->renderer, NULL)) + } + else { + rect = pgRect_AsRect(rectobj); + RENDERER_ERROR_CHECK(SDL_RenderSetViewport(self->renderer, &rect)) + } + Py_RETURN_NONE; +} + +static PyObject * +compose_custom_blend_mode(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *color_mode, *alpha_mode; + float mode[6]; + int blend_mode; + static char *keywords[] = {"color_mode", "alpha_mode", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", keywords, &color_mode, + &alpha_mode)) { + return NULL; + } + if (!PySequence_Check(color_mode)) + return RAISE(PyExc_TypeError, "color_mode has to be sequence"); + if (!PySequence_Check(alpha_mode)) + return RAISE(PyExc_TypeError, "alpha_mode has to be sequence"); + if (PySequence_Size(color_mode) != 3) + return RAISE(PyExc_TypeError, "color_mode has to have 3 elements"); + if (PySequence_Size(alpha_mode) != 3) + return RAISE(PyExc_TypeError, "alpha_mode has to have 3 elements"); + if (!pg_FloatFromObjIndex(color_mode, 0, &mode[0])) + return RAISE(PyExc_TypeError, + "color_mode first element must be float"); + if (!pg_FloatFromObjIndex(color_mode, 1, &mode[1])) + return RAISE(PyExc_TypeError, + "color_mode second element must be float"); + if (!pg_FloatFromObjIndex(color_mode, 2, &mode[2])) + return RAISE(PyExc_TypeError, + "color_mode third element must be float"); + if (!pg_FloatFromObjIndex(alpha_mode, 0, &mode[3])) + return RAISE(PyExc_TypeError, + "alpha_mode first element must be float"); + if (!pg_FloatFromObjIndex(alpha_mode, 1, &mode[4])) + return RAISE(PyExc_TypeError, + "alpha_mode second element must be float"); + if (!pg_FloatFromObjIndex(alpha_mode, 2, &mode[5])) + return RAISE(PyExc_TypeError, + "alpha_mode third element must be float"); + blend_mode = SDL_ComposeCustomBlendMode(mode[0], mode[1], mode[2], mode[3], + mode[4], mode[5]); + return PyLong_FromLong((long)blend_mode); +} + +static PyObject * +renderer_to_surface(pgRendererObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *surfobj = Py_None, *rectobj = Py_None; + SDL_Surface *surf; + pgSurfaceObject *surface; + SDL_Rect viewport, *areaparam, rarea; + Uint32 format; + static char *keywords[] = {"surface", "area", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", keywords, &surfobj, + &rectobj)) { + return NULL; + } + if (!Py_IsNone(rectobj)) { + if (!pgRect_FromObject(rectobj, &rarea)) { + return RAISE(PyExc_TypeError, "area must be None or a rect"); + } + SDL_RenderGetViewport(self->renderer, &viewport); + SDL_IntersectRect(&rarea, &viewport, &rarea); + areaparam = &rarea; + } + else { + SDL_RenderGetViewport(self->renderer, &rarea); + areaparam = NULL; + } + if (!Py_IsNone(surfobj)) { + if (!(pgSurface_Check(surfobj))) { + return RAISE(PyExc_TypeError, "surface must be None or a Surface"); + } + surface = (pgSurfaceObject *)surfobj; + Py_INCREF(surface); + surf = pgSurface_AsSurface(surfobj); + if (surf->w < rarea.w || surf->h < rarea.h) { + return RAISE(PyExc_ValueError, "the surface is too small"); + } + format = surf->format->format; + } + else { + format = SDL_GetWindowPixelFormat(self->window->_win); + if (format == SDL_PIXELFORMAT_UNKNOWN) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + surf = SDL_CreateRGBSurfaceWithFormat( + 0, rarea.w, rarea.h, SDL_BITSPERPIXEL(format), format); + if (surf == NULL) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + surface = pgSurface_New(surf); + } + RENDERER_ERROR_CHECK(SDL_RenderReadPixels( + self->renderer, areaparam, format, surf->pixels, surf->pitch)); + return (PyObject *)surface; +} + +// TODO MightyJosip For blit need Texture/Image +static PyObject * +renderer_blit(pgRendererObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *sourceobj, *destobj = Py_None, *areaobj = Py_None; + int special_flags = 0; + static char *keywords[] = {"source", "dest", "area", "special_flags", + NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOi", keywords, + &sourceobj, &destobj, &areaobj, + &special_flags)) { + return NULL; + } + + if (pgTexture_Check(sourceobj)) { + texture_renderer_draw((pgTextureObject *)sourceobj, areaobj, destobj); + } + else if (pgImage_Check(sourceobj)) { + image_renderer_draw((pgImageObject *)sourceobj, areaobj, destobj); + } + else if (PyObject_HasAttrString(sourceobj, "draw")) { + PyObject *draw_method = PyObject_GetAttrString(sourceobj, "draw"); + if (draw_method && PyCallable_Check(draw_method)) { + PyObject_CallMethodObjArgs(sourceobj, PyUnicode_FromString("draw"), + areaobj, destobj, NULL); + Py_DECREF(draw_method); + } + else { + return RAISE(PyExc_AttributeError, "source.draw is not callable"); + } + } + else { + return RAISE(PyExc_AttributeError, + "source object doesn't have draw method"); + } + + if (Py_IsNone(destobj)) { + return renderer_get_viewport(self, NULL); + } + Py_INCREF(destobj); + return destobj; +} + +static PyObject * +renderer_get_draw_color(pgRendererObject *self, void *closure) +{ + Uint8 rgba[4]; + RENDERER_ERROR_CHECK(SDL_GetRenderDrawColor(self->renderer, &rgba[0], + &rgba[1], &rgba[2], &rgba[3])) + return pgColor_NewLength(rgba, 4); +} + +static int +renderer_set_draw_color(pgRendererObject *self, PyObject *arg, void *closure) +{ + Uint8 color[4]; + if (!pg_RGBAFromObjEx(arg, color, PG_COLOR_HANDLE_ALL)) { + return -1; + } + RENDERER_PROPERTY_ERROR_CHECK(SDL_SetRenderDrawColor( + self->renderer, color[0], color[1], color[2], color[3])) + return 0; +} + +static PyObject * +renderer_get_draw_blend_mode(pgRendererObject *self, void *closure) +{ + SDL_BlendMode blend_mode; + RENDERER_ERROR_CHECK( + SDL_GetRenderDrawBlendMode(self->renderer, &blend_mode)) + return PyLong_FromLong((long)blend_mode); +} + +static int +renderer_set_draw_blend_mode(pgRendererObject *self, PyObject *arg, + void *closure) +{ + if (!PyLong_Check(arg)) { + RAISE(PyExc_TypeError, "Draw blend mode must be int"); + return -1; + } + RENDERER_PROPERTY_ERROR_CHECK( + SDL_SetRenderDrawBlendMode(self->renderer, (int)PyLong_AsLong(arg))) + return 0; +} + +static PyObject * +renderer_get_logical_size(pgRendererObject *self, void *closure) +{ + int w, h; + SDL_RenderGetLogicalSize(self->renderer, &w, &h); + return pg_tuple_couple_from_values_int(w, h); +} + +static int +renderer_set_logical_size(pgRendererObject *self, PyObject *arg, void *closure) +{ + int w, h; + if (!pg_TwoIntsFromObj(arg, &w, &h)) { + RAISE(PyExc_TypeError, "invalid logical size"); + return -1; + } + RENDERER_PROPERTY_ERROR_CHECK( + SDL_RenderSetLogicalSize(self->renderer, w, h)) + return 0; +} + +static PyObject * +renderer_get_scale(pgRendererObject *self, void *closure) +{ + float x, y; + SDL_RenderGetScale(self->renderer, &x, &y); + return pg_tuple_couple_from_values_double(x, y); +} + +static int +renderer_set_scale(pgRendererObject *self, PyObject *arg, void *closure) +{ + float x, y; + if (!pg_TwoFloatsFromObj(arg, &x, &y)) { + RAISE(PyExc_TypeError, "invalid scale"); + return -1; + } + RENDERER_PROPERTY_ERROR_CHECK(SDL_RenderSetScale(self->renderer, x, y)) + return 0; +} + +static PyObject * +renderer_get_target(pgRendererObject *self, void *closure) +{ + if (self->target == NULL) { + Py_RETURN_NONE; + } + return (PyObject *)self->target; +} + +static int +renderer_set_target(pgRendererObject *self, PyObject *arg, void *closure) +{ + if (Py_IsNone(arg)) { + self->target = NULL; + RENDERER_PROPERTY_ERROR_CHECK( + SDL_SetRenderTarget(self->renderer, NULL)) + return 0; + } + else if (pgTexture_Check(arg)) { + self->target = (pgTextureObject *)arg; + RENDERER_PROPERTY_ERROR_CHECK( + SDL_SetRenderTarget(self->renderer, self->target->texture)) + return 0; + } + else { + RAISE(PyExc_TypeError, "target must be Texture object or None"); + return -1; + } +} + +static int +renderer_init(pgRendererObject *self, PyObject *args, PyObject *kwargs) +{ + SDL_Renderer *renderer = NULL; + pgWindowObject *window; + int index = -1; + int accelerated = -1; + int vsync = 0; + int target_texture = 0; + Uint32 flags = 0; + + char *keywords[] = {"window", "index", "accelerated", + "vsync", "target_texture", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iipp", keywords, &window, + &index, &accelerated, &vsync, + &target_texture)) { + return -1; + } + if (accelerated >= 0) { + flags |= + accelerated ? SDL_RENDERER_ACCELERATED : SDL_RENDERER_SOFTWARE; + } + if (vsync) { + flags |= SDL_RENDERER_PRESENTVSYNC; + } + if (target_texture) { + flags |= SDL_RENDERER_TARGETTEXTURE; + } + renderer = SDL_CreateRenderer(window->_win, index, flags); + if (!renderer) { + PyErr_SetString(pgExc_SDLError, SDL_GetError()); + return -1; + } + self->renderer = renderer; + self->window = window; + self->target = NULL; + self->_is_borrowed = SDL_FALSE; + return 0; +} + +static void +renderer_dealloc(pgRendererObject *self, PyObject *_null) +{ + if (!self->_is_borrowed && self->renderer) { + SDL_DestroyRenderer(self->renderer); + } + Py_TYPE(self)->tp_free(self); +} + +static PyMethodDef renderer_methods[] = { + {"draw_point", (PyCFunction)renderer_draw_point, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_DRAWPOINT}, + {"draw_line", (PyCFunction)renderer_draw_line, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_DRAWLINE}, + {"draw_rect", (PyCFunction)renderer_draw_rect, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_DRAWRECT}, + {"draw_triangle", (PyCFunction)renderer_draw_triangle, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_DRAWTRIANGLE}, + {"draw_quad", (PyCFunction)renderer_draw_quad, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_DRAWQUAD}, + {"fill_rect", (PyCFunction)renderer_fill_rect, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_FILLRECT}, + {"fill_triangle", (PyCFunction)renderer_fill_triangle, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_FILLTRIANGLE}, + {"fill_quad", (PyCFunction)renderer_fill_quad, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_FILLQUAD}, + {"present", (PyCFunction)renderer_present, METH_NOARGS, + DOC_SDL2_VIDEO_RENDERER_PRESENT}, + {"clear", (PyCFunction)renderer_clear, METH_NOARGS, + DOC_SDL2_VIDEO_RENDERER_CLEAR}, + {"set_viewport", (PyCFunction)renderer_set_viewport, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_SETVIEWPORT}, + {"get_viewport", (PyCFunction)renderer_get_viewport, METH_NOARGS, + DOC_SDL2_VIDEO_RENDERER_GETVIEWPORT}, + {"compose_custom_blend_mode", (PyCFunction)compose_custom_blend_mode, + METH_VARARGS | METH_KEYWORDS | METH_CLASS, + DOC_SDL2_VIDEO_RENDERER_COMPOSECUSTOMBLENDMODE}, + {"from_window", (PyCFunction)from_window, + METH_CLASS | METH_VARARGS | METH_KEYWORDS, + DOC_SDL2_VIDEO_GETGRABBEDWINDOW}, + {"to_surface", (PyCFunction)renderer_to_surface, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_TOSURFACE}, + {"blit", (PyCFunction)renderer_blit, METH_VARARGS | METH_KEYWORDS, + DOC_SDL2_VIDEO_RENDERER_SETVIEWPORT}, + {NULL, NULL, 0, NULL}}; + +static PyGetSetDef renderer_getset[] = { + {"draw_color", (getter)renderer_get_draw_color, + (setter)renderer_set_draw_color, DOC_SDL2_VIDEO_RENDERER_DRAWCOLOR, NULL}, + {"draw_blend_mode", (getter)renderer_get_draw_blend_mode, + (setter)renderer_set_draw_blend_mode, DOC_SDL2_VIDEO_RENDERER_DRAWCOLOR, + NULL}, + {"logical_size", (getter)renderer_get_logical_size, + (setter)renderer_set_logical_size, DOC_SDL2_VIDEO_RENDERER_LOGICALSIZE, + NULL}, + {"scale", (getter)renderer_get_scale, (setter)renderer_set_scale, + DOC_SDL2_VIDEO_RENDERER_SCALE, NULL}, + {"target", (getter)renderer_get_target, (setter)renderer_set_target, + DOC_SDL2_VIDEO_RENDERER_TARGET, NULL}, + {NULL, 0, NULL, NULL, NULL}}; static PyMethodDef texture_methods[] = {{NULL, NULL, 0, NULL}}; @@ -76,6 +772,21 @@ MODINIT_DEFINE(_renderer) return NULL; } + import_pygame_surface(); + if (PyErr_Occurred()) { + return NULL; + } + + import_pygame_rect(); + if (PyErr_Occurred()) { + return NULL; + } + + import_pygame_color(); + if (PyErr_Occurred()) { + return NULL; + } + if (PyType_Ready(&pgRenderer_Type) < 0) { return NULL; } diff --git a/src_c/renderer_image.c b/src_c/renderer_image.c index 49831fec2a..d9a6dc0b4c 100644 --- a/src_c/renderer_image.c +++ b/src_c/renderer_image.c @@ -4,6 +4,14 @@ #include "doc/sdl2_video_doc.h" +#define pgImage_Check(x) (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) + +static void +image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) +{ + ; // TODO MightyJosip Implement with Image class +} + static PyTypeObject pgImage_Type; static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; From 9710ba9c98ff8e370ee9f03ab4b4dc86a671bb76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Mon, 3 Feb 2025 13:28:01 +0100 Subject: [PATCH 13/22] Port Renderer to C code --- src_c/renderer.c | 44 +++++++++++++++++++++++++++++++++++------- src_c/renderer_image.c | 27 -------------------------- 2 files changed, 37 insertions(+), 34 deletions(-) delete mode 100644 src_c/renderer_image.c diff --git a/src_c/renderer.c b/src_c/renderer.c index 362d1fe63e..90d9e1c192 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -6,15 +6,21 @@ #include "doc/sdl2_video_doc.h" -#include "texture.c" -#include "renderer_image.c" - +/* Declarations */ static PyTypeObject pgRenderer_Type; static PyTypeObject pgTexture_Type; static PyTypeObject pgImage_Type; +#define pgRenderer_Check(x) \ + (PyObject_IsInstance((x), (PyObject *)&pgRenderer_Type)) + +#define pgTexture_Check(x) \ + (PyObject_IsInstance((x), (PyObject *)&pgTexture_Type)) + +#define pgImage_Check(x) (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) + #define RENDERER_ERROR_CHECK(x) \ if (x < 0) { \ return RAISE(pgExc_SDLError, SDL_GetError()); \ @@ -26,6 +32,13 @@ static PyTypeObject pgImage_Type; return -1; \ } +static void +texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest); + +static void +image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest); + +/* Renderer implementation */ static PyObject * from_window(PyTypeObject *cls, PyObject *args, PyObject *kwargs) { @@ -663,6 +676,21 @@ renderer_dealloc(pgRendererObject *self, PyObject *_null) Py_TYPE(self)->tp_free(self); } +/* Texture implementation */ +static void +texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest) +{ + ; // TODO MightyJosip Implement with Texture class +} + +/* Image implementation */ +static void +image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) +{ + ; // TODO MightyJosip Implement with Image class +} + +/* Module definition */ static PyMethodDef renderer_methods[] = { {"draw_point", (PyCFunction)renderer_draw_point, METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_DRAWPOINT}, @@ -726,10 +754,12 @@ static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; static PyTypeObject pgRenderer_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Renderer", .tp_basicsize = sizeof(pgRendererObject), - //.tp_dealloc = (destructor)renderer_dealloc, - .tp_doc = DOC_SDL2_VIDEO_RENDERER, .tp_methods = renderer_methods, - //.tp_init = (initproc)renderer_init, - .tp_new = PyType_GenericNew, .tp_getset = renderer_getset}; + .tp_dealloc = (destructor)renderer_dealloc, + .tp_doc = DOC_SDL2_VIDEO_RENDERER, + .tp_methods = renderer_methods, + .tp_init = (initproc)renderer_init, + .tp_new = PyType_GenericNew, + .tp_getset = renderer_getset}; static PyTypeObject pgTexture_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Texture", diff --git a/src_c/renderer_image.c b/src_c/renderer_image.c deleted file mode 100644 index d9a6dc0b4c..0000000000 --- a/src_c/renderer_image.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "pygame.h" - -#include "pgcompat.h" - -#include "doc/sdl2_video_doc.h" - -#define pgImage_Check(x) (PyObject_IsInstance((x), (PyObject *)&pgImage_Type)) - -static void -image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) -{ - ; // TODO MightyJosip Implement with Image class -} - -static PyTypeObject pgImage_Type; - -static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; - -static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; - -static PyTypeObject pgImage_Type = { - PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Image", - .tp_basicsize = sizeof(pgImageObject), - //.tp_dealloc = (destructor)image_dealloc, - .tp_doc = DOC_SDL2_VIDEO_IMAGE, .tp_methods = image_methods, - //.tp_init = (initproc)image_init, - .tp_new = PyType_GenericNew, .tp_getset = image_getset}; From 844f787bdfbffa437ccebf22028a8aa43efa6949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Wed, 29 Jan 2025 15:49:01 +0100 Subject: [PATCH 14/22] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 813f3848e07d268892a4081a9939bb9ab0895a23 Author: Josip Komljenović Date: Wed Jan 29 15:43:45 2025 +0100 Add interface for _sdl2.video classes commit 702958c883149d4321fe96eab6de2ecbbae5cf31 Author: Josip Komljenović Date: Wed Jan 29 15:38:01 2025 +0100 Add interface for _sdl2.video classes commit 081b032255cbcc5ce32c39bebe0a5187765c5d04 Author: Josip Komljenović Date: Wed Jan 29 15:33:20 2025 +0100 Add interface for _sdl2.video classes commit c9ffd1c5517cdd61d3ac00f82d50930d7965cdb3 Author: Josip Komljenović Date: Wed Jan 29 15:25:10 2025 +0100 Add interface for _sdl2.video classes --- src_c/renderer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src_c/renderer.c b/src_c/renderer.c index 90d9e1c192..85cd0b58f1 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -6,7 +6,6 @@ #include "doc/sdl2_video_doc.h" -/* Declarations */ static PyTypeObject pgRenderer_Type; static PyTypeObject pgTexture_Type; From 7354bfcf8feb49582d840d684db431212457f57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Fri, 7 Feb 2025 15:02:54 +0100 Subject: [PATCH 15/22] Port Texture to C code --- src_c/renderer.c | 544 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 536 insertions(+), 8 deletions(-) diff --git a/src_c/renderer.c b/src_c/renderer.c index 85cd0b58f1..097d1b2c28 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -37,6 +37,29 @@ texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest); static void image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest); +/* Helper functions */ +static inline Uint32 +format_from_depth(int depth) { + Uint32 Rmask, Gmask, Bmask, Amask; + if (depth == 0 || depth == 32) { + Rmask = 0xFF << 16; + Gmask = 0xFF << 8; + Bmask = 0xFF; + Amask = 0xFF << 24; + } + else if (depth == 16) { + Rmask = 0xF << 8; + Gmask = 0xF << 4; + Bmask = 0xF; + Amask = 0xF << 12; + } + else { + RAISE(PyExc_ValueError, "no standard masks exist for given bitdepth with alpha"); + return -1; + } + return SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask); +} + /* Renderer implementation */ static PyObject * from_window(PyTypeObject *cls, PyObject *args, PyObject *kwargs) @@ -602,6 +625,7 @@ renderer_get_target(pgRendererObject *self, void *closure) if (self->target == NULL) { Py_RETURN_NONE; } + Py_INCREF(self->target); return (PyObject *)self->target; } @@ -679,7 +703,480 @@ renderer_dealloc(pgRendererObject *self, PyObject *_null) static void texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest) { - ; // TODO MightyJosip Implement with Texture class + SDL_Rect srcrect, *srcrectptr = NULL; + SDL_FRect dstrect, *dstrectptr = NULL; + if (!Py_IsNone(area)) { + if (!(srcrectptr = pgRect_FromObject(area, &srcrect))) { + RAISE(PyExc_ValueError, "srcrect must be a Rect or None"); + } + } + if (!Py_IsNone(dest)) { + if (!(dstrectptr = pgFRect_FromObject(dest, &dstrect))) { + if (!pg_TwoFloatsFromObj(dest, &dstrect.x, &dstrect.y)) { + RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); + } + dstrect.w = (float)self->width; + dstrect.h = (float)self->height; + } + } + if (SDL_RenderCopyExF(self->renderer->renderer, self->texture, srcrectptr, dstrectptr, 0, NULL, SDL_FLIP_NONE) < 0) { + RAISE(pgExc_SDLError, SDL_GetError()); + } +} + +static PyObject * +from_surface(PyObject *self, PyObject *args, PyObject *kwargs) { + pgRendererObject *renderer; + pgSurfaceObject *surfobj; + pgTextureObject *new_texture; + SDL_Surface *surf = NULL; + static char *keywords[] = {"renderer", "surface", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO!", keywords, + &renderer, &pgSurface_Type, &surfobj)) { + return NULL; /* Exception already set. */ + } + new_texture = (pgTextureObject *)(&(pgTexture_Type))->tp_alloc(&pgTexture_Type, 0); + surf = pgSurface_AsSurface(surfobj); + SURF_INIT_CHECK(surf) + new_texture->texture = SDL_CreateTextureFromSurface(renderer->renderer, surf); + if (!new_texture->texture) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + new_texture->renderer = renderer; + new_texture->width = surf->w; + new_texture->height = surf->h; + return (PyObject *)new_texture; +} + +static PyObject * +texture_get_rect(pgTextureObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs) { + PyObject *rect = pgRect_New4(0, 0, self->width, self->height); + return pgObject_getRectHelper(rect, args, nargs, kwargs, "rect"); +} + +static PyObject * +texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) { + PyObject *srcrectobj = Py_None, *dstrectobj = Py_None, *originobj = Py_None; + SDL_Rect srcrect, *srcrectptr = NULL; + SDL_FRect dstrect, *dstrectptr = NULL; + SDL_FPoint origin, *originptr = NULL; + int has_origin = 0; + double angle = 0; + int flip_x = 0; + int flip_y = 0; + SDL_RendererFlip flip = SDL_FLIP_NONE; + static char *keywords[] = {"srcrect", "dstrect", "angle", "origin", "flip_x", "flip_y", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOdOpp", keywords, + &srcrectobj, &dstrectobj, &angle, &originobj, &flip_x, &flip_y)) { + return NULL; /* Exception already set. */ + } + if (!Py_IsNone(srcrectobj)) { + if (!(srcrectptr = pgRect_FromObject(srcrectobj, &srcrect))) { + return RAISE(PyExc_ValueError, "srcrect must be a Rect or None"); + } + } + if (!Py_IsNone(dstrectobj)) { + if (!(dstrectptr = pgFRect_FromObject(dstrectobj, &dstrect))) { + if (!pg_TwoFloatsFromObj(dstrectobj, &dstrect.x, &dstrect.y)) { + return RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); + } + dstrect.w = (float)self->width; + dstrect.h = (float)self->height; + } + } + if (!Py_IsNone(originobj)) { + if (!pg_TwoFloatsFromObj(originobj, &origin.x, &origin.y)) { + return RAISE(PyExc_ValueError, "origin must be a point or None"); + } + originptr = &origin; + } + if (flip_x) flip |= SDL_FLIP_HORIZONTAL; + if (flip_y) flip |= SDL_FLIP_VERTICAL; + RENDERER_ERROR_CHECK(SDL_RenderCopyExF(self->renderer->renderer, self->texture, srcrectptr, dstrectptr, angle, originptr, flip)) + Py_RETURN_NONE; +} + +static PyObject * +texture_draw_triangle(pgTextureObject *self, PyObject *args, PyObject *kwargs) { +#if SDL_VERSION_ATLEAST(2, 0, 18) + PyObject *p1_xyobj, *p2_xyobj, *p3_xyobj, *p1_uvobj = Py_None, *p2_uvobj = Py_None, *p3_uvobj = Py_None, *p1_modobj = Py_None, *p2_modobj = Py_None, *p3_modobj = Py_None; + Uint8 _r_mod, _g_mod, _b_mod, _a_mod; + float r_mod, g_mod, b_mod, a_mod; + SDL_Vertex vertices[3]; + float p1_xy[2], p2_xy[2], p3_xy[2], p1_uv[] = {0.0, 0.0}, p2_uv[] = {1.0, 1.0}, p3_uv[] = {0.0, 1.0}; + int p1_mod[] = {255, 255, 255, 255}, p2_mod[] = {255, 255, 255, 255}, p3_mod[] = {255, 255, 255, 255}; + static char *keywords[] = {"p1_xy", "p2_xy", "p3_xy", "p1_uv", "p2_uv", "p3_uv", "p1_mod", "p2_mod", "p3_mod", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOO|OOOOOO", keywords, + &p1_xyobj, &p2_xyobj, &p3_xyobj, &p1_uvobj, &p2_uvobj, &p3_uvobj, &p1_modobj, &p2_modobj, &p3_modobj)) { + return NULL; /* Exception already set. */ + } + if (!pg_TwoFloatsFromObj(p1_xyobj, &p1_xy[0], &p1_xy[1])) { + return RAISE(PyExc_TypeError, "invalid p1_xy argument"); + } + if (!pg_TwoFloatsFromObj(p2_xyobj, &p2_xy[0], &p2_xy[1])) { + return RAISE(PyExc_TypeError, "invalid p2_xy argument"); + } + if (!pg_TwoFloatsFromObj(p3_xyobj, &p3_xy[0], &p3_xy[1])) { + return RAISE(PyExc_TypeError, "invalid p3_xy argument"); + } + if (!Py_IsNone(p1_uvobj) && !pg_TwoFloatsFromObj(p1_uvobj, &p1_uv[0], &p1_uv[1])) { + return RAISE(PyExc_TypeError, "invalid p1_uv argument"); + } + if (!Py_IsNone(p2_uvobj) && !pg_TwoFloatsFromObj(p2_uvobj, &p2_uv[0], &p2_uv[1])) { + return RAISE(PyExc_TypeError, "invalid p2_uv argument"); + } + if (!Py_IsNone(p3_uvobj) && !pg_TwoFloatsFromObj(p3_uvobj, &p3_uv[0], &p3_uv[1])) { + return RAISE(PyExc_TypeError, "invalid p3_uv argument"); + } + if (!Py_IsNone(p1_modobj)) { + if (!pg_IntFromObjIndex(p1_modobj, 0, &p1_mod[0]) || !pg_IntFromObjIndex(p1_modobj, 1, &p1_mod[1]) || + !pg_IntFromObjIndex(p1_modobj, 2, &p1_mod[2])) { + return RAISE(PyExc_TypeError, "invalid p1_mod argument"); + } + if (PySequence_Size(p1_modobj) == 4) pg_IntFromObjIndex(p1_modobj, 3, &p1_mod[3]); + } + if (!Py_IsNone(p2_modobj)) { + if (!pg_IntFromObjIndex(p2_modobj, 0, &p2_mod[0]) || !pg_IntFromObjIndex(p2_modobj, 1, &p2_mod[1]) || + !pg_IntFromObjIndex(p2_modobj, 2, &p2_mod[2])) { + return RAISE(PyExc_TypeError, "invalid p2_mod argument"); + } + if (PySequence_Size(p2_modobj) == 4) pg_IntFromObjIndex(p2_modobj, 3, &p2_mod[3]); + } + if (!Py_IsNone(p3_modobj)) { + if (!pg_IntFromObjIndex(p3_modobj, 0, &p3_mod[0]) || !pg_IntFromObjIndex(p3_modobj, 1, &p3_mod[1]) || + !pg_IntFromObjIndex(p3_modobj, 2, &p3_mod[2])) { + return RAISE(PyExc_TypeError, "invalid p3_mod argument"); + } + if (PySequence_Size(p3_modobj) == 4) pg_IntFromObjIndex(p3_modobj, 3, &p3_mod[3]); + } + RENDERER_ERROR_CHECK(SDL_GetTextureColorMod(self->texture, &_r_mod, &_g_mod, &_b_mod)); + RENDERER_ERROR_CHECK(SDL_GetTextureAlphaMod(self->texture, &_a_mod)); + r_mod = _r_mod / (float)255.0; + g_mod = _g_mod / (float)255.0; + b_mod = _b_mod / (float)255.0; + a_mod = _a_mod / (float)255.0; + + vertices[0].position.x = p1_xy[0]; vertices[0].position.y = p1_xy[1]; vertices[0].tex_coord.x = p1_uv[0]; vertices[0].tex_coord.y = p1_uv[1]; + vertices[0].color.r = (int)r_mod * p1_mod[0]; vertices[0].color.g = (int)g_mod * p1_mod[1]; vertices[0].color.b = (int)b_mod * p1_mod[2]; vertices[0].color.a = (int)a_mod * p1_mod[3]; + vertices[1].position.x = p2_xy[0]; vertices[1].position.y = p2_xy[1]; vertices[1].tex_coord.x = p2_uv[0]; vertices[1].tex_coord.y = p2_uv[1]; + vertices[1].color.r = (int)r_mod * p2_mod[0]; vertices[1].color.g = (int)g_mod * p2_mod[1]; vertices[1].color.b = (int)b_mod * p2_mod[2]; vertices[1].color.a = (int)a_mod * p2_mod[3]; + vertices[2].position.x = p3_xy[0]; vertices[2].position.y = p3_xy[1]; vertices[2].tex_coord.x = p3_uv[0]; vertices[2].tex_coord.y = p3_uv[1]; + vertices[2].color.r = (int)r_mod * p3_mod[0]; vertices[2].color.g = (int)g_mod * p3_mod[1]; vertices[2].color.b = (int)b_mod * p3_mod[2]; vertices[2].color.a = (int)a_mod * p3_mod[3]; + RENDERER_ERROR_CHECK(SDL_RenderGeometry(self->renderer->renderer, self->texture, vertices, 3, NULL, 0)) + Py_RETURN_NONE; +#else + RAISE(PyExc_TypeError, "draw_triangle() requires SDL 2.0.18 or newer"); + Py_RETURN_NONE; +#endif +} + +static PyObject * +texture_draw_quad(pgTextureObject *self, PyObject *args, PyObject *kwargs) { +#if SDL_VERSION_ATLEAST(2, 0, 18) + PyObject *p1_xyobj, *p2_xyobj, *p3_xyobj, *p4_xyobj, *p1_uvobj = Py_None, *p2_uvobj = Py_None, *p3_uvobj = Py_None, *p4_uvobj = Py_None, *p1_modobj = Py_None, *p2_modobj = Py_None, *p3_modobj = Py_None, *p4_modobj = Py_None; + Uint8 _r_mod, _g_mod, _b_mod, _a_mod; + float r_mod, g_mod, b_mod, a_mod; + SDL_Vertex vertices[6]; + float p1_xy[2], p2_xy[2], p3_xy[2], p4_xy[2], p1_uv[] = {0.0, 0.0}, p2_uv[] = {1.0, 0.0}, p3_uv[] = {1.0, 1.0}, p4_uv[] = {0.0, 1.0}; + int p1_mod[] = {255, 255, 255, 255}, p2_mod[] = {255, 255, 255, 255}, p3_mod[] = {255, 255, 255, 255}, p4_mod[] = {255, 255, 255, 255}; + static char *keywords[] = {"p1_xy", "p2_xy", "p3_xy", "p4_xy", "p1_uv", "p2_uv", "p3_uv", "p4_uv", "p1_mod", "p2_mod", "p3_mod", "p4_mod", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOOO|OOOOOOOO", keywords, + &p1_xyobj, &p2_xyobj, &p3_xyobj, &p4_xyobj, &p1_uvobj, &p2_uvobj, &p3_uvobj, &p4_uvobj, &p1_modobj, &p2_modobj, &p3_modobj, &p4_modobj)) { + return NULL; /* Exception already set. */ + } + if (!pg_TwoFloatsFromObj(p1_xyobj, &p1_xy[0], &p1_xy[1])) { + return RAISE(PyExc_TypeError, "invalid p1_xy argument"); + } + if (!pg_TwoFloatsFromObj(p2_xyobj, &p2_xy[0], &p2_xy[1])) { + return RAISE(PyExc_TypeError, "invalid p2_xy argument"); + } + if (!pg_TwoFloatsFromObj(p3_xyobj, &p3_xy[0], &p3_xy[1])) { + return RAISE(PyExc_TypeError, "invalid p3_xy argument"); + } + if (!pg_TwoFloatsFromObj(p4_xyobj, &p4_xy[0], &p4_xy[1])) { + return RAISE(PyExc_TypeError, "invalid p3_xy argument"); + } + if (!Py_IsNone(p1_uvobj) && !pg_TwoFloatsFromObj(p1_uvobj, &p1_uv[0], &p1_uv[1])) { + return RAISE(PyExc_TypeError, "invalid p1_uv argument"); + } + if (!Py_IsNone(p2_uvobj) && !pg_TwoFloatsFromObj(p2_uvobj, &p2_uv[0], &p2_uv[1])) { + return RAISE(PyExc_TypeError, "invalid p2_uv argument"); + } + if (!Py_IsNone(p3_uvobj) && !pg_TwoFloatsFromObj(p3_uvobj, &p3_uv[0], &p3_uv[1])) { + return RAISE(PyExc_TypeError, "invalid p3_uv argument"); + } + if (!Py_IsNone(p4_uvobj) && !pg_TwoFloatsFromObj(p3_uvobj, &p4_uv[0], &p4_uv[1])) { + return RAISE(PyExc_TypeError, "invalid p4_uv argument"); + } + if (!Py_IsNone(p1_modobj)) { + if (!pg_IntFromObjIndex(p1_modobj, 0, &p1_mod[0]) || !pg_IntFromObjIndex(p1_modobj, 1, &p1_mod[1]) || + !pg_IntFromObjIndex(p1_modobj, 2, &p1_mod[2])) { + return RAISE(PyExc_TypeError, "invalid p1_mod argument"); + } + if (PySequence_Size(p1_modobj) == 4) pg_IntFromObjIndex(p1_modobj, 3, &p1_mod[3]); + } + if (!Py_IsNone(p2_modobj)) { + if (!pg_IntFromObjIndex(p2_modobj, 0, &p2_mod[0]) || !pg_IntFromObjIndex(p2_modobj, 1, &p2_mod[1]) || + !pg_IntFromObjIndex(p2_modobj, 2, &p2_mod[2])) { + return RAISE(PyExc_TypeError, "invalid p2_mod argument"); + } + if (PySequence_Size(p2_modobj) == 4) pg_IntFromObjIndex(p2_modobj, 3, &p2_mod[3]); + } + if (!Py_IsNone(p3_modobj)) { + if (!pg_IntFromObjIndex(p3_modobj, 0, &p3_mod[0]) || !pg_IntFromObjIndex(p3_modobj, 1, &p3_mod[1]) || + !pg_IntFromObjIndex(p3_modobj, 2, &p3_mod[2])) { + return RAISE(PyExc_TypeError, "invalid p3_mod argument"); + } + if (PySequence_Size(p3_modobj) == 4) pg_IntFromObjIndex(p3_modobj, 3, &p3_mod[3]); + } + if (!Py_IsNone(p4_modobj)) { + if (!pg_IntFromObjIndex(p4_modobj, 0, &p4_mod[0]) || !pg_IntFromObjIndex(p4_modobj, 1, &p4_mod[1]) || + !pg_IntFromObjIndex(p4_modobj, 2, &p4_mod[2])) { + return RAISE(PyExc_TypeError, "invalid p4_mod argument"); + } + if (PySequence_Size(p4_modobj) == 4) pg_IntFromObjIndex(p4_modobj, 3, &p4_mod[3]); + } + RENDERER_ERROR_CHECK(SDL_GetTextureColorMod(self->texture, &_r_mod, &_g_mod, &_b_mod)); + RENDERER_ERROR_CHECK(SDL_GetTextureAlphaMod(self->texture, &_a_mod)); + + r_mod = _r_mod / (float)255.0; + g_mod = _g_mod / (float)255.0; + b_mod = _b_mod / (float)255.0; + a_mod = _a_mod / (float)255.0; + + vertices[0].position.x = p1_xy[0]; vertices[0].position.y = p1_xy[1]; vertices[0].tex_coord.x = p1_uv[0]; vertices[0].tex_coord.y = p1_uv[1]; + vertices[0].color.r = (int)r_mod * p1_mod[0]; vertices[0].color.g = (int)g_mod * p1_mod[1]; vertices[0].color.b = (int)b_mod * p1_mod[2]; vertices[0].color.a = (int)a_mod * p1_mod[3]; + vertices[1].position.x = p2_xy[0]; vertices[1].position.y = p2_xy[1]; vertices[1].tex_coord.x = p2_uv[0]; vertices[1].tex_coord.y = p2_uv[1]; + vertices[1].color.r = (int)r_mod * p2_mod[0]; vertices[1].color.g = (int)g_mod * p2_mod[1]; vertices[1].color.b = (int)b_mod * p2_mod[2]; vertices[1].color.a = (int)a_mod * p2_mod[3]; + vertices[2].position.x = p3_xy[0]; vertices[2].position.y = p3_xy[1]; vertices[2].tex_coord.x = p3_uv[0]; vertices[2].tex_coord.y = p3_uv[1]; + vertices[2].color.r = (int)r_mod * p3_mod[0]; vertices[2].color.g = (int)g_mod * p3_mod[1]; vertices[2].color.b = (int)b_mod * p3_mod[2]; vertices[2].color.a = (int)a_mod * p3_mod[3]; + vertices[3].position.x = p3_xy[0]; vertices[3].position.y = p3_xy[1]; vertices[3].tex_coord.x = p3_uv[0]; vertices[3].tex_coord.y = p3_uv[1]; + vertices[3].color.r = (int)r_mod * p3_mod[0]; vertices[3].color.g = (int)g_mod * p3_mod[1]; vertices[3].color.b = (int)b_mod * p3_mod[2]; vertices[3].color.a = (int)a_mod * p3_mod[3]; + vertices[4].position.x = p4_xy[0]; vertices[4].position.y = p4_xy[1]; vertices[4].tex_coord.x = p4_uv[0]; vertices[4].tex_coord.y = p4_uv[1]; + vertices[4].color.r = (int)r_mod * p4_mod[0]; vertices[4].color.g = (int)g_mod * p4_mod[1]; vertices[4].color.b = (int)b_mod * p4_mod[2]; vertices[4].color.a = (int)a_mod * p4_mod[3]; + vertices[5].position.x = p1_xy[0]; vertices[5].position.y = p1_xy[1]; vertices[5].tex_coord.x = p1_uv[0]; vertices[5].tex_coord.y = p1_uv[1]; + vertices[5].color.r = (int)r_mod * p1_mod[0]; vertices[5].color.g = (int)g_mod * p1_mod[1]; vertices[5].color.b = (int)b_mod * p1_mod[2]; vertices[5].color.a = (int)a_mod * p1_mod[3]; + RENDERER_ERROR_CHECK(SDL_RenderGeometry(self->renderer->renderer, self->texture, vertices, 6, NULL, 0)) + Py_RETURN_NONE; +#else + RAISE(PyExc_TypeError, "draw_triangle() requires SDL 2.0.18 or newer"); + Py_RETURN_NONE; +#endif +} + +static PyObject * +texture_update(pgTextureObject *self, PyObject *args, PyObject *kwargs) { + pgSurfaceObject *surfobj; + PyObject *rectobj = Py_None; + SDL_Surface *surf = NULL; + SDL_Rect area, *areaptr = NULL; + SDL_Surface *converted_surf = NULL; + SDL_PixelFormat *pixel_format = NULL; + SDL_BlendMode blend; + Uint32 format; + int res; + int dst_width, dst_height; + static char *keywords[] = {"surface", "area", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", keywords, + &pgSurface_Type, &surfobj, &rectobj)) { + return NULL; /* Exception already set. */ + } + surf = pgSurface_AsSurface(surfobj); + SURF_INIT_CHECK(surf) + area.x = 0; + area.y = 0; + if (!Py_IsNone(rectobj)) { + if (!(areaptr = pgRect_FromObject(rectobj, &area))) { + return RAISE(PyExc_ValueError, "area must be a rectangle or None"); + } + } + if (areaptr == NULL) { + dst_width = self->width; + dst_height = self->height; + } + else { + dst_width = area.w; + dst_height = area.h; + } + if (dst_width > surf->w || dst_height > surf->h) { + areaptr = &area; + area.w = surf->w; + area.h = surf->h; + } + RENDERER_ERROR_CHECK(SDL_QueryTexture(self->texture, &format, NULL, NULL, NULL)) + if (format != surf->format->format) { + RENDERER_ERROR_CHECK(SDL_GetSurfaceBlendMode(surf, &blend)) + pixel_format = SDL_AllocFormat(format); + if (pixel_format == NULL) return RAISE(pgExc_SDLError, SDL_GetError()); + converted_surf = SDL_ConvertSurface(surf, pixel_format, 0); + if (SDL_SetSurfaceBlendMode(converted_surf, blend) < 0) { + SDL_FreeSurface(converted_surf); + SDL_FreeFormat(pixel_format); + return RAISE(pgExc_SDLError, SDL_GetError()); + } + + res = SDL_UpdateTexture(self->texture, areaptr, converted_surf->pixels, converted_surf->pitch); + SDL_FreeSurface(converted_surf); + SDL_FreeFormat(pixel_format); + } + else { + res = SDL_UpdateTexture(self->texture, areaptr, surf->pixels, surf->pitch); + } + if (res < 0) return RAISE(pgExc_SDLError, SDL_GetError()); + Py_RETURN_NONE; +} + +static PyObject * +texture_get_renderer(pgTextureObject *self, void *closure) { + Py_INCREF(self->renderer); + return (PyObject *)self->renderer; +} + +static PyObject * +texture_get_width(pgTextureObject *self, void *closure) { + return PyLong_FromLong(self->width); +} + +static PyObject * +texture_get_height(pgTextureObject *self, void *closure) { + return PyLong_FromLong(self->height); +} + +static PyObject * +texture_get_alpha(pgTextureObject *self, void *closure) { + Uint8 alpha; + RENDERER_ERROR_CHECK(SDL_GetTextureAlphaMod(self->texture, &alpha)); + return PyLong_FromLong(alpha); +} + +static int +texture_set_alpha(pgTextureObject *self, PyObject *arg, void *closure) { + if (PyLong_Check(arg)) { + unsigned long longval = PyLong_AsUnsignedLong(arg); + RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureAlphaMod(self->texture, (Uint8)longval)) + return 0; + } + return -1; +} + +static PyObject * +texture_get_blend_mode(pgTextureObject *self, void *closure) { + SDL_BlendMode blend_mode; + RENDERER_ERROR_CHECK(SDL_GetTextureBlendMode(self->texture, &blend_mode)); + return PyLong_FromLong((long) blend_mode); +} + +static int +texture_set_blend_mode(pgTextureObject *self, PyObject *arg, void *closure) { + if (PyLong_Check(arg)) { + long longval = PyLong_AsLong(arg); + RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureBlendMode(self->texture, (int)longval)) + return 0; + } + return 1; +} + +static PyObject * +texture_get_color(pgTextureObject *self, void *closure) { + Uint8 color[4]; + RENDERER_ERROR_CHECK(SDL_GetTextureColorMod(self->texture, &color[0], &color[1], &color[2])); + color[3] = 255; + return pgColor_NewLength(color, 4); +} + +static int +texture_set_color(pgTextureObject *self, PyObject *arg, void *closure) { + Uint8 color[4]; + if (!pg_RGBAFromObjEx(arg, color, PG_COLOR_HANDLE_ALL)) { + return -1; + } + RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureColorMod(self->texture, color[0], color[1], color[2])) + return 0; +} + +static int +texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) { + SDL_Texture *texture = NULL; + pgRendererObject *renderer; + PyObject *sizeobj; + int width; + int height; + int depth = 0; + int staticc = 0; + int streaming = 0; + int target = 0; + int scale_quality = -1; + int access = SDL_TEXTUREACCESS_STATIC; + Uint32 format; + + char *keywords[] = {"renderer", "size", "depth", "static", "streaming", "target", "scale_quality", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|ipppi", keywords, &renderer, &sizeobj, &depth, &staticc, &streaming, &target, &scale_quality)) { + return -1; + } + format = format_from_depth(depth); + if (!pg_TwoIntsFromObj(sizeobj, &width, &height)) { + RAISE(PyExc_TypeError, "invalid size argument"); + return -1; + } + if (width <= 0 || height <= 0) { + RAISE(PyExc_ValueError, "size must contain two positive values"); + return -1; + } + if (staticc) { + if (streaming || target) { + RAISE(PyExc_ValueError, "only one of static, streaming, or target can be true"); + return -1; + } + access = SDL_TEXTUREACCESS_STATIC; + } + if (streaming) { + if (staticc || target) { + RAISE(PyExc_ValueError, "only one of static, streaming, or target can be true"); + return -1; + } + access = SDL_TEXTUREACCESS_STREAMING; + } + if (target) { + if (staticc || streaming) { + RAISE(PyExc_ValueError, "only one of static, streaming, or target can be true"); + return -1; + } + access = SDL_TEXTUREACCESS_TARGET; + } + self->renderer = renderer; + self->texture = SDL_CreateTexture(renderer->renderer, format, access, width, height); + if (!self->texture) { + RAISE(pgExc_SDLError, SDL_GetError()); + return -1; + } + if (scale_quality != -1) { +#if SDL_VERSION_ATLEAST(2,0,12) + if (SDL_SetTextureScaleMode(self->texture, scale_quality) < 0) { + RAISE(pgExc_SDLError, SDL_GetError()); + return -1; + } +#else + switch (scale_quality) { + case 0: + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); break; + case 1: + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); break; + case 2: + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); break; + } +#endif + } + self->width = width; + self->height = height; + return 0; +} + +static void +texture_dealloc(pgTextureObject *self, PyObject *_null) { + if (self->texture) { + SDL_DestroyTexture(self->texture); + } + Py_TYPE(self)->tp_free(self); } /* Image implementation */ @@ -742,9 +1239,37 @@ static PyGetSetDef renderer_getset[] = { DOC_SDL2_VIDEO_RENDERER_TARGET, NULL}, {NULL, 0, NULL, NULL, NULL}}; -static PyMethodDef texture_methods[] = {{NULL, NULL, 0, NULL}}; - -static PyGetSetDef texture_getset[] = {{NULL, 0, NULL, NULL, NULL}}; +static PyMethodDef texture_methods[] = { + {"get_rect", (PyCFunction)texture_get_rect, METH_FASTCALL | METH_KEYWORDS, + DOC_SDL2_VIDEO_TEXTURE_GETRECT}, + {"draw", (PyCFunction)texture_draw, METH_VARARGS | METH_KEYWORDS, + DOC_SDL2_VIDEO_TEXTURE_DRAW}, + {"draw_triangle", (PyCFunction)texture_draw_triangle, METH_VARARGS | METH_KEYWORDS, + DOC_SDL2_VIDEO_TEXTURE_DRAWTRIANGLE}, + {"draw_quad", (PyCFunction)texture_draw_quad, METH_VARARGS | METH_KEYWORDS, + DOC_SDL2_VIDEO_TEXTURE_DRAWQUAD}, + {"update", (PyCFunction)texture_update, METH_VARARGS | METH_KEYWORDS, + DOC_SDL2_VIDEO_TEXTURE_UPDATE}, + {"from_surface", (PyCFunction)from_surface, METH_VARARGS | METH_KEYWORDS | METH_CLASS, + DOC_SDL2_VIDEO_TEXTURE_FROMSURFACE}, + {NULL, NULL, 0, NULL} +}; + +static PyGetSetDef texture_getset[] = { + {"renderer", (getter)texture_get_renderer, (setter)NULL, + DOC_SDL2_VIDEO_TEXTURE_RENDERER, NULL}, + {"width", (getter)texture_get_width, (setter)NULL, + DOC_SDL2_VIDEO_TEXTURE_WIDTH, NULL}, + {"height", (getter)texture_get_height, (setter)NULL, + DOC_SDL2_VIDEO_TEXTURE_HEIGHT, NULL}, + {"alpha", (getter)texture_get_alpha, (setter)texture_set_alpha, + DOC_SDL2_VIDEO_TEXTURE_ALPHA, NULL}, + {"blend_mode", (getter)texture_get_blend_mode, (setter)texture_set_blend_mode, + DOC_SDL2_VIDEO_TEXTURE_BLENDMODE, NULL}, + {"color", (getter)texture_get_color, (setter)texture_set_color, + DOC_SDL2_VIDEO_TEXTURE_COLOR, NULL}, + {NULL, 0, NULL, NULL, NULL} +}; static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; @@ -763,10 +1288,13 @@ static PyTypeObject pgRenderer_Type = { static PyTypeObject pgTexture_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Texture", .tp_basicsize = sizeof(pgTextureObject), - //.tp_dealloc = (destructor)texture_dealloc, - .tp_doc = DOC_SDL2_VIDEO_TEXTURE, .tp_methods = texture_methods, - //.tp_init = (initproc)texture_init, - .tp_new = PyType_GenericNew, .tp_getset = texture_getset}; + .tp_dealloc = (destructor)texture_dealloc, + .tp_doc = DOC_SDL2_VIDEO_TEXTURE, + .tp_methods = texture_methods, + .tp_init = (initproc)texture_init, + .tp_new = PyType_GenericNew, + .tp_getset = texture_getset +}; static PyTypeObject pgImage_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Image", From 98abc4a56c8d070620272edc45defb4944e41cdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Fri, 7 Feb 2025 15:05:15 +0100 Subject: [PATCH 16/22] Port Texture to C code --- src_c/renderer.c | 383 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 264 insertions(+), 119 deletions(-) diff --git a/src_c/renderer.c b/src_c/renderer.c index 097d1b2c28..fb99a450d8 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -39,7 +39,8 @@ image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest); /* Helper functions */ static inline Uint32 -format_from_depth(int depth) { +format_from_depth(int depth) +{ Uint32 Rmask, Gmask, Bmask, Amask; if (depth == 0 || depth == 32) { Rmask = 0xFF << 16; @@ -54,7 +55,8 @@ format_from_depth(int depth) { Amask = 0xF << 12; } else { - RAISE(PyExc_ValueError, "no standard masks exist for given bitdepth with alpha"); + RAISE(PyExc_ValueError, + "no standard masks exist for given bitdepth with alpha"); return -1; } return SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask); @@ -713,32 +715,37 @@ texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest) if (!Py_IsNone(dest)) { if (!(dstrectptr = pgFRect_FromObject(dest, &dstrect))) { if (!pg_TwoFloatsFromObj(dest, &dstrect.x, &dstrect.y)) { - RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); + RAISE(PyExc_ValueError, + "dstrect must be a point, Rect, or None"); } dstrect.w = (float)self->width; dstrect.h = (float)self->height; } } - if (SDL_RenderCopyExF(self->renderer->renderer, self->texture, srcrectptr, dstrectptr, 0, NULL, SDL_FLIP_NONE) < 0) { + if (SDL_RenderCopyExF(self->renderer->renderer, self->texture, srcrectptr, + dstrectptr, 0, NULL, SDL_FLIP_NONE) < 0) { RAISE(pgExc_SDLError, SDL_GetError()); } } static PyObject * -from_surface(PyObject *self, PyObject *args, PyObject *kwargs) { +from_surface(PyObject *self, PyObject *args, PyObject *kwargs) +{ pgRendererObject *renderer; pgSurfaceObject *surfobj; pgTextureObject *new_texture; SDL_Surface *surf = NULL; static char *keywords[] = {"renderer", "surface", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO!", keywords, - &renderer, &pgSurface_Type, &surfobj)) { + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO!", keywords, &renderer, + &pgSurface_Type, &surfobj)) { return NULL; /* Exception already set. */ } - new_texture = (pgTextureObject *)(&(pgTexture_Type))->tp_alloc(&pgTexture_Type, 0); + new_texture = + (pgTextureObject *)(&(pgTexture_Type))->tp_alloc(&pgTexture_Type, 0); surf = pgSurface_AsSurface(surfobj); SURF_INIT_CHECK(surf) - new_texture->texture = SDL_CreateTextureFromSurface(renderer->renderer, surf); + new_texture->texture = + SDL_CreateTextureFromSurface(renderer->renderer, surf); if (!new_texture->texture) { return RAISE(pgExc_SDLError, SDL_GetError()); } @@ -749,14 +756,18 @@ from_surface(PyObject *self, PyObject *args, PyObject *kwargs) { } static PyObject * -texture_get_rect(pgTextureObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs) { +texture_get_rect(pgTextureObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwargs) +{ PyObject *rect = pgRect_New4(0, 0, self->width, self->height); return pgObject_getRectHelper(rect, args, nargs, kwargs, "rect"); } static PyObject * -texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) { - PyObject *srcrectobj = Py_None, *dstrectobj = Py_None, *originobj = Py_None; +texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *srcrectobj = Py_None, *dstrectobj = Py_None, + *originobj = Py_None; SDL_Rect srcrect, *srcrectptr = NULL; SDL_FRect dstrect, *dstrectptr = NULL; SDL_FPoint origin, *originptr = NULL; @@ -765,9 +776,11 @@ texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) { int flip_x = 0; int flip_y = 0; SDL_RendererFlip flip = SDL_FLIP_NONE; - static char *keywords[] = {"srcrect", "dstrect", "angle", "origin", "flip_x", "flip_y", NULL}; + static char *keywords[] = {"srcrect", "dstrect", "angle", "origin", + "flip_x", "flip_y", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOdOpp", keywords, - &srcrectobj, &dstrectobj, &angle, &originobj, &flip_x, &flip_y)) { + &srcrectobj, &dstrectobj, &angle, + &originobj, &flip_x, &flip_y)) { return NULL; /* Exception already set. */ } if (!Py_IsNone(srcrectobj)) { @@ -778,7 +791,8 @@ texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) { if (!Py_IsNone(dstrectobj)) { if (!(dstrectptr = pgFRect_FromObject(dstrectobj, &dstrect))) { if (!pg_TwoFloatsFromObj(dstrectobj, &dstrect.x, &dstrect.y)) { - return RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); + return RAISE(PyExc_ValueError, + "dstrect must be a point, Rect, or None"); } dstrect.w = (float)self->width; dstrect.h = (float)self->height; @@ -790,24 +804,36 @@ texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) { } originptr = &origin; } - if (flip_x) flip |= SDL_FLIP_HORIZONTAL; - if (flip_y) flip |= SDL_FLIP_VERTICAL; - RENDERER_ERROR_CHECK(SDL_RenderCopyExF(self->renderer->renderer, self->texture, srcrectptr, dstrectptr, angle, originptr, flip)) + if (flip_x) + flip |= SDL_FLIP_HORIZONTAL; + if (flip_y) + flip |= SDL_FLIP_VERTICAL; + RENDERER_ERROR_CHECK(SDL_RenderCopyExF(self->renderer->renderer, + self->texture, srcrectptr, + dstrectptr, angle, originptr, flip)) Py_RETURN_NONE; } static PyObject * -texture_draw_triangle(pgTextureObject *self, PyObject *args, PyObject *kwargs) { +texture_draw_triangle(pgTextureObject *self, PyObject *args, PyObject *kwargs) +{ #if SDL_VERSION_ATLEAST(2, 0, 18) - PyObject *p1_xyobj, *p2_xyobj, *p3_xyobj, *p1_uvobj = Py_None, *p2_uvobj = Py_None, *p3_uvobj = Py_None, *p1_modobj = Py_None, *p2_modobj = Py_None, *p3_modobj = Py_None; + PyObject *p1_xyobj, *p2_xyobj, *p3_xyobj, + *p1_uvobj = Py_None, *p2_uvobj = Py_None, *p3_uvobj = Py_None, + *p1_modobj = Py_None, *p2_modobj = Py_None, *p3_modobj = Py_None; Uint8 _r_mod, _g_mod, _b_mod, _a_mod; float r_mod, g_mod, b_mod, a_mod; SDL_Vertex vertices[3]; - float p1_xy[2], p2_xy[2], p3_xy[2], p1_uv[] = {0.0, 0.0}, p2_uv[] = {1.0, 1.0}, p3_uv[] = {0.0, 1.0}; - int p1_mod[] = {255, 255, 255, 255}, p2_mod[] = {255, 255, 255, 255}, p3_mod[] = {255, 255, 255, 255}; - static char *keywords[] = {"p1_xy", "p2_xy", "p3_xy", "p1_uv", "p2_uv", "p3_uv", "p1_mod", "p2_mod", "p3_mod", NULL}; + float p1_xy[2], p2_xy[2], p3_xy[2], + p1_uv[] = {0.0, 0.0}, p2_uv[] = {1.0, 1.0}, p3_uv[] = {0.0, 1.0}; + int p1_mod[] = {255, 255, 255, 255}, p2_mod[] = {255, 255, 255, 255}, + p3_mod[] = {255, 255, 255, 255}; + static char *keywords[] = {"p1_xy", "p2_xy", "p3_xy", "p1_uv", "p2_uv", + "p3_uv", "p1_mod", "p2_mod", "p3_mod", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOO|OOOOOO", keywords, - &p1_xyobj, &p2_xyobj, &p3_xyobj, &p1_uvobj, &p2_uvobj, &p3_uvobj, &p1_modobj, &p2_modobj, &p3_modobj)) { + &p1_xyobj, &p2_xyobj, &p3_xyobj, + &p1_uvobj, &p2_uvobj, &p3_uvobj, + &p1_modobj, &p2_modobj, &p3_modobj)) { return NULL; /* Exception already set. */ } if (!pg_TwoFloatsFromObj(p1_xyobj, &p1_xy[0], &p1_xy[1])) { @@ -819,50 +845,79 @@ texture_draw_triangle(pgTextureObject *self, PyObject *args, PyObject *kwargs) { if (!pg_TwoFloatsFromObj(p3_xyobj, &p3_xy[0], &p3_xy[1])) { return RAISE(PyExc_TypeError, "invalid p3_xy argument"); } - if (!Py_IsNone(p1_uvobj) && !pg_TwoFloatsFromObj(p1_uvobj, &p1_uv[0], &p1_uv[1])) { + if (!Py_IsNone(p1_uvobj) && + !pg_TwoFloatsFromObj(p1_uvobj, &p1_uv[0], &p1_uv[1])) { return RAISE(PyExc_TypeError, "invalid p1_uv argument"); } - if (!Py_IsNone(p2_uvobj) && !pg_TwoFloatsFromObj(p2_uvobj, &p2_uv[0], &p2_uv[1])) { + if (!Py_IsNone(p2_uvobj) && + !pg_TwoFloatsFromObj(p2_uvobj, &p2_uv[0], &p2_uv[1])) { return RAISE(PyExc_TypeError, "invalid p2_uv argument"); } - if (!Py_IsNone(p3_uvobj) && !pg_TwoFloatsFromObj(p3_uvobj, &p3_uv[0], &p3_uv[1])) { + if (!Py_IsNone(p3_uvobj) && + !pg_TwoFloatsFromObj(p3_uvobj, &p3_uv[0], &p3_uv[1])) { return RAISE(PyExc_TypeError, "invalid p3_uv argument"); } if (!Py_IsNone(p1_modobj)) { - if (!pg_IntFromObjIndex(p1_modobj, 0, &p1_mod[0]) || !pg_IntFromObjIndex(p1_modobj, 1, &p1_mod[1]) || + if (!pg_IntFromObjIndex(p1_modobj, 0, &p1_mod[0]) || + !pg_IntFromObjIndex(p1_modobj, 1, &p1_mod[1]) || !pg_IntFromObjIndex(p1_modobj, 2, &p1_mod[2])) { return RAISE(PyExc_TypeError, "invalid p1_mod argument"); } - if (PySequence_Size(p1_modobj) == 4) pg_IntFromObjIndex(p1_modobj, 3, &p1_mod[3]); + if (PySequence_Size(p1_modobj) == 4) + pg_IntFromObjIndex(p1_modobj, 3, &p1_mod[3]); } if (!Py_IsNone(p2_modobj)) { - if (!pg_IntFromObjIndex(p2_modobj, 0, &p2_mod[0]) || !pg_IntFromObjIndex(p2_modobj, 1, &p2_mod[1]) || + if (!pg_IntFromObjIndex(p2_modobj, 0, &p2_mod[0]) || + !pg_IntFromObjIndex(p2_modobj, 1, &p2_mod[1]) || !pg_IntFromObjIndex(p2_modobj, 2, &p2_mod[2])) { return RAISE(PyExc_TypeError, "invalid p2_mod argument"); } - if (PySequence_Size(p2_modobj) == 4) pg_IntFromObjIndex(p2_modobj, 3, &p2_mod[3]); + if (PySequence_Size(p2_modobj) == 4) + pg_IntFromObjIndex(p2_modobj, 3, &p2_mod[3]); } if (!Py_IsNone(p3_modobj)) { - if (!pg_IntFromObjIndex(p3_modobj, 0, &p3_mod[0]) || !pg_IntFromObjIndex(p3_modobj, 1, &p3_mod[1]) || + if (!pg_IntFromObjIndex(p3_modobj, 0, &p3_mod[0]) || + !pg_IntFromObjIndex(p3_modobj, 1, &p3_mod[1]) || !pg_IntFromObjIndex(p3_modobj, 2, &p3_mod[2])) { return RAISE(PyExc_TypeError, "invalid p3_mod argument"); } - if (PySequence_Size(p3_modobj) == 4) pg_IntFromObjIndex(p3_modobj, 3, &p3_mod[3]); + if (PySequence_Size(p3_modobj) == 4) + pg_IntFromObjIndex(p3_modobj, 3, &p3_mod[3]); } - RENDERER_ERROR_CHECK(SDL_GetTextureColorMod(self->texture, &_r_mod, &_g_mod, &_b_mod)); + RENDERER_ERROR_CHECK( + SDL_GetTextureColorMod(self->texture, &_r_mod, &_g_mod, &_b_mod)); RENDERER_ERROR_CHECK(SDL_GetTextureAlphaMod(self->texture, &_a_mod)); r_mod = _r_mod / (float)255.0; g_mod = _g_mod / (float)255.0; b_mod = _b_mod / (float)255.0; a_mod = _a_mod / (float)255.0; - vertices[0].position.x = p1_xy[0]; vertices[0].position.y = p1_xy[1]; vertices[0].tex_coord.x = p1_uv[0]; vertices[0].tex_coord.y = p1_uv[1]; - vertices[0].color.r = (int)r_mod * p1_mod[0]; vertices[0].color.g = (int)g_mod * p1_mod[1]; vertices[0].color.b = (int)b_mod * p1_mod[2]; vertices[0].color.a = (int)a_mod * p1_mod[3]; - vertices[1].position.x = p2_xy[0]; vertices[1].position.y = p2_xy[1]; vertices[1].tex_coord.x = p2_uv[0]; vertices[1].tex_coord.y = p2_uv[1]; - vertices[1].color.r = (int)r_mod * p2_mod[0]; vertices[1].color.g = (int)g_mod * p2_mod[1]; vertices[1].color.b = (int)b_mod * p2_mod[2]; vertices[1].color.a = (int)a_mod * p2_mod[3]; - vertices[2].position.x = p3_xy[0]; vertices[2].position.y = p3_xy[1]; vertices[2].tex_coord.x = p3_uv[0]; vertices[2].tex_coord.y = p3_uv[1]; - vertices[2].color.r = (int)r_mod * p3_mod[0]; vertices[2].color.g = (int)g_mod * p3_mod[1]; vertices[2].color.b = (int)b_mod * p3_mod[2]; vertices[2].color.a = (int)a_mod * p3_mod[3]; - RENDERER_ERROR_CHECK(SDL_RenderGeometry(self->renderer->renderer, self->texture, vertices, 3, NULL, 0)) + vertices[0].position.x = p1_xy[0]; + vertices[0].position.y = p1_xy[1]; + vertices[0].tex_coord.x = p1_uv[0]; + vertices[0].tex_coord.y = p1_uv[1]; + vertices[0].color.r = (int)r_mod * p1_mod[0]; + vertices[0].color.g = (int)g_mod * p1_mod[1]; + vertices[0].color.b = (int)b_mod * p1_mod[2]; + vertices[0].color.a = (int)a_mod * p1_mod[3]; + vertices[1].position.x = p2_xy[0]; + vertices[1].position.y = p2_xy[1]; + vertices[1].tex_coord.x = p2_uv[0]; + vertices[1].tex_coord.y = p2_uv[1]; + vertices[1].color.r = (int)r_mod * p2_mod[0]; + vertices[1].color.g = (int)g_mod * p2_mod[1]; + vertices[1].color.b = (int)b_mod * p2_mod[2]; + vertices[1].color.a = (int)a_mod * p2_mod[3]; + vertices[2].position.x = p3_xy[0]; + vertices[2].position.y = p3_xy[1]; + vertices[2].tex_coord.x = p3_uv[0]; + vertices[2].tex_coord.y = p3_uv[1]; + vertices[2].color.r = (int)r_mod * p3_mod[0]; + vertices[2].color.g = (int)g_mod * p3_mod[1]; + vertices[2].color.b = (int)b_mod * p3_mod[2]; + vertices[2].color.a = (int)a_mod * p3_mod[3]; + RENDERER_ERROR_CHECK(SDL_RenderGeometry( + self->renderer->renderer, self->texture, vertices, 3, NULL, 0)) Py_RETURN_NONE; #else RAISE(PyExc_TypeError, "draw_triangle() requires SDL 2.0.18 or newer"); @@ -871,17 +926,28 @@ texture_draw_triangle(pgTextureObject *self, PyObject *args, PyObject *kwargs) { } static PyObject * -texture_draw_quad(pgTextureObject *self, PyObject *args, PyObject *kwargs) { +texture_draw_quad(pgTextureObject *self, PyObject *args, PyObject *kwargs) +{ #if SDL_VERSION_ATLEAST(2, 0, 18) - PyObject *p1_xyobj, *p2_xyobj, *p3_xyobj, *p4_xyobj, *p1_uvobj = Py_None, *p2_uvobj = Py_None, *p3_uvobj = Py_None, *p4_uvobj = Py_None, *p1_modobj = Py_None, *p2_modobj = Py_None, *p3_modobj = Py_None, *p4_modobj = Py_None; + PyObject *p1_xyobj, *p2_xyobj, *p3_xyobj, *p4_xyobj, + *p1_uvobj = Py_None, *p2_uvobj = Py_None, *p3_uvobj = Py_None, + *p4_uvobj = Py_None, *p1_modobj = Py_None, *p2_modobj = Py_None, + *p3_modobj = Py_None, *p4_modobj = Py_None; Uint8 _r_mod, _g_mod, _b_mod, _a_mod; float r_mod, g_mod, b_mod, a_mod; SDL_Vertex vertices[6]; - float p1_xy[2], p2_xy[2], p3_xy[2], p4_xy[2], p1_uv[] = {0.0, 0.0}, p2_uv[] = {1.0, 0.0}, p3_uv[] = {1.0, 1.0}, p4_uv[] = {0.0, 1.0}; - int p1_mod[] = {255, 255, 255, 255}, p2_mod[] = {255, 255, 255, 255}, p3_mod[] = {255, 255, 255, 255}, p4_mod[] = {255, 255, 255, 255}; - static char *keywords[] = {"p1_xy", "p2_xy", "p3_xy", "p4_xy", "p1_uv", "p2_uv", "p3_uv", "p4_uv", "p1_mod", "p2_mod", "p3_mod", "p4_mod", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOOO|OOOOOOOO", keywords, - &p1_xyobj, &p2_xyobj, &p3_xyobj, &p4_xyobj, &p1_uvobj, &p2_uvobj, &p3_uvobj, &p4_uvobj, &p1_modobj, &p2_modobj, &p3_modobj, &p4_modobj)) { + float p1_xy[2], p2_xy[2], p3_xy[2], p4_xy[2], + p1_uv[] = {0.0, 0.0}, p2_uv[] = {1.0, 0.0}, p3_uv[] = {1.0, 1.0}, + p4_uv[] = {0.0, 1.0}; + int p1_mod[] = {255, 255, 255, 255}, p2_mod[] = {255, 255, 255, 255}, + p3_mod[] = {255, 255, 255, 255}, p4_mod[] = {255, 255, 255, 255}; + static char *keywords[] = {"p1_xy", "p2_xy", "p3_xy", "p4_xy", "p1_uv", + "p2_uv", "p3_uv", "p4_uv", "p1_mod", "p2_mod", + "p3_mod", "p4_mod", NULL}; + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "OOOO|OOOOOOOO", keywords, &p1_xyobj, &p2_xyobj, + &p3_xyobj, &p4_xyobj, &p1_uvobj, &p2_uvobj, &p3_uvobj, &p4_uvobj, + &p1_modobj, &p2_modobj, &p3_modobj, &p4_modobj)) { return NULL; /* Exception already set. */ } if (!pg_TwoFloatsFromObj(p1_xyobj, &p1_xy[0], &p1_xy[1])) { @@ -896,47 +962,60 @@ texture_draw_quad(pgTextureObject *self, PyObject *args, PyObject *kwargs) { if (!pg_TwoFloatsFromObj(p4_xyobj, &p4_xy[0], &p4_xy[1])) { return RAISE(PyExc_TypeError, "invalid p3_xy argument"); } - if (!Py_IsNone(p1_uvobj) && !pg_TwoFloatsFromObj(p1_uvobj, &p1_uv[0], &p1_uv[1])) { + if (!Py_IsNone(p1_uvobj) && + !pg_TwoFloatsFromObj(p1_uvobj, &p1_uv[0], &p1_uv[1])) { return RAISE(PyExc_TypeError, "invalid p1_uv argument"); } - if (!Py_IsNone(p2_uvobj) && !pg_TwoFloatsFromObj(p2_uvobj, &p2_uv[0], &p2_uv[1])) { + if (!Py_IsNone(p2_uvobj) && + !pg_TwoFloatsFromObj(p2_uvobj, &p2_uv[0], &p2_uv[1])) { return RAISE(PyExc_TypeError, "invalid p2_uv argument"); } - if (!Py_IsNone(p3_uvobj) && !pg_TwoFloatsFromObj(p3_uvobj, &p3_uv[0], &p3_uv[1])) { + if (!Py_IsNone(p3_uvobj) && + !pg_TwoFloatsFromObj(p3_uvobj, &p3_uv[0], &p3_uv[1])) { return RAISE(PyExc_TypeError, "invalid p3_uv argument"); } - if (!Py_IsNone(p4_uvobj) && !pg_TwoFloatsFromObj(p3_uvobj, &p4_uv[0], &p4_uv[1])) { + if (!Py_IsNone(p4_uvobj) && + !pg_TwoFloatsFromObj(p3_uvobj, &p4_uv[0], &p4_uv[1])) { return RAISE(PyExc_TypeError, "invalid p4_uv argument"); } if (!Py_IsNone(p1_modobj)) { - if (!pg_IntFromObjIndex(p1_modobj, 0, &p1_mod[0]) || !pg_IntFromObjIndex(p1_modobj, 1, &p1_mod[1]) || + if (!pg_IntFromObjIndex(p1_modobj, 0, &p1_mod[0]) || + !pg_IntFromObjIndex(p1_modobj, 1, &p1_mod[1]) || !pg_IntFromObjIndex(p1_modobj, 2, &p1_mod[2])) { return RAISE(PyExc_TypeError, "invalid p1_mod argument"); } - if (PySequence_Size(p1_modobj) == 4) pg_IntFromObjIndex(p1_modobj, 3, &p1_mod[3]); + if (PySequence_Size(p1_modobj) == 4) + pg_IntFromObjIndex(p1_modobj, 3, &p1_mod[3]); } if (!Py_IsNone(p2_modobj)) { - if (!pg_IntFromObjIndex(p2_modobj, 0, &p2_mod[0]) || !pg_IntFromObjIndex(p2_modobj, 1, &p2_mod[1]) || + if (!pg_IntFromObjIndex(p2_modobj, 0, &p2_mod[0]) || + !pg_IntFromObjIndex(p2_modobj, 1, &p2_mod[1]) || !pg_IntFromObjIndex(p2_modobj, 2, &p2_mod[2])) { return RAISE(PyExc_TypeError, "invalid p2_mod argument"); } - if (PySequence_Size(p2_modobj) == 4) pg_IntFromObjIndex(p2_modobj, 3, &p2_mod[3]); + if (PySequence_Size(p2_modobj) == 4) + pg_IntFromObjIndex(p2_modobj, 3, &p2_mod[3]); } if (!Py_IsNone(p3_modobj)) { - if (!pg_IntFromObjIndex(p3_modobj, 0, &p3_mod[0]) || !pg_IntFromObjIndex(p3_modobj, 1, &p3_mod[1]) || + if (!pg_IntFromObjIndex(p3_modobj, 0, &p3_mod[0]) || + !pg_IntFromObjIndex(p3_modobj, 1, &p3_mod[1]) || !pg_IntFromObjIndex(p3_modobj, 2, &p3_mod[2])) { return RAISE(PyExc_TypeError, "invalid p3_mod argument"); } - if (PySequence_Size(p3_modobj) == 4) pg_IntFromObjIndex(p3_modobj, 3, &p3_mod[3]); + if (PySequence_Size(p3_modobj) == 4) + pg_IntFromObjIndex(p3_modobj, 3, &p3_mod[3]); } if (!Py_IsNone(p4_modobj)) { - if (!pg_IntFromObjIndex(p4_modobj, 0, &p4_mod[0]) || !pg_IntFromObjIndex(p4_modobj, 1, &p4_mod[1]) || + if (!pg_IntFromObjIndex(p4_modobj, 0, &p4_mod[0]) || + !pg_IntFromObjIndex(p4_modobj, 1, &p4_mod[1]) || !pg_IntFromObjIndex(p4_modobj, 2, &p4_mod[2])) { return RAISE(PyExc_TypeError, "invalid p4_mod argument"); } - if (PySequence_Size(p4_modobj) == 4) pg_IntFromObjIndex(p4_modobj, 3, &p4_mod[3]); + if (PySequence_Size(p4_modobj) == 4) + pg_IntFromObjIndex(p4_modobj, 3, &p4_mod[3]); } - RENDERER_ERROR_CHECK(SDL_GetTextureColorMod(self->texture, &_r_mod, &_g_mod, &_b_mod)); + RENDERER_ERROR_CHECK( + SDL_GetTextureColorMod(self->texture, &_r_mod, &_g_mod, &_b_mod)); RENDERER_ERROR_CHECK(SDL_GetTextureAlphaMod(self->texture, &_a_mod)); r_mod = _r_mod / (float)255.0; @@ -944,19 +1023,56 @@ texture_draw_quad(pgTextureObject *self, PyObject *args, PyObject *kwargs) { b_mod = _b_mod / (float)255.0; a_mod = _a_mod / (float)255.0; - vertices[0].position.x = p1_xy[0]; vertices[0].position.y = p1_xy[1]; vertices[0].tex_coord.x = p1_uv[0]; vertices[0].tex_coord.y = p1_uv[1]; - vertices[0].color.r = (int)r_mod * p1_mod[0]; vertices[0].color.g = (int)g_mod * p1_mod[1]; vertices[0].color.b = (int)b_mod * p1_mod[2]; vertices[0].color.a = (int)a_mod * p1_mod[3]; - vertices[1].position.x = p2_xy[0]; vertices[1].position.y = p2_xy[1]; vertices[1].tex_coord.x = p2_uv[0]; vertices[1].tex_coord.y = p2_uv[1]; - vertices[1].color.r = (int)r_mod * p2_mod[0]; vertices[1].color.g = (int)g_mod * p2_mod[1]; vertices[1].color.b = (int)b_mod * p2_mod[2]; vertices[1].color.a = (int)a_mod * p2_mod[3]; - vertices[2].position.x = p3_xy[0]; vertices[2].position.y = p3_xy[1]; vertices[2].tex_coord.x = p3_uv[0]; vertices[2].tex_coord.y = p3_uv[1]; - vertices[2].color.r = (int)r_mod * p3_mod[0]; vertices[2].color.g = (int)g_mod * p3_mod[1]; vertices[2].color.b = (int)b_mod * p3_mod[2]; vertices[2].color.a = (int)a_mod * p3_mod[3]; - vertices[3].position.x = p3_xy[0]; vertices[3].position.y = p3_xy[1]; vertices[3].tex_coord.x = p3_uv[0]; vertices[3].tex_coord.y = p3_uv[1]; - vertices[3].color.r = (int)r_mod * p3_mod[0]; vertices[3].color.g = (int)g_mod * p3_mod[1]; vertices[3].color.b = (int)b_mod * p3_mod[2]; vertices[3].color.a = (int)a_mod * p3_mod[3]; - vertices[4].position.x = p4_xy[0]; vertices[4].position.y = p4_xy[1]; vertices[4].tex_coord.x = p4_uv[0]; vertices[4].tex_coord.y = p4_uv[1]; - vertices[4].color.r = (int)r_mod * p4_mod[0]; vertices[4].color.g = (int)g_mod * p4_mod[1]; vertices[4].color.b = (int)b_mod * p4_mod[2]; vertices[4].color.a = (int)a_mod * p4_mod[3]; - vertices[5].position.x = p1_xy[0]; vertices[5].position.y = p1_xy[1]; vertices[5].tex_coord.x = p1_uv[0]; vertices[5].tex_coord.y = p1_uv[1]; - vertices[5].color.r = (int)r_mod * p1_mod[0]; vertices[5].color.g = (int)g_mod * p1_mod[1]; vertices[5].color.b = (int)b_mod * p1_mod[2]; vertices[5].color.a = (int)a_mod * p1_mod[3]; - RENDERER_ERROR_CHECK(SDL_RenderGeometry(self->renderer->renderer, self->texture, vertices, 6, NULL, 0)) + vertices[0].position.x = p1_xy[0]; + vertices[0].position.y = p1_xy[1]; + vertices[0].tex_coord.x = p1_uv[0]; + vertices[0].tex_coord.y = p1_uv[1]; + vertices[0].color.r = (int)r_mod * p1_mod[0]; + vertices[0].color.g = (int)g_mod * p1_mod[1]; + vertices[0].color.b = (int)b_mod * p1_mod[2]; + vertices[0].color.a = (int)a_mod * p1_mod[3]; + vertices[1].position.x = p2_xy[0]; + vertices[1].position.y = p2_xy[1]; + vertices[1].tex_coord.x = p2_uv[0]; + vertices[1].tex_coord.y = p2_uv[1]; + vertices[1].color.r = (int)r_mod * p2_mod[0]; + vertices[1].color.g = (int)g_mod * p2_mod[1]; + vertices[1].color.b = (int)b_mod * p2_mod[2]; + vertices[1].color.a = (int)a_mod * p2_mod[3]; + vertices[2].position.x = p3_xy[0]; + vertices[2].position.y = p3_xy[1]; + vertices[2].tex_coord.x = p3_uv[0]; + vertices[2].tex_coord.y = p3_uv[1]; + vertices[2].color.r = (int)r_mod * p3_mod[0]; + vertices[2].color.g = (int)g_mod * p3_mod[1]; + vertices[2].color.b = (int)b_mod * p3_mod[2]; + vertices[2].color.a = (int)a_mod * p3_mod[3]; + vertices[3].position.x = p3_xy[0]; + vertices[3].position.y = p3_xy[1]; + vertices[3].tex_coord.x = p3_uv[0]; + vertices[3].tex_coord.y = p3_uv[1]; + vertices[3].color.r = (int)r_mod * p3_mod[0]; + vertices[3].color.g = (int)g_mod * p3_mod[1]; + vertices[3].color.b = (int)b_mod * p3_mod[2]; + vertices[3].color.a = (int)a_mod * p3_mod[3]; + vertices[4].position.x = p4_xy[0]; + vertices[4].position.y = p4_xy[1]; + vertices[4].tex_coord.x = p4_uv[0]; + vertices[4].tex_coord.y = p4_uv[1]; + vertices[4].color.r = (int)r_mod * p4_mod[0]; + vertices[4].color.g = (int)g_mod * p4_mod[1]; + vertices[4].color.b = (int)b_mod * p4_mod[2]; + vertices[4].color.a = (int)a_mod * p4_mod[3]; + vertices[5].position.x = p1_xy[0]; + vertices[5].position.y = p1_xy[1]; + vertices[5].tex_coord.x = p1_uv[0]; + vertices[5].tex_coord.y = p1_uv[1]; + vertices[5].color.r = (int)r_mod * p1_mod[0]; + vertices[5].color.g = (int)g_mod * p1_mod[1]; + vertices[5].color.b = (int)b_mod * p1_mod[2]; + vertices[5].color.a = (int)a_mod * p1_mod[3]; + RENDERER_ERROR_CHECK(SDL_RenderGeometry( + self->renderer->renderer, self->texture, vertices, 6, NULL, 0)) Py_RETURN_NONE; #else RAISE(PyExc_TypeError, "draw_triangle() requires SDL 2.0.18 or newer"); @@ -965,7 +1081,8 @@ texture_draw_quad(pgTextureObject *self, PyObject *args, PyObject *kwargs) { } static PyObject * -texture_update(pgTextureObject *self, PyObject *args, PyObject *kwargs) { +texture_update(pgTextureObject *self, PyObject *args, PyObject *kwargs) +{ pgSurfaceObject *surfobj; PyObject *rectobj = Py_None; SDL_Surface *surf = NULL; @@ -1003,11 +1120,13 @@ texture_update(pgTextureObject *self, PyObject *args, PyObject *kwargs) { area.w = surf->w; area.h = surf->h; } - RENDERER_ERROR_CHECK(SDL_QueryTexture(self->texture, &format, NULL, NULL, NULL)) + RENDERER_ERROR_CHECK( + SDL_QueryTexture(self->texture, &format, NULL, NULL, NULL)) if (format != surf->format->format) { RENDERER_ERROR_CHECK(SDL_GetSurfaceBlendMode(surf, &blend)) pixel_format = SDL_AllocFormat(format); - if (pixel_format == NULL) return RAISE(pgExc_SDLError, SDL_GetError()); + if (pixel_format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); converted_surf = SDL_ConvertSurface(surf, pixel_format, 0); if (SDL_SetSurfaceBlendMode(converted_surf, blend) < 0) { SDL_FreeSurface(converted_surf); @@ -1015,87 +1134,104 @@ texture_update(pgTextureObject *self, PyObject *args, PyObject *kwargs) { return RAISE(pgExc_SDLError, SDL_GetError()); } - res = SDL_UpdateTexture(self->texture, areaptr, converted_surf->pixels, converted_surf->pitch); + res = SDL_UpdateTexture(self->texture, areaptr, converted_surf->pixels, + converted_surf->pitch); SDL_FreeSurface(converted_surf); SDL_FreeFormat(pixel_format); } else { - res = SDL_UpdateTexture(self->texture, areaptr, surf->pixels, surf->pitch); + res = SDL_UpdateTexture(self->texture, areaptr, surf->pixels, + surf->pitch); } - if (res < 0) return RAISE(pgExc_SDLError, SDL_GetError()); + if (res < 0) + return RAISE(pgExc_SDLError, SDL_GetError()); Py_RETURN_NONE; } static PyObject * -texture_get_renderer(pgTextureObject *self, void *closure) { +texture_get_renderer(pgTextureObject *self, void *closure) +{ Py_INCREF(self->renderer); return (PyObject *)self->renderer; } static PyObject * -texture_get_width(pgTextureObject *self, void *closure) { +texture_get_width(pgTextureObject *self, void *closure) +{ return PyLong_FromLong(self->width); } static PyObject * -texture_get_height(pgTextureObject *self, void *closure) { +texture_get_height(pgTextureObject *self, void *closure) +{ return PyLong_FromLong(self->height); -} +} static PyObject * -texture_get_alpha(pgTextureObject *self, void *closure) { +texture_get_alpha(pgTextureObject *self, void *closure) +{ Uint8 alpha; RENDERER_ERROR_CHECK(SDL_GetTextureAlphaMod(self->texture, &alpha)); return PyLong_FromLong(alpha); } static int -texture_set_alpha(pgTextureObject *self, PyObject *arg, void *closure) { +texture_set_alpha(pgTextureObject *self, PyObject *arg, void *closure) +{ if (PyLong_Check(arg)) { unsigned long longval = PyLong_AsUnsignedLong(arg); - RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureAlphaMod(self->texture, (Uint8)longval)) + RENDERER_PROPERTY_ERROR_CHECK( + SDL_SetTextureAlphaMod(self->texture, (Uint8)longval)) return 0; } return -1; } static PyObject * -texture_get_blend_mode(pgTextureObject *self, void *closure) { +texture_get_blend_mode(pgTextureObject *self, void *closure) +{ SDL_BlendMode blend_mode; RENDERER_ERROR_CHECK(SDL_GetTextureBlendMode(self->texture, &blend_mode)); - return PyLong_FromLong((long) blend_mode); + return PyLong_FromLong((long)blend_mode); } static int -texture_set_blend_mode(pgTextureObject *self, PyObject *arg, void *closure) { +texture_set_blend_mode(pgTextureObject *self, PyObject *arg, void *closure) +{ if (PyLong_Check(arg)) { long longval = PyLong_AsLong(arg); - RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureBlendMode(self->texture, (int)longval)) + RENDERER_PROPERTY_ERROR_CHECK( + SDL_SetTextureBlendMode(self->texture, (int)longval)) return 0; } return 1; } static PyObject * -texture_get_color(pgTextureObject *self, void *closure) { +texture_get_color(pgTextureObject *self, void *closure) +{ Uint8 color[4]; - RENDERER_ERROR_CHECK(SDL_GetTextureColorMod(self->texture, &color[0], &color[1], &color[2])); + RENDERER_ERROR_CHECK(SDL_GetTextureColorMod(self->texture, &color[0], + &color[1], &color[2])); color[3] = 255; return pgColor_NewLength(color, 4); } static int -texture_set_color(pgTextureObject *self, PyObject *arg, void *closure) { +texture_set_color(pgTextureObject *self, PyObject *arg, void *closure) +{ Uint8 color[4]; if (!pg_RGBAFromObjEx(arg, color, PG_COLOR_HANDLE_ALL)) { return -1; } - RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureColorMod(self->texture, color[0], color[1], color[2])) + RENDERER_PROPERTY_ERROR_CHECK( + SDL_SetTextureColorMod(self->texture, color[0], color[1], color[2])) return 0; } static int -texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) { +texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) +{ SDL_Texture *texture = NULL; pgRendererObject *renderer; PyObject *sizeobj; @@ -1109,8 +1245,11 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) { int access = SDL_TEXTUREACCESS_STATIC; Uint32 format; - char *keywords[] = {"renderer", "size", "depth", "static", "streaming", "target", "scale_quality", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|ipppi", keywords, &renderer, &sizeobj, &depth, &staticc, &streaming, &target, &scale_quality)) { + char *keywords[] = {"renderer", "size", "depth", "static", + "streaming", "target", "scale_quality", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|ipppi", keywords, + &renderer, &sizeobj, &depth, &staticc, + &streaming, &target, &scale_quality)) { return -1; } format = format_from_depth(depth); @@ -1124,33 +1263,37 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) { } if (staticc) { if (streaming || target) { - RAISE(PyExc_ValueError, "only one of static, streaming, or target can be true"); + RAISE(PyExc_ValueError, + "only one of static, streaming, or target can be true"); return -1; } access = SDL_TEXTUREACCESS_STATIC; } if (streaming) { if (staticc || target) { - RAISE(PyExc_ValueError, "only one of static, streaming, or target can be true"); + RAISE(PyExc_ValueError, + "only one of static, streaming, or target can be true"); return -1; } access = SDL_TEXTUREACCESS_STREAMING; } if (target) { if (staticc || streaming) { - RAISE(PyExc_ValueError, "only one of static, streaming, or target can be true"); + RAISE(PyExc_ValueError, + "only one of static, streaming, or target can be true"); return -1; } access = SDL_TEXTUREACCESS_TARGET; } self->renderer = renderer; - self->texture = SDL_CreateTexture(renderer->renderer, format, access, width, height); + self->texture = + SDL_CreateTexture(renderer->renderer, format, access, width, height); if (!self->texture) { RAISE(pgExc_SDLError, SDL_GetError()); return -1; } if (scale_quality != -1) { -#if SDL_VERSION_ATLEAST(2,0,12) +#if SDL_VERSION_ATLEAST(2, 0, 12) if (SDL_SetTextureScaleMode(self->texture, scale_quality) < 0) { RAISE(pgExc_SDLError, SDL_GetError()); return -1; @@ -1158,11 +1301,14 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) { #else switch (scale_quality) { case 0: - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); break; + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); + break; case 1: - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); break; + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + break; case 2: - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); break; + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); + break; } #endif } @@ -1172,7 +1318,8 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) { } static void -texture_dealloc(pgTextureObject *self, PyObject *_null) { +texture_dealloc(pgTextureObject *self, PyObject *_null) +{ if (self->texture) { SDL_DestroyTexture(self->texture); } @@ -1244,16 +1391,16 @@ static PyMethodDef texture_methods[] = { DOC_SDL2_VIDEO_TEXTURE_GETRECT}, {"draw", (PyCFunction)texture_draw, METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_TEXTURE_DRAW}, - {"draw_triangle", (PyCFunction)texture_draw_triangle, METH_VARARGS | METH_KEYWORDS, - DOC_SDL2_VIDEO_TEXTURE_DRAWTRIANGLE}, + {"draw_triangle", (PyCFunction)texture_draw_triangle, + METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_TEXTURE_DRAWTRIANGLE}, {"draw_quad", (PyCFunction)texture_draw_quad, METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_TEXTURE_DRAWQUAD}, {"update", (PyCFunction)texture_update, METH_VARARGS | METH_KEYWORDS, - DOC_SDL2_VIDEO_TEXTURE_UPDATE}, - {"from_surface", (PyCFunction)from_surface, METH_VARARGS | METH_KEYWORDS | METH_CLASS, + DOC_SDL2_VIDEO_TEXTURE_UPDATE}, + {"from_surface", (PyCFunction)from_surface, + METH_VARARGS | METH_KEYWORDS | METH_CLASS, DOC_SDL2_VIDEO_TEXTURE_FROMSURFACE}, - {NULL, NULL, 0, NULL} -}; + {NULL, NULL, 0, NULL}}; static PyGetSetDef texture_getset[] = { {"renderer", (getter)texture_get_renderer, (setter)NULL, @@ -1264,12 +1411,11 @@ static PyGetSetDef texture_getset[] = { DOC_SDL2_VIDEO_TEXTURE_HEIGHT, NULL}, {"alpha", (getter)texture_get_alpha, (setter)texture_set_alpha, DOC_SDL2_VIDEO_TEXTURE_ALPHA, NULL}, - {"blend_mode", (getter)texture_get_blend_mode, (setter)texture_set_blend_mode, - DOC_SDL2_VIDEO_TEXTURE_BLENDMODE, NULL}, + {"blend_mode", (getter)texture_get_blend_mode, + (setter)texture_set_blend_mode, DOC_SDL2_VIDEO_TEXTURE_BLENDMODE, NULL}, {"color", (getter)texture_get_color, (setter)texture_set_color, DOC_SDL2_VIDEO_TEXTURE_COLOR, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; + {NULL, 0, NULL, NULL, NULL}}; static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; @@ -1293,8 +1439,7 @@ static PyTypeObject pgTexture_Type = { .tp_methods = texture_methods, .tp_init = (initproc)texture_init, .tp_new = PyType_GenericNew, - .tp_getset = texture_getset -}; + .tp_getset = texture_getset}; static PyTypeObject pgImage_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Image", From 990e0e14e647ccf9dd57fc33dc9799b9e9601fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Sat, 8 Feb 2025 12:14:35 +0100 Subject: [PATCH 17/22] Port Image to C code --- src_c/include/_pygame.h | 3 +- src_c/renderer.c | 425 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 389 insertions(+), 39 deletions(-) diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index 6e0fc30bde..9dba2affb2 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -545,7 +545,8 @@ typedef struct { pgColorObject *color; float angle; float alpha; - SDL_Point origin; + SDL_bool has_origin; + SDL_FPoint origin; SDL_bool flip_x; SDL_bool flip_y; SDL_BlendMode blend_mode; diff --git a/src_c/renderer.c b/src_c/renderer.c index fb99a450d8..fd29769ce5 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -62,6 +62,27 @@ format_from_depth(int depth) return SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask); } +static inline int +set_texture_blend_mode_helper(SDL_Texture* texture, SDL_BlendMode value) +{ + RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureBlendMode(texture, value)) + return 0; +} + +static inline int +set_texture_color_helper(SDL_Texture* texture, Uint8 r, Uint8 g, Uint8 b) +{ + RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureColorMod(texture, r, g, b)) + return 0; +} + +static inline int +set_texture_alpha_helper(SDL_Texture* texture, Uint8 alpha) +{ + RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureAlphaMod(texture, alpha)); + return 0; +} + /* Renderer implementation */ static PyObject * from_window(PyTypeObject *cls, PyObject *args, PyObject *kwargs) @@ -446,7 +467,7 @@ renderer_to_surface(pgRendererObject *self, PyObject *args, PyObject *kwargs) PyObject *surfobj = Py_None, *rectobj = Py_None; SDL_Surface *surf; pgSurfaceObject *surface; - SDL_Rect viewport, *areaparam, rarea; + SDL_Rect viewport, *areaparam, rarea, *rareaptr = &rarea; Uint32 format; static char *keywords[] = {"surface", "area", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", keywords, &surfobj, @@ -454,15 +475,15 @@ renderer_to_surface(pgRendererObject *self, PyObject *args, PyObject *kwargs) return NULL; } if (!Py_IsNone(rectobj)) { - if (!pgRect_FromObject(rectobj, &rarea)) { + if (!(rareaptr = pgRect_FromObject(rectobj, &rarea))) { return RAISE(PyExc_TypeError, "area must be None or a rect"); } SDL_RenderGetViewport(self->renderer, &viewport); - SDL_IntersectRect(&rarea, &viewport, &rarea); - areaparam = &rarea; + SDL_IntersectRect(rareaptr, &viewport, rareaptr); + areaparam = rareaptr; } else { - SDL_RenderGetViewport(self->renderer, &rarea); + SDL_RenderGetViewport(self->renderer, rareaptr); areaparam = NULL; } if (!Py_IsNone(surfobj)) { @@ -472,7 +493,7 @@ renderer_to_surface(pgRendererObject *self, PyObject *args, PyObject *kwargs) surface = (pgSurfaceObject *)surfobj; Py_INCREF(surface); surf = pgSurface_AsSurface(surfobj); - if (surf->w < rarea.w || surf->h < rarea.h) { + if (surf->w < rareaptr->w || surf->h < rareaptr->h) { return RAISE(PyExc_ValueError, "the surface is too small"); } format = surf->format->format; @@ -483,7 +504,7 @@ renderer_to_surface(pgRendererObject *self, PyObject *args, PyObject *kwargs) return RAISE(pgExc_SDLError, SDL_GetError()); } surf = SDL_CreateRGBSurfaceWithFormat( - 0, rarea.w, rarea.h, SDL_BITSPERPIXEL(format), format); + 0, rareaptr->w, rareaptr->h, SDL_BITSPERPIXEL(format), format); if (surf == NULL) { return RAISE(pgExc_SDLError, SDL_GetError()); } @@ -494,7 +515,6 @@ renderer_to_surface(pgRendererObject *self, PyObject *args, PyObject *kwargs) return (PyObject *)surface; } -// TODO MightyJosip For blit need Texture/Image static PyObject * renderer_blit(pgRendererObject *self, PyObject *args, PyObject *kwargs) { @@ -714,12 +734,12 @@ texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest) } if (!Py_IsNone(dest)) { if (!(dstrectptr = pgFRect_FromObject(dest, &dstrect))) { - if (!pg_TwoFloatsFromObj(dest, &dstrect.x, &dstrect.y)) { + if (!pg_TwoFloatsFromObj(dest, &dstrectptr->x, &dstrectptr->y)) { RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); } - dstrect.w = (float)self->width; - dstrect.h = (float)self->height; + dstrectptr->w = (float)self->width; + dstrectptr->h = (float)self->height; } } if (SDL_RenderCopyExF(self->renderer->renderer, self->texture, srcrectptr, @@ -790,12 +810,12 @@ texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) } if (!Py_IsNone(dstrectobj)) { if (!(dstrectptr = pgFRect_FromObject(dstrectobj, &dstrect))) { - if (!pg_TwoFloatsFromObj(dstrectobj, &dstrect.x, &dstrect.y)) { + if (!pg_TwoFloatsFromObj(dstrectobj, &dstrectptr->x, &dstrectptr->y)) { return RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); } - dstrect.w = (float)self->width; - dstrect.h = (float)self->height; + dstrectptr->w = (float)self->width; + dstrectptr->h = (float)self->height; } } if (!Py_IsNone(originobj)) { @@ -1112,13 +1132,13 @@ texture_update(pgTextureObject *self, PyObject *args, PyObject *kwargs) dst_height = self->height; } else { - dst_width = area.w; - dst_height = area.h; + dst_width = areaptr->w; + dst_height = areaptr->h; } if (dst_width > surf->w || dst_height > surf->h) { areaptr = &area; - area.w = surf->w; - area.h = surf->h; + areaptr->w = surf->w; + areaptr->h = surf->h; } RENDERER_ERROR_CHECK( SDL_QueryTexture(self->texture, &format, NULL, NULL, NULL)) @@ -1179,10 +1199,8 @@ static int texture_set_alpha(pgTextureObject *self, PyObject *arg, void *closure) { if (PyLong_Check(arg)) { - unsigned long longval = PyLong_AsUnsignedLong(arg); - RENDERER_PROPERTY_ERROR_CHECK( - SDL_SetTextureAlphaMod(self->texture, (Uint8)longval)) - return 0; + unsigned long ulongval = PyLong_AsUnsignedLong(arg); + return set_texture_alpha_helper(self->texture, (Uint8)ulongval); } return -1; } @@ -1200,9 +1218,7 @@ texture_set_blend_mode(pgTextureObject *self, PyObject *arg, void *closure) { if (PyLong_Check(arg)) { long longval = PyLong_AsLong(arg); - RENDERER_PROPERTY_ERROR_CHECK( - SDL_SetTextureBlendMode(self->texture, (int)longval)) - return 0; + return set_texture_blend_mode_helper(self->texture, (SDL_BlendMode)longval); } return 1; } @@ -1224,9 +1240,7 @@ texture_set_color(pgTextureObject *self, PyObject *arg, void *closure) if (!pg_RGBAFromObjEx(arg, color, PG_COLOR_HANDLE_ALL)) { return -1; } - RENDERER_PROPERTY_ERROR_CHECK( - SDL_SetTextureColorMod(self->texture, color[0], color[1], color[2])) - return 0; + return set_texture_color_helper(self->texture, color[0], color[1], color[2]); } static int @@ -1330,7 +1344,313 @@ texture_dealloc(pgTextureObject *self, PyObject *_null) static void image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) { - ; // TODO MightyJosip Implement with Image class + SDL_Rect tmp, *srcrectptr = NULL; + SDL_FRect ftmp, *dstrectptr = NULL; + SDL_FPoint* originptr = (self->has_origin) ? &self->origin : NULL; + SDL_RendererFlip flip = SDL_FLIP_NONE; + if (!Py_IsNone(area)) { + if (!(srcrectptr = pgRect_FromObject(area, &tmp))) { + RAISE(PyExc_ValueError, "srcrect must be a Rect or None"); + } + } + else { + srcrectptr = &self->srcrect->r; + } + if (!Py_IsNone(dest)) { + if (!(dstrectptr = pgFRect_FromObject(dest, &ftmp))) { + if (!pg_TwoFloatsFromObj(dest, &dstrectptr->x, &dstrectptr->y)) { + RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); + } + dstrectptr->w = (float)self->texture->width; + dstrectptr->h = (float)self->texture->height; + } + } + if (self->flip_x) + flip |= SDL_FLIP_HORIZONTAL; + if (self->flip_y) + flip |= SDL_FLIP_VERTICAL; + set_texture_color_helper(self->texture->texture, self->color->data[0], self->color->data[1], self->color->data[2]); + set_texture_alpha_helper(self->texture->texture, (Uint8)self->alpha); + set_texture_blend_mode_helper(self->texture->texture, self->blend_mode); + if (SDL_RenderCopyExF(self->texture->renderer->renderer, self->texture->texture, srcrectptr, dstrectptr, self->angle, originptr, flip) < 0) { + RAISE(pgExc_SDLError, SDL_GetError()); + } +} + +static PyObject * +image_get_rect(pgImageObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs) +{ + return pgRect_New(&(self->srcrect->r)); +} + +static PyObject * +image_draw(pgImageObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *srcrectobj = Py_None, *dstrectobj = Py_None; + SDL_Rect tmp, *srcrectptr = NULL; + SDL_FRect ftmp, *dstrectptr = NULL; + SDL_FPoint* originptr = (self->has_origin) ? &self->origin : NULL; + SDL_RendererFlip flip = SDL_FLIP_NONE; + static char *keywords[] = {"srcrect", "dstrect", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", keywords, + &srcrectobj, &dstrectobj)) { + return NULL; + } + if (!Py_IsNone(srcrectobj)) { + if (!(srcrectptr = pgRect_FromObject(srcrectobj, &tmp))) { + return RAISE(PyExc_ValueError, "srcrect must be a Rect or None"); + } + } + else { + srcrectptr = &self->srcrect->r; + } + if (!Py_IsNone(dstrectobj)) { + if (!(dstrectptr = pgFRect_FromObject(dstrectobj, &ftmp))) { + if (!pg_TwoFloatsFromObj(dstrectobj, &dstrectptr->x, &dstrectptr->y)) { + return RAISE(PyExc_ValueError, + "dstrect must be a point, Rect, or None"); + } + dstrectptr->w = (float)self->texture->width; + dstrectptr->h = (float)self->texture->height; + } + } + if (self->flip_x) + flip |= SDL_FLIP_HORIZONTAL; + if (self->flip_y) + flip |= SDL_FLIP_VERTICAL; + set_texture_color_helper(self->texture->texture, self->color->data[0], self->color->data[1], self->color->data[2]); + set_texture_alpha_helper(self->texture->texture, (Uint8)self->alpha); + set_texture_blend_mode_helper(self->texture->texture, self->blend_mode); + RENDERER_ERROR_CHECK(SDL_RenderCopyExF(self->texture->renderer->renderer, self->texture->texture, srcrectptr, dstrectptr, self->angle, originptr, flip)); + Py_RETURN_NONE; +} + +static PyObject * +image_get_alpha(pgImageObject *self, void *closure) +{ + return PyFloat_FromDouble((double)self->alpha); +} + +static int +image_set_alpha(pgImageObject *self, PyObject *arg, void *closure) +{ + if (!PyNumber_Check(arg)) { + RAISE(PyExc_TypeError, "alpha must be real number"); + return -1; + } + self->alpha = (float)PyFloat_AsDouble(arg); + return 0; +} + +static PyObject * +image_get_angle(pgImageObject *self, void *closure) +{ + return PyFloat_FromDouble((double)self->angle); +} + +static int +image_set_angle(pgImageObject *self, PyObject *arg, void *closure) +{ + if (!PyNumber_Check(arg)) { + RAISE(PyExc_TypeError, "angle must be real number"); + return -1; + } + self->angle = (float)PyFloat_AsDouble(arg); + return 0; +} + +static PyObject * +image_get_blend_mode(pgImageObject *self, void *closure) +{ + return PyLong_FromLong((long)self->blend_mode); +} + +static int +image_set_blend_mode(pgImageObject *self, PyObject *arg, void *closure) +{ + if (!PyLong_Check(arg)) { + RAISE(PyExc_TypeError, "Blend mode must be an integer"); + return -1; + } + self->blend_mode = (SDL_BlendMode)(PyLong_AsLong(arg)); + return 0; +} + +static PyObject * +image_get_color(pgImageObject *self, void *closure) +{ + Py_INCREF(self->color); + return (PyObject *)self->color; +} + +static int +image_set_color(pgImageObject *self, PyObject *arg, void *closure) +{ + Uint8 color[4]; + if (!pg_RGBAFromObjEx(arg, color, PG_COLOR_HANDLE_ALL)) { + RAISE(PyExc_TypeError, "Unable to convert argument to Color"); + return -1; + } + for (int i = 0; i < 3; i++) { + self->color->data[i] = color[i]; + } + return 0; +} + +static PyObject * +image_get_flip_x(pgImageObject *self, void *closure) +{ + return PyBool_FromLong(self->flip_x); +} + +static int +image_set_flip_x(pgImageObject *self, PyObject *arg, void *closure) +{ + int value = PyObject_IsTrue(arg); + if (value == -1) { + RAISE(PyExc_TypeError, "flip_x must be boolean value"); + return -1; + } + self->flip_x = (SDL_bool)value; + return 0; +} + +static PyObject * +image_get_flip_y(pgImageObject *self, void *closure) +{ + return PyBool_FromLong(self->flip_y); +} + +static int +image_set_flip_y(pgImageObject *self, PyObject *arg, void *closure) +{ + int value = PyObject_IsTrue(arg); + if (value == -1) { + RAISE(PyExc_TypeError, "flip_y must be boolean value"); + return -1; + } + self->flip_y = (SDL_bool)value; + return 0; +} + +static PyObject * +image_get_origin(pgImageObject *self, void *closure) +{ + if (!self->has_origin) { + Py_RETURN_NONE; + } + return pg_tuple_couple_from_values_double(self->origin.x, self->origin.y); +} + +static int +image_set_origin(pgImageObject *self, PyObject *arg, void *closure) +{ + if (!Py_IsNone(arg)) { + if (!pg_TwoFloatsFromObj(arg, &self->origin.x, &self->origin.y)) { + RAISE(PyExc_TypeError, "origin must be pair of floats"); + return -1; + } + self->has_origin = SDL_TRUE; + } + else { + self->has_origin = SDL_FALSE; + } + return 0; +} + +static PyObject * +image_get_srcrect(pgImageObject *self, void *closure) +{ + Py_INCREF(self->srcrect); + return (PyObject *)self->srcrect; +} + +static int +image_set_srcrect(pgImageObject *self, PyObject *arg, void *closure) +{ + SDL_Rect *rect, temp; + if (!(rect = pgRect_FromObject(arg, &temp))) { + RAISE(PyExc_TypeError, "srcrect must be a rectangle"); + return -1; + } + self->srcrect = (pgRectObject *)pgRect_New(rect); + return 0; +} + +static PyObject * +image_get_texture(pgImageObject *self, void *closure) +{ + Py_INCREF(self->texture); + return (PyObject *)self->texture; +} + +static int +image_set_texture(pgImageObject *self, PyObject *arg, void *closure) { + if (!pgTexture_Check(arg)) { + RAISE(PyExc_TypeError, "texture must be a Texture"); + return -1; + } + self->texture = (pgTextureObject *)arg; + return 0; +} + +static int +image_init(pgImageObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *texture_or_imageobj, *srcrectobj = Py_None; + pgTextureObject *textureprt; + SDL_Rect *rect, temp, old_srcrect; + Uint8 rgba[4] = {255, 255, 255, 255}; + char *keywords[] = {"texture_or_image", "srcrect", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", keywords, + &texture_or_imageobj, &srcrectobj)) { + return -1; + } + if (pgTexture_Check(texture_or_imageobj)) { + textureprt = (pgTextureObject *)texture_or_imageobj; + temp = (SDL_Rect) {0, 0, textureprt->width, textureprt->height}; + } + else if (pgImage_Check(texture_or_imageobj)) { + textureprt = ((pgImageObject *)texture_or_imageobj)->texture; + temp = ((pgImageObject *)texture_or_imageobj)->srcrect->r; + } + else { + RAISE(PyExc_AttributeError, "First argument must be either Texture or Image object"); + return -1; + } + self->texture = textureprt; + if (Py_IsNone(srcrectobj)) { + self->srcrect = (pgRectObject *)pgRect_New(&temp); + } + else { + old_srcrect = temp; + if (!(rect = pgRect_FromObject(srcrectobj, &temp))) { + RAISE(PyExc_TypeError, "srcrect must be a rectangle or None"); + return -1; + } + if (rect->x < 0 || rect->y < 0 || rect->w < 0 || rect->h < 0 || rect->x + rect->w > old_srcrect.w || rect->y + rect->h > old_srcrect.h) { + RAISE(PyExc_ValueError, "srcrect values are out of range"); + return -1; + } + rect->x += old_srcrect.x; + rect->y += old_srcrect.y; + self->srcrect = (pgRectObject *)pgRect_New(rect); + } + self->angle = 0; + self->origin.x = 0; + self->origin.y = 0; + self->has_origin = SDL_FALSE; + self->flip_x = SDL_FALSE; + self->flip_y = SDL_FALSE; + self->alpha = 255; + self->color = (pgColorObject *)pgColor_NewLength(rgba, 4); + return 0; +} + +static void +image_dealloc(pgTextureObject *self, PyObject *_null) +{ + Py_TYPE(self)->tp_free((PyObject *)self); } /* Module definition */ @@ -1369,7 +1689,8 @@ static PyMethodDef renderer_methods[] = { METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_TOSURFACE}, {"blit", (PyCFunction)renderer_blit, METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_SETVIEWPORT}, - {NULL, NULL, 0, NULL}}; + {NULL, NULL, 0, NULL} +}; static PyGetSetDef renderer_getset[] = { {"draw_color", (getter)renderer_get_draw_color, @@ -1384,7 +1705,8 @@ static PyGetSetDef renderer_getset[] = { DOC_SDL2_VIDEO_RENDERER_SCALE, NULL}, {"target", (getter)renderer_get_target, (setter)renderer_set_target, DOC_SDL2_VIDEO_RENDERER_TARGET, NULL}, - {NULL, 0, NULL, NULL, NULL}}; + {NULL, 0, NULL, NULL, NULL} +}; static PyMethodDef texture_methods[] = { {"get_rect", (PyCFunction)texture_get_rect, METH_FASTCALL | METH_KEYWORDS, @@ -1415,11 +1737,38 @@ static PyGetSetDef texture_getset[] = { (setter)texture_set_blend_mode, DOC_SDL2_VIDEO_TEXTURE_BLENDMODE, NULL}, {"color", (getter)texture_get_color, (setter)texture_set_color, DOC_SDL2_VIDEO_TEXTURE_COLOR, NULL}, - {NULL, 0, NULL, NULL, NULL}}; - -static PyMethodDef image_methods[] = {{NULL, NULL, 0, NULL}}; - -static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; + {NULL, 0, NULL, NULL, NULL} +}; + +static PyMethodDef image_methods[] = { + {"get_rect", (PyCFunction)image_get_rect, METH_NOARGS, + DOC_SDL2_VIDEO_IMAGE_GETRECT}, + {"draw", (PyCFunction)image_draw, METH_VARARGS | METH_KEYWORDS, + DOC_SDL2_VIDEO_IMAGE_DRAW}, + {NULL, NULL, 0, NULL} +}; + +static PyGetSetDef image_getset[] = { + {"alpha", (getter)image_get_alpha, (setter)image_set_alpha, + DOC_SDL2_VIDEO_IMAGE_ALPHA, NULL}, + {"angle", (getter)image_get_angle, (setter)image_set_angle, + DOC_SDL2_VIDEO_IMAGE_ANGLE, NULL}, + {"blend_mode", (getter)image_get_blend_mode, (setter)image_set_blend_mode, + DOC_SDL2_VIDEO_IMAGE_BLENDMODE, NULL}, + {"color", (getter)image_get_color, (setter)image_set_color, + DOC_SDL2_VIDEO_IMAGE_COLOR, NULL}, + {"flip_x", (getter)image_get_flip_x, (setter)image_set_flip_x, + DOC_SDL2_VIDEO_IMAGE_FLIPX, NULL}, + {"flip_y", (getter)image_get_flip_y, (setter)image_set_flip_y, + DOC_SDL2_VIDEO_IMAGE_FLIPY, NULL}, + {"origin", (getter)image_get_origin, (setter)image_set_origin, + DOC_SDL2_VIDEO_IMAGE_ORIGIN, NULL}, + {"srcrect", (getter)image_get_srcrect, (setter)image_set_srcrect, + DOC_SDL2_VIDEO_IMAGE_SRCRECT, NULL}, + {"texture", (getter)image_get_texture, (setter)image_set_texture, + DOC_SDL2_VIDEO_IMAGE_TEXTURE, NULL}, + {NULL, 0, NULL, NULL, NULL} +}; static PyTypeObject pgRenderer_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Renderer", @@ -1444,9 +1793,9 @@ static PyTypeObject pgTexture_Type = { static PyTypeObject pgImage_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Image", .tp_basicsize = sizeof(pgImageObject), - //.tp_dealloc = (destructor)image_dealloc, + .tp_dealloc = (destructor)image_dealloc, .tp_doc = DOC_SDL2_VIDEO_IMAGE, .tp_methods = image_methods, - //.tp_init = (initproc)image_init, + .tp_init = (initproc)image_init, .tp_new = PyType_GenericNew, .tp_getset = image_getset}; static PyMethodDef _renderer_methods[] = {{NULL, NULL, 0, NULL}}; From 852440bfa257a1880386300f0c26952cc0fc4c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Sat, 8 Feb 2025 13:26:38 +0100 Subject: [PATCH 18/22] Port Image to C code --- src_c/renderer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src_c/renderer.c b/src_c/renderer.c index fd29769ce5..56754b4a09 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -1600,6 +1600,7 @@ image_init(pgImageObject *self, PyObject *args, PyObject *kwargs) PyObject *texture_or_imageobj, *srcrectobj = Py_None; pgTextureObject *textureprt; SDL_Rect *rect, temp, old_srcrect; + SDL_BlendMode blend_mode; Uint8 rgba[4] = {255, 255, 255, 255}; char *keywords[] = {"texture_or_image", "srcrect", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", keywords, @@ -1636,7 +1637,9 @@ image_init(pgImageObject *self, PyObject *args, PyObject *kwargs) rect->y += old_srcrect.y; self->srcrect = (pgRectObject *)pgRect_New(rect); } + RENDERER_PROPERTY_ERROR_CHECK(SDL_GetTextureBlendMode(self->texture->texture, &blend_mode)); self->angle = 0; + self->blend_mode = blend_mode; self->origin.x = 0; self->origin.y = 0; self->has_origin = SDL_FALSE; From a288e3a3419c42cee15a05c4e4f0cb5d29790849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Sat, 8 Feb 2025 15:01:28 +0100 Subject: [PATCH 19/22] Port Image to C code --- src_c/renderer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src_c/renderer.c b/src_c/renderer.c index 56754b4a09..4d7cff295e 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -1620,6 +1620,7 @@ image_init(pgImageObject *self, PyObject *args, PyObject *kwargs) return -1; } self->texture = textureprt; + Py_INCREF(self->texture); if (Py_IsNone(srcrectobj)) { self->srcrect = (pgRectObject *)pgRect_New(&temp); } From cb17e50a66c9f4caa620e0a63c99583353380e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Sat, 8 Feb 2025 15:16:19 +0100 Subject: [PATCH 20/22] Port Image to C code --- src_c/renderer.c | 78 ++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/src_c/renderer.c b/src_c/renderer.c index 4d7cff295e..dc3f4b0e38 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -63,21 +63,21 @@ format_from_depth(int depth) } static inline int -set_texture_blend_mode_helper(SDL_Texture* texture, SDL_BlendMode value) +set_texture_blend_mode_helper(SDL_Texture *texture, SDL_BlendMode value) { RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureBlendMode(texture, value)) return 0; } static inline int -set_texture_color_helper(SDL_Texture* texture, Uint8 r, Uint8 g, Uint8 b) +set_texture_color_helper(SDL_Texture *texture, Uint8 r, Uint8 g, Uint8 b) { RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureColorMod(texture, r, g, b)) return 0; } static inline int -set_texture_alpha_helper(SDL_Texture* texture, Uint8 alpha) +set_texture_alpha_helper(SDL_Texture *texture, Uint8 alpha) { RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureAlphaMod(texture, alpha)); return 0; @@ -810,7 +810,8 @@ texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) } if (!Py_IsNone(dstrectobj)) { if (!(dstrectptr = pgFRect_FromObject(dstrectobj, &dstrect))) { - if (!pg_TwoFloatsFromObj(dstrectobj, &dstrectptr->x, &dstrectptr->y)) { + if (!pg_TwoFloatsFromObj(dstrectobj, &dstrectptr->x, + &dstrectptr->y)) { return RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); } @@ -1218,7 +1219,8 @@ texture_set_blend_mode(pgTextureObject *self, PyObject *arg, void *closure) { if (PyLong_Check(arg)) { long longval = PyLong_AsLong(arg); - return set_texture_blend_mode_helper(self->texture, (SDL_BlendMode)longval); + return set_texture_blend_mode_helper(self->texture, + (SDL_BlendMode)longval); } return 1; } @@ -1240,7 +1242,8 @@ texture_set_color(pgTextureObject *self, PyObject *arg, void *closure) if (!pg_RGBAFromObjEx(arg, color, PG_COLOR_HANDLE_ALL)) { return -1; } - return set_texture_color_helper(self->texture, color[0], color[1], color[2]); + return set_texture_color_helper(self->texture, color[0], color[1], + color[2]); } static int @@ -1346,7 +1349,7 @@ image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) { SDL_Rect tmp, *srcrectptr = NULL; SDL_FRect ftmp, *dstrectptr = NULL; - SDL_FPoint* originptr = (self->has_origin) ? &self->origin : NULL; + SDL_FPoint *originptr = (self->has_origin) ? &self->origin : NULL; SDL_RendererFlip flip = SDL_FLIP_NONE; if (!Py_IsNone(area)) { if (!(srcrectptr = pgRect_FromObject(area, &tmp))) { @@ -1359,7 +1362,8 @@ image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) if (!Py_IsNone(dest)) { if (!(dstrectptr = pgFRect_FromObject(dest, &ftmp))) { if (!pg_TwoFloatsFromObj(dest, &dstrectptr->x, &dstrectptr->y)) { - RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); + RAISE(PyExc_ValueError, + "dstrect must be a point, Rect, or None"); } dstrectptr->w = (float)self->texture->width; dstrectptr->h = (float)self->texture->height; @@ -1369,16 +1373,20 @@ image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) flip |= SDL_FLIP_HORIZONTAL; if (self->flip_y) flip |= SDL_FLIP_VERTICAL; - set_texture_color_helper(self->texture->texture, self->color->data[0], self->color->data[1], self->color->data[2]); + set_texture_color_helper(self->texture->texture, self->color->data[0], + self->color->data[1], self->color->data[2]); set_texture_alpha_helper(self->texture->texture, (Uint8)self->alpha); set_texture_blend_mode_helper(self->texture->texture, self->blend_mode); - if (SDL_RenderCopyExF(self->texture->renderer->renderer, self->texture->texture, srcrectptr, dstrectptr, self->angle, originptr, flip) < 0) { + if (SDL_RenderCopyExF(self->texture->renderer->renderer, + self->texture->texture, srcrectptr, dstrectptr, + self->angle, originptr, flip) < 0) { RAISE(pgExc_SDLError, SDL_GetError()); } } static PyObject * -image_get_rect(pgImageObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs) +image_get_rect(pgImageObject *self, PyObject *const *args, Py_ssize_t nargs, + PyObject *kwargs) { return pgRect_New(&(self->srcrect->r)); } @@ -1389,7 +1397,7 @@ image_draw(pgImageObject *self, PyObject *args, PyObject *kwargs) PyObject *srcrectobj = Py_None, *dstrectobj = Py_None; SDL_Rect tmp, *srcrectptr = NULL; SDL_FRect ftmp, *dstrectptr = NULL; - SDL_FPoint* originptr = (self->has_origin) ? &self->origin : NULL; + SDL_FPoint *originptr = (self->has_origin) ? &self->origin : NULL; SDL_RendererFlip flip = SDL_FLIP_NONE; static char *keywords[] = {"srcrect", "dstrect", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", keywords, @@ -1406,7 +1414,8 @@ image_draw(pgImageObject *self, PyObject *args, PyObject *kwargs) } if (!Py_IsNone(dstrectobj)) { if (!(dstrectptr = pgFRect_FromObject(dstrectobj, &ftmp))) { - if (!pg_TwoFloatsFromObj(dstrectobj, &dstrectptr->x, &dstrectptr->y)) { + if (!pg_TwoFloatsFromObj(dstrectobj, &dstrectptr->x, + &dstrectptr->y)) { return RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); } @@ -1418,10 +1427,13 @@ image_draw(pgImageObject *self, PyObject *args, PyObject *kwargs) flip |= SDL_FLIP_HORIZONTAL; if (self->flip_y) flip |= SDL_FLIP_VERTICAL; - set_texture_color_helper(self->texture->texture, self->color->data[0], self->color->data[1], self->color->data[2]); + set_texture_color_helper(self->texture->texture, self->color->data[0], + self->color->data[1], self->color->data[2]); set_texture_alpha_helper(self->texture->texture, (Uint8)self->alpha); set_texture_blend_mode_helper(self->texture->texture, self->blend_mode); - RENDERER_ERROR_CHECK(SDL_RenderCopyExF(self->texture->renderer->renderer, self->texture->texture, srcrectptr, dstrectptr, self->angle, originptr, flip)); + RENDERER_ERROR_CHECK(SDL_RenderCopyExF( + self->texture->renderer->renderer, self->texture->texture, srcrectptr, + dstrectptr, self->angle, originptr, flip)); Py_RETURN_NONE; } @@ -1585,7 +1597,8 @@ image_get_texture(pgImageObject *self, void *closure) } static int -image_set_texture(pgImageObject *self, PyObject *arg, void *closure) { +image_set_texture(pgImageObject *self, PyObject *arg, void *closure) +{ if (!pgTexture_Check(arg)) { RAISE(PyExc_TypeError, "texture must be a Texture"); return -1; @@ -1609,14 +1622,15 @@ image_init(pgImageObject *self, PyObject *args, PyObject *kwargs) } if (pgTexture_Check(texture_or_imageobj)) { textureprt = (pgTextureObject *)texture_or_imageobj; - temp = (SDL_Rect) {0, 0, textureprt->width, textureprt->height}; + temp = (SDL_Rect){0, 0, textureprt->width, textureprt->height}; } else if (pgImage_Check(texture_or_imageobj)) { textureprt = ((pgImageObject *)texture_or_imageobj)->texture; temp = ((pgImageObject *)texture_or_imageobj)->srcrect->r; } else { - RAISE(PyExc_AttributeError, "First argument must be either Texture or Image object"); + RAISE(PyExc_AttributeError, + "First argument must be either Texture or Image object"); return -1; } self->texture = textureprt; @@ -1630,7 +1644,9 @@ image_init(pgImageObject *self, PyObject *args, PyObject *kwargs) RAISE(PyExc_TypeError, "srcrect must be a rectangle or None"); return -1; } - if (rect->x < 0 || rect->y < 0 || rect->w < 0 || rect->h < 0 || rect->x + rect->w > old_srcrect.w || rect->y + rect->h > old_srcrect.h) { + if (rect->x < 0 || rect->y < 0 || rect->w < 0 || rect->h < 0 || + rect->x + rect->w > old_srcrect.w || + rect->y + rect->h > old_srcrect.h) { RAISE(PyExc_ValueError, "srcrect values are out of range"); return -1; } @@ -1638,7 +1654,8 @@ image_init(pgImageObject *self, PyObject *args, PyObject *kwargs) rect->y += old_srcrect.y; self->srcrect = (pgRectObject *)pgRect_New(rect); } - RENDERER_PROPERTY_ERROR_CHECK(SDL_GetTextureBlendMode(self->texture->texture, &blend_mode)); + RENDERER_PROPERTY_ERROR_CHECK( + SDL_GetTextureBlendMode(self->texture->texture, &blend_mode)); self->angle = 0; self->blend_mode = blend_mode; self->origin.x = 0; @@ -1693,8 +1710,7 @@ static PyMethodDef renderer_methods[] = { METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_TOSURFACE}, {"blit", (PyCFunction)renderer_blit, METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_RENDERER_SETVIEWPORT}, - {NULL, NULL, 0, NULL} -}; + {NULL, NULL, 0, NULL}}; static PyGetSetDef renderer_getset[] = { {"draw_color", (getter)renderer_get_draw_color, @@ -1709,8 +1725,7 @@ static PyGetSetDef renderer_getset[] = { DOC_SDL2_VIDEO_RENDERER_SCALE, NULL}, {"target", (getter)renderer_get_target, (setter)renderer_set_target, DOC_SDL2_VIDEO_RENDERER_TARGET, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; + {NULL, 0, NULL, NULL, NULL}}; static PyMethodDef texture_methods[] = { {"get_rect", (PyCFunction)texture_get_rect, METH_FASTCALL | METH_KEYWORDS, @@ -1741,16 +1756,14 @@ static PyGetSetDef texture_getset[] = { (setter)texture_set_blend_mode, DOC_SDL2_VIDEO_TEXTURE_BLENDMODE, NULL}, {"color", (getter)texture_get_color, (setter)texture_set_color, DOC_SDL2_VIDEO_TEXTURE_COLOR, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; + {NULL, 0, NULL, NULL, NULL}}; static PyMethodDef image_methods[] = { {"get_rect", (PyCFunction)image_get_rect, METH_NOARGS, DOC_SDL2_VIDEO_IMAGE_GETRECT}, {"draw", (PyCFunction)image_draw, METH_VARARGS | METH_KEYWORDS, DOC_SDL2_VIDEO_IMAGE_DRAW}, - {NULL, NULL, 0, NULL} -}; + {NULL, NULL, 0, NULL}}; static PyGetSetDef image_getset[] = { {"alpha", (getter)image_get_alpha, (setter)image_set_alpha, @@ -1771,8 +1784,7 @@ static PyGetSetDef image_getset[] = { DOC_SDL2_VIDEO_IMAGE_SRCRECT, NULL}, {"texture", (getter)image_get_texture, (setter)image_set_texture, DOC_SDL2_VIDEO_IMAGE_TEXTURE, NULL}, - {NULL, 0, NULL, NULL, NULL} -}; + {NULL, 0, NULL, NULL, NULL}}; static PyTypeObject pgRenderer_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Renderer", @@ -1798,9 +1810,11 @@ static PyTypeObject pgImage_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Image", .tp_basicsize = sizeof(pgImageObject), .tp_dealloc = (destructor)image_dealloc, - .tp_doc = DOC_SDL2_VIDEO_IMAGE, .tp_methods = image_methods, + .tp_doc = DOC_SDL2_VIDEO_IMAGE, + .tp_methods = image_methods, .tp_init = (initproc)image_init, - .tp_new = PyType_GenericNew, .tp_getset = image_getset}; + .tp_new = PyType_GenericNew, + .tp_getset = image_getset}; static PyMethodDef _renderer_methods[] = {{NULL, NULL, 0, NULL}}; From 2f2d6fe2ff2b47b7beee80139cc3e4f1ec5d391c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Sat, 8 Feb 2025 16:39:37 +0100 Subject: [PATCH 21/22] Port Image to C code --- src_c/renderer.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/src_c/renderer.c b/src_c/renderer.c index dc3f4b0e38..25079563ba 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -1286,7 +1286,7 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) } access = SDL_TEXTUREACCESS_STATIC; } - if (streaming) { + else if (streaming) { if (staticc || target) { RAISE(PyExc_ValueError, "only one of static, streaming, or target can be true"); @@ -1294,7 +1294,7 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) } access = SDL_TEXTUREACCESS_STREAMING; } - if (target) { + else if (target) { if (staticc || streaming) { RAISE(PyExc_ValueError, "only one of static, streaming, or target can be true"); @@ -1310,24 +1310,7 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) return -1; } if (scale_quality != -1) { -#if SDL_VERSION_ATLEAST(2, 0, 12) - if (SDL_SetTextureScaleMode(self->texture, scale_quality) < 0) { - RAISE(pgExc_SDLError, SDL_GetError()); - return -1; - } -#else - switch (scale_quality) { - case 0: - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); - break; - case 1: - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); - break; - case 2: - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); - break; - } -#endif + RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureScaleMode(self->texture, scale_quality) < 0); } self->width = width; self->height = height; From 3d7afd93550f8f0d4f4cff85101813ce65ab25c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Sat, 8 Feb 2025 17:18:29 +0100 Subject: [PATCH 22/22] Port Image to C code --- src_c/renderer.c | 56 +++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/src_c/renderer.c b/src_c/renderer.c index 25079563ba..61e7c7c5af 100644 --- a/src_c/renderer.c +++ b/src_c/renderer.c @@ -83,6 +83,19 @@ set_texture_alpha_helper(SDL_Texture *texture, Uint8 alpha) return 0; } +static inline SDL_FRect * +parse_dest_rect(pgTextureObject *texture, PyObject *dstrectobj, SDL_FRect *tmp) +{ + SDL_FRect *dstrectptr = NULL; + if (!(dstrectptr = pgFRect_FromObject(dstrectobj, tmp))) { + if (pg_TwoFloatsFromObj(dstrectobj, &dstrectptr->x, &dstrectptr->y)) { + dstrectptr->w = (float)texture->width; + dstrectptr->h = (float)texture->height; + } + } + return dstrectptr; +} + /* Renderer implementation */ static PyObject * from_window(PyTypeObject *cls, PyObject *args, PyObject *kwargs) @@ -733,13 +746,8 @@ texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest) } } if (!Py_IsNone(dest)) { - if (!(dstrectptr = pgFRect_FromObject(dest, &dstrect))) { - if (!pg_TwoFloatsFromObj(dest, &dstrectptr->x, &dstrectptr->y)) { - RAISE(PyExc_ValueError, - "dstrect must be a point, Rect, or None"); - } - dstrectptr->w = (float)self->width; - dstrectptr->h = (float)self->height; + if (!(dstrectptr = parse_dest_rect(self, dest, &dstrect))) { + RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); } } if (SDL_RenderCopyExF(self->renderer->renderer, self->texture, srcrectptr, @@ -809,14 +817,9 @@ texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) } } if (!Py_IsNone(dstrectobj)) { - if (!(dstrectptr = pgFRect_FromObject(dstrectobj, &dstrect))) { - if (!pg_TwoFloatsFromObj(dstrectobj, &dstrectptr->x, - &dstrectptr->y)) { - return RAISE(PyExc_ValueError, - "dstrect must be a point, Rect, or None"); - } - dstrectptr->w = (float)self->width; - dstrectptr->h = (float)self->height; + if (!(dstrectptr = parse_dest_rect(self, dstrectobj, &dstrect))) { + return RAISE(PyExc_ValueError, + "dstrect must be a point, Rect, or None"); } } if (!Py_IsNone(originobj)) { @@ -1310,7 +1313,8 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) return -1; } if (scale_quality != -1) { - RENDERER_PROPERTY_ERROR_CHECK(SDL_SetTextureScaleMode(self->texture, scale_quality) < 0); + RENDERER_PROPERTY_ERROR_CHECK( + SDL_SetTextureScaleMode(self->texture, scale_quality) < 0); } self->width = width; self->height = height; @@ -1343,13 +1347,8 @@ image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) srcrectptr = &self->srcrect->r; } if (!Py_IsNone(dest)) { - if (!(dstrectptr = pgFRect_FromObject(dest, &ftmp))) { - if (!pg_TwoFloatsFromObj(dest, &dstrectptr->x, &dstrectptr->y)) { - RAISE(PyExc_ValueError, - "dstrect must be a point, Rect, or None"); - } - dstrectptr->w = (float)self->texture->width; - dstrectptr->h = (float)self->texture->height; + if (!(dstrectptr = parse_dest_rect(self->texture, dest, &ftmp))) { + RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); } } if (self->flip_x) @@ -1396,14 +1395,9 @@ image_draw(pgImageObject *self, PyObject *args, PyObject *kwargs) srcrectptr = &self->srcrect->r; } if (!Py_IsNone(dstrectobj)) { - if (!(dstrectptr = pgFRect_FromObject(dstrectobj, &ftmp))) { - if (!pg_TwoFloatsFromObj(dstrectobj, &dstrectptr->x, - &dstrectptr->y)) { - return RAISE(PyExc_ValueError, - "dstrect must be a point, Rect, or None"); - } - dstrectptr->w = (float)self->texture->width; - dstrectptr->h = (float)self->texture->height; + if (!(dstrectptr = + parse_dest_rect(self->texture, dstrectobj, &ftmp))) { + RAISE(PyExc_ValueError, "dstrect must be a point, Rect, or None"); } } if (self->flip_x)