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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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 f83daad922af43b00c1d67d8fb69defea6945fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Thu, 15 May 2025 11:39:09 +0200 Subject: [PATCH 17/21] Port Texture to C code --- src_c/render.c | 583 +++++++++++++++++- src_c/renderer.c | 1542 ---------------------------------------------- src_c/static.c | 1 - 3 files changed, 576 insertions(+), 1550 deletions(-) delete mode 100644 src_c/renderer.c diff --git a/src_c/render.c b/src_c/render.c index 7dbdf29ccc..3282c784be 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -35,6 +35,20 @@ static PyTypeObject pgImage_Type; return RAISE(PyExc_TypeError, "invalid " #name " argument"); \ } +#define PARSE_COLOR(obj, r, g, b, a, name) \ + if (Py_IsNone(obj)) { \ + r = 255; g = 255; b = 255; a = 255; \ + } \ + else { \ + if (!pg_IntFromObjIndex(obj, 0, &r) || \ + !pg_IntFromObjIndex(obj, 1, &g) || \ + !pg_IntFromObjIndex(obj, 2, &b)) { \ + return RAISE(PyExc_TypeError, "invalid " #name " argument"); \ + } \ + if (PySequence_Size(obj) == 4) \ + pg_IntFromObjIndex(obj, 3, &a); \ + } + static void texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest); @@ -546,7 +560,527 @@ renderer_dealloc(pgRendererObject *self, PyObject *_null) static void texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest) { - return; + 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 * +texture_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; + int p1_mod[4], p2_mod[4], p3_mod[4]; + SDL_Vertex vertices[3]; + 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. */ + } + /* Parse position */ + PARSE_POINT(p1_xyobj, vertices[0].position.x, vertices[0].position.y, "p1_xy") + PARSE_POINT(p2_xyobj, vertices[1].position.x, vertices[1].position.y, "p2_xy") + PARSE_POINT(p3_xyobj, vertices[2].position.x, vertices[2].position.y, "p3_xy") + /* Parse tex_coord */ + if (Py_IsNone(p1_uvobj)) { + vertices[0].tex_coord.x = 0.0; + vertices[0].tex_coord.y = 0.0; + } + else { + PARSE_POINT(p1_xyobj, vertices[0].tex_coord.x, vertices[0].tex_coord.y, "p1_uv") + } + if (Py_IsNone(p2_uvobj)) { + vertices[1].tex_coord.x = 1.0; + vertices[1].tex_coord.y = 1.0; + } + else { + PARSE_POINT(p2_xyobj, vertices[1].tex_coord.x, vertices[1].tex_coord.y, "p2_uv") + } + if (Py_IsNone(p3_uvobj)) { + vertices[2].tex_coord.x = 0.0; + vertices[2].tex_coord.y = 1.0; + } + else { + PARSE_POINT(p3_xyobj, vertices[2].tex_coord.x, vertices[2].tex_coord.y, "p3_uv") + } + /* Parse color */ + PARSE_COLOR(p1_modobj, p1_mod[0], p1_mod[1], p1_mod[2], p1_mod[3], "p1_mod") + PARSE_COLOR(p2_modobj, p2_mod[0], p2_mod[1], p2_mod[2], p2_mod[3], "p2_mod") + PARSE_COLOR(p3_modobj, p3_mod[0], p3_mod[1], p3_mod[2], p3_mod[3], "p3_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 / 255.0; + g_mod = _g_mod / 255.0; + b_mod = _b_mod / 255.0; + a_mod = _a_mod / 255.0; + 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].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].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]; + 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. */ + } + /* Parse position */ + PARSE_POINT(p1_xyobj, vertices[0].position.x, vertices[0].position.y, "p1_xy") + PARSE_POINT(p2_xyobj, vertices[1].position.x, vertices[1].position.y, "p2_xy") + PARSE_POINT(p3_xyobj, vertices[2].position.x, vertices[2].position.y, "p3_xy") + vertices[3].position = vertices[2].position; + PARSE_POINT(p4_xyobj, vertices[4].position.x, vertices[4].position.y, "p4_xy") + vertices[5].position = vertices[0].position; + /* Parse tex_coord */ + if (Py_IsNone(p1_uvobj)) { + vertices[0].tex_coord.x = 0.0; + vertices[0].tex_coord.y = 0.0; + } + else { + PARSE_POINT(p1_xyobj, vertices[0].tex_coord.x, vertices[0].tex_coord.y, "p1_uv") + } + if (Py_IsNone(p2_uvobj)) { + vertices[1].tex_coord.x = 1.0; + vertices[1].tex_coord.y = 0.0; + } + else { + PARSE_POINT(p2_xyobj, vertices[1].tex_coord.x, vertices[1].tex_coord.y, "p2_uv") + } + if (Py_IsNone(p3_uvobj)) { + vertices[2].tex_coord.x = 1.0; + vertices[2].tex_coord.y = 1.0; + } + else { + PARSE_POINT(p3_xyobj, vertices[2].tex_coord.x, vertices[2].tex_coord.y, "p3_uv") + } + vertices[3].tex_coord = vertices[2].tex_coord; + if (Py_IsNone(p4_uvobj)) { + vertices[4].tex_coord.x = 0.0; + vertices[4].tex_coord.y = 1.0; + } + else { + PARSE_POINT(p4_xyobj, vertices[4].tex_coord.x, vertices[4].tex_coord.y, "p4_uv") + } + vertices[5].tex_coord = vertices[0].tex_coord; + /* Parse color */ + PARSE_COLOR(p1_modobj, p1_mod[0], p1_mod[1], p1_mod[2], p1_mod[3], "p1_mod") + PARSE_COLOR(p2_modobj, p2_mod[0], p2_mod[1], p2_mod[2], p2_mod[3], "p2_mod") + PARSE_COLOR(p3_modobj, p3_mod[0], p3_mod[1], p3_mod[2], p3_mod[3], "p3_mod") + PARSE_COLOR(p4_modobj, p4_mod[0], p4_mod[1], p4_mod[2], p4_mod[3], "p4_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 / 255.0; + g_mod = _g_mod / 255.0; + b_mod = _b_mod / 255.0; + a_mod = _a_mod / 255.0; + 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].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].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].color = vertices[2].color; + 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].color = vertices[0].color; + 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 (streaming) { + if (staticc || target) { + RAISE(PyExc_ValueError, + "only one of static, streaming, or target can be true"); + return -1; + } + access = SDL_TEXTUREACCESS_STREAMING; + } + else if (target) { + if (staticc) { + RAISE(PyExc_ValueError, + "only one of static, streaming, or target can be true"); + return -1; + } + access = SDL_TEXTUREACCESS_TARGET; + } + else { + access = SDL_TEXTUREACCESS_STATIC; + } + 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 */ @@ -610,6 +1144,37 @@ static PyGetSetDef renderer_getset[] = { DOC_SDL2_VIDEO_RENDERER_TARGET, NULL}, {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)texture_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 texture_methods[] = {{NULL, NULL, 0, NULL}}; static PyGetSetDef texture_getset[] = {{NULL, 0, NULL, NULL, NULL}}; @@ -626,15 +1191,19 @@ static PyTypeObject pgRenderer_Type = { .tp_methods = renderer_methods, .tp_init = (initproc)renderer_init, .tp_new = PyType_GenericNew, - .tp_getset = renderer_getset}; + .tp_getset = renderer_getset +}; static PyTypeObject pgTexture_Type = { - PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._render.Texture", + 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._render.Image", diff --git a/src_c/renderer.c b/src_c/renderer.c deleted file mode 100644 index fb99a450d8..0000000000 --- a/src_c/renderer.c +++ /dev/null @@ -1,1542 +0,0 @@ -#define PYGAMEAPI_RENDERER_INTERNAL - -#include "pygame.h" - -#include "pgcompat.h" - -#include "doc/sdl2_video_doc.h" - -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()); \ - } - -#define RENDERER_PROPERTY_ERROR_CHECK(x) \ - if (x < 0) { \ - RAISE(pgExc_SDLError, SDL_GetError()); \ - return -1; \ - } - -static void -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) -{ - 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 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; - } - Py_INCREF(self->target); - 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); -} - -/* Texture implementation */ -static void -texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest) -{ - 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 */ -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}, - {"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[] = { - {"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}}; - -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}; - -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) -{ - 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; - } - - 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; - } - - 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) { - return NULL; - } - - Py_INCREF(&pgRenderer_Type); - if (PyModule_AddObject(module, "Renderer", (PyObject *)&pgRenderer_Type)) { - Py_DECREF(&pgRenderer_Type); - Py_DECREF(module); - 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); - Py_DECREF(module); - return NULL; - } - - return module; -} diff --git a/src_c/static.c b/src_c/static.c index b7dc3936b1..87c0264d14 100644 --- a/src_c/static.c +++ b/src_c/static.c @@ -370,7 +370,6 @@ PyInit_pygame_static() #include "simd_blitters_sse2.c" #include "window.c" -#include "renderer.c" #undef pgVidInfo_Type #undef pgVidInfo_New From dbab0bc570c7fa77ea27db8d22e2a2e42a9b5940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Thu, 15 May 2025 14:47:58 +0200 Subject: [PATCH 18/21] Port Texture to C code --- buildconfig/stubs/pygame/_render.pyi | 73 ++++++++- src_c/render.c | 140 ++++++++++------ test/render_test.py | 233 ++++++++++++++++++++++++++- 3 files changed, 394 insertions(+), 52 deletions(-) diff --git a/buildconfig/stubs/pygame/_render.pyi b/buildconfig/stubs/pygame/_render.pyi index 2a76653dec..032921d80c 100644 --- a/buildconfig/stubs/pygame/_render.pyi +++ b/buildconfig/stubs/pygame/_render.pyi @@ -1,11 +1,11 @@ -from typing import Optional, Protocol, Union, final +from collections.abc import Iterable +from typing import Any, Optional, Protocol, Union, final from pygame.color import Color from pygame.rect import Rect from pygame.surface import Surface from pygame.typing import ColorLike, IntPoint, Point, RectLike, SequenceLike from pygame.window import Window -from typing_extensions import deprecated # added in 3.13 class _DrawableClass(Protocol): # Object that has the draw method that accepts area and dest arguments @@ -74,7 +74,74 @@ class Renderer: @final class Texture: - pass + def __init__( + self, + renderer: Renderer, + size: Iterable[int], + depth: int = 0, + static: bool = False, + streaming: bool = False, + target: bool = False, + scale_quality: Optional[int] = None, + ) -> None: ... + @property + def alpha(self) -> int: ... + @alpha.setter + def alpha(self, value: int) -> None: ... + @property + def blend_mode(self) -> int: ... + @blend_mode.setter + def blend_mode(self, value: int) -> None: ... + @property + def color(self) -> Color: ... + @color.setter + def color(self, value: ColorLike) -> None: ... + @property + def width(self) -> int: ... + @property + def height(self) -> int: ... + @property + def renderer(self) -> Renderer: ... + @classmethod + def from_surface(cls, renderer: Renderer, surface: Surface) -> Texture: ... + def draw( + self, + srcrect: Optional[RectLike] = None, + dstrect: Optional[RectLike] = None, + angle: float = 0.0, + origin: Optional[Iterable[int]] = None, + flip_x: bool = False, + flip_y: bool = False, + ) -> None: ... + def draw_triangle( + self, + p1_xy: Point, + p2_xy: Point, + p3_xy: Point, + p1_uv: Point = (0.0, 0.0), + p2_uv: Point = (1.0, 1.0), + p3_uv: Point = (0.0, 1.0), + p1_mod: Iterable[int] = (255, 255, 255, 255), + p2_mod: Iterable[int] = (255, 255, 255, 255), + p3_mod: Iterable[int] = (255, 255, 255, 255), + ) -> None: ... + def draw_quad( + self, + p1_xy: Point, + p2_xy: Point, + p3_xy: Point, + p4_xy: Point, + p1_uv: Point = (0.0, 0.0), + p2_uv: Point = (1.0, 0.0), + p3_uv: Point = (1.0, 1.0), + p4_uv: Point = (0.0, 1.0), + p1_mod: Iterable[int] = (255, 255, 255, 255), + p2_mod: Iterable[int] = (255, 255, 255, 255), + p3_mod: Iterable[int] = (255, 255, 255, 255), + p4_mod: Iterable[int] = (255, 255, 255, 255), + ) -> None: ... + def get_rect(self, **kwargs: Any) -> Rect: ... + def update(self, surface: Surface, area: Optional[RectLike] = None) -> None: ... @final class Image: diff --git a/src_c/render.c b/src_c/render.c index 3282c784be..292c0dcb16 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -37,7 +37,10 @@ static PyTypeObject pgImage_Type; #define PARSE_COLOR(obj, r, g, b, a, name) \ if (Py_IsNone(obj)) { \ - r = 255; g = 255; b = 255; a = 255; \ + r = 255; \ + g = 255; \ + b = 255; \ + a = 255; \ } \ else { \ if (!pg_IntFromObjIndex(obj, 0, &r) || \ @@ -55,6 +58,31 @@ 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 * renderer_from_window(PyTypeObject *cls, PyObject *args, PyObject *kwargs) @@ -659,10 +687,12 @@ texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) } originptr = &origin; } - if (flip_x) + if (flip_x) { flip |= SDL_FLIP_HORIZONTAL; - if (flip_y) + } + if (flip_y) { flip |= SDL_FLIP_VERTICAL; + } RENDERER_ERROR_CHECK(SDL_RenderCopyExF(self->renderer->renderer, self->texture, srcrectptr, dstrectptr, angle, originptr, flip)) @@ -689,41 +719,51 @@ texture_draw_triangle(pgTextureObject *self, PyObject *args, PyObject *kwargs) return NULL; /* Exception already set. */ } /* Parse position */ - PARSE_POINT(p1_xyobj, vertices[0].position.x, vertices[0].position.y, "p1_xy") - PARSE_POINT(p2_xyobj, vertices[1].position.x, vertices[1].position.y, "p2_xy") - PARSE_POINT(p3_xyobj, vertices[2].position.x, vertices[2].position.y, "p3_xy") + PARSE_POINT(p1_xyobj, vertices[0].position.x, vertices[0].position.y, + "p1_xy") + PARSE_POINT(p2_xyobj, vertices[1].position.x, vertices[1].position.y, + "p2_xy") + PARSE_POINT(p3_xyobj, vertices[2].position.x, vertices[2].position.y, + "p3_xy") /* Parse tex_coord */ if (Py_IsNone(p1_uvobj)) { vertices[0].tex_coord.x = 0.0; vertices[0].tex_coord.y = 0.0; } else { - PARSE_POINT(p1_xyobj, vertices[0].tex_coord.x, vertices[0].tex_coord.y, "p1_uv") + PARSE_POINT(p1_uvobj, vertices[0].tex_coord.x, vertices[0].tex_coord.y, + "p1_uv") } if (Py_IsNone(p2_uvobj)) { vertices[1].tex_coord.x = 1.0; vertices[1].tex_coord.y = 1.0; } else { - PARSE_POINT(p2_xyobj, vertices[1].tex_coord.x, vertices[1].tex_coord.y, "p2_uv") + PARSE_POINT(p2_uvobj, vertices[1].tex_coord.x, vertices[1].tex_coord.y, + "p2_uv") } if (Py_IsNone(p3_uvobj)) { vertices[2].tex_coord.x = 0.0; vertices[2].tex_coord.y = 1.0; } else { - PARSE_POINT(p3_xyobj, vertices[2].tex_coord.x, vertices[2].tex_coord.y, "p3_uv") + PARSE_POINT(p3_uvobj, vertices[2].tex_coord.x, vertices[2].tex_coord.y, + "p3_uv") } /* Parse color */ - PARSE_COLOR(p1_modobj, p1_mod[0], p1_mod[1], p1_mod[2], p1_mod[3], "p1_mod") - PARSE_COLOR(p2_modobj, p2_mod[0], p2_mod[1], p2_mod[2], p2_mod[3], "p2_mod") - PARSE_COLOR(p3_modobj, p3_mod[0], p3_mod[1], p3_mod[2], p3_mod[3], "p3_mod") - RENDERER_ERROR_CHECK(SDL_GetTextureColorMod(self->texture, &_r_mod, &_g_mod, &_b_mod)); + PARSE_COLOR(p1_modobj, p1_mod[0], p1_mod[1], p1_mod[2], p1_mod[3], + "p1_mod") + PARSE_COLOR(p2_modobj, p2_mod[0], p2_mod[1], p2_mod[2], p2_mod[3], + "p2_mod") + PARSE_COLOR(p3_modobj, p3_mod[0], p3_mod[1], p3_mod[2], p3_mod[3], + "p3_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 / 255.0; - g_mod = _g_mod / 255.0; - b_mod = _b_mod / 255.0; - a_mod = _a_mod / 255.0; + 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].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]; @@ -768,11 +808,15 @@ texture_draw_quad(pgTextureObject *self, PyObject *args, PyObject *kwargs) return NULL; /* Exception already set. */ } /* Parse position */ - PARSE_POINT(p1_xyobj, vertices[0].position.x, vertices[0].position.y, "p1_xy") - PARSE_POINT(p2_xyobj, vertices[1].position.x, vertices[1].position.y, "p2_xy") - PARSE_POINT(p3_xyobj, vertices[2].position.x, vertices[2].position.y, "p3_xy") + PARSE_POINT(p1_xyobj, vertices[0].position.x, vertices[0].position.y, + "p1_xy") + PARSE_POINT(p2_xyobj, vertices[1].position.x, vertices[1].position.y, + "p2_xy") + PARSE_POINT(p3_xyobj, vertices[2].position.x, vertices[2].position.y, + "p3_xy") vertices[3].position = vertices[2].position; - PARSE_POINT(p4_xyobj, vertices[4].position.x, vertices[4].position.y, "p4_xy") + PARSE_POINT(p4_xyobj, vertices[4].position.x, vertices[4].position.y, + "p4_xy") vertices[5].position = vertices[0].position; /* Parse tex_coord */ if (Py_IsNone(p1_uvobj)) { @@ -780,21 +824,24 @@ texture_draw_quad(pgTextureObject *self, PyObject *args, PyObject *kwargs) vertices[0].tex_coord.y = 0.0; } else { - PARSE_POINT(p1_xyobj, vertices[0].tex_coord.x, vertices[0].tex_coord.y, "p1_uv") + PARSE_POINT(p1_uvobj, vertices[0].tex_coord.x, vertices[0].tex_coord.y, + "p1_uv") } if (Py_IsNone(p2_uvobj)) { vertices[1].tex_coord.x = 1.0; vertices[1].tex_coord.y = 0.0; } else { - PARSE_POINT(p2_xyobj, vertices[1].tex_coord.x, vertices[1].tex_coord.y, "p2_uv") + PARSE_POINT(p2_uvobj, vertices[1].tex_coord.x, vertices[1].tex_coord.y, + "p2_uv") } if (Py_IsNone(p3_uvobj)) { vertices[2].tex_coord.x = 1.0; vertices[2].tex_coord.y = 1.0; } else { - PARSE_POINT(p3_xyobj, vertices[2].tex_coord.x, vertices[2].tex_coord.y, "p3_uv") + PARSE_POINT(p3_uvobj, vertices[2].tex_coord.x, vertices[2].tex_coord.y, + "p3_uv") } vertices[3].tex_coord = vertices[2].tex_coord; if (Py_IsNone(p4_uvobj)) { @@ -802,20 +849,26 @@ texture_draw_quad(pgTextureObject *self, PyObject *args, PyObject *kwargs) vertices[4].tex_coord.y = 1.0; } else { - PARSE_POINT(p4_xyobj, vertices[4].tex_coord.x, vertices[4].tex_coord.y, "p4_uv") + PARSE_POINT(p4_uvobj, vertices[4].tex_coord.x, vertices[4].tex_coord.y, + "p4_uv") } vertices[5].tex_coord = vertices[0].tex_coord; /* Parse color */ - PARSE_COLOR(p1_modobj, p1_mod[0], p1_mod[1], p1_mod[2], p1_mod[3], "p1_mod") - PARSE_COLOR(p2_modobj, p2_mod[0], p2_mod[1], p2_mod[2], p2_mod[3], "p2_mod") - PARSE_COLOR(p3_modobj, p3_mod[0], p3_mod[1], p3_mod[2], p3_mod[3], "p3_mod") - PARSE_COLOR(p4_modobj, p4_mod[0], p4_mod[1], p4_mod[2], p4_mod[3], "p4_mod") - RENDERER_ERROR_CHECK(SDL_GetTextureColorMod(self->texture, &_r_mod, &_g_mod, &_b_mod)); + PARSE_COLOR(p1_modobj, p1_mod[0], p1_mod[1], p1_mod[2], p1_mod[3], + "p1_mod") + PARSE_COLOR(p2_modobj, p2_mod[0], p2_mod[1], p2_mod[2], p2_mod[3], + "p2_mod") + PARSE_COLOR(p3_modobj, p3_mod[0], p3_mod[1], p3_mod[2], p3_mod[3], + "p3_mod") + PARSE_COLOR(p4_modobj, p4_mod[0], p4_mod[1], p4_mod[2], p4_mod[3], + "p4_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 / 255.0; - g_mod = _g_mod / 255.0; - b_mod = _b_mod / 255.0; - a_mod = _a_mod / 255.0; + 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].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]; @@ -888,8 +941,9 @@ texture_update(pgTextureObject *self, PyObject *args, PyObject *kwargs) if (format != surf->format->format) { RENDERER_ERROR_CHECK(SDL_GetSurfaceBlendMode(surf, &blend)) pixel_format = SDL_AllocFormat(format); - if (pixel_format == NULL) + 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); @@ -906,8 +960,9 @@ texture_update(pgTextureObject *self, PyObject *args, PyObject *kwargs) res = SDL_UpdateTexture(self->texture, areaptr, surf->pixels, surf->pitch); } - if (res < 0) + if (res < 0) { return RAISE(pgExc_SDLError, SDL_GetError()); + } Py_RETURN_NONE; } @@ -1044,7 +1099,8 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) access = SDL_TEXTUREACCESS_STATIC; } 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; @@ -1175,10 +1231,6 @@ static PyGetSetDef texture_getset[] = { DOC_SDL2_VIDEO_TEXTURE_COLOR, 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 image_methods[] = {{NULL, NULL, 0, NULL}}; static PyGetSetDef image_getset[] = {{NULL, 0, NULL, NULL, NULL}}; @@ -1191,8 +1243,7 @@ static PyTypeObject pgRenderer_Type = { .tp_methods = renderer_methods, .tp_init = (initproc)renderer_init, .tp_new = PyType_GenericNew, - .tp_getset = renderer_getset -}; + .tp_getset = renderer_getset}; static PyTypeObject pgTexture_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "pygame._renderer.Texture", @@ -1202,8 +1253,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._render.Image", diff --git a/test/render_test.py b/test/render_test.py index b04a635ddd..b1fd639350 100644 --- a/test/render_test.py +++ b/test/render_test.py @@ -45,15 +45,21 @@ def test_to_surface(self): self.renderer.to_surface(small_surf) def test_blit(self): - texture = _render.Texture(self.renderer, (20, 20)) + surface = pygame.Surface((10, 10)) + surface.fill((80, 120, 160, 200)) + texture = _render.Texture.from_surface(self.renderer, surface) image = _render.Image(texture) drawable_object = DrawableObject() dest = pygame.Rect(10, 10, 20, 20) area = pygame.Rect(0, 0, 15, 15) - self.renderer.blit( - texture, dest, area - ) # TODO Assert after Texture implementation + self.renderer.blit(texture, dest, area) + result = self.renderer.to_surface() + self.assertEqual(pygame.Color(0, 0, 0, 255), result.get_at((9, 20))) + for x in range(10, 30): + self.assertEqual(pygame.Color(80, 120, 160, 255), result.get_at((x, 20))) + self.assertEqual(pygame.Color(0, 0, 0, 255), result.get_at((30, 20))) + self.renderer.clear() self.renderer.blit(image, dest, area) # TODO Assert after Image implementation @@ -212,3 +218,222 @@ def test_draw_color(self): self.assertEqual(self.renderer.draw_color, pygame.Color(0, 0, 0, 0)) self.renderer.draw_color = "YELLOW" self.assertEqual(self.renderer.draw_color, pygame.Color(255, 255, 0, 255)) + + +class TextureTest(unittest.TestCase): + def setUp(self): + self.window = pygame.Window(size=(100, 100)) + self.renderer = _render.Renderer(self.window) + self.texture = _render.Texture(self.renderer, (80, 60)) + + def create_texture_from_surface(self): + surface = pygame.Surface((100, 100)) + surface.fill(pygame.Color(80, 120, 160, 128)) + return _render.Texture.from_surface(self.renderer, surface) + + def test_alpha(self): + self.assertEqual(255, self.texture.alpha) + self.texture.alpha = 128 + self.assertEqual(128, self.texture.alpha) + + def test_blend_mode(self): + self.assertEqual(pygame.BLENDMODE_NONE, self.texture.blend_mode) + self.texture.blend_mode = pygame.BLENDMODE_BLEND + self.assertEqual(pygame.BLENDMODE_BLEND, self.texture.blend_mode) + + def test_color(self): + self.assertEqual(pygame.Color(255, 255, 255, 255), self.texture.color) + self.texture.color = pygame.Color(100, 110, 120, 130) + self.assertEqual(pygame.Color(100, 110, 120, 255), self.texture.color) + + def test_width(self): + self.assertEqual(80, self.texture.width) + with self.assertRaises(AttributeError): + self.texture.width = 100 + + def test_height(self): + self.assertEqual(60, self.texture.height) + with self.assertRaises(AttributeError): + self.texture.height = 100 + + def test_renderer(self): + self.assertEqual(self.renderer, self.texture.renderer) + window2 = pygame.Window(size=(128, 128)) + renderer2 = _render.Renderer(window2) + with self.assertRaises(AttributeError): + self.texture.renderer = renderer2 + + def test_get_rect(self): + self.assertEqual(pygame.Rect(0, 0, 80, 60), self.texture.get_rect()) + self.assertEqual( + pygame.Rect(10, 20, 80, 60), self.texture.get_rect(center=(50, 50)) + ) + + def test_from_surface(self): + surf_size = (50, 40) + surface = pygame.Surface(surf_size) + texture2 = _render.Texture.from_surface(self.renderer, surface) + self.assertEqual(surf_size, (texture2.width, texture2.height)) + + def test_draw_triangle(self): + texture2 = self.create_texture_from_surface() + texture2.draw_triangle( + (50, 10), + (10, 90), + (90, 90), + (0.5, 0.5), + (0.8, 0.2), + (1, 1), + (100, 100, 100, 100), + (80, 60, 40, 20), + (150, 170, 190, 210), + ) + result = self.renderer.to_surface() + expected = [ + (0, 0, 0, 255), + (0, 0, 0, 255), + (0, 0, 0, 255), + (0, 0, 0, 255), + (0, 0, 0, 255), + (28, 38, 45, 255), + (29, 39, 46, 255), + (29, 39, 47, 255), + (29, 40, 48, 255), + (29, 41, 49, 255), + (30, 41, 50, 255), + (30, 42, 52, 255), + (30, 43, 53, 255), + (31, 43, 54, 255), + (31, 44, 55, 255), + (31, 44, 56, 255), + (31, 45, 57, 255), + (32, 46, 59, 255), + (32, 46, 60, 255), + (32, 47, 61, 255), + (32, 48, 62, 255), + (33, 48, 63, 255), + (33, 49, 65, 255), + (33, 50, 66, 255), + (34, 50, 67, 255), + (34, 51, 68, 255), + (34, 52, 69, 255), + (34, 52, 70, 255), + (35, 53, 72, 255), + (35, 54, 73, 255), + (35, 54, 74, 255), + (35, 55, 75, 255), + (36, 55, 76, 255), + (36, 56, 78, 255), + (36, 57, 79, 255), + (37, 57, 80, 255), + (37, 58, 81, 255), + (37, 59, 82, 255), + (37, 59, 83, 255), + (38, 60, 85, 255), + (38, 61, 86, 255), + (38, 61, 87, 255), + (39, 62, 88, 255), + (39, 63, 89, 255), + (39, 63, 90, 255), + (0, 0, 0, 255), + (0, 0, 0, 255), + (0, 0, 0, 255), + (0, 0, 0, 255), + (0, 0, 0, 255), + ] + actual = [] + for x in range(25, 75): + actual.append(result.get_at((x, 50))) + self.assertEqual(expected, actual) + + def test_draw_quad(self): + texture2 = self.create_texture_from_surface() + texture2.draw_quad( + (10, 10), + (90, 10), + (90, 90), + (10, 90), + (0.5, 0.5), + (0.8, 0.2), + (0.2, 0.8), + (0.9, 0.9), + (100, 100, 100, 100), + (80, 60, 40, 20), + (150, 170, 190, 210), + (128, 128, 128, 128), + ) + result = self.renderer.to_surface() + expected = [ + (37, 58, 79, 255), + (37, 58, 80, 255), + (37, 58, 80, 255), + (37, 58, 81, 255), + (37, 59, 81, 255), + (38, 59, 82, 255), + (38, 59, 82, 255), + (38, 59, 83, 255), + (38, 60, 83, 255), + (38, 60, 84, 255), + (38, 60, 84, 255), + (38, 60, 84, 255), + (38, 61, 85, 255), + (38, 61, 85, 255), + (38, 61, 86, 255), + (38, 61, 86, 255), + (39, 62, 87, 255), + (39, 62, 87, 255), + (39, 62, 88, 255), + (39, 62, 88, 255), + (39, 62, 89, 255), + (39, 63, 89, 255), + (39, 63, 90, 255), + (39, 63, 90, 255), + (39, 63, 91, 255), + (39, 64, 91, 255), + (39, 63, 91, 255), + (39, 63, 90, 255), + (39, 63, 90, 255), + (39, 63, 89, 255), + (39, 63, 89, 255), + (39, 62, 88, 255), + (39, 62, 88, 255), + (39, 62, 88, 255), + (39, 62, 87, 255), + (38, 61, 87, 255), + (38, 61, 86, 255), + (38, 61, 86, 255), + (38, 61, 85, 255), + (38, 60, 85, 255), + (38, 60, 84, 255), + (38, 60, 84, 255), + (38, 60, 83, 255), + (38, 59, 83, 255), + (38, 59, 82, 255), + (38, 59, 82, 255), + (38, 59, 81, 255), + (38, 59, 81, 255), + (37, 58, 80, 255), + (37, 58, 80, 255), + ] + actual = [] + for x in range(25, 75): + actual.append(result.get_at((x, 50))) + self.assertEqual(expected, actual) + + def test_draw(self): + texture2 = self.create_texture_from_surface() + texture2.draw(pygame.Rect(10, 20, 40, 40), pygame.Rect(50, 30, 35, 20), 45) + result = self.renderer.to_surface() + self.assertEqual(pygame.Color(0, 0, 0, 255), result.get_at((63, 50))) + for x in range(64, 82): + self.assertEqual(pygame.Color(80, 120, 160, 255), result.get_at((x, 50))) + self.assertEqual(pygame.Color(0, 0, 0, 255), result.get_at((82, 50))) + + def test_update(self): + surface = pygame.Surface((100, 100)) + surface.fill(pygame.Color(80, 120, 160, 128)) + self.texture.update(surface, pygame.Rect(10, 10, 80, 80)) + self.texture.draw() + result = self.renderer.to_surface() + for x in range(0, 100): + self.assertEqual(pygame.Color(80, 120, 160, 255), result.get_at((x, 50))) From a3e7a92e5dcbee3813b0bac32dcef17d135ff798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Thu, 15 May 2025 15:02:19 +0200 Subject: [PATCH 19/21] Port Texture to C code --- src_c/render.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src_c/render.c b/src_c/render.c index 292c0dcb16..a67c8a327b 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -76,9 +76,9 @@ format_from_depth(int depth) Amask = 0xF << 12; } else { - RAISE(PyExc_ValueError, - "no standard masks exist for given bitdepth with alpha"); - return -1; + RAISERETURN(PyExc_ValueError, + "no standard masks exist for given bitdepth with alpha", + -1) } return SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask); } @@ -1050,7 +1050,6 @@ texture_set_color(pgTextureObject *self, PyObject *arg, void *closure) static int texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) { - SDL_Texture *texture = NULL; pgRendererObject *renderer; PyObject *sizeobj; int width; @@ -1102,15 +1101,12 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) self->texture = SDL_CreateTexture(renderer->renderer, format, access, width, height); if (!self->texture) { - RAISE(pgExc_SDLError, SDL_GetError()); - return -1; + RAISERETURN(pgExc_SDLError, SDL_GetError(), -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; - } + RENDERER_PROPERTY_ERROR_CHECK( + SDL_SetTextureScaleMode(self->texture, scale_quality)) #else switch (scale_quality) { case 0: From f564f753e32d2433bd6c17b6f348031adc74fc4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Thu, 15 May 2025 15:16:18 +0200 Subject: [PATCH 20/21] Port Texture to C code --- src_c/render.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src_c/render.c b/src_c/render.c index a67c8a327b..f90f35b657 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -592,7 +592,8 @@ texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest) 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"); + PyErr_SetString(PyExc_ValueError, + "srcrect must be a Rect or None"); } } if (!Py_IsNone(dest)) { @@ -654,7 +655,6 @@ texture_draw(pgTextureObject *self, PyObject *args, PyObject *kwargs) 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; @@ -1071,26 +1071,25 @@ texture_init(pgTextureObject *self, PyObject *args, PyObject *kwargs) } format = format_from_depth(depth); if (!pg_TwoIntsFromObj(sizeobj, &width, &height)) { - RAISE(PyExc_TypeError, "invalid size argument"); - return -1; + RAISERETURN(PyExc_TypeError, "invalid size argument", -1) } if (width <= 0 || height <= 0) { - RAISE(PyExc_ValueError, "size must contain two positive values"); - return -1; + RAISERETURN(PyExc_ValueError, "size must contain two positive values", + -1) } if (streaming) { if (staticc || target) { - RAISE(PyExc_ValueError, - "only one of static, streaming, or target can be true"); - return -1; + RAISERETURN(PyExc_ValueError, + "only one of static, streaming, or target can be true", + -1) } access = SDL_TEXTUREACCESS_STREAMING; } else if (target) { if (staticc) { - RAISE(PyExc_ValueError, - "only one of static, streaming, or target can be true"); - return -1; + RAISERETURN(PyExc_ValueError, + "only one of static, streaming, or target can be true", + -1) } access = SDL_TEXTUREACCESS_TARGET; } From e9cdace909a3af6d6dda74e90c4fb953211057dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Thu, 15 May 2025 15:24:40 +0200 Subject: [PATCH 21/21] Port Texture to C code --- src_c/render.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src_c/render.c b/src_c/render.c index f90f35b657..bffc20aa19 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -599,8 +599,8 @@ 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"); + PyErr_SetString(PyExc_ValueError, + "dstrect must be a point, Rect, or None"); } dstrect.w = (float)self->width; dstrect.h = (float)self->height; @@ -608,7 +608,7 @@ texture_renderer_draw(pgTextureObject *self, PyObject *area, PyObject *dest) } if (SDL_RenderCopyExF(self->renderer->renderer, self->texture, srcrectptr, dstrectptr, 0, NULL, SDL_FLIP_NONE) < 0) { - RAISE(pgExc_SDLError, SDL_GetError()); + PyErr_SetString(pgExc_SDLError, SDL_GetError()); } }