From da808f828564cd4d7b55ace22a720806fa3a2cb9 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Mon, 9 Feb 2026 18:12:51 +0100 Subject: [PATCH 1/8] get_line_render_method() / set_line_render_method(method) added to pygame._render, LINE_RENDER_* constants --- buildconfig/stubs/pygame/_render.pyi | 3 +++ src_c/constants.c | 5 ++++ src_c/render.c | 38 +++++++++++++++++++++++++++- test/render_test.py | 22 ++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/buildconfig/stubs/pygame/_render.pyi b/buildconfig/stubs/pygame/_render.pyi index 907bda2601..60352cb0ca 100644 --- a/buildconfig/stubs/pygame/_render.pyi +++ b/buildconfig/stubs/pygame/_render.pyi @@ -146,3 +146,6 @@ class Texture: @final class Image: pass + +def get_line_render_method() -> int: ... +def set_line_render_method(method: int) -> bool: ... diff --git a/src_c/constants.c b/src_c/constants.c index 3ed987be38..d212fed75c 100644 --- a/src_c/constants.c +++ b/src_c/constants.c @@ -671,6 +671,11 @@ MODINIT_DEFINE(constants) DEC_CONSTS(FLASH_UNTIL_FOCUSED, -1); #endif + DEC_CONSTS(LINE_RENDER_DEFAULT, 0) + DEC_CONSTS(LINE_RENDER_POINT, 1) + DEC_CONSTS(LINE_RENDER_LINE, 2) + DEC_CONSTS(LINE_RENDER_GEOMETRY, 3) + if (PyModule_AddObject(module, "__all__", all_list)) { Py_DECREF(all_list); Py_DECREF(module); diff --git a/src_c/render.c b/src_c/render.c index a994665d1b..663b4f033f 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -1183,6 +1183,36 @@ image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) return 1; } +static PyObject * +get_line_render_method(PyObject* self, PyObject *Py_UNUSED(ignored)) +{ + const char *hint = SDL_GetHint(SDL_HINT_RENDER_LINE_METHOD); + return PyLong_FromLong(hint[0] - 48); // hint is a char between 0-3 +} + +static PyObject * +set_line_render_method(PyObject* self, PyObject *args) +{ + int method; + if (!PyArg_ParseTuple(args, "i", &method)) { + return RAISE(PyExc_ValueError, "Invalid line render method: must be an int" + " (use LINE_RENDER_* constants)"); + } + if (method < 0 || 3 < method) { + return RAISE(PyExc_ValueError, "Invalid line render method: must be between" + " 0 and 3 (use LINE_RENDER_* constants)"); + } + + // SDL_SetHint expects the method as a string + char hint[2]; + hint[0] = method + 48; // ascii char manipulation + hint[1] = '\0'; + + if (SDL_SetHint(SDL_HINT_RENDER_LINE_METHOD, hint)) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + /* Module definition */ static PyMethodDef renderer_methods[] = { {"draw_point", (PyCFunction)renderer_draw_point, @@ -1307,7 +1337,13 @@ static PyTypeObject pgImage_Type = { //.tp_init = (initproc)image_init, .tp_new = PyType_GenericNew, .tp_getset = image_getset}; -static PyMethodDef _render_methods[] = {{NULL, NULL, 0, NULL}}; +static PyMethodDef _render_methods[] = { + {"get_line_render_method", (PyCFunction)get_line_render_method, + METH_NOARGS, NULL}, + {"set_line_render_method", (PyCFunction)set_line_render_method, + METH_VARARGS, NULL}, + + {NULL, NULL, 0, NULL}}; MODINIT_DEFINE(_render) { diff --git a/test/render_test.py b/test/render_test.py index 112e93786a..fc6b846acf 100644 --- a/test/render_test.py +++ b/test/render_test.py @@ -482,3 +482,25 @@ def test_update(self): result = self.renderer.to_surface() for x in range(25, 75): self.assertEqual(pygame.Color(80, 120, 160, 255), result.get_at((x, 50))) + + +class LineRenderMethodTest(unittest.TestCase): + def test_correct_argument(self): + with self.assertRaises(ValueError): + _render.set_line_render_method(-1) + with self.assertRaises(ValueError): + _render.set_line_render_method(10) + with self.assertRaises(ValueError): + _render.set_line_render_method("foo") + with self.assertRaises(ValueError): + _render.set_line_render_method(None) + + def test_get_set_line_render_method(self): + if _render.set_line_render_method(pygame.LINE_RENDER_DEFAULT): + self.assertEqual(pygame.LINE_RENDER_DEFAULT, _render.get_line_render_method()) + if _render.set_line_render_method(pygame.LINE_RENDER_POINT): + self.assertEqual(pygame.LINE_RENDER_POINT, _render.get_line_render_method()) + if _render.set_line_render_method(pygame.LINE_RENDER_LINE): + self.assertEqual(pygame.LINE_RENDER_LINE, _render.get_line_render_method()) + if _render.set_line_render_method(pygame.LINE_RENDER_GEOMETRY): + self.assertEqual(pygame.LINE_RENDER_GEOMETRY, _render.get_line_render_method()) From 39840778995a00cad16a6532fdc8d2abbf184e89 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Mon, 9 Feb 2026 18:14:23 +0100 Subject: [PATCH 2/8] nitpick: add asterisks to the right side --- src_c/render.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src_c/render.c b/src_c/render.c index 663b4f033f..1b6f566293 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -1184,14 +1184,14 @@ image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) } static PyObject * -get_line_render_method(PyObject* self, PyObject *Py_UNUSED(ignored)) +get_line_render_method(PyObject *self, PyObject *Py_UNUSED(ignored)) { const char *hint = SDL_GetHint(SDL_HINT_RENDER_LINE_METHOD); return PyLong_FromLong(hint[0] - 48); // hint is a char between 0-3 } static PyObject * -set_line_render_method(PyObject* self, PyObject *args) +set_line_render_method(PyObject *self, PyObject *args) { int method; if (!PyArg_ParseTuple(args, "i", &method)) { From 93d4c1f515b557a7e03b69efa745930204e2444c Mon Sep 17 00:00:00 2001 From: BuildTools Date: Mon, 9 Feb 2026 18:32:02 +0100 Subject: [PATCH 3/8] NULL SDL_GetHint fix, ensures that SDL2 >= 2.0.20, remove magic number --- src_c/render.c | 8 ++++++-- test.py | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 test.py diff --git a/src_c/render.c b/src_c/render.c index 1b6f566293..5e064621e3 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -1183,11 +1183,12 @@ image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) return 1; } +#if SDL_VERSION_ATLEAST(2, 0, 20) static PyObject * get_line_render_method(PyObject *self, PyObject *Py_UNUSED(ignored)) { const char *hint = SDL_GetHint(SDL_HINT_RENDER_LINE_METHOD); - return PyLong_FromLong(hint[0] - 48); // hint is a char between 0-3 + return PyLong_FromLong(hint == NULL ? 0 : hint[0] - '0'); // hint is a char between 0-3 } static PyObject * @@ -1205,13 +1206,14 @@ set_line_render_method(PyObject *self, PyObject *args) // SDL_SetHint expects the method as a string char hint[2]; - hint[0] = method + 48; // ascii char manipulation + hint[0] = method + '0'; // ascii char manipulation hint[1] = '\0'; if (SDL_SetHint(SDL_HINT_RENDER_LINE_METHOD, hint)) Py_RETURN_TRUE; Py_RETURN_FALSE; } +#endif /* Module definition */ static PyMethodDef renderer_methods[] = { @@ -1338,10 +1340,12 @@ static PyTypeObject pgImage_Type = { .tp_new = PyType_GenericNew, .tp_getset = image_getset}; static PyMethodDef _render_methods[] = { +#if SDL_VERSION_ATLEAST(2, 0, 20) {"get_line_render_method", (PyCFunction)get_line_render_method, METH_NOARGS, NULL}, {"set_line_render_method", (PyCFunction)set_line_render_method, METH_VARARGS, NULL}, +#endif {NULL, NULL, 0, NULL}}; diff --git a/test.py b/test.py new file mode 100644 index 0000000000..ffd5e5a611 --- /dev/null +++ b/test.py @@ -0,0 +1,7 @@ +from pygame import _render + +import pygame + + +pygame.init() +_render.set_line_render_method("test") \ No newline at end of file From a16e23cd48e9c85cff235ce3c732f2b91635dfdc Mon Sep 17 00:00:00 2001 From: BuildTools Date: Mon, 9 Feb 2026 18:34:32 +0100 Subject: [PATCH 4/8] forgot to remove test.py: i'm dumb --- test.py | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 test.py diff --git a/test.py b/test.py deleted file mode 100644 index ffd5e5a611..0000000000 --- a/test.py +++ /dev/null @@ -1,7 +0,0 @@ -from pygame import _render - -import pygame - - -pygame.init() -_render.set_line_render_method("test") \ No newline at end of file From be9e7d73343b543f05fb10de1eb39c7e912358ce Mon Sep 17 00:00:00 2001 From: BuildTools Date: Tue, 17 Feb 2026 11:37:24 +0100 Subject: [PATCH 5/8] Fixed indentation, added stubs --- buildconfig/stubs/pygame/__init__.pyi | 4 ++++ buildconfig/stubs/pygame/constants.pyi | 8 ++++++++ buildconfig/stubs/pygame/locals.pyi | 8 ++++++++ src_c/render.c | 20 ++++++++++++-------- test/render_test.py | 10 +++++++--- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/buildconfig/stubs/pygame/__init__.pyi b/buildconfig/stubs/pygame/__init__.pyi index bf79ffaf71..254c04f431 100644 --- a/buildconfig/stubs/pygame/__init__.pyi +++ b/buildconfig/stubs/pygame/__init__.pyi @@ -597,6 +597,10 @@ from .constants import ( K_y as K_y, K_z as K_z, LIL_ENDIAN as LIL_ENDIAN, + LINE_RENDER_DEFAULT as LINE_RENDER_DEFAULT, + LINE_RENDER_GEOMETRY as LINE_RENDER_GEOMETRY, + LINE_RENDER_LINE as LINE_RENDER_LINE, + LINE_RENDER_POINT as LINE_RENDER_POINT, LOCALECHANGED as LOCALECHANGED, MIDIIN as MIDIIN, MIDIOUT as MIDIOUT, diff --git a/buildconfig/stubs/pygame/constants.pyi b/buildconfig/stubs/pygame/constants.pyi index 044d9534fa..6382b5cf6a 100644 --- a/buildconfig/stubs/pygame/constants.pyi +++ b/buildconfig/stubs/pygame/constants.pyi @@ -519,6 +519,10 @@ K_x: int K_y: int K_z: int LIL_ENDIAN: int +LINE_RENDER_DEFAULT: int +LINE_RENDER_GEOMETRY: int +LINE_RENDER_LINE: int +LINE_RENDER_POINT: int LOCALECHANGED: int MIDIIN: int MIDIOUT: int @@ -1191,4 +1195,8 @@ __all__ = [ "FLASH_CANCEL", "FLASH_BRIEFLY", "FLASH_UNTIL_FOCUSED", + "LINE_RENDER_DEFAULT", + "LINE_RENDER_POINT", + "LINE_RENDER_LINE", + "LINE_RENDER_GEOMETRY", ] diff --git a/buildconfig/stubs/pygame/locals.pyi b/buildconfig/stubs/pygame/locals.pyi index 95b838fa80..89c3836310 100644 --- a/buildconfig/stubs/pygame/locals.pyi +++ b/buildconfig/stubs/pygame/locals.pyi @@ -520,6 +520,10 @@ K_x: int K_y: int K_z: int LIL_ENDIAN: int +LINE_RENDER_DEFAULT: int +LINE_RENDER_GEOMETRY: int +LINE_RENDER_LINE: int +LINE_RENDER_POINT: int LOCALECHANGED: int MIDIIN: int MIDIOUT: int @@ -1193,6 +1197,10 @@ __all__ = [ "FLASH_CANCEL", "FLASH_BRIEFLY", "FLASH_UNTIL_FOCUSED", + "LINE_RENDER_DEFAULT", + "LINE_RENDER_POINT", + "LINE_RENDER_LINE", + "LINE_RENDER_GEOMETRY", "Rect", "Color", ] diff --git a/src_c/render.c b/src_c/render.c index 5e064621e3..cd0f6ca5d3 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -1188,7 +1188,8 @@ static PyObject * get_line_render_method(PyObject *self, PyObject *Py_UNUSED(ignored)) { const char *hint = SDL_GetHint(SDL_HINT_RENDER_LINE_METHOD); - return PyLong_FromLong(hint == NULL ? 0 : hint[0] - '0'); // hint is a char between 0-3 + return PyLong_FromLong( + hint == NULL ? 0 : hint[0] - '0'); // hint is a char between 0-3 } static PyObject * @@ -1196,21 +1197,24 @@ set_line_render_method(PyObject *self, PyObject *args) { int method; if (!PyArg_ParseTuple(args, "i", &method)) { - return RAISE(PyExc_ValueError, "Invalid line render method: must be an int" - " (use LINE_RENDER_* constants)"); + return RAISE(PyExc_ValueError, + "Invalid line render method: must be an int" + " (use LINE_RENDER_* constants)"); } if (method < 0 || 3 < method) { - return RAISE(PyExc_ValueError, "Invalid line render method: must be between" - " 0 and 3 (use LINE_RENDER_* constants)"); + return RAISE(PyExc_ValueError, + "Invalid line render method: must be between" + " 0 and 3 (use LINE_RENDER_* constants)"); } // SDL_SetHint expects the method as a string char hint[2]; - hint[0] = method + '0'; // ascii char manipulation + hint[0] = method + '0'; // ascii char manipulation hint[1] = '\0'; - - if (SDL_SetHint(SDL_HINT_RENDER_LINE_METHOD, hint)) + + if (SDL_SetHint(SDL_HINT_RENDER_LINE_METHOD, hint)) { Py_RETURN_TRUE; + } Py_RETURN_FALSE; } #endif diff --git a/test/render_test.py b/test/render_test.py index fc6b846acf..916a2f8895 100644 --- a/test/render_test.py +++ b/test/render_test.py @@ -494,13 +494,17 @@ def test_correct_argument(self): _render.set_line_render_method("foo") with self.assertRaises(ValueError): _render.set_line_render_method(None) - + def test_get_set_line_render_method(self): if _render.set_line_render_method(pygame.LINE_RENDER_DEFAULT): - self.assertEqual(pygame.LINE_RENDER_DEFAULT, _render.get_line_render_method()) + self.assertEqual( + pygame.LINE_RENDER_DEFAULT, _render.get_line_render_method() + ) if _render.set_line_render_method(pygame.LINE_RENDER_POINT): self.assertEqual(pygame.LINE_RENDER_POINT, _render.get_line_render_method()) if _render.set_line_render_method(pygame.LINE_RENDER_LINE): self.assertEqual(pygame.LINE_RENDER_LINE, _render.get_line_render_method()) if _render.set_line_render_method(pygame.LINE_RENDER_GEOMETRY): - self.assertEqual(pygame.LINE_RENDER_GEOMETRY, _render.get_line_render_method()) + self.assertEqual( + pygame.LINE_RENDER_GEOMETRY, _render.get_line_render_method() + ) From 89a10396ee1478ede87313a2cbea0251067e5e36 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Tue, 17 Feb 2026 11:50:20 +0100 Subject: [PATCH 6/8] Doesn't override the type error anymore --- src_c/render.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src_c/render.c b/src_c/render.c index cd0f6ca5d3..552664186e 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -1197,9 +1197,7 @@ set_line_render_method(PyObject *self, PyObject *args) { int method; if (!PyArg_ParseTuple(args, "i", &method)) { - return RAISE(PyExc_ValueError, - "Invalid line render method: must be an int" - " (use LINE_RENDER_* constants)"); + Py_RETURN_NONE; } if (method < 0 || 3 < method) { return RAISE(PyExc_ValueError, From 5747f0d08cde005071f86d4efc7ad3334459fc60 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Tue, 17 Feb 2026 11:55:03 +0100 Subject: [PATCH 7/8] me trying to make something work (impossible challenge) --- src_c/render.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src_c/render.c b/src_c/render.c index 552664186e..dcac7ec8d8 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -1183,7 +1183,7 @@ image_renderer_draw(pgImageObject *self, PyObject *area, PyObject *dest) return 1; } -#if SDL_VERSION_ATLEAST(2, 0, 20) +#if (SDL_VERSION_ATLEAST(2, 0, 20) && !SDL_VERSION_ATLEAST(3, 0, 0)) || SDL_VERSION_ATLEAST(3, 2, 0) static PyObject * get_line_render_method(PyObject *self, PyObject *Py_UNUSED(ignored)) { @@ -1197,7 +1197,7 @@ set_line_render_method(PyObject *self, PyObject *args) { int method; if (!PyArg_ParseTuple(args, "i", &method)) { - Py_RETURN_NONE; + return NULL; } if (method < 0 || 3 < method) { return RAISE(PyExc_ValueError, From 39961de06f4a175790f9580cd3a9130acd7fe0ec Mon Sep 17 00:00:00 2001 From: BuildTools Date: Tue, 17 Feb 2026 12:01:06 +0100 Subject: [PATCH 8/8] get/set_line_render_method returns NotImplemented errors for non-supported SDL versions --- src_c/render.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src_c/render.c b/src_c/render.c index dcac7ec8d8..e1b65a852f 100644 --- a/src_c/render.c +++ b/src_c/render.c @@ -1215,6 +1215,22 @@ set_line_render_method(PyObject *self, PyObject *args) } Py_RETURN_FALSE; } +#else +static PyObject * +get_line_render_method(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return RAISE(PyExc_NotImplementedError, "Setting/getting the " + "line render method is only available when built with SDL2 2.0.20" + " or SDL3 3.2.0") +} + +static PyObject * +set_line_render_method(PyObject *self, PyObject *args) +{ + return RAISE(PyExc_NotImplementedError, "Setting/getting the " + "line render method is only available when built with SDL2 2.0.20" + " or SDL3 3.2.0") +} #endif /* Module definition */ @@ -1342,12 +1358,10 @@ static PyTypeObject pgImage_Type = { .tp_new = PyType_GenericNew, .tp_getset = image_getset}; static PyMethodDef _render_methods[] = { -#if SDL_VERSION_ATLEAST(2, 0, 20) {"get_line_render_method", (PyCFunction)get_line_render_method, METH_NOARGS, NULL}, {"set_line_render_method", (PyCFunction)set_line_render_method, METH_VARARGS, NULL}, -#endif {NULL, NULL, 0, NULL}};