From 293078cf4cf67d85241a24c4ee134bd232499126 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Sat, 12 Oct 2024 23:10:38 -0700 Subject: [PATCH 01/36] Fix geometry has-attribute protocols --- buildconfig/stubs/pygame/geometry.pyi | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/buildconfig/stubs/pygame/geometry.pyi b/buildconfig/stubs/pygame/geometry.pyi index d5230ef98c..5dac798409 100644 --- a/buildconfig/stubs/pygame/geometry.pyi +++ b/buildconfig/stubs/pygame/geometry.pyi @@ -19,17 +19,19 @@ _CanBeLine = Union[ SequenceLike[Point], ] -class _HasCirclettribute(Protocol): +class _HasCircleAttribute(Protocol): # An object that has a circle attribute that is either a circle, or a function # that returns a circle - circle: Union[_CanBeCircle, Callable[[], _CanBeCircle]] + @property + def circle(self) -> Union[_CanBeCircle, Callable[[], _CanBeCircle]]: ... -_CircleValue = Union[_CanBeCircle, _HasCirclettribute] +_CircleValue = Union[_CanBeCircle, _HasCircleAttribute] class _HasLineAttribute(Protocol): # An object that has a line attribute that is either a line, or a function # that returns a line - line: Union[_CanBeLine, Callable[[], _CanBeLine]] + @property + def line(self) -> Union[_CanBeLine, Callable[[], _CanBeLine]]: ... _LineValue = Union[_CanBeLine, _HasLineAttribute] From ed821b6c371e4fc79d9642532dd8fc5177a3de5d Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Sat, 12 Oct 2024 23:11:24 -0700 Subject: [PATCH 02/36] Remove redundant type from type union --- buildconfig/stubs/pygame/geometry.pyi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/buildconfig/stubs/pygame/geometry.pyi b/buildconfig/stubs/pygame/geometry.pyi index 5dac798409..dbcba946e8 100644 --- a/buildconfig/stubs/pygame/geometry.pyi +++ b/buildconfig/stubs/pygame/geometry.pyi @@ -10,7 +10,6 @@ from typing import ( from pygame import Rect, FRect from pygame.typing import Point, RectLike, SequenceLike -from .math import Vector2 _CanBeCircle = Union[Circle, Tuple[Point, float], SequenceLike[float]] _CanBeLine = Union[ @@ -36,7 +35,7 @@ class _HasLineAttribute(Protocol): _LineValue = Union[_CanBeLine, _HasLineAttribute] -_CanBeCollided = Union[Circle, Rect, FRect, Point, Vector2] +_CanBeCollided = Union[Circle, Rect, FRect, Point] _CanBeIntersected = Union[Circle] class Circle: From e1c2335ed8195838472c1464f9c5ec1ca3c2be5e Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Sat, 12 Oct 2024 23:18:07 -0700 Subject: [PATCH 03/36] Type Circle.contains parameter as positional-only --- buildconfig/stubs/pygame/geometry.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildconfig/stubs/pygame/geometry.pyi b/buildconfig/stubs/pygame/geometry.pyi index dbcba946e8..dc4e0985a6 100644 --- a/buildconfig/stubs/pygame/geometry.pyi +++ b/buildconfig/stubs/pygame/geometry.pyi @@ -129,7 +129,7 @@ class Circle: def collidelist(self, colliders: Sequence[_CanBeCollided], /) -> int: ... def collidelistall(self, colliders: Sequence[_CanBeCollided], /) -> List[int]: ... def intersect(self, other: _CanBeIntersected, /) -> List[Tuple[float, float]]: ... - def contains(self, shape: _CanBeCollided) -> bool: ... + def contains(self, shape: _CanBeCollided, /) -> bool: ... @overload def update(self, circle: _CircleValue, /) -> None: ... @overload From d735f3a67818c439c4f61dbba54c49153ed03d89 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Sat, 12 Oct 2024 23:19:55 -0700 Subject: [PATCH 04/36] Format geometry.pyi --- buildconfig/stubs/pygame/geometry.pyi | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/buildconfig/stubs/pygame/geometry.pyi b/buildconfig/stubs/pygame/geometry.pyi index dc4e0985a6..8b22de4788 100644 --- a/buildconfig/stubs/pygame/geometry.pyi +++ b/buildconfig/stubs/pygame/geometry.pyi @@ -12,11 +12,7 @@ from pygame import Rect, FRect from pygame.typing import Point, RectLike, SequenceLike _CanBeCircle = Union[Circle, Tuple[Point, float], SequenceLike[float]] -_CanBeLine = Union[ - Line, - SequenceLike[float], - SequenceLike[Point], -] +_CanBeLine = Union[Line, SequenceLike[float], SequenceLike[Point]] class _HasCircleAttribute(Protocol): # An object that has a circle attribute that is either a circle, or a function @@ -32,7 +28,6 @@ class _HasLineAttribute(Protocol): @property def line(self) -> Union[_CanBeLine, Callable[[], _CanBeLine]]: ... - _LineValue = Union[_CanBeLine, _HasLineAttribute] _CanBeCollided = Union[Circle, Rect, FRect, Point] From 06888230809cf0d510c93b18bdb0fef23694b81e Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Sat, 12 Oct 2024 23:34:36 -0700 Subject: [PATCH 05/36] Combine geometry type unions --- buildconfig/stubs/pygame/geometry.pyi | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/buildconfig/stubs/pygame/geometry.pyi b/buildconfig/stubs/pygame/geometry.pyi index 8b22de4788..d0ae492dd9 100644 --- a/buildconfig/stubs/pygame/geometry.pyi +++ b/buildconfig/stubs/pygame/geometry.pyi @@ -11,24 +11,23 @@ from typing import ( from pygame import Rect, FRect from pygame.typing import Point, RectLike, SequenceLike -_CanBeCircle = Union[Circle, Tuple[Point, float], SequenceLike[float]] -_CanBeLine = Union[Line, SequenceLike[float], SequenceLike[Point]] - class _HasCircleAttribute(Protocol): # An object that has a circle attribute that is either a circle, or a function # that returns a circle @property - def circle(self) -> Union[_CanBeCircle, Callable[[], _CanBeCircle]]: ... + def circle(self) -> Union[_CircleValue, Callable[[], _CircleValue]]: ... -_CircleValue = Union[_CanBeCircle, _HasCircleAttribute] +_CircleValue = Union[ + Circle, Tuple[Point, float], SequenceLike[float], _HasCircleAttribute +] class _HasLineAttribute(Protocol): # An object that has a line attribute that is either a line, or a function # that returns a line @property - def line(self) -> Union[_CanBeLine, Callable[[], _CanBeLine]]: ... + def line(self) -> Union[_LineValue, Callable[[], _LineValue]]: ... -_LineValue = Union[_CanBeLine, _HasLineAttribute] +_LineValue = Union[Line, SequenceLike[float], SequenceLike[Point], _HasLineAttribute] _CanBeCollided = Union[Circle, Rect, FRect, Point] _CanBeIntersected = Union[Circle] From fea6cc7cdd3b96aef07d5a7ca96765717ebf4623 Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Sat, 12 Oct 2024 23:35:58 -0700 Subject: [PATCH 06/36] Rename internal geometry type unions --- buildconfig/stubs/pygame/geometry.pyi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/buildconfig/stubs/pygame/geometry.pyi b/buildconfig/stubs/pygame/geometry.pyi index d0ae492dd9..f7c1edf517 100644 --- a/buildconfig/stubs/pygame/geometry.pyi +++ b/buildconfig/stubs/pygame/geometry.pyi @@ -15,9 +15,9 @@ class _HasCircleAttribute(Protocol): # An object that has a circle attribute that is either a circle, or a function # that returns a circle @property - def circle(self) -> Union[_CircleValue, Callable[[], _CircleValue]]: ... + def circle(self) -> Union[_CircleLike, Callable[[], _CircleLike]]: ... -_CircleValue = Union[ +_CircleLike = Union[ Circle, Tuple[Point, float], SequenceLike[float], _HasCircleAttribute ] @@ -25,9 +25,9 @@ class _HasLineAttribute(Protocol): # An object that has a line attribute that is either a line, or a function # that returns a line @property - def line(self) -> Union[_LineValue, Callable[[], _LineValue]]: ... + def line(self) -> Union[_LineLike, Callable[[], _LineLike]]: ... -_LineValue = Union[Line, SequenceLike[float], SequenceLike[Point], _HasLineAttribute] +_LineLike = Union[Line, SequenceLike[float], SequenceLike[Point], _HasLineAttribute] _CanBeCollided = Union[Circle, Rect, FRect, Point] _CanBeIntersected = Union[Circle] @@ -94,7 +94,7 @@ class Circle: @overload def __init__(self, pos: Point, r: float) -> None: ... @overload - def __init__(self, circle: _CircleValue) -> None: ... + def __init__(self, circle: _CircleLike) -> None: ... @overload def move(self, x: float, y: float, /) -> Circle: ... @overload @@ -108,7 +108,7 @@ class Circle: @overload def collidepoint(self, point: Point, /) -> bool: ... @overload - def collidecircle(self, circle: _CircleValue, /) -> bool: ... + def collidecircle(self, circle: _CircleLike, /) -> bool: ... @overload def collidecircle(self, x: float, y: float, r: float, /) -> bool: ... @overload @@ -125,7 +125,7 @@ class Circle: def intersect(self, other: _CanBeIntersected, /) -> List[Tuple[float, float]]: ... def contains(self, shape: _CanBeCollided, /) -> bool: ... @overload - def update(self, circle: _CircleValue, /) -> None: ... + def update(self, circle: _CircleLike, /) -> None: ... @overload def update(self, x: float, y: float, r: float, /) -> None: ... @overload @@ -173,6 +173,6 @@ class Line: @overload def __init__(self, a: Point, b: Point) -> None: ... @overload - def __init__(self, line: _LineValue) -> None: ... + def __init__(self, line: _LineLike) -> None: ... def __copy__(self) -> Line: ... def copy(self) -> Line: ... From 6aaa776e70d99d2c9efaf1e5de5074a3db91a167 Mon Sep 17 00:00:00 2001 From: Starbuck5 <46412508+Starbuck5@users.noreply.github.com> Date: Thu, 10 Oct 2024 22:59:28 -0700 Subject: [PATCH 07/36] Image module SDL3 support - Rework argument order of PG_CreateSurfaceFrom to match newest SDL3 (they changed it) - Deal with all the pixelformat fallout throughout the file - Fix TGA saving routine file writes - Switch out SDL_SetPaletteColors (all colors) for SDL_SetSurfacePalette --- src_c/_pygame.h | 6 +- src_c/image.c | 212 +++++++++++++++++++++++++++++----------------- src_c/meson.build | 3 - src_c/surface.c | 4 +- src_c/transform.c | 6 +- 5 files changed, 143 insertions(+), 88 deletions(-) diff --git a/src_c/_pygame.h b/src_c/_pygame.h index bca86455ff..049e346bb5 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -98,8 +98,8 @@ PG_UnlockMutex(SDL_mutex *mutex) return 0; } -#define PG_SURF_BitsPerPixel(surf) surf->format->bits_per_pixel -#define PG_SURF_BytesPerPixel(surf) surf->format->bytes_per_pixel +#define PG_SURF_BitsPerPixel(surf) SDL_BITSPERPIXEL(surf->format) +#define PG_SURF_BytesPerPixel(surf) SDL_BYTESPERPIXEL(surf->format) #define PG_FORMAT_BitsPerPixel(format) format->bits_per_pixel #define PG_FORMAT_BytesPerPixel(format) format->bytes_per_pixel @@ -138,7 +138,7 @@ PG_UnlockMutex(SDL_mutex *mutex) #define PG_CreateSurface(width, height, format) \ SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, format) -#define PG_CreateSurfaceFrom(pixels, width, height, pitch, format) \ +#define PG_CreateSurfaceFrom(width, height, format, pixels, pitch) \ SDL_CreateRGBSurfaceWithFormatFrom(pixels, width, height, 0, pitch, format) #define PG_ConvertSurface(src, fmt) SDL_ConvertSurface(src, fmt, 0) #define PG_ConvertSurfaceFormat(src, pixel_format) \ diff --git a/src_c/image.c b/src_c/image.c index 74bf992e5d..c07a3d01cf 100644 --- a/src_c/image.c +++ b/src_c/image.c @@ -422,24 +422,39 @@ tobytes_surf_32bpp_sse42(SDL_Surface *surf, int flipped, char *data, #endif /* PG_COMPILE_SSE4_2 */ static void -tobytes_surf_32bpp(SDL_Surface *surf, int flipped, int hascolorkey, - Uint32 colorkey, char *serialized_image, int color_offset, - int alpha_offset, int padding) +#if SDL_VERSION_ATLEAST(3, 0, 0) +tobytes_surf_32bpp(SDL_Surface *surf, + const SDL_PixelFormatDetails *format_details, int flipped, + int hascolorkey, Uint32 colorkey, char *serialized_image, + int color_offset, int alpha_offset, int padding) +#else +tobytes_surf_32bpp(SDL_Surface *surf, SDL_PixelFormat *format_details, + int flipped, int hascolorkey, Uint32 colorkey, + char *serialized_image, int color_offset, int alpha_offset, + int padding) +#endif { int w, h; - Uint32 Rmask = surf->format->Rmask; - Uint32 Gmask = surf->format->Gmask; - Uint32 Bmask = surf->format->Bmask; - Uint32 Amask = surf->format->Amask; - Uint32 Rshift = surf->format->Rshift; - Uint32 Gshift = surf->format->Gshift; - Uint32 Bshift = surf->format->Bshift; - Uint32 Ashift = surf->format->Ashift; - Uint32 Rloss = surf->format->Rloss; - Uint32 Gloss = surf->format->Gloss; - Uint32 Bloss = surf->format->Bloss; - Uint32 Aloss = surf->format->Aloss; +#if SDL_VERSION_ATLEAST(3, 0, 0) + Uint32 Rloss = format_details->Rbits; + Uint32 Gloss = format_details->Gbits; + Uint32 Bloss = format_details->Bbits; + Uint32 Aloss = format_details->Abits; +#else + Uint32 Rloss = format_details->Rloss; + Uint32 Gloss = format_details->Gloss; + Uint32 Bloss = format_details->Bloss; + Uint32 Aloss = format_details->Aloss; +#endif + Uint32 Rmask = format_details->Rmask; + Uint32 Gmask = format_details->Gmask; + Uint32 Bmask = format_details->Bmask; + Uint32 Amask = format_details->Amask; + Uint32 Rshift = format_details->Rshift; + Uint32 Gshift = format_details->Gshift; + Uint32 Bshift = format_details->Bshift; + Uint32 Ashift = format_details->Ashift; #if PG_COMPILE_SSE4_2 if (/* SDL uses Uint32, SSE uses int for building vectors. @@ -456,17 +471,16 @@ tobytes_surf_32bpp(SDL_Surface *surf, int flipped, int hascolorkey, /* The SSE code assumes it will always read at least 4 pixels */ && surf->w >= 4 /* Our SSE code assumes masks are at most 0xff */ - && (surf->format->Rmask >> surf->format->Rshift) <= 0x0ff && - (surf->format->Gmask >> surf->format->Gshift) <= 0x0ff && - (surf->format->Bmask >> surf->format->Bshift) <= 0x0ff && + && (Rmask >> Rshift) <= 0x0ff && (Gmask >> Gshift) <= 0x0ff && + (Bmask >> Bshift) <= 0x0ff && (Amask >> Ashift) <= 0x0ff /* Our SSE code cannot handle losses other than 0 or 8 * Note the mask check above ensures that losses can be * at most be 8 (assuming the pixel format makes sense * at all). */ - && (surf->format->Rloss % 8) == 0 && (surf->format->Bloss % 8) == 0 && - (surf->format->Gloss % 8) == 0 && (Aloss % 8) == 0) { + && (Rloss % 8) == 0 && (Bloss % 8) == 0 && (Gloss % 8) == 0 && + (Aloss % 8) == 0) { tobytes_surf_32bpp_sse42(surf, flipped, serialized_image, color_offset, alpha_offset); return; @@ -526,18 +540,33 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg) return NULL; surf = pgSurface_AsSurface(surfobj); - Rmask = surf->format->Rmask; - Gmask = surf->format->Gmask; - Bmask = surf->format->Bmask; - Amask = surf->format->Amask; - Rshift = surf->format->Rshift; - Gshift = surf->format->Gshift; - Bshift = surf->format->Bshift; - Ashift = surf->format->Ashift; - Rloss = surf->format->Rloss; - Gloss = surf->format->Gloss; - Bloss = surf->format->Bloss; - Aloss = surf->format->Aloss; +#if SDL_VERSION_ATLEAST(3, 0, 0) + const SDL_PixelFormatDetails *format_details = + SDL_GetPixelFormatDetails(surf->format); + if (!format_details) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + SDL_Palette *surf_palette = SDL_GetSurfacePalette(surf); + Rloss = format_details->Rbits; + Gloss = format_details->Gbits; + Bloss = format_details->Bbits; + Aloss = format_details->Abits; +#else + SDL_PixelFormat *format_details = surf->format; + SDL_Palette *surf_palette = surf->format->palette; + Rloss = format_details->Rloss; + Gloss = format_details->Gloss; + Bloss = format_details->Bloss; + Aloss = format_details->Aloss; +#endif + Rmask = format_details->Rmask; + Gmask = format_details->Gmask; + Bmask = format_details->Bmask; + Amask = format_details->Amask; + Rshift = format_details->Rshift; + Gshift = format_details->Gshift; + Bshift = format_details->Bshift; + Ashift = format_details->Ashift; if (!strcmp(format, "P")) { if (PG_SURF_BytesPerPixel(surf) != 1) @@ -561,7 +590,7 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg) } else if (!strcmp(format, "RGBA_PREMULT") || !strcmp(format, "ARGB_PREMULT")) { - if (PG_SURF_BytesPerPixel(surf) == 1 || surf->format->Amask == 0) + if (PG_SURF_BytesPerPixel(surf) == 1 || Amask == 0) return RAISE(PyExc_ValueError, "Can only create pre-multiplied alpha bytes if " "the surface has per-pixel alpha"); @@ -609,9 +638,9 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg) surf->h, flipped); for (w = 0; w < surf->w; ++w) { color = *ptr++; - data[0] = (char)surf->format->palette->colors[color].r; - data[1] = (char)surf->format->palette->colors[color].g; - data[2] = (char)surf->format->palette->colors[color].b; + data[0] = (char)surf_palette->colors[color].r; + data[1] = (char)surf_palette->colors[color].g; + data[2] = (char)surf_palette->colors[color].b; data += 3; } pad(&data, padding); @@ -677,9 +706,9 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg) surf->h, flipped); for (w = 0; w < surf->w; ++w) { color = *ptr++; - data[0] = (char)surf->format->palette->colors[color].r; - data[1] = (char)surf->format->palette->colors[color].g; - data[2] = (char)surf->format->palette->colors[color].b; + data[0] = (char)surf_palette->colors[color].r; + data[1] = (char)surf_palette->colors[color].g; + data[2] = (char)surf_palette->colors[color].b; data[3] = hascolorkey ? (char)(color != colorkey) * 255 : (char)255; data += 4; @@ -733,8 +762,8 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg) } break; case 4: - tobytes_surf_32bpp(surf, flipped, hascolorkey, colorkey, data, - 0, 3, padding); + tobytes_surf_32bpp(surf, format_details, flipped, hascolorkey, + colorkey, data, 0, 3, padding); break; } pgSurface_Unlock(surfobj); @@ -748,9 +777,9 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg) surf->h, flipped); for (w = 0; w < surf->w; ++w) { color = *ptr++; - data[1] = (char)surf->format->palette->colors[color].r; - data[2] = (char)surf->format->palette->colors[color].g; - data[3] = (char)surf->format->palette->colors[color].b; + data[1] = (char)surf_palette->colors[color].r; + data[2] = (char)surf_palette->colors[color].g; + data[3] = (char)surf_palette->colors[color].b; data[0] = (char)255; data += 4; } @@ -797,8 +826,8 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg) } break; case 4: - tobytes_surf_32bpp(surf, flipped, hascolorkey, colorkey, data, - 1, 0, padding); + tobytes_surf_32bpp(surf, format_details, flipped, hascolorkey, + colorkey, data, 1, 0, padding); break; } pgSurface_Unlock(surfobj); @@ -812,9 +841,9 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg) surf->h, flipped); for (w = 0; w < surf->w; ++w) { color = *ptr++; - data[2] = (char)surf->format->palette->colors[color].r; - data[1] = (char)surf->format->palette->colors[color].g; - data[0] = (char)surf->format->palette->colors[color].b; + data[2] = (char)surf_palette->colors[color].r; + data[1] = (char)surf_palette->colors[color].g; + data[0] = (char)surf_palette->colors[color].b; data[3] = (char)255; data += 4; } @@ -889,9 +918,9 @@ image_tobytes(PyObject *self, PyObject *arg, PyObject *kwarg) surf->h, flipped); for (w = 0; w < surf->w; ++w) { color = *ptr++; - data[3] = (char)surf->format->palette->colors[color].r; - data[2] = (char)surf->format->palette->colors[color].g; - data[1] = (char)surf->format->palette->colors[color].b; + data[3] = (char)surf_palette->colors[color].r; + data[2] = (char)surf_palette->colors[color].g; + data[1] = (char)surf_palette->colors[color].b; data[0] = (char)255; data += 4; } @@ -1412,7 +1441,7 @@ image_frombuffer(PyObject *self, PyObject *arg, PyObject *kwds) PyExc_ValueError, "Buffer length does not equal format and resolution size"); - surf = PG_CreateSurfaceFrom(data, w, h, pitch, SDL_PIXELFORMAT_INDEX8); + surf = PG_CreateSurfaceFrom(w, h, SDL_PIXELFORMAT_INDEX8, data, pitch); } else if (!strcmp(format, "RGB")) { if (pitch == -1) { @@ -1428,7 +1457,7 @@ image_frombuffer(PyObject *self, PyObject *arg, PyObject *kwds) return RAISE( PyExc_ValueError, "Buffer length does not equal format and resolution size"); - surf = PG_CreateSurfaceFrom(data, w, h, pitch, SDL_PIXELFORMAT_RGB24); + surf = PG_CreateSurfaceFrom(w, h, SDL_PIXELFORMAT_RGB24, data, pitch); } else if (!strcmp(format, "BGR")) { if (pitch == -1) { @@ -1444,7 +1473,7 @@ image_frombuffer(PyObject *self, PyObject *arg, PyObject *kwds) return RAISE( PyExc_ValueError, "Buffer length does not equal format and resolution size"); - surf = PG_CreateSurfaceFrom(data, w, h, pitch, SDL_PIXELFORMAT_BGR24); + surf = PG_CreateSurfaceFrom(w, h, SDL_PIXELFORMAT_BGR24, data, pitch); } else if (!strcmp(format, "BGRA")) { if (pitch == -1) { @@ -1460,7 +1489,7 @@ image_frombuffer(PyObject *self, PyObject *arg, PyObject *kwds) return RAISE( PyExc_ValueError, "Buffer length does not equal format and resolution size"); - surf = PG_CreateSurfaceFrom(data, w, h, pitch, SDL_PIXELFORMAT_BGRA32); + surf = PG_CreateSurfaceFrom(w, h, SDL_PIXELFORMAT_BGRA32, data, pitch); } else if (!strcmp(format, "RGBA") || !strcmp(format, "RGBX")) { if (pitch == -1) { @@ -1478,8 +1507,8 @@ image_frombuffer(PyObject *self, PyObject *arg, PyObject *kwds) PyExc_ValueError, "Buffer length does not equal format and resolution size"); surf = PG_CreateSurfaceFrom( - data, w, h, pitch, - (alphamult ? SDL_PIXELFORMAT_RGBA32 : PG_PIXELFORMAT_RGBX32)); + w, h, (alphamult ? SDL_PIXELFORMAT_RGBA32 : PG_PIXELFORMAT_RGBX32), + data, pitch); } else if (!strcmp(format, "ARGB")) { if (pitch == -1) { @@ -1495,7 +1524,7 @@ image_frombuffer(PyObject *self, PyObject *arg, PyObject *kwds) return RAISE( PyExc_ValueError, "Buffer length does not equal format and resolution size"); - surf = PG_CreateSurfaceFrom(data, w, h, pitch, SDL_PIXELFORMAT_ARGB32); + surf = PG_CreateSurfaceFrom(w, h, SDL_PIXELFORMAT_ARGB32, data, pitch); } else return RAISE(PyExc_ValueError, "Unrecognized type of format"); @@ -1620,7 +1649,6 @@ SaveTGA_RW(SDL_Surface *surface, SDL_RWops *out, int rle) Uint8 surf_alpha; int have_surf_colorkey = 0; Uint32 surf_colorkey; - Uint32 format; SDL_Rect r; int bpp; Uint8 *rlebuf = NULL; @@ -1634,6 +1662,21 @@ SaveTGA_RW(SDL_Surface *surface, SDL_RWops *out, int rle) return -1; } +#if SDL_VERSION_ATLEAST(3, 0, 0) + const SDL_PixelFormatDetails *surf_format = + SDL_GetPixelFormatDetails(surface->format); + if (!surf_format) { + return -1; + } + SDL_PixelFormat output_format; + + SDL_Palette *surf_palette = SDL_GetSurfacePalette(surface); +#else + SDL_PixelFormat *surf_format = surface->format; + SDL_Palette *surf_palette = surface->format->palette; + Uint32 output_format; +#endif + SDL_GetSurfaceAlphaMod(surface, &surf_alpha); if ((have_surf_colorkey = SDL_HasColorKey(surface))) { SDL_GetColorKey(surface, &surf_colorkey); @@ -1646,23 +1689,23 @@ SaveTGA_RW(SDL_Surface *surface, SDL_RWops *out, int rle) h.cmap_bits = 32; else h.cmap_bits = 24; - SETLE16(h.cmap_len, surface->format->palette->ncolors); + SETLE16(h.cmap_len, surf_palette->ncolors); h.pixel_bits = 8; - format = SDL_PIXELFORMAT_INDEX8; + output_format = SDL_PIXELFORMAT_INDEX8; } else { h.has_cmap = 0; h.type = TGA_TYPE_RGB; h.cmap_bits = 0; SETLE16(h.cmap_len, 0); - if (surface->format->Amask) { + if (surf_format->Amask) { alpha = 1; h.pixel_bits = 32; - format = SDL_PIXELFORMAT_BGRA32; + output_format = SDL_PIXELFORMAT_BGRA32; } else { h.pixel_bits = 24; - format = SDL_PIXELFORMAT_BGR24; + output_format = SDL_PIXELFORMAT_BGR24; } } bpp = h.pixel_bits >> 3; @@ -1675,34 +1718,41 @@ SaveTGA_RW(SDL_Surface *surface, SDL_RWops *out, int rle) SETLE16(h.height, surface->h); h.flags = TGA_ORIGIN_UPPER | (alpha ? 8 : 0); +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (!SDL_WriteIO(out, &h, sizeof(h))) +#else if (!SDL_RWwrite(out, &h, sizeof(h), 1)) +#endif return -1; if (h.has_cmap) { int i; - SDL_Palette *pal = surface->format->palette; Uint8 entry[4]; - for (i = 0; i < pal->ncolors; i++) { - entry[0] = pal->colors[i].b; - entry[1] = pal->colors[i].g; - entry[2] = pal->colors[i].r; + for (i = 0; i < surf_palette->ncolors; i++) { + entry[0] = surf_palette->colors[i].b; + entry[1] = surf_palette->colors[i].g; + entry[2] = surf_palette->colors[i].r; entry[3] = ((unsigned)i == surf_colorkey) ? 0 : 0xff; +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (!SDL_WriteIO(out, entry, h.cmap_bits >> 3)) +#else if (!SDL_RWwrite(out, entry, h.cmap_bits >> 3, 1)) +#endif return -1; } } - linebuf = PG_CreateSurface(surface->w, 1, format); + linebuf = PG_CreateSurface(surface->w, 1, output_format); if (!linebuf) return -1; if (h.has_cmap) { - if (0 != SDL_SetPaletteColors(linebuf->format->palette, - surface->format->palette->colors, 0, - surface->format->palette->ncolors)) { - /* SDL error already set. */ - goto error; - } +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (!SDL_SetSurfacePalette(linebuf, surf_palette)) +#else + if (SDL_SetSurfacePalette(linebuf, surf_palette) < 0) +#endif + goto error; /* SDL error already set. */ } if (rle) { @@ -1725,7 +1775,11 @@ SaveTGA_RW(SDL_Surface *surface, SDL_RWops *out, int rle) for (r.y = 0; r.y < surface->h; r.y++) { int n; void *buf; +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (!SDL_BlitSurface(surface, &r, linebuf, NULL)) +#else if (SDL_BlitSurface(surface, &r, linebuf, NULL) < 0) +#endif break; if (rle) { buf = rlebuf; @@ -1735,7 +1789,11 @@ SaveTGA_RW(SDL_Surface *surface, SDL_RWops *out, int rle) buf = linebuf->pixels; n = surface->w * bpp; } +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (!SDL_WriteIO(out, buf, n)) +#else if (!SDL_RWwrite(out, buf, n, 1)) +#endif break; } diff --git a/src_c/meson.build b/src_c/meson.build index 4be6a4683a..ca10cca737 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -198,8 +198,6 @@ draw = py.extension_module( ) endif -# TODO: support SDL3 -if sdl_api != 3 image = py.extension_module( 'image', 'image.c', @@ -208,7 +206,6 @@ image = py.extension_module( install: true, subdir: pg, ) -endif # TODO: support SDL3 if sdl_api != 3 diff --git a/src_c/surface.c b/src_c/surface.c index 1330f6b93b..31b1a7072b 100644 --- a/src_c/surface.c +++ b/src_c/surface.c @@ -2575,8 +2575,8 @@ surf_subsurface(PyObject *self, PyObject *args) rect->x * PG_FORMAT_BytesPerPixel(format) + rect->y * surf->pitch; - sub = PG_CreateSurfaceFrom(startpixel, rect->w, rect->h, surf->pitch, - format->format); + sub = PG_CreateSurfaceFrom(rect->w, rect->h, format->format, startpixel, + surf->pitch); pgSurface_Unlock((pgSurfaceObject *)self); diff --git a/src_c/transform.c b/src_c/transform.c index 22d010f657..00f72efb19 100644 --- a/src_c/transform.c +++ b/src_c/transform.c @@ -450,9 +450,9 @@ scale_to(pgSurfaceObject *srcobj, pgSurfaceObject *dstobj, int width, * rejects the input. * For example, RGBA and RGBX surfaces are compatible in this way. */ if (retsurf->format->Amask != src->format->Amask) { - modsurf = - PG_CreateSurfaceFrom(retsurf->pixels, retsurf->w, retsurf->h, - retsurf->pitch, src->format->format); + modsurf = PG_CreateSurfaceFrom(retsurf->w, retsurf->h, + src->format->format, + retsurf->pixels, retsurf->pitch); } } From a20c77eff0f28f3dda082664b4c7cc1993b998ea Mon Sep 17 00:00:00 2001 From: Starbuck5 <46412508+Starbuck5@users.noreply.github.com> Date: Fri, 11 Oct 2024 22:10:51 -0700 Subject: [PATCH 08/36] Adjust type in image.c --- src_c/image.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_c/image.c b/src_c/image.c index c07a3d01cf..6141ae8871 100644 --- a/src_c/image.c +++ b/src_c/image.c @@ -1674,7 +1674,7 @@ SaveTGA_RW(SDL_Surface *surface, SDL_RWops *out, int rle) #else SDL_PixelFormat *surf_format = surface->format; SDL_Palette *surf_palette = surface->format->palette; - Uint32 output_format; + SDL_PixelFormatEnum output_format; #endif SDL_GetSurfaceAlphaMod(surface, &surf_alpha); From 8c377c0bd5242bd1520eeb37ef718189646db21b Mon Sep 17 00:00:00 2001 From: Damiano <97639432+damusss@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:31:41 +0200 Subject: [PATCH 09/36] Add main guard to examples + very small fixes --- examples/README.rst | 3 + examples/audiocapture.py | 63 ++++--- examples/font_viewer.py | 7 +- examples/go_over_there.py | 64 ++++--- examples/multiplayer_joystick.py | 212 +++++++++++---------- examples/ninepatch.py | 3 +- examples/prevent_display_stretching.py | 123 +++++++------ examples/resizing_new.py | 80 ++++---- examples/scrap_clipboard.py | 102 ++++++----- examples/setmodescale.py | 133 +++++++------- examples/sprite_texture.py | 133 +++++++------- examples/video.py | 243 +++++++++++++------------ examples/window_opengl.py | 136 +++++++------- 13 files changed, 682 insertions(+), 620 deletions(-) diff --git a/examples/README.rst b/examples/README.rst index fce9b30b90..1e38461b5d 100644 --- a/examples/README.rst +++ b/examples/README.rst @@ -78,6 +78,9 @@ music_drop_fade.py several events. Uses fade_ms added in pygame2, as well as set_endevent, set_volume, drag and drop events, and the scrap module. +ninepatch.py + Demonstrate the purpose of the 9-patch scale method and a way to implement it. + pixelarray.py Process whole arrays of pixels at a time. Like numpy, but for pixels, and also built into pygame. diff --git a/examples/audiocapture.py b/examples/audiocapture.py index 3811a20567..c4026516f9 100644 --- a/examples/audiocapture.py +++ b/examples/audiocapture.py @@ -18,14 +18,6 @@ ) from pygame._sdl2.mixer import set_post_mix - -pygame.mixer.pre_init(44100, 32, 2, 512) -pygame.init() - -# init_subsystem(INIT_AUDIO) -names = get_audio_device_names(True) -print(names) - sounds = [] sound_chunks = [] @@ -49,31 +41,42 @@ def postmix_callback(postmix, audiomemoryview): print(postmix) -set_post_mix(postmix_callback) +def main(): + pygame.mixer.pre_init(44100, 32, 2, 512) + pygame.init() -audio = AudioDevice( - devicename=names[0], - iscapture=True, - frequency=44100, - audioformat=AUDIO_F32, - numchannels=2, - chunksize=512, - allowed_changes=AUDIO_ALLOW_FORMAT_CHANGE, - callback=callback, -) -# start recording. -audio.pause(0) + # init_subsystem(INIT_AUDIO) + names = get_audio_device_names(True) + print(names) + + set_post_mix(postmix_callback) + + audio = AudioDevice( + devicename=names[0], + iscapture=True, + frequency=44100, + audioformat=AUDIO_F32, + numchannels=2, + chunksize=512, + allowed_changes=AUDIO_ALLOW_FORMAT_CHANGE, + callback=callback, + ) + # start recording. + audio.pause(0) + + print(audio) -print(audio) + print(f"recording with '{names[0]}'") + time.sleep(5) -print(f"recording with '{names[0]}'") -time.sleep(5) + print("Turning data into a pygame.mixer.Sound") + sound = pygame.mixer.Sound(buffer=b"".join(sound_chunks)) + print("playing back recorded sound") + sound.play() + time.sleep(5) + pygame.quit() -print("Turning data into a pygame.mixer.Sound") -sound = pygame.mixer.Sound(buffer=b"".join(sound_chunks)) -print("playing back recorded sound") -sound.play() -time.sleep(5) -pygame.quit() +if __name__ == "__main__": + main() diff --git a/examples/font_viewer.py b/examples/font_viewer.py index 67569e4351..3acd24c034 100644 --- a/examples/font_viewer.py +++ b/examples/font_viewer.py @@ -122,7 +122,7 @@ def render_fonts(self, text="A display of font &N"): line = text.replace("&N", name) try: surf = font.render( - line, 1, color, self.back_color, self.screen_size[0] - 20 + line, True, color, self.back_color, self.screen_size[0] - 20 ) except pygame.error as e: print(e) @@ -281,5 +281,6 @@ def handle_events(self): return True -viewer = FontViewer() -pygame.quit() +if __name__ == "__main__": + viewer = FontViewer() + pygame.quit() diff --git a/examples/go_over_there.py b/examples/go_over_there.py index 10ff3742ee..7284134190 100644 --- a/examples/go_over_there.py +++ b/examples/go_over_there.py @@ -19,10 +19,6 @@ SCREEN_SIZE = pygame.Vector2(1000, 600) CIRCLE_RADIUS = 5 -pygame.init() -screen = pygame.display.set_mode(SCREEN_SIZE) -clock = pygame.Clock() - target_position = None balls = [] @@ -49,35 +45,47 @@ def reset(): balls.append(b) -reset() -delta_time = 0 -running = True -while running: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False +def main(): + global target_position + global balls - if event.type == pygame.MOUSEBUTTONUP: - target_position = pygame.mouse.get_pos() + pygame.init() + screen = pygame.display.set_mode(SCREEN_SIZE) + clock = pygame.Clock() - if event.type == pygame.KEYUP: - if event.key == pygame.K_ESCAPE: + reset() + delta_time = 0 + running = True + while running: + for event in pygame.event.get(): + if event.type == pygame.QUIT: running = False - if event.key == pygame.K_r: - reset() + if event.type == pygame.MOUSEBUTTONUP: + target_position = pygame.mouse.get_pos() + + if event.type == pygame.KEYUP: + if event.key == pygame.K_ESCAPE: + running = False - screen.fill((31, 143, 65)) + if event.key == pygame.K_r: + reset() + + screen.fill((31, 143, 65)) + + for o in balls: + if target_position is not None: + o.position.move_towards_ip(target_position, o.speed * delta_time) + pygame.draw.circle(screen, (118, 207, 145), o.position, CIRCLE_RADIUS) + + pygame.display.flip() + delta_time = clock.tick(60) + pygame.display.set_caption( + f"fps: {round(clock.get_fps(), 2)}, ball count: {len(balls)}" + ) - for o in balls: - if target_position is not None: - o.position.move_towards_ip(target_position, o.speed * delta_time) - pygame.draw.circle(screen, (118, 207, 145), o.position, CIRCLE_RADIUS) + pygame.quit() - pygame.display.flip() - delta_time = clock.tick(60) - pygame.display.set_caption( - f"fps: {round(clock.get_fps(), 2)}, ball count: {len(balls)}" - ) -pygame.quit() +if __name__ == "__main__": + main() diff --git a/examples/multiplayer_joystick.py b/examples/multiplayer_joystick.py index a95d652b6e..6c8eac7a07 100644 --- a/examples/multiplayer_joystick.py +++ b/examples/multiplayer_joystick.py @@ -1,8 +1,10 @@ import sys import pygame +WIDTH, HEIGHT = 500, 500 + -def connect_joystick(index): +def connect_joystick(index, active_players, players, colors): if len(active_players) < len(players): joy = pygame.Joystick(index) index = players.index(None) @@ -18,7 +20,7 @@ def connect_joystick(index): print(f"P{index + 1} Connected") -def disconnect_joystick(instance_id: int): +def disconnect_joystick(instance_id: int, active_players, players): index = active_players[instance_id] players[index] = None del active_players[instance_id] @@ -39,106 +41,116 @@ def create_surf(size, color): return surf -pygame.init() +def main(): + pygame.init() + + screen = pygame.display.set_mode((WIDTH, HEIGHT)) + pygame.display.set_caption("Multiplayer Joystick example") + clock = pygame.Clock() + font_b = pygame.font.SysFont(None, 25) + font_a = pygame.font.SysFont(None, 16) + + players = [None, None] # two players limit + active_players = {} + + colors = [ + create_surf((32, 32), (220, 180, 10)), + create_surf((32, 32), (60, 230, 170)), + create_surf((32, 32), (230, 20, 70)), + create_surf((32, 32), (20, 170, 230)), + ] + are_no_controllers_connected = True + + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() + elif event.type == pygame.JOYDEVICEADDED: + if len(active_players) < len(players): + # connect controller + connect_joystick( + event.device_index, active_players, players, colors + ) + are_no_controllers_connected = False + elif event.type == pygame.JOYDEVICEREMOVED: + # disconnect controller + if event.instance_id in active_players: + disconnect_joystick(event.instance_id, active_players, players) + # check if there is at least one controller connected + are_no_controllers_connected = True + for player in players: + if player: + are_no_controllers_connected = False + break + elif event.type == pygame.JOYBUTTONDOWN: + if event.instance_id in active_players: + # join player + if event.button == 0: + index = active_players[event.instance_id] + players[index]["joined"] = True + print(f"P{index + 1} joined") + # leave player + if event.button == 1: + index = active_players[event.instance_id] + if players[index]["joined"]: + players[index]["joined"] = False + players[index]["pos"] = [WIDTH * 0.25 + index * 64, 128] + print(f"P{index + 1} leave") + elif event.type == pygame.JOYAXISMOTION: + if event.instance_id in active_players: + # change the color if player still hasn't joined + if event.axis == 0: + index = active_players[event.instance_id] + player = players[index] + if not player["joined"]: + if event.value >= 1.0: + player["surf_idx"] += 1 + elif event.value <= -1.0: + player["surf_idx"] -= 1 + player["surf_idx"] = player["surf_idx"] % len(colors) + player["surf"] = colors[player["surf_idx"]] + + screen.fill((30, 30, 30)) + pygame.draw.line(screen, (230, 230, 230), (0, 96), (WIDTH, 96), 2) + + # update and draw players + for player in players: + if player: + control_player(player) + screen.blit(player["surf"], player["pos"]) + + # draw available colors + for i, surf in enumerate(colors): + screen.blit(surf, (WIDTH * 0.25 + i * 64, 32)) + + # show message for connecting a controller + if are_no_controllers_connected: + screen.blit( + font_b.render( + "Please connect a controller.", + True, + (230, 230, 230), + None, + 500 - 20, + ), + (WIDTH * 0.3, HEIGHT * 0.5), + ) -WIDTH, HEIGHT = 500, 500 -screen = pygame.display.set_mode((WIDTH, HEIGHT)) -pygame.display.set_caption("Multiplayer Joystick example") -clock = pygame.Clock() -font_b = pygame.font.SysFont(None, 25) -font_a = pygame.font.SysFont(None, 16) - -players = [None, None] # two players limit -active_players = {} - -colors = [ - create_surf((32, 32), (220, 180, 10)), - create_surf((32, 32), (60, 230, 170)), - create_surf((32, 32), (230, 20, 70)), - create_surf((32, 32), (20, 170, 230)), -] -are_no_controllers_connected = True - -while True: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - pygame.quit() - sys.exit() - elif event.type == pygame.JOYDEVICEADDED: - if len(active_players) < len(players): - # connect controller - connect_joystick(event.device_index) - are_no_controllers_connected = False - elif event.type == pygame.JOYDEVICEREMOVED: - # disconnect controller - if event.instance_id in active_players: - disconnect_joystick(event.instance_id) - # check if there is at least one controller connected - are_no_controllers_connected = True - for player in players: - if player: - are_no_controllers_connected = False - break - elif event.type == pygame.JOYBUTTONDOWN: - if event.instance_id in active_players: - # join player - if event.button == 0: - index = active_players[event.instance_id] - players[index]["joined"] = True - print(f"P{index + 1} joined") - # leave player - if event.button == 1: - index = active_players[event.instance_id] - if players[index]["joined"]: - players[index]["joined"] = False - players[index]["pos"] = [WIDTH * 0.25 + index * 64, 128] - print(f"P{index + 1} leave") - elif event.type == pygame.JOYAXISMOTION: - if event.instance_id in active_players: - # change the color if player still hasn't joined - if event.axis == 0: - index = active_players[event.instance_id] - player = players[index] - if not player["joined"]: - if event.value >= 1.0: - player["surf_idx"] += 1 - elif event.value <= -1.0: - player["surf_idx"] -= 1 - player["surf_idx"] = player["surf_idx"] % len(colors) - player["surf"] = colors[player["surf_idx"]] - - screen.fill((30, 30, 30)) - pygame.draw.line(screen, (230, 230, 230), (0, 96), (WIDTH, 96), 2) - - # update and draw players - for player in players: - if player: - control_player(player) - screen.blit(player["surf"], player["pos"]) - - # draw available colors - for i, surf in enumerate(colors): - screen.blit(surf, (WIDTH * 0.25 + i * 64, 32)) - - # show message for connecting a controller - if are_no_controllers_connected: screen.blit( - font_b.render( - "Please connect a controller.", True, (230, 230, 230), None, 500 - 20 + font_a.render( + "A: join B: leave Joystick: move / change color", + True, + (230, 230, 230), + None, + WIDTH - 20, ), - (WIDTH * 0.3, HEIGHT * 0.5), + (10, HEIGHT - 20), ) - screen.blit( - font_a.render( - "A: join B: leave Joystick: move / change color", - True, - (230, 230, 230), - None, - WIDTH - 20, - ), - (10, HEIGHT - 20), - ) - - clock.tick(60) - pygame.display.update() + clock.tick(60) + pygame.display.update() + + +if __name__ == "__main__": + main() diff --git a/examples/ninepatch.py b/examples/ninepatch.py index ddcfdb9220..ccdac7dc4f 100644 --- a/examples/ninepatch.py +++ b/examples/ninepatch.py @@ -17,7 +17,6 @@ import os import pygame -import typing SCREEN_SIZE = pygame.Vector2(600, 500) SCALE_SIZE = pygame.Vector2(500, 150) @@ -28,7 +27,7 @@ def ninepatch_scale( surface: pygame.Surface, - size: typing.Sequence[int], + size: pygame.typing.Point, corner_size: int, alpha: bool = True, smooth: bool = False, diff --git a/examples/prevent_display_stretching.py b/examples/prevent_display_stretching.py index 53dafafa88..35c0ad5d1f 100644 --- a/examples/prevent_display_stretching.py +++ b/examples/prevent_display_stretching.py @@ -29,64 +29,69 @@ raise NotImplementedError("this script requires Windows Vista or newer") import pygame - import ctypes -# Determine whether or not the user would like to prevent stretching -if os.path.basename(sys.executable) == "pythonw.exe": - selection = "y" -else: - selection = None - while selection not in ("y", "n"): - selection = input("Prevent stretching? (y/n): ").strip().lower() - -if selection == "y": - msg = "Stretching is prevented." -else: - msg = "Stretching is not prevented." - -# Prevent stretching -if selection == "y": - user32 = ctypes.windll.user32 - user32.SetProcessDPIAware() - -# Show screen -pygame.display.init() -RESOLUTION = (350, 350) -screen = pygame.display.set_mode(RESOLUTION) - -# Render message onto a surface -pygame.font.init() -font = pygame.Font(None, 36) -msg_surf = font.render(msg, 1, TEXTCOLOR) -res_surf = font.render("Intended resolution: %ix%i" % RESOLUTION, 1, TEXTCOLOR) - -# Control loop -running = True -clock = pygame.Clock() -counter = 0 -while running: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False - - screen.fill(BACKGROUNDCOLOR) - - # Draw lines which will be blurry if the window is stretched - # or clear if the window is not stretched. - pygame.draw.line(screen, AXISCOLOR, (0, counter), (RESOLUTION[0] - 1, counter)) - pygame.draw.line(screen, AXISCOLOR, (counter, 0), (counter, RESOLUTION[1] - 1)) - - # Blit message onto screen surface - msg_blit_rect = screen.blit(msg_surf, (0, 0)) - screen.blit(res_surf, (0, msg_blit_rect.bottom)) - - clock.tick(10) - - pygame.display.flip() - - counter += 1 - if counter == RESOLUTION[0]: - counter = 0 - -pygame.quit() + +def main(): + # Determine whether or not the user would like to prevent stretching + if os.path.basename(sys.executable) == "pythonw.exe": + selection = "y" + else: + selection = None + while selection not in ("y", "n"): + selection = input("Prevent stretching? (y/n): ").strip().lower() + + if selection == "y": + msg = "Stretching is prevented." + else: + msg = "Stretching is not prevented." + + # Prevent stretching + if selection == "y": + user32 = ctypes.windll.user32 + user32.SetProcessDPIAware() + + # Show screen + pygame.display.init() + RESOLUTION = (350, 350) + screen = pygame.display.set_mode(RESOLUTION) + + # Render message onto a surface + pygame.font.init() + font = pygame.Font(None, 36) + msg_surf = font.render(msg, True, TEXTCOLOR) + res_surf = font.render("Intended resolution: %ix%i" % RESOLUTION, 1, TEXTCOLOR) + + # Control loop + running = True + clock = pygame.Clock() + counter = 0 + while running: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + screen.fill(BACKGROUNDCOLOR) + + # Draw lines which will be blurry if the window is stretched + # or clear if the window is not stretched. + pygame.draw.line(screen, AXISCOLOR, (0, counter), (RESOLUTION[0] - 1, counter)) + pygame.draw.line(screen, AXISCOLOR, (counter, 0), (counter, RESOLUTION[1] - 1)) + + # Blit message onto screen surface + msg_blit_rect = screen.blit(msg_surf, (0, 0)) + screen.blit(res_surf, (0, msg_blit_rect.bottom)) + + clock.tick(10) + + pygame.display.flip() + + counter += 1 + if counter == RESOLUTION[0]: + counter = 0 + + pygame.quit() + + +if __name__ == "__main__": + main() diff --git a/examples/resizing_new.py b/examples/resizing_new.py index cccde5badd..48eeadf06a 100644 --- a/examples/resizing_new.py +++ b/examples/resizing_new.py @@ -1,41 +1,49 @@ #!/usr/bin/env python import pygame -pygame.init() RESOLUTION = (160, 120) FPS = 30 -clock = pygame.Clock() - -screen = pygame.display.set_mode(RESOLUTION, pygame.RESIZABLE) -pygame.display._set_autoresize(False) - -# MAIN LOOP - -done = False - -i = 0 -j = 0 - -while not done: - for event in pygame.event.get(): - if event.type == pygame.KEYDOWN and event.key == pygame.K_q: - done = True - elif event.type == pygame.VIDEORESIZE: - screen = pygame.display.get_surface() - elif event.type == pygame.QUIT: - done = True - i += 1 - i = i % screen.get_width() - j += i % 2 - j = j % screen.get_height() - - screen.fill((255, 0, 255)) - pygame.draw.circle(screen, (0, 0, 0), (100, 100), 20) - pygame.draw.circle(screen, (0, 0, 200), (0, 0), 10) - pygame.draw.circle(screen, (200, 0, 0), (160, 120), 30) - pygame.draw.line(screen, (250, 250, 0), (0, 120), (160, 0)) - pygame.draw.circle(screen, (255, 255, 255), (i, j), 5) - - pygame.display.flip() - clock.tick(FPS) -pygame.quit() + + +def main(): + pygame.init() + + clock = pygame.Clock() + + screen = pygame.display.set_mode(RESOLUTION, pygame.RESIZABLE) + pygame.display._set_autoresize(False) + + # MAIN LOOP + + done = False + + i = 0 + j = 0 + + while not done: + for event in pygame.event.get(): + if event.type == pygame.KEYDOWN and event.key == pygame.K_q: + done = True + elif event.type == pygame.VIDEORESIZE: + screen = pygame.display.get_surface() + elif event.type == pygame.QUIT: + done = True + i += 1 + i = i % screen.get_width() + j += i % 2 + j = j % screen.get_height() + + screen.fill((255, 0, 255)) + pygame.draw.circle(screen, (0, 0, 0), (100, 100), 20) + pygame.draw.circle(screen, (0, 0, 200), (0, 0), 10) + pygame.draw.circle(screen, (200, 0, 0), (160, 120), 30) + pygame.draw.line(screen, (250, 250, 0), (0, 120), (160, 0)) + pygame.draw.circle(screen, (255, 255, 255), (i, j), 5) + + pygame.display.flip() + clock.tick(FPS) + pygame.quit() + + +if __name__ == "__main__": + main() diff --git a/examples/scrap_clipboard.py b/examples/scrap_clipboard.py index db37250e31..f5f957c381 100644 --- a/examples/scrap_clipboard.py +++ b/examples/scrap_clipboard.py @@ -16,54 +16,58 @@ import pygame -pygame.init() -pygame.display.set_caption("Clipboard Example") -width, height = (960, 540) -screen = pygame.display.set_mode((width, height)) -clock = pygame.Clock() -font = pygame.Font(None, 30) - - -clipboard_text = "" -running = True - -while running: - screen.fill("black") - - instruction = "Keyboard Controls:\nV - View the current clipboard data.\nC - Copy some text into the clipboard.\nEscape - Quit" - text = font.render(instruction, True, "white") - screen.blit(text, (0, 0)) - - text = font.render( - f"Text on the clipboard:\n{clipboard_text}", True, "white", None, width - 20 - ) - screen.blit(text, (0, 100)) - - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False - - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_v: - # Look for any text data in the clipboard. - print("Looking for text in the clipboard.") - if pygame.scrap.has_text(): - print("Text found in the clipboard.") - clipboard_text = pygame.scrap.get_text() - else: - print("No text in the clipboard.") - - elif event.key == pygame.K_c: - # put some text into the clipboard. - print("Putting text into the clipboard.") - - pygame.scrap.put_text( - "Hello World! This is some text from the pygame scrap example.", - ) - - elif event.key == pygame.K_ESCAPE: +def main(): + pygame.init() + pygame.display.set_caption("Clipboard Example") + width, height = (960, 540) + screen = pygame.display.set_mode((width, height)) + clock = pygame.Clock() + font = pygame.Font(None, 30) + + clipboard_text = "" + running = True + + while running: + screen.fill("black") + + instruction = "Keyboard Controls:\nV - View the current clipboard data.\nC - Copy some text into the clipboard.\nEscape - Quit" + text = font.render(instruction, True, "white") + screen.blit(text, (0, 0)) + + text = font.render( + f"Text on the clipboard:\n{clipboard_text}", True, "white", None, width - 20 + ) + screen.blit(text, (0, 100)) + + for event in pygame.event.get(): + if event.type == pygame.QUIT: running = False - pygame.display.flip() - clock.tick(60) -pygame.quit() + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_v: + # Look for any text data in the clipboard. + print("Looking for text in the clipboard.") + if pygame.scrap.has_text(): + print("Text found in the clipboard.") + clipboard_text = pygame.scrap.get_text() + else: + print("No text in the clipboard.") + + elif event.key == pygame.K_c: + # put some text into the clipboard. + print("Putting text into the clipboard.") + + pygame.scrap.put_text( + "Hello World! This is some text from the pygame scrap example.", + ) + + elif event.key == pygame.K_ESCAPE: + running = False + + pygame.display.flip() + clock.tick(60) + pygame.quit() + + +if __name__ == "__main__": + main() diff --git a/examples/setmodescale.py b/examples/setmodescale.py index 2e58f50868..b8d119da77 100644 --- a/examples/setmodescale.py +++ b/examples/setmodescale.py @@ -13,71 +13,78 @@ import pygame import sys -pygame.init() - RES = (160, 120) FPS = 30 -clock = pygame.Clock() - -print("desktops", pygame.display.get_desktop_sizes()) - -do_vsync = bool("--vsync" in sys.argv) - -if do_vsync: - screen = pygame.display.set_mode(RES, pygame.SCALED | pygame.RESIZABLE, vsync=1) -else: - screen = pygame.display.set_mode(RES, pygame.SCALED | pygame.RESIZABLE) - -# MAIN LOOP - -done = False - -i = 0 -j = 0 - -r_name, r_flags = pygame.display._get_renderer_info() -print("renderer:", r_name, "flags:", bin(r_flags)) -for flag, name in [ - (1, "software"), - (2, "accelerated"), - (4, "VSync"), - (8, "render to texture"), -]: - if flag & r_flags: - print(name) - -while not done: - for event in pygame.event.get(): - if event.type == pygame.KEYDOWN and event.key == pygame.K_q: - done = True - if event.type == pygame.QUIT: - done = True - if event.type == pygame.KEYDOWN and event.key == pygame.K_f: - pygame.display.toggle_fullscreen() - i += 1 - i = i % screen.get_width() - j += i % 2 - j = j % screen.get_height() - - screen.fill((255, 0, 255)) - pygame.draw.circle(screen, (0, 0, 0), (100, 100), 20) - pygame.draw.circle(screen, (0, 0, 200), (0, 0), 10) - pygame.draw.circle(screen, (200, 0, 0), (160, 120), 30) - if do_vsync: - # vertical line that moves horizontally to make screen tearing obvious - pygame.draw.line(screen, (250, 250, 0), (i, 0), (i, 120)) - else: - pygame.draw.line(screen, (250, 250, 0), (0, 120), (160, 0)) - pygame.draw.circle(screen, (255, 255, 255), (i, j), 5) - pygame.display.set_caption("FPS:" + str(clock.get_fps())) + +def main(): + pygame.init() + + clock = pygame.Clock() + + print("desktops", pygame.display.get_desktop_sizes()) + + do_vsync = bool("--vsync" in sys.argv) + if do_vsync: - pygame.display.flip() - # FPS should be limited by vsync, so we tick really fast - # we only need to have the clock tick to track FPS - clock.tick() + screen = pygame.display.set_mode(RES, pygame.SCALED | pygame.RESIZABLE, vsync=1) else: - clock.tick(FPS) - pygame.display.flip() - -pygame.quit() + screen = pygame.display.set_mode(RES, pygame.SCALED | pygame.RESIZABLE) + + # MAIN LOOP + + done = False + + i = 0 + j = 0 + + r_name, r_flags = pygame.display._get_renderer_info() + print("renderer:", r_name, "flags:", bin(r_flags)) + for flag, name in [ + (1, "software"), + (2, "accelerated"), + (4, "VSync"), + (8, "render to texture"), + ]: + if flag & r_flags: + print(name) + + while not done: + for event in pygame.event.get(): + if event.type == pygame.KEYDOWN and event.key == pygame.K_q: + done = True + if event.type == pygame.QUIT: + done = True + if event.type == pygame.KEYDOWN and event.key == pygame.K_f: + pygame.display.toggle_fullscreen() + i += 1 + i = i % screen.get_width() + j += i % 2 + j = j % screen.get_height() + + screen.fill((255, 0, 255)) + pygame.draw.circle(screen, (0, 0, 0), (100, 100), 20) + pygame.draw.circle(screen, (0, 0, 200), (0, 0), 10) + pygame.draw.circle(screen, (200, 0, 0), (160, 120), 30) + if do_vsync: + # vertical line that moves horizontally to make screen tearing obvious + pygame.draw.line(screen, (250, 250, 0), (i, 0), (i, 120)) + else: + pygame.draw.line(screen, (250, 250, 0), (0, 120), (160, 0)) + pygame.draw.circle(screen, (255, 255, 255), (i, j), 5) + + pygame.display.set_caption("FPS:" + str(clock.get_fps())) + if do_vsync: + pygame.display.flip() + # FPS should be limited by vsync, so we tick really fast + # we only need to have the clock tick to track FPS + clock.tick() + else: + clock.tick(FPS) + pygame.display.flip() + + pygame.quit() + + +if __name__ == "__main__": + main() diff --git a/examples/sprite_texture.py b/examples/sprite_texture.py index 72eb5bfd16..34539c833f 100644 --- a/examples/sprite_texture.py +++ b/examples/sprite_texture.py @@ -24,81 +24,84 @@ def load_img(file): return pygame.image.load(os.path.join(data_dir, file)) -pygame.display.init() -pygame.key.set_repeat(10, 10) +def main(): + pygame.display.init() + pygame.key.set_repeat(10, 10) -win = Window("asdf", resizable=True) -renderer = Renderer(win) -tex = Texture.from_surface(renderer, load_img("alien1.gif")) + win = Window("asdf", resizable=True) + renderer = Renderer(win) + tex = Texture.from_surface(renderer, load_img("alien1.gif")) + class Something(pygame.sprite.Sprite): + def __init__(self, img): + pygame.sprite.Sprite.__init__(self) -class Something(pygame.sprite.Sprite): - def __init__(self, img): - pygame.sprite.Sprite.__init__(self) + self.rect = img.get_rect() + self.image = img - self.rect = img.get_rect() - self.image = img + self.rect.w *= 5 + self.rect.h *= 5 - self.rect.w *= 5 - self.rect.h *= 5 + img.origin = self.rect.w / 2, self.rect.h / 2 - img.origin = self.rect.w / 2, self.rect.h / 2 + sprite = Something(Image(tex, (0, 0, tex.width / 2, tex.height / 2))) + sprite.rect.x = 250 + sprite.rect.y = 50 + # sprite2 = Something(Image(sprite.image)) + sprite2 = Something(Image(tex)) + sprite2.rect.x = 250 + sprite2.rect.y = 250 + sprite2.rect.w /= 2 + sprite2.rect.h /= 2 -sprite = Something(Image(tex, (0, 0, tex.width / 2, tex.height / 2))) -sprite.rect.x = 250 -sprite.rect.y = 50 + group = pygame.sprite.Group() + group.add(sprite2) + group.add(sprite) -# sprite2 = Something(Image(sprite.image)) -sprite2 = Something(Image(tex)) -sprite2.rect.x = 250 -sprite2.rect.y = 250 -sprite2.rect.w /= 2 -sprite2.rect.h /= 2 + import math -group = pygame.sprite.Group() -group.add(sprite2) -group.add(sprite) + t = 0 + running = True + clock = pygame.Clock() + renderer.draw_color = (255, 0, 0, 255) -import math + while running: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + running = False + elif event.key == pygame.K_LEFT: + sprite.rect.x -= 5 + elif event.key == pygame.K_RIGHT: + sprite.rect.x += 5 + elif event.key == pygame.K_DOWN: + sprite.rect.y += 5 + elif event.key == pygame.K_UP: + sprite.rect.y -= 5 -t = 0 -running = True -clock = pygame.Clock() -renderer.draw_color = (255, 0, 0, 255) + renderer.clear() + t += 1 -while running: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_ESCAPE: - running = False - elif event.key == pygame.K_LEFT: - sprite.rect.x -= 5 - elif event.key == pygame.K_RIGHT: - sprite.rect.x += 5 - elif event.key == pygame.K_DOWN: - sprite.rect.y += 5 - elif event.key == pygame.K_UP: - sprite.rect.y -= 5 - - renderer.clear() - t += 1 - - img = sprite.image - img.angle += 1 - img.flip_x = t % 50 < 25 - img.flip_y = t % 100 < 50 - img.color[0] = int(255.0 * (0.5 + math.sin(0.5 * t + 10.0) / 2.0)) - img.alpha = int(255.0 * (0.5 + math.sin(0.1 * t) / 2.0)) - # img.draw(dstrect=(x, y, 5 * img.srcrect['w'], 5 * img.srcrect['h'])) - - group.draw(renderer) - - renderer.present() - - clock.tick(60) - win.title = str(f"FPS: {clock.get_fps()}") - -pygame.quit() + img = sprite.image + img.angle += 1 + img.flip_x = t % 50 < 25 + img.flip_y = t % 100 < 50 + img.color[0] = int(255.0 * (0.5 + math.sin(0.5 * t + 10.0) / 2.0)) + img.alpha = int(255.0 * (0.5 + math.sin(0.1 * t) / 2.0)) + # img.draw(dstrect=(x, y, 5 * img.srcrect['w'], 5 * img.srcrect['h'])) + + group.draw(renderer) + + renderer.present() + + clock.tick(60) + win.title = str(f"FPS: {clock.get_fps()}") + + pygame.quit() + + +if __name__ == "__main__": + main() diff --git a/examples/video.py b/examples/video.py index e4da1aded2..81b11f03dc 100644 --- a/examples/video.py +++ b/examples/video.py @@ -22,139 +22,142 @@ def load_img(file): return pygame.image.load(os.path.join(data_dir, file)) -pygame.display.init() -pygame.key.set_repeat(1000, 10) +def main(): + pygame.display.init() + pygame.key.set_repeat(1000, 10) -for driver in get_drivers(): - print(driver) + for driver in get_drivers(): + print(driver) -import random + import random -answer = pygame.display.message_box( - "I will open two windows! Continue?", - "Hello!", - message_type="info", - buttons=("Yes", "No", "Chance"), - return_button=0, - escape_button=1, -) + answer = pygame.display.message_box( + "I will open two windows! Continue?", + "Hello!", + message_type="info", + buttons=("Yes", "No", "Chance"), + return_button=0, + escape_button=1, + ) -if answer == 1 or (answer == 2 and random.random() < 0.5): - import sys + if answer == 1 or (answer == 2 and random.random() < 0.5): + import sys - sys.exit(0) + sys.exit(0) -win = Window("asdf", resizable=True) -renderer = Renderer(win) -tex = Texture.from_surface(renderer, load_img("alien1.gif")) + win = Window("asdf", resizable=True) + renderer = Renderer(win) + tex = Texture.from_surface(renderer, load_img("alien1.gif")) -running = True + running = True -x, y = 250, 50 -clock = pygame.Clock() + x, y = 250, 50 + clock = pygame.Clock() -backgrounds = [(255, 0, 0, 255), (0, 255, 0, 255), (0, 0, 255, 255)] -bg_index = 0 + backgrounds = [(255, 0, 0, 255), (0, 255, 0, 255), (0, 0, 255, 255)] + bg_index = 0 -renderer.draw_color = backgrounds[bg_index] - -win2 = Window("2nd window", size=(256, 256), always_on_top=True) -win2.opacity = 0.5 -win2.set_icon(load_img("bomb.gif")) -renderer2 = Renderer(win2) -tex2 = Texture.from_surface(renderer2, load_img("asprite.bmp")) -renderer2.clear() -tex2.draw() -renderer2.present() -del tex2 - -full = 0 + renderer.draw_color = backgrounds[bg_index] -tex = Image(tex) + win2 = Window("2nd window", size=(256, 256), always_on_top=True) + win2.opacity = 0.5 + win2.set_icon(load_img("bomb.gif")) + renderer2 = Renderer(win2) + tex2 = Texture.from_surface(renderer2, load_img("asprite.bmp")) + renderer2.clear() + tex2.draw() + renderer2.present() + del tex2 + full = 0 -surf = pygame.Surface((64, 64)) -streamtex = Texture(renderer, (64, 64), streaming=True) -tex_update_interval = 1000 -next_tex_update = pygame.time.get_ticks() + tex = Image(tex) + surf = pygame.Surface((64, 64)) + streamtex = Texture(renderer, (64, 64), streaming=True) + tex_update_interval = 1000 + next_tex_update = pygame.time.get_ticks() -while running: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False - elif getattr(event, "window", None) == win2: - if ( - event.type == pygame.KEYDOWN - and event.key == pygame.K_ESCAPE - or event.type == pygame.WINDOWCLOSE - ): - win2.destroy() - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_ESCAPE: + while running: + for event in pygame.event.get(): + if event.type == pygame.QUIT: running = False - elif event.key == pygame.K_LEFT: - x -= 5 - elif event.key == pygame.K_RIGHT: - x += 5 - elif event.key == pygame.K_DOWN: - y += 5 - elif event.key == pygame.K_UP: - y -= 5 - elif event.key == pygame.K_f: - if full == 0: - win.set_fullscreen(True) - full = 1 - else: - win.set_windowed() - full = 0 - elif event.key == pygame.K_s: - readsurf = renderer.to_surface() - pygame.image.save(readsurf, "test.png") - - elif event.key == pygame.K_SPACE: - bg_index = (bg_index + 1) % len(backgrounds) - renderer.draw_color = backgrounds[bg_index] - - renderer.clear() - - # update texture - curtime = pygame.time.get_ticks() - if curtime >= next_tex_update: - for x_ in range(streamtex.width // 4): - for y_ in range(streamtex.height // 4): - newcol = ( - random.randint(0, 255), - random.randint(0, 255), - random.randint(0, 255), - 255, - ) - area = (4 * x_, 4 * y_, 4, 4) - surf.fill(newcol, area) - streamtex.update(surf) - next_tex_update = curtime + tex_update_interval - streamtex.draw(dstrect=pygame.Rect(64, 128, 64, 64)) - - tex.draw(dstrect=(x, y)) - - # TODO: should these be? - # - line instead of draw_line - # - point instead of draw_point - # - rect(rect, width=1)->draw 1 pixel, instead of draw_rect - # - rect(rect, width=0)->filled ? , instead of fill_rect - # - # TODO: should these work with pygame.draw.line(renderer, ...) functions? - renderer.draw_color = (255, 255, 255, 255) - renderer.draw_line((0, 0), (64, 64)) - renderer.draw_line((64, 64), (128, 0)) - renderer.draw_point((72, 32)) - renderer.draw_rect(pygame.Rect(0, 64, 64, 64)) - renderer.fill_rect(pygame.Rect(0, 128, 64, 64)) - renderer.draw_color = backgrounds[bg_index] - - renderer.present() - - clock.tick(60) - win.title = str(f"FPS: {clock.get_fps()}") - -pygame.quit() + elif getattr(event, "window", None) == win2: + if ( + event.type == pygame.KEYDOWN + and event.key == pygame.K_ESCAPE + or event.type == pygame.WINDOWCLOSE + ): + win2.destroy() + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + running = False + elif event.key == pygame.K_LEFT: + x -= 5 + elif event.key == pygame.K_RIGHT: + x += 5 + elif event.key == pygame.K_DOWN: + y += 5 + elif event.key == pygame.K_UP: + y -= 5 + elif event.key == pygame.K_f: + if full == 0: + win.set_fullscreen(True) + full = 1 + else: + win.set_windowed() + full = 0 + elif event.key == pygame.K_s: + readsurf = renderer.to_surface() + pygame.image.save(readsurf, "test.png") + + elif event.key == pygame.K_SPACE: + bg_index = (bg_index + 1) % len(backgrounds) + renderer.draw_color = backgrounds[bg_index] + + renderer.clear() + + # update texture + curtime = pygame.time.get_ticks() + if curtime >= next_tex_update: + for x_ in range(streamtex.width // 4): + for y_ in range(streamtex.height // 4): + newcol = ( + random.randint(0, 255), + random.randint(0, 255), + random.randint(0, 255), + 255, + ) + area = (4 * x_, 4 * y_, 4, 4) + surf.fill(newcol, area) + streamtex.update(surf) + next_tex_update = curtime + tex_update_interval + streamtex.draw(dstrect=pygame.Rect(64, 128, 64, 64)) + + tex.draw(dstrect=(x, y)) + + # TODO: should these be? + # - line instead of draw_line + # - point instead of draw_point + # - rect(rect, width=1)->draw 1 pixel, instead of draw_rect + # - rect(rect, width=0)->filled ? , instead of fill_rect + # + # TODO: should these work with pygame.draw.line(renderer, ...) functions? + renderer.draw_color = (255, 255, 255, 255) + renderer.draw_line((0, 0), (64, 64)) + renderer.draw_line((64, 64), (128, 0)) + renderer.draw_point((72, 32)) + renderer.draw_rect(pygame.Rect(0, 64, 64, 64)) + renderer.fill_rect(pygame.Rect(0, 128, 64, 64)) + renderer.draw_color = backgrounds[bg_index] + + renderer.present() + + clock.tick(60) + win.title = str(f"FPS: {clock.get_fps()}") + + pygame.quit() + + +if __name__ == "__main__": + main() diff --git a/examples/window_opengl.py b/examples/window_opengl.py index 9f10e4b400..253e5def48 100644 --- a/examples/window_opengl.py +++ b/examples/window_opengl.py @@ -9,68 +9,74 @@ import pygame import zengl -window_size = (1280, 720) - -pygame.init() -window = pygame.Window(size=window_size, opengl=True) - -ctx = zengl.context() - -image = ctx.image(window_size, "rgba8unorm", samples=4) - -pipeline = ctx.pipeline( - vertex_shader=""" - #version 330 core - - out vec3 v_color; - - vec2 vertices[3] = vec2[]( - vec2(0.0, 0.8), - vec2(-0.6, -0.8), - vec2(0.6, -0.8) - ); - - vec3 colors[3] = vec3[]( - vec3(1.0, 0.0, 0.0), - vec3(0.0, 1.0, 0.0), - vec3(0.0, 0.0, 1.0) - ); - - void main() { - gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0); - v_color = colors[gl_VertexID]; - } - """, - fragment_shader=""" - #version 330 core - - in vec3 v_color; - - layout (location = 0) out vec4 out_color; - - void main() { - out_color = vec4(v_color, 1.0); - out_color.rgb = pow(out_color.rgb, vec3(1.0 / 2.2)); - } - """, - framebuffer=[image], - topology="triangles", - vertex_count=3, -) - -clock = pygame.Clock() - -while True: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - pygame.quit() - quit() - - ctx.new_frame() - image.clear() - pipeline.render() - image.blit() - ctx.end_frame() - - window.flip() - clock.tick(60) + +def main(): + window_size = (1280, 720) + + pygame.init() + window = pygame.Window(size=window_size, opengl=True) + + ctx = zengl.context() + + image = ctx.image(window_size, "rgba8unorm", samples=4) + + pipeline = ctx.pipeline( + vertex_shader=""" + #version 330 core + + out vec3 v_color; + + vec2 vertices[3] = vec2[]( + vec2(0.0, 0.8), + vec2(-0.6, -0.8), + vec2(0.6, -0.8) + ); + + vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) + ); + + void main() { + gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0); + v_color = colors[gl_VertexID]; + } + """, + fragment_shader=""" + #version 330 core + + in vec3 v_color; + + layout (location = 0) out vec4 out_color; + + void main() { + out_color = vec4(v_color, 1.0); + out_color.rgb = pow(out_color.rgb, vec3(1.0 / 2.2)); + } + """, + framebuffer=[image], + topology="triangles", + vertex_count=3, + ) + + clock = pygame.Clock() + + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + quit() + + ctx.new_frame() + image.clear() + pipeline.render() + image.blit() + ctx.end_frame() + + window.flip() + clock.tick(60) + + +if __name__ == "__main__": + main() From 5af69f9caea3c41d8aaccfd88f7c989b87eee881 Mon Sep 17 00:00:00 2001 From: Lody <69472620+bilhox@users.noreply.github.com> Date: Thu, 17 Oct 2024 21:11:34 +0200 Subject: [PATCH 10/36] Better meson error on windows when libraries versions are not correct (#3178) * try except * proper meson error when problem of version --- meson.build | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/meson.build b/meson.build index dcaeb92fb7..8a62fa1ba9 100644 --- a/meson.build +++ b/meson.build @@ -194,8 +194,18 @@ if plat == 'win' and host_machine.cpu_family().startswith('x86') check: true, ) + foreach lib : dlls + if not fs.exists(lib) + error(f''' + File "@lib@" does not exist. + Please try to delete "prebuilt_downloads/", "prebuilt-x64/" and "prebuilt-x86/" directories, and retry the installation. + ''') + endif + endforeach + # put dlls in root of install install_data(dlls, install_dir: pg_dir, install_tag: 'pg-tag') + else bases = ['/usr/local', '/usr', '/opt/homebrew', '/opt/local'] foreach inc_dir : bases From 120675aa4ca031d858d89fe294d714ee0b1555df Mon Sep 17 00:00:00 2001 From: Damiano <97639432+damusss@users.noreply.github.com> Date: Fri, 18 Oct 2024 11:50:55 +0200 Subject: [PATCH 11/36] Allow erasing pixels in pygame.Surface.scroll and add repeat functionality (#2855) * Implementation, stubs and docs * Remove spaces added by clang-format * Fix variable could not be initialized * Rewrite tests, fix code, add more exceptions * Fix format 1 * Modify test * Generate docs * Allow non erasing pixels * Fix doc * Fix bug with erase * Remove useless memset * Separate in 2 functions for clarity * Use SDL function to secure the clip * Update docs * build docs * FLAG SYSTEM (I can revert if you don't like it) * FLAG_SYSTEM fix stubs * Update Docs * Update versionchanged Co-authored-by: Dan Lawrence * FIX THE MISSING PIXEL BUG * Simplify conditional statement * fix format * Split in 2 functions, update versionchanged * Fix docs and remove redundant C code --------- Co-authored-by: Damus666 <97639432+Damus666@users.noreply.github.com> Co-authored-by: Dan Lawrence --- buildconfig/stubs/pygame/__init__.pyi | 2 + buildconfig/stubs/pygame/constants.pyi | 2 + buildconfig/stubs/pygame/locals.pyi | 2 + buildconfig/stubs/pygame/surface.pyi | 4 +- docs/reST/ref/surface.rst | 27 ++- src_c/_pygame.h | 6 + src_c/constants.c | 3 + src_c/doc/surface_doc.h | 2 +- src_c/surface.c | 297 ++++++++++++++++++++----- test/surface_test.py | 89 +++----- 10 files changed, 302 insertions(+), 132 deletions(-) diff --git a/buildconfig/stubs/pygame/__init__.pyi b/buildconfig/stubs/pygame/__init__.pyi index a8ecdd7f25..ffb58f4cdb 100644 --- a/buildconfig/stubs/pygame/__init__.pyi +++ b/buildconfig/stubs/pygame/__init__.pyi @@ -605,6 +605,8 @@ from .constants import ( SCRAP_PPM as SCRAP_PPM, SCRAP_SELECTION as SCRAP_SELECTION, SCRAP_TEXT as SCRAP_TEXT, + SCROLL_ERASE as SCROLL_ERASE, + SCROLL_REPEAT as SCROLL_REPEAT, SHOWN as SHOWN, SRCALPHA as SRCALPHA, SRCCOLORKEY as SRCCOLORKEY, diff --git a/buildconfig/stubs/pygame/constants.pyi b/buildconfig/stubs/pygame/constants.pyi index 3d793e3c50..463f2509c8 100644 --- a/buildconfig/stubs/pygame/constants.pyi +++ b/buildconfig/stubs/pygame/constants.pyi @@ -528,6 +528,8 @@ SCRAP_PBM: str SCRAP_PPM: str SCRAP_SELECTION: int SCRAP_TEXT: str +SCROLL_ERASE: int +SCROLL_REPEAT: int SHOWN: int SRCALPHA: int SRCCOLORKEY: int diff --git a/buildconfig/stubs/pygame/locals.pyi b/buildconfig/stubs/pygame/locals.pyi index ef822c62d6..e596355311 100644 --- a/buildconfig/stubs/pygame/locals.pyi +++ b/buildconfig/stubs/pygame/locals.pyi @@ -530,6 +530,8 @@ SCRAP_PBM: str SCRAP_PPM: str SCRAP_SELECTION: int SCRAP_TEXT: str +SCROLL_ERASE: int +SCROLL_REPEAT: int SHOWN: int SRCALPHA: int SRCCOLORKEY: int diff --git a/buildconfig/stubs/pygame/surface.pyi b/buildconfig/stubs/pygame/surface.pyi index 535f5d776e..a32c840eba 100644 --- a/buildconfig/stubs/pygame/surface.pyi +++ b/buildconfig/stubs/pygame/surface.pyi @@ -103,7 +103,9 @@ class Surface: rect: Optional[RectLike] = None, special_flags: int = 0, ) -> Rect: ... - def scroll(self, dx: int = 0, dy: int = 0, /) -> None: ... + def scroll( + self, dx: int = 0, dy: int = 0, scroll_flag: int = 0, / + ) -> None: ... @overload def set_colorkey(self, color: ColorLike, flags: int = 0, /) -> None: ... @overload diff --git a/docs/reST/ref/surface.rst b/docs/reST/ref/surface.rst index bed760c271..dbaac65828 100644 --- a/docs/reST/ref/surface.rst +++ b/docs/reST/ref/surface.rst @@ -316,17 +316,30 @@ .. method:: scroll - | :sl:`shift the surface image in place` - | :sg:`scroll(dx=0, dy=0, /) -> None` + | :sl:`shift the Surface pixels in place` + | :sg:`scroll(dx=0, dy=0, scroll_flag=0, /) -> None` - Move the image by dx pixels right and dy pixels down. dx and dy may be - negative for left and up scrolls respectively. Areas of the surface that - are not overwritten retain their original pixel values. Scrolling is - contained by the Surface clip area. It is safe to have dx and dy values - that exceed the surface size. + Move the Surface by dx pixels right and dy pixels down. dx and dy may be + negative for left and up scrolls respectively. + + Scrolling is contained by the Surface clip area. It is safe to have dx + and dy values that exceed the surface size. + + The scroll flag can be: + * ``0`` (default): the pixels are shifted but previous pixels are + not modified. + + * ``pygame.SCROLL_ERASE``: the space created by the shifting pixels + is filled with black or transparency. + + * ``pygame.SCROLL_REPEAT``: the pixels that disappear out of the + surface or clip bounds are brought back on the opposite side + resulting in an infinitely scrolling and repeating surface. .. versionaddedold:: 1.9 + .. versionchanged:: 2.5.3 Add repeating scroll and allow erasing pixels + .. ## Surface.scroll ## .. method:: set_colorkey diff --git a/src_c/_pygame.h b/src_c/_pygame.h index 049e346bb5..0cbfed872f 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -430,6 +430,12 @@ typedef enum { PGS_PREALLOC = 0x01000000 } PygameSurfaceFlags; +typedef enum { + PGS_SCROLL_DEFAULT = 0x00000000, + PGS_SCROLL_REPEAT = 0x00000001, + PGS_SCROLL_ERASE = 0x00000004 +} PygameScrollSurfaceFlags; + #define RAISE(x, y) (PyErr_SetString((x), (y)), NULL) #define RAISERETURN(x, y, r) \ PyErr_SetString((x), (y)); \ diff --git a/src_c/constants.c b/src_c/constants.c index 6856db5568..f9eb244007 100644 --- a/src_c/constants.c +++ b/src_c/constants.c @@ -116,6 +116,9 @@ MODINIT_DEFINE(constants) DEC_CONSTSF(SHOWN); DEC_CONSTSF(HIDDEN); + DEC_CONSTSF(SCROLL_ERASE); + DEC_CONSTSF(SCROLL_REPEAT); + DEC_CONSTSF(SCALED); DEC_CONST(GL_RED_SIZE); diff --git a/src_c/doc/surface_doc.h b/src_c/doc/surface_doc.h index b76fd8f586..43b62cbfa5 100644 --- a/src_c/doc/surface_doc.h +++ b/src_c/doc/surface_doc.h @@ -7,7 +7,7 @@ #define DOC_SURFACE_CONVERTALPHA "convert_alpha() -> Surface\nchange the pixel format of a surface including per pixel alphas" #define DOC_SURFACE_COPY "copy() -> Surface\ncreate a new copy of a Surface" #define DOC_SURFACE_FILL "fill(color, rect=None, special_flags=0) -> Rect\nfill Surface with a solid color" -#define DOC_SURFACE_SCROLL "scroll(dx=0, dy=0, /) -> None\nshift the surface image in place" +#define DOC_SURFACE_SCROLL "scroll(dx=0, dy=0, scroll_flag=0, /) -> None\nshift the Surface pixels in place" #define DOC_SURFACE_SETCOLORKEY "set_colorkey(color, flags=0, /) -> None\nset_colorkey(None) -> None\nset the transparent colorkey" #define DOC_SURFACE_GETCOLORKEY "get_colorkey() -> RGBA or None\nget the current transparent colorkey" #define DOC_SURFACE_SETALPHA "set_alpha(value, flags=0, /) -> None\nset_alpha(None) -> None\nset the alpha value for the full Surface" diff --git a/src_c/surface.c b/src_c/surface.c index 31b1a7072b..b9e3008ae3 100644 --- a/src_c/surface.c +++ b/src_c/surface.c @@ -82,9 +82,6 @@ static void surface_dealloc(PyObject *self); static void surface_cleanup(pgSurfaceObject *self); -static void -surface_move(Uint8 *src, Uint8 *dst, int h, int span, int srcpitch, - int dstpitch); static PyObject * surf_get_at(PyObject *self, PyObject *args); @@ -2271,19 +2268,204 @@ surf_fblits(pgSurfaceObject *self, PyObject *const *args, Py_ssize_t nargs) return RAISE(PyExc_TypeError, "Unknown error"); } +static int +scroll_repeat(int h, int dx, int dy, int pitch, int span, int xoffset, + Uint8 *startsrc, Uint8 *endsrc, Uint8 *linesrc) +{ + if (dy != 0) { + int yincrease = dy > 0 ? -pitch : pitch; + int spanincrease = dy > 0 ? -span : span; + int templen = (dy > 0 ? dy * span : -dy * span); + int tempheight = (dy > 0 ? dy : -dy); + /* Create a temporary buffer to store the pixels that + are disappearing from the surface */ + Uint8 *tempbuf = (Uint8 *)malloc(templen); + if (tempbuf == NULL) { + PyErr_NoMemory(); + return -1; + } + memset(tempbuf, 0, templen); + Uint8 *templine = tempbuf; + Uint8 *tempend = + templine + (dy > 0 ? (dy - 1) * span : -(dy + 1) * span); + if (dy > 0) { + templine = tempend; + } + int looph = h; + while (looph--) { + // If the current line should disappear copy it to the + // temporary buffer + if ((templine <= tempend && dy < 0) || + (templine >= tempbuf && dy > 0)) { + if (dx > 0) { + memcpy(templine, linesrc + span - xoffset, xoffset); + memcpy(templine + xoffset, linesrc, span - xoffset); + } + else if (dx < 0) { + memcpy(templine + span + xoffset, linesrc, -xoffset); + memcpy(templine, linesrc - xoffset, span + xoffset); + } + else { + memcpy(templine, linesrc, span); + } + memset(linesrc, 0, span); + templine += spanincrease; + } + else { + Uint8 *pastesrc = linesrc + pitch * dy; + if ((dy < 0 && pastesrc >= startsrc) || + (dy > 0 && pastesrc <= endsrc)) { + if (dx > 0) { + memcpy(pastesrc, linesrc + span - xoffset, xoffset); + memcpy(pastesrc + xoffset, linesrc, span - xoffset); + } + else if (dx < 0) { + memcpy(pastesrc + span + xoffset, linesrc, -xoffset); + memcpy(pastesrc, linesrc - xoffset, span + xoffset); + } + else { + memcpy(pastesrc, linesrc, span); + } + } + } + linesrc += yincrease; + } + // Copy the data of the buffer back to the original pixels to + // repeat + templine = tempbuf; + if (dy < 0) { + linesrc = startsrc + pitch * (h - tempheight); + } + else { + linesrc = startsrc; + } + while (tempheight--) { + memcpy(linesrc, templine, span); + linesrc += pitch; + templine += span; + } + free(tempbuf); + } + else { + // No y-shifting, the temporary buffer should only store the x loss + Uint8 *tempbuf = (Uint8 *)malloc((dx > 0 ? xoffset : -xoffset)); + if (tempbuf == NULL) { + PyErr_NoMemory(); + return -1; + } + while (h--) { + if (dx > 0) { + memcpy(tempbuf, linesrc + span - xoffset, xoffset); + memcpy(linesrc + xoffset, linesrc, span - xoffset); + memcpy(linesrc, tempbuf, xoffset); + } + else if (dx < 0) { + memcpy(tempbuf, linesrc, -xoffset); + memcpy(linesrc, linesrc - xoffset, span + xoffset); + memcpy(linesrc + span + xoffset, tempbuf, -xoffset); + } + linesrc += pitch; + } + free(tempbuf); + } + return 0; +} + +static int +scroll_default(int h, int dx, int dy, int pitch, int span, int xoffset, + Uint8 *startsrc, Uint8 *endsrc, Uint8 *linesrc, int erase) +{ + if (dy != 0) { + /* Copy the current line to a before or after position if it's + valid with consideration of x offset and memset to avoid + artifacts */ + int yincrease = dy > 0 ? -pitch : pitch; + while (h--) { + Uint8 *pastesrc = linesrc + pitch * dy; + if ((dy < 0 && pastesrc >= startsrc) || + (dy > 0 && pastesrc <= endsrc)) { + if (dx > 0) { + memcpy(pastesrc + xoffset, linesrc, span - xoffset); + } + else if (dx < 0) { + memcpy(pastesrc, linesrc - xoffset, span + xoffset); + } + else { + memcpy(pastesrc, linesrc, span); + } + if (erase) { + memset(linesrc, 0, span); + // Fix the missing pixel bug + if (dx < 0) { + memset(pastesrc + span + xoffset, 0, -xoffset); + } + else if (dx > 0) { + memset(pastesrc, 0, xoffset); + } + } + } + linesrc += yincrease; + } + } + else { + // No y-shifting, we only need to move pixels on the same line + while (h--) { + if (dx > 0) { + memcpy(linesrc + xoffset, linesrc, span - xoffset); + if (erase) { + memset(linesrc, 0, xoffset); + } + } + else if (dx < 0) { + memcpy(linesrc, linesrc - xoffset, span + xoffset); + if (erase) { + memset(linesrc + span + xoffset, 0, -xoffset); + } + } + linesrc += pitch; + } + } + return 0; +} + +static int +scroll(SDL_Surface *surf, int dx, int dy, int x, int y, int w, int h, + int repeat, int erase) +{ + int bpp = PG_SURF_BytesPerPixel(surf); + int pitch = surf->pitch; + int span = w * bpp; + Uint8 *linesrc = (Uint8 *)surf->pixels + pitch * y + bpp * x; + Uint8 *startsrc = linesrc; + int xoffset = dx * bpp; + Uint8 *endsrc = linesrc; + if (dy > 0) { + endsrc = linesrc + pitch * (h - 1); + linesrc = endsrc; + } + + if (repeat) { + return scroll_repeat(h, dx, dy, pitch, span, xoffset, startsrc, endsrc, + linesrc); + } + else { + return scroll_default(h, dx, dy, pitch, span, xoffset, startsrc, + endsrc, linesrc, erase); + } +} + static PyObject * surf_scroll(PyObject *self, PyObject *args, PyObject *keywds) { - int dx = 0, dy = 0; + int dx = 0, dy = 0, scroll_flag = PGS_SCROLL_DEFAULT; + int erase = 0, repeat = 0; SDL_Surface *surf; - int bpp; - int pitch; - SDL_Rect *clip_rect; - int w, h; - Uint8 *src, *dst; + SDL_Rect *clip_rect, work_rect; + int w = 0, h = 0, x = 0, y = 0; - static char *kwids[] = {"dx", "dy", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "|ii", kwids, &dx, &dy)) { + static char *kwids[] = {"dx", "dy", "scroll_flag", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|iii", kwids, &dx, &dy, + &scroll_flag)) { return NULL; } @@ -2294,46 +2476,60 @@ surf_scroll(PyObject *self, PyObject *args, PyObject *keywds) Py_RETURN_NONE; } + switch (scroll_flag) { + case PGS_SCROLL_REPEAT: { + repeat = 1; + break; + } + case PGS_SCROLL_ERASE: { + erase = 1; + break; + } + default: { + if (scroll_flag != PGS_SCROLL_DEFAULT) { + return RAISE(PyExc_ValueError, "Invalid scroll flag"); + } + } + } + clip_rect = &surf->clip_rect; - w = clip_rect->w; - h = clip_rect->h; - if (dx >= w || dx <= -w || dy >= h || dy <= -h) { + SDL_Rect surf_rect = {0, 0, surf->w, surf->h}; + + // In SDL3, SDL_IntersectRect is renamed to SDL_GetRectIntersection + if (!SDL_IntersectRect(clip_rect, &surf_rect, &work_rect)) { Py_RETURN_NONE; } + w = work_rect.w; + h = work_rect.h; + x = work_rect.x; + y = work_rect.y; + + /* If the clip rect is outside the surface fill and return + for scrolls without repeat. Only fill when erase is true */ + if (!repeat) { + if (dx >= w || dx <= -w || dy >= h || dy <= -h) { + if (erase) { + if (SDL_FillRect(surf, NULL, 0) == -1) { + PyErr_SetString(pgExc_SDLError, SDL_GetError()); + return NULL; + } + } + Py_RETURN_NONE; + } + } + // Repeated scrolls are periodic so we can delete the exceeding value + dx = dx % w; + dy = dy % h; + if (!pgSurface_Lock((pgSurfaceObject *)self)) { return NULL; } - bpp = PG_SURF_BytesPerPixel(surf); - pitch = surf->pitch; - src = dst = - (Uint8 *)surf->pixels + clip_rect->y * pitch + clip_rect->x * bpp; - if (dx >= 0) { - w -= dx; - if (dy > 0) { - h -= dy; - dst += dy * pitch + dx * bpp; - } - else { - h += dy; - src -= dy * pitch; - dst += dx * bpp; - } - } - else { - w += dx; - if (dy > 0) { - h -= dy; - src -= dx * bpp; - dst += dy * pitch; - } - else { - h += dy; - src -= dy * pitch + dx * bpp; - } + if (scroll(surf, dx, dy, x, y, w, h, repeat, erase) < 0) { + pgSurface_Unlock((pgSurfaceObject *)self); + return NULL; } - surface_move(src, dst, h, w * bpp, pitch, pitch); if (!pgSurface_Unlock((pgSurfaceObject *)self)) { return NULL; @@ -3683,23 +3879,6 @@ surf_get_pixels_address(PyObject *self, PyObject *closure) #endif } -static void -surface_move(Uint8 *src, Uint8 *dst, int h, int span, int srcpitch, - int dstpitch) -{ - if (src < dst) { - src += (h - 1) * srcpitch; - dst += (h - 1) * dstpitch; - srcpitch = -srcpitch; - dstpitch = -dstpitch; - } - while (h--) { - memmove(dst, src, span); - src += srcpitch; - dst += dstpitch; - } -} - static int surface_do_overlap(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect) diff --git a/test/surface_test.py b/test/surface_test.py index 0e6a7b6de7..4e4b5d40ca 100644 --- a/test/surface_test.py +++ b/test/surface_test.py @@ -2679,70 +2679,31 @@ def test_unmap_rgb(self): self.assertIsInstance(unmapped_c, pygame.Color) def test_scroll(self): - scrolls = [ - (8, 2, 3), - (16, 2, 3), - (24, 2, 3), - (32, 2, 3), - (32, -1, -3), - (32, 0, 0), - (32, 11, 0), - (32, 0, 11), - (32, -11, 0), - (32, 0, -11), - (32, -11, 2), - (32, 2, -11), - ] - for bitsize, dx, dy in scrolls: - surf = pygame.Surface((10, 10), 0, bitsize) - surf.fill((255, 0, 0)) - surf.fill((0, 255, 0), (2, 2, 2, 2)) - comp = surf.copy() - comp.blit(surf, (dx, dy)) - surf.scroll(dx, dy) - w, h = surf.get_size() - for x in range(w): - for y in range(h): - with self.subTest(x=x, y=y): - self.assertEqual( - surf.get_at((x, y)), - comp.get_at((x, y)), - "%s != %s, bpp:, %i, x: %i, y: %i" - % ( - surf.get_at((x, y)), - comp.get_at((x, y)), - bitsize, - dx, - dy, - ), - ) - # Confirm clip rect containment - surf = pygame.Surface((20, 13), 0, 32) - surf.fill((255, 0, 0)) - surf.fill((0, 255, 0), (7, 1, 6, 6)) - comp = surf.copy() - clip = Rect(3, 1, 8, 14) - surf.set_clip(clip) - comp.set_clip(clip) - comp.blit(surf, (clip.x + 2, clip.y + 3), surf.get_clip()) - surf.scroll(2, 3) - w, h = surf.get_size() - for x in range(w): - for y in range(h): - self.assertEqual(surf.get_at((x, y)), comp.get_at((x, y))) - # Confirm keyword arguments and per-pixel alpha - spot_color = (0, 255, 0, 128) - surf = pygame.Surface((4, 4), pygame.SRCALPHA, 32) - surf.fill((255, 0, 0, 255)) - surf.set_at((1, 1), spot_color) - surf.scroll(dx=1) - self.assertEqual(surf.get_at((2, 1)), spot_color) - surf.scroll(dy=1) - self.assertEqual(surf.get_at((2, 2)), spot_color) - surf.scroll(dy=1, dx=1) - self.assertEqual(surf.get_at((3, 3)), spot_color) - surf.scroll(dx=-3, dy=-3) - self.assertEqual(surf.get_at((0, 0)), spot_color) + # Check segfaults for any direction or bits or mode + for bits in [8, 16, 24, 32]: + for flag in [0, pygame.SCROLL_ERASE, pygame.SCROLL_REPEAT]: + for dx in range(-1, 1): + for dy in range(-1, 1): + surface = pygame.Surface((20, 20), 0, bits) + surface.scroll(dx * 2, dy * 2, flag) + # Check non repeating mode working + surface = pygame.Surface((20, 20)) + surface.fill("green") + surface.scroll(10, 0) + self.assertEqual(surface.get_at((0, 0)), pygame.Color("green")) + # Check non repeating, erasing mode working + surface = pygame.Surface((20, 20)) + surface.fill("green") + surface.scroll(2, 2, pygame.SCROLL_ERASE) + self.assertEqual(surface.get_at((0, 0)), pygame.Color("black")) + # Check repeating mode working + surface = pygame.Surface((20, 20)) + surface.fill("green") + pygame.draw.rect(surface, "red", (0, 0, 10, 20)) + surface.scroll(4, 0, pygame.SCROLL_REPEAT) + self.assertEqual(surface.get_at((0, 0)), pygame.Color("green")) + # kwargs + surface.scroll(dx=1, dy=1, scroll_flag=0) class SurfaceSubtypeTest(unittest.TestCase): From 8b09b1f31eafc42b92b30808bba979399f1d283d Mon Sep 17 00:00:00 2001 From: aatle <168398276+aatle@users.noreply.github.com> Date: Sat, 19 Oct 2024 06:03:20 -0700 Subject: [PATCH 12/36] Include the explicit type in `ColorLike` and `RectLike` (#3183) * Include the explicit type in type unions * Sort ColorLike types by how common they are --- buildconfig/stubs/pygame/typing.pyi | 24 +++++++++++++++++++++--- src_py/typing.py | 24 +++++++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/buildconfig/stubs/pygame/typing.pyi b/buildconfig/stubs/pygame/typing.pyi index 45d793a4ac..ca88863a59 100644 --- a/buildconfig/stubs/pygame/typing.pyi +++ b/buildconfig/stubs/pygame/typing.pyi @@ -16,6 +16,10 @@ import sys from abc import abstractmethod from typing import IO, Callable, Tuple, Union, TypeVar, Protocol +from pygame.color import Color +from pygame.rect import Rect, FRect + + if sys.version_info >= (3, 9): from os import PathLike as _PathProtocol else: @@ -53,7 +57,7 @@ Point = SequenceLike[float] # This is used where ints are strictly required IntPoint = SequenceLike[int] -ColorLike = Union[int, str, SequenceLike[int]] +ColorLike = Union[Color, SequenceLike[int], str, int] class _HasRectAttribute(Protocol): @@ -63,8 +67,22 @@ class _HasRectAttribute(Protocol): def rect(self) -> Union["RectLike", Callable[[], "RectLike"]]: ... -RectLike = Union[SequenceLike[float], SequenceLike[Point], _HasRectAttribute] +RectLike = Union[ + Rect, FRect, SequenceLike[float], SequenceLike[Point], _HasRectAttribute +] # cleanup namespace -del sys, abstractmethod, IO, Callable, Tuple, Union, TypeVar, Protocol +del ( + sys, + abstractmethod, + Color, + Rect, + FRect, + IO, + Callable, + Tuple, + Union, + TypeVar, + Protocol, +) diff --git a/src_py/typing.py b/src_py/typing.py index 45d793a4ac..ca88863a59 100644 --- a/src_py/typing.py +++ b/src_py/typing.py @@ -16,6 +16,10 @@ from abc import abstractmethod from typing import IO, Callable, Tuple, Union, TypeVar, Protocol +from pygame.color import Color +from pygame.rect import Rect, FRect + + if sys.version_info >= (3, 9): from os import PathLike as _PathProtocol else: @@ -53,7 +57,7 @@ def __len__(self) -> int: ... # This is used where ints are strictly required IntPoint = SequenceLike[int] -ColorLike = Union[int, str, SequenceLike[int]] +ColorLike = Union[Color, SequenceLike[int], str, int] class _HasRectAttribute(Protocol): @@ -63,8 +67,22 @@ class _HasRectAttribute(Protocol): def rect(self) -> Union["RectLike", Callable[[], "RectLike"]]: ... -RectLike = Union[SequenceLike[float], SequenceLike[Point], _HasRectAttribute] +RectLike = Union[ + Rect, FRect, SequenceLike[float], SequenceLike[Point], _HasRectAttribute +] # cleanup namespace -del sys, abstractmethod, IO, Callable, Tuple, Union, TypeVar, Protocol +del ( + sys, + abstractmethod, + Color, + Rect, + FRect, + IO, + Callable, + Tuple, + Union, + TypeVar, + Protocol, +) From a04e99bed036fb064c12d8bf7d577c2c55b40faf Mon Sep 17 00:00:00 2001 From: Ankith Date: Sun, 20 Oct 2024 23:46:43 +0530 Subject: [PATCH 13/36] Ignore new gcc version mask array bounds warning --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 8a62fa1ba9..c7e81698ef 100644 --- a/meson.build +++ b/meson.build @@ -399,6 +399,7 @@ else '-Wno-error=unused-but-set-variable', '-Wno-error=array-bounds', ] + warnings_temp_mask += '-Wno-error=array-bounds' endif if cc.sizeof('long') != 8 From c3b05a553399a31ef71f6b45d857734dcae03eb9 Mon Sep 17 00:00:00 2001 From: Gavin Morrow Date: Sat, 26 Oct 2024 06:35:11 -0700 Subject: [PATCH 14/36] Fix grammar in window.rst --- docs/reST/ref/window.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reST/ref/window.rst b/docs/reST/ref/window.rst index dfd293f166..cbdb96092e 100644 --- a/docs/reST/ref/window.rst +++ b/docs/reST/ref/window.rst @@ -61,8 +61,8 @@ Event behavior if multiple Windows are created: When the close button is pressed, a ``WINDOWCLOSE`` event is sent. You need to explicitly destroy - the window. Note that the event ``QUIT`` will only be sent if all Window - has been destroyed. + the window. Note that the event ``QUIT`` will only be sent if all Windows + have been destroyed. .. code-block:: python From deea5f1a21905ff76e965c10d1c0e873ecabe103 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 06:36:08 +0000 Subject: [PATCH 15/36] Bump actions/cache from 4.1.1 to 4.1.2 Bumps [actions/cache](https://github.com/actions/cache) from 4.1.1 to 4.1.2. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4.1.1...v4.1.2) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/build-macos.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 3034df22d7..dde5061e72 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -51,7 +51,7 @@ jobs: - name: Test for Mac Deps cache hit id: macdep-cache - uses: actions/cache@v4.1.1 + uses: actions/cache@v4.1.2 with: path: ${{ github.workspace }}/pygame_mac_deps_${{ matrix.macarch }} # The hash of all files in buildconfig manylinux-build and macdependencies is @@ -119,14 +119,14 @@ jobs: - uses: actions/checkout@v4.2.1 - name: pip cache - uses: actions/cache@v4.1.1 + uses: actions/cache@v4.1.2 with: path: ~/Library/Caches/pip # This cache path is only right on mac key: pip-cache-${{ matrix.macarch }}-${{ matrix.os }} - name: Fetch Mac deps id: macdep-cache - uses: actions/cache@v4.1.1 + uses: actions/cache@v4.1.2 with: path: ${{ github.workspace }}/pygame_mac_deps_${{ matrix.macarch }} key: macdep-${{ hashFiles('buildconfig/manylinux-build/**') }}-${{ hashFiles('buildconfig/macdependencies/*.sh') }}-${{ matrix.macarch }} From 5bfaae3db29984bfd344ed90e0e222d3b31f2a27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 06:36:14 +0000 Subject: [PATCH 16/36] Bump uraimo/run-on-arch-action from 2.7.2 to 2.8.1 Bumps [uraimo/run-on-arch-action](https://github.com/uraimo/run-on-arch-action) from 2.7.2 to 2.8.1. - [Release notes](https://github.com/uraimo/run-on-arch-action/releases) - [Commits](https://github.com/uraimo/run-on-arch-action/compare/v2.7.2...v2.8.1) --- updated-dependencies: - dependency-name: uraimo/run-on-arch-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build-debian-multiarch.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-debian-multiarch.yml b/.github/workflows/build-debian-multiarch.yml index 8e60e6b160..17b01a157c 100644 --- a/.github/workflows/build-debian-multiarch.yml +++ b/.github/workflows/build-debian-multiarch.yml @@ -68,7 +68,7 @@ jobs: - uses: actions/checkout@v4.2.1 - name: Build sources and run tests - uses: uraimo/run-on-arch-action@v2.7.2 + uses: uraimo/run-on-arch-action@v2.8.1 id: build with: arch: ${{ matrix.base_image && 'none' || matrix.arch }} @@ -136,7 +136,7 @@ jobs: done - name: Test armv7 wheel on armv6 - uses: uraimo/run-on-arch-action@v2.7.2 + uses: uraimo/run-on-arch-action@v2.8.1 with: arch: armv6 distro: bookworm From 40623b9351c7a217f96ad229ec03cad5fe9c2a2f Mon Sep 17 00:00:00 2001 From: Ankith Date: Mon, 28 Oct 2024 19:48:40 +0530 Subject: [PATCH 17/36] Install SDL3 dependencies before building it --- .github/workflows/build-sdl3.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-sdl3.yml b/.github/workflows/build-sdl3.yml index cb2c555f04..c0ce2a8cde 100644 --- a/.github/workflows/build-sdl3.yml +++ b/.github/workflows/build-sdl3.yml @@ -54,14 +54,24 @@ jobs: steps: - uses: actions/checkout@v4.2.1 - - name: Install deps (linux) + - name: Install pygame deps (linux) if: matrix.os == 'ubuntu-24.04' run: sudo apt-get install libfreetype6-dev libportmidi-dev python3-dev - - name: Install deps (mac) + - name: Install pygame deps (mac) if: matrix.os == 'macos-14' run: brew install freetype portmidi + # taken from dependencies of the 'libsdl2-dev' package + - name: Install SDL deps (linux) + if: matrix.os == 'ubuntu-24.04' + run: > + sudo apt-get install libasound2-dev libdbus-1-dev libdecor-0-dev libdrm-dev + libegl-dev libgbm-dev libgl-dev libgles-dev libibus-1.0-dev libpulse-dev + libsamplerate0-dev libsndio-dev libudev-dev libwayland-dev libx11-dev + libxcursor-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev + libxkbcommon-dev libxrandr-dev libxss-dev libxt-dev libxv-dev libxxf86vm-dev + # taken from https://wiki.libsdl.org/SDL3/Installation - name: Install SDL3 if: matrix.os != 'windows-latest' @@ -74,7 +84,7 @@ jobs: cmake --build . --config Release --parallel sudo cmake --install . --config Release - - name: Make sdist and install it + - name: Build with SDL3 run: > python3 -m pip install . -v -Csetup-args=-Dsdl_api=3 -Csetup-args=-Dimage=disabled From 44a33702dbd38c7b0984962bb8c1546da80c8ec6 Mon Sep 17 00:00:00 2001 From: Ankith Date: Tue, 29 Oct 2024 11:20:22 +0530 Subject: [PATCH 18/36] Drop mingw32 in msys2 CI --- .github/workflows/build-on-msys2.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build-on-msys2.yml b/.github/workflows/build-on-msys2.yml index 315e7c41f1..ea3cc08df8 100644 --- a/.github/workflows/build-on-msys2.yml +++ b/.github/workflows/build-on-msys2.yml @@ -42,7 +42,6 @@ jobs: matrix: include: - { sys: mingw64, env: x86_64 } - - { sys: mingw32, env: i686 } - { sys: ucrt64, env: ucrt-x86_64 } - { sys: clang64, env: clang-x86_64 } # - { sys: clangarm64, env: clang-aarch64 } From 7b26b0a53423adb73c57233cd2c4ec50b1e47940 Mon Sep 17 00:00:00 2001 From: Gavin Morrow Date: Wed, 30 Oct 2024 12:04:47 -0400 Subject: [PATCH 19/36] Add code block around `Window` Review comments --- docs/reST/ref/window.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reST/ref/window.rst b/docs/reST/ref/window.rst index cbdb96092e..246bc5c44c 100644 --- a/docs/reST/ref/window.rst +++ b/docs/reST/ref/window.rst @@ -12,7 +12,7 @@ The Window class (formerly known as _sdl2.video.Window), is a newly published feature of pygame-ce 2.5.2. This class allows for programs - to drive multiple Windows on-screen at once, something not possible with + to drive multiple windows on-screen at once, something not possible with the :func:`pygame.display.set_mode` API. Not everything possible with :mod:`pygame.display` is possible yet in the Window API, but the new window class will continue to be developed, and we're excited to share @@ -59,9 +59,9 @@ pygame.quit() raise SystemExit - Event behavior if multiple Windows are created: When the close button is + Event behavior if multiple ``Window``s are created: When the close button is pressed, a ``WINDOWCLOSE`` event is sent. You need to explicitly destroy - the window. Note that the event ``QUIT`` will only be sent if all Windows + the window. Note that the event ``QUIT`` will only be sent if all ``Window``s have been destroyed. .. code-block:: python From 368e9ca8eaa354c6ef85be44e6906d91a8c4a3f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 06:18:17 +0000 Subject: [PATCH 20/36] Bump actions/checkout from 4.2.1 to 4.2.2 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.1 to 4.2.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.2.1...v4.2.2) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/build-debian-multiarch.yml | 2 +- .github/workflows/build-emsdk.yml | 2 +- .github/workflows/build-macos.yml | 4 ++-- .github/workflows/build-manylinux.yml | 2 +- .github/workflows/build-on-msys2.yml | 2 +- .github/workflows/build-sdl3.yml | 2 +- .github/workflows/build-ubuntu-coverage.yml | 2 +- .github/workflows/build-ubuntu-sdist.yml | 2 +- .github/workflows/build-windows.yml | 2 +- .github/workflows/cppcheck.yml | 2 +- .github/workflows/format-lint.yml | 4 ++-- .github/workflows/release-gh-draft.yml | 2 +- .github/workflows/release-pypi.yml | 2 +- 13 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-debian-multiarch.yml b/.github/workflows/build-debian-multiarch.yml index 17b01a157c..543486b8e7 100644 --- a/.github/workflows/build-debian-multiarch.yml +++ b/.github/workflows/build-debian-multiarch.yml @@ -65,7 +65,7 @@ jobs: - { arch: armv7, base_image: 'balenalib/raspberrypi3-debian:bookworm' } steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Build sources and run tests uses: uraimo/run-on-arch-action@v2.8.1 diff --git a/.github/workflows/build-emsdk.yml b/.github/workflows/build-emsdk.yml index fb9e15c963..d61e0c5420 100644 --- a/.github/workflows/build-emsdk.yml +++ b/.github/workflows/build-emsdk.yml @@ -41,7 +41,7 @@ jobs: SDKROOT: /opt/python-wasm-sdk steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Regen with latest cython (using system python3) run: | diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index dde5061e72..23e304285f 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -47,7 +47,7 @@ jobs: - { macarch: x86_64, os: macos-13 } steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Test for Mac Deps cache hit id: macdep-cache @@ -116,7 +116,7 @@ jobs: CIBW_BEFORE_TEST: rm -rf ${{ github.workspace }}/pygame_mac_deps steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: pip cache uses: actions/cache@v4.1.2 diff --git a/.github/workflows/build-manylinux.yml b/.github/workflows/build-manylinux.yml index bac5362375..b3bda630ad 100644 --- a/.github/workflows/build-manylinux.yml +++ b/.github/workflows/build-manylinux.yml @@ -52,7 +52,7 @@ jobs: CIBW_ARCHS: ${{ matrix.arch }} steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Log in to the Container registry uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 diff --git a/.github/workflows/build-on-msys2.yml b/.github/workflows/build-on-msys2.yml index ea3cc08df8..6ac74c15f4 100644 --- a/.github/workflows/build-on-msys2.yml +++ b/.github/workflows/build-on-msys2.yml @@ -47,7 +47,7 @@ jobs: # - { sys: clangarm64, env: clang-aarch64 } steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - uses: msys2/setup-msys2@v2 with: msystem: ${{ matrix.sys }} diff --git a/.github/workflows/build-sdl3.yml b/.github/workflows/build-sdl3.yml index c0ce2a8cde..6f442d58e5 100644 --- a/.github/workflows/build-sdl3.yml +++ b/.github/workflows/build-sdl3.yml @@ -52,7 +52,7 @@ jobs: PG_DEPS_FROM_SYSTEM: 1 steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Install pygame deps (linux) if: matrix.os == 'ubuntu-24.04' diff --git a/.github/workflows/build-ubuntu-coverage.yml b/.github/workflows/build-ubuntu-coverage.yml index 5999252842..29260ccefb 100644 --- a/.github/workflows/build-ubuntu-coverage.yml +++ b/.github/workflows/build-ubuntu-coverage.yml @@ -58,7 +58,7 @@ jobs: PG_DEPS_FROM_SYSTEM: 1 steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Install deps # install numpy from pip and not apt because the one from pip is newer, diff --git a/.github/workflows/build-ubuntu-sdist.yml b/.github/workflows/build-ubuntu-sdist.yml index d7382a34bb..ad0ab48eef 100644 --- a/.github/workflows/build-ubuntu-sdist.yml +++ b/.github/workflows/build-ubuntu-sdist.yml @@ -58,7 +58,7 @@ jobs: PG_DEPS_FROM_SYSTEM: 1 steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Install deps # install numpy from pip and not apt because the one from pip is newer, diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 6fc13d8203..d868bfabce 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -50,7 +50,7 @@ jobs: CIBW_ARCHS: ${{ matrix.winarch }} steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - uses: TheMrMilchmann/setup-msvc-dev@v3 # this lets us use the developer command prompt on windows with: diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml index a1746369b8..2594db25d7 100644 --- a/.github/workflows/cppcheck.yml +++ b/.github/workflows/cppcheck.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Install deps # https://github.com/actions/runner-images/issues/7192 diff --git a/.github/workflows/format-lint.yml b/.github/workflows/format-lint.yml index 99016b7dde..2030d0bf4f 100644 --- a/.github/workflows/format-lint.yml +++ b/.github/workflows/format-lint.yml @@ -30,7 +30,7 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - uses: actions/setup-python@v5 with: python-version: 3.x @@ -45,7 +45,7 @@ jobs: PIP_BREAK_SYSTEM_PACKAGES: 1 steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Install deps run: python3 -m pip install pylint sphinx"<7.2.0" diff --git a/.github/workflows/release-gh-draft.yml b/.github/workflows/release-gh-draft.yml index 3aebecc494..32917cf703 100644 --- a/.github/workflows/release-gh-draft.yml +++ b/.github/workflows/release-gh-draft.yml @@ -38,7 +38,7 @@ jobs: contents: write steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Download all artifacts uses: actions/download-artifact@v4 diff --git a/.github/workflows/release-pypi.yml b/.github/workflows/release-pypi.yml index 64aa7ac25b..97db455522 100644 --- a/.github/workflows/release-pypi.yml +++ b/.github/workflows/release-pypi.yml @@ -12,7 +12,7 @@ jobs: # IMPORTANT: this permission is mandatory for trusted publishing id-token: write steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - name: Pull all release assets uses: robinraju/release-downloader@v1.11 From 4d6a8e34bf009091a15f18f02ed64058313a3b91 Mon Sep 17 00:00:00 2001 From: Starbuck5 <46412508+Starbuck5@users.noreply.github.com> Date: Sat, 12 Oct 2024 17:04:00 -0700 Subject: [PATCH 21/36] Rework SDL_INIT_TIMER for SDL3 No longer exists in SDL3, so simple compat is to mock it out to a macro that is zero in SDL3. --- src_c/_pygame.h | 4 ++++ src_c/base.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src_c/_pygame.h b/src_c/_pygame.h index 0cbfed872f..d5bdf7fe40 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -115,6 +115,8 @@ PG_UnlockMutex(SDL_mutex *mutex) #define PG_FIND_VNUM_MINOR(ver) SDL_VERSIONNUM_MINOR(ver) #define PG_FIND_VNUM_MICRO(ver) SDL_VERSIONNUM_MICRO(ver) +#define PG_INIT_TIMER 0 + #else /* ~SDL_VERSION_ATLEAST(3, 0, 0)*/ #define PG_ShowCursor() SDL_ShowCursor(SDL_ENABLE) #define PG_HideCursor() SDL_ShowCursor(SDL_DISABLE) @@ -180,6 +182,8 @@ PG_UnlockMutex(SDL_mutex *mutex) #define PG_FIND_VNUM_MINOR(ver) ver.minor #define PG_FIND_VNUM_MICRO(ver) ver.patch +#define PG_INIT_TIMER SDL_INIT_TIMER + #if SDL_VERSION_ATLEAST(2, 0, 14) #define PG_SurfaceHasRLE SDL_HasSurfaceRLE #else diff --git a/src_c/base.c b/src_c/base.c index 573bca3aa2..d4f33c813c 100644 --- a/src_c/base.c +++ b/src_c/base.c @@ -341,10 +341,10 @@ pg_init(PyObject *self, PyObject *_null) /*nice to initialize timer, so startup time will reflec pg_init() time*/ #if defined(WITH_THREAD) && !defined(MS_WIN32) && defined(SDL_INIT_EVENTTHREAD) - pg_sdl_was_init = SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_TIMER | + pg_sdl_was_init = SDL_Init(SDL_INIT_EVENTTHREAD | PG_INIT_TIMER | PG_INIT_NOPARACHUTE) == 0; #else - pg_sdl_was_init = SDL_Init(SDL_INIT_TIMER | PG_INIT_NOPARACHUTE) == 0; + pg_sdl_was_init = SDL_Init(PG_INIT_TIMER | PG_INIT_NOPARACHUTE) == 0; #endif pg_env_blend_alpha_SDL2 = SDL_getenv("PYGAME_BLEND_ALPHA_SDL2"); From 582792472e9a224e6d4c089937399443053cdcf1 Mon Sep 17 00:00:00 2001 From: Starbuck5 <46412508+Starbuck5@users.noreply.github.com> Date: Sat, 12 Oct 2024 17:07:03 -0700 Subject: [PATCH 22/36] Rework pg_EnvShouldBlendAlphaSDL2 for SDL3 SDL_getenv now returns a const char* instead of a char*, so rather than worry about propagating that through or casting it away, lets just have pg_EnvShouldBlendAlphaSDL2 return an int, and have the callers evaluate that instead of evaluating whether a char* is NULL or not. This requires no changes to the callers. --- src_c/base.c | 8 ++++---- src_c/include/_pygame.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src_c/base.c b/src_c/base.c index d4f33c813c..04379ba0f2 100644 --- a/src_c/base.c +++ b/src_c/base.c @@ -81,7 +81,7 @@ static int pg_is_init = 0; static int pg_sdl_was_init = 0; SDL_Window *pg_default_window = NULL; pgSurfaceObject *pg_default_screen = NULL; -static char *pg_env_blend_alpha_SDL2 = NULL; +static int pg_env_blend_alpha_SDL2 = 0; static void pg_install_parachute(void); @@ -170,7 +170,7 @@ static pgSurfaceObject * pg_GetDefaultWindowSurface(void); static void pg_SetDefaultWindowSurface(pgSurfaceObject *); -static char * +static int pg_EnvShouldBlendAlphaSDL2(void); /* compare compiled to linked, raise python error on incompatibility */ @@ -347,7 +347,7 @@ pg_init(PyObject *self, PyObject *_null) pg_sdl_was_init = SDL_Init(PG_INIT_TIMER | PG_INIT_NOPARACHUTE) == 0; #endif - pg_env_blend_alpha_SDL2 = SDL_getenv("PYGAME_BLEND_ALPHA_SDL2"); + pg_env_blend_alpha_SDL2 = SDL_getenv("PYGAME_BLEND_ALPHA_SDL2") != NULL; /* initialize all pygame modules */ for (i = 0; modnames[i]; i++) { @@ -2096,7 +2096,7 @@ pg_SetDefaultConvertFormat(Uint32 format) return pg_default_convert_format; // returns for NULL error checking } -static char * +static int pg_EnvShouldBlendAlphaSDL2(void) { return pg_env_blend_alpha_SDL2; diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index bcfb0fdc8c..8158fe68df 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -181,7 +181,7 @@ typedef struct pg_bufferinfo_s { (*(void (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(base, 22)) #define pg_EnvShouldBlendAlphaSDL2 \ - (*(char *(*)(void))PYGAMEAPI_GET_SLOT(base, 23)) + (*(int (*)(void))PYGAMEAPI_GET_SLOT(base, 23)) #define pg_GetDefaultConvertFormat \ (*(SDL_PixelFormat * (*)(void)) PYGAMEAPI_GET_SLOT(base, 27)) From a2511c5e2e7d40cc105f25708820c23128c04d41 Mon Sep 17 00:00:00 2001 From: Ankith Date: Sat, 2 Nov 2024 09:21:38 +0530 Subject: [PATCH 23/36] Bump SDL2 to 2.30.9 and SDL3 to 3.1.6 --- buildconfig/download_win_prebuilt.py | 16 ++++++++-------- .../docker_base/sdl_libs/build-sdl2-libs.sh | 2 +- .../docker_base/sdl_libs/sdl2.sha512 | 2 +- meson.build | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/buildconfig/download_win_prebuilt.py b/buildconfig/download_win_prebuilt.py index a03b225933..aa12faca0f 100644 --- a/buildconfig/download_win_prebuilt.py +++ b/buildconfig/download_win_prebuilt.py @@ -78,12 +78,12 @@ def get_urls(x86=True, x64=True): url_sha1 = [] url_sha1.extend([ [ - 'https://github.com/libsdl-org/SDL/releases/download/release-2.30.8/SDL2-devel-2.30.8-VC.zip', - '389a7575afaeccd3586a8105520cbec46b930dcb', + 'https://github.com/libsdl-org/SDL/releases/download/release-2.30.9/SDL2-devel-2.30.9-VC.zip', + 'd89a2ad46b98ba08db5ec5877cb2fde46e127825', ], [ - 'https://github.com/libsdl-org/SDL/releases/download/preview-3.1.3/SDL3-devel-3.1.3-VC.zip', - '8e4d7104193ba976406fe9968301de6f6b57f342' + 'https://github.com/libsdl-org/SDL/releases/download/preview-3.1.6/SDL3-devel-3.1.6-VC.zip', + '7a3b9ed85cfe735c7e106d98c4b6395a113e5d7e' ], [ 'https://github.com/pygame-community/SDL_image/releases/download/2.8.2-pgce/SDL2_image-devel-2.8.2-VCpgce.zip', @@ -238,23 +238,23 @@ def copy(src, dst): copy( os.path.join( temp_dir, - 'SDL2-devel-2.30.8-VC/SDL2-2.30.8' + 'SDL2-devel-2.30.9-VC/SDL2-2.30.9' ), os.path.join( move_to_dir, prebuilt_dir, - 'SDL2-2.30.8' + 'SDL2-2.30.9' ) ) copy( os.path.join( temp_dir, - 'SDL3-devel-3.1.3-VC/SDL3-3.1.3' + 'SDL3-devel-3.1.6-VC/SDL3-3.1.6' ), os.path.join( move_to_dir, prebuilt_dir, - 'SDL3-3.1.3' + 'SDL3-3.1.6' ) ) diff --git a/buildconfig/manylinux-build/docker_base/sdl_libs/build-sdl2-libs.sh b/buildconfig/manylinux-build/docker_base/sdl_libs/build-sdl2-libs.sh index f096177fec..d0546b18bb 100644 --- a/buildconfig/manylinux-build/docker_base/sdl_libs/build-sdl2-libs.sh +++ b/buildconfig/manylinux-build/docker_base/sdl_libs/build-sdl2-libs.sh @@ -3,7 +3,7 @@ set -e -x cd $(dirname `readlink -f "$0"`) -SDL2_VER="2.30.8" +SDL2_VER="2.30.9" SDL2="SDL2-$SDL2_VER" IMG2_VER="2.8.2" IMG2="SDL2_image-$IMG2_VER" diff --git a/buildconfig/manylinux-build/docker_base/sdl_libs/sdl2.sha512 b/buildconfig/manylinux-build/docker_base/sdl_libs/sdl2.sha512 index 699b618be4..2cae1f3830 100644 --- a/buildconfig/manylinux-build/docker_base/sdl_libs/sdl2.sha512 +++ b/buildconfig/manylinux-build/docker_base/sdl_libs/sdl2.sha512 @@ -1,4 +1,4 @@ -72e49d8a67f5ca1241a262e7e7ae7f6ff148e8774343110db652589ab2e72d3425534ca7f8c7825b2ae1afc779c09228da33a9586219ac4e53546a4930380b64 SDL2-2.30.8.tar.gz +30dfa86fcced174fef0ed78ffa53476a31765e19cdcdf8233ab92876445b4dedaa758fc42a3ec332324d13faa2daafcadcc44fc0f536a2969ef836162ec3cd36 SDL2-2.30.9.tar.gz 0ff345824f95158dfa72f83f9d4a540601c178cd759334bf849c14a2920b5330d0763413b58c08b3deba8d3a4ccb6ea2a8159f87efe4cbb0e8ea850f63d09454 SDL2_image-2.8.2.tar.gz 5ddbc4b0b5fad2e0844a503daa79564b912654192599ef8fa7698531f08323ce01801f6bb17b2b3905020a3df362a967b7566ae725eb085da991578cc0807aad SDL2_mixer-2.8.0.tar.gz 34a1d210d8f1b1e802139d65ba47e36033bb7881e75a8862c1b1c515565bef85e3d81ee42e952aa664de043debef387ba60088a9cf3ba3297413db39a13af912 SDL2_ttf-2.22.0.tar.gz diff --git a/meson.build b/meson.build index c7e81698ef..318de28b1f 100644 --- a/meson.build +++ b/meson.build @@ -109,7 +109,7 @@ if plat == 'win' and host_machine.cpu_family().startswith('x86') ) endif - sdl_ver = (sdl_api == 3) ? '3.1.3' : '2.30.8' + sdl_ver = (sdl_api == 3) ? '3.1.6' : '2.30.9' sdl_image_ver = '2.8.2' sdl_mixer_ver = '2.8.0' sdl_ttf_ver = '2.22.0' From 979390de3aadeb4d17896e647e5e68d99a8eaf18 Mon Sep 17 00:00:00 2001 From: Ankith Date: Sat, 2 Nov 2024 10:07:09 +0530 Subject: [PATCH 24/36] Clean pre-installed libdeflate --- buildconfig/macdependencies/clean_usr_local.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/buildconfig/macdependencies/clean_usr_local.sh b/buildconfig/macdependencies/clean_usr_local.sh index 0551d67759..c058008ac2 100644 --- a/buildconfig/macdependencies/clean_usr_local.sh +++ b/buildconfig/macdependencies/clean_usr_local.sh @@ -15,6 +15,7 @@ ln -s /usr/bin/git /opt/homebrew/bin/git rm -rf /usr/local/lib/libtiff* rm -rf /usr/local/lib/libzstd* rm -rf /usr/local/lib/libwebp* +rm -rf /usr/local/lib/libdeflate* rm -rf /usr/local/lib/libsndfile* rm -rf /usr/local/lib/glib* rm -rf /usr/local/lib/libglib* @@ -27,6 +28,7 @@ rm -rf /usr/local/opt/freetype* rm -rf /usr/local/Cellar/libtiff /opt/homebrew/Cellar/libtiff rm -rf /usr/local/Cellar/libsndfile /opt/homebrew/Cellar/libsndfile +rm -rf /usr/local/Cellar/libdeflate* /opt/homebrew/Cellar/libdeflate* rm -rf /usr/local/Cellar/glib /opt/homebrew/Cellar/glib rm -rf /usr/local/Cellar/brotli /opt/homebrew/Cellar/brotli rm -rf /usr/local/Cellar/pcre* /opt/homebrew/Cellar/pcre* From 74837359538db4c2626a3a5621dd0d6fcfb448bd Mon Sep 17 00:00:00 2001 From: Starbuck5 <46412508+Starbuck5@users.noreply.github.com> Date: Sat, 2 Nov 2024 00:23:25 -0700 Subject: [PATCH 25/36] Correct draw.aaline docs --- docs/reST/ref/draw.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reST/ref/draw.rst b/docs/reST/ref/draw.rst index 44ac398a3c..53f5c35b44 100644 --- a/docs/reST/ref/draw.rst +++ b/docs/reST/ref/draw.rst @@ -493,7 +493,7 @@ object around the draw calls (see :func:`pygame.Surface.lock` and .. versionchangedold:: 2.0.0 Added support for keyword arguments. .. versionchanged:: 2.4.0 Removed deprecated 'blend' argument .. versionchanged:: 2.5.0 ``blend`` argument readded for backcompat, but will always raise a deprecation exception when used - .. versionchanged:: 2.5.2 Added line width + .. versionchanged:: 2.5.3 Added line width .. ## pygame.draw.aaline ## From cc260b3908be71e765e04b961eed230214a2b282 Mon Sep 17 00:00:00 2001 From: Starbuck5 <46412508+Starbuck5@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:51:51 -0700 Subject: [PATCH 26/36] Adjust pg_(Get/Set)DefaultConvertFormat for SDL3 This reworks the functions to work on pixel format enums instead of structs, because in SDL3 the enums are much easier to get than the structs. This required involved changes to surface.c, but I think the previous mask logic is much clearer now that it is expressed using format enums. --- src_c/_pygame.h | 6 +++- src_c/base.c | 18 ++++++------ src_c/include/_pygame.h | 4 +-- src_c/meson.build | 3 -- src_c/surface.c | 64 +++++++++++++++++------------------------ src_c/window.c | 8 ++---- 6 files changed, 44 insertions(+), 59 deletions(-) diff --git a/src_c/_pygame.h b/src_c/_pygame.h index d5bdf7fe40..46fe2d966d 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -75,7 +75,9 @@ #define PG_CreateSurface SDL_CreateSurface #define PG_CreateSurfaceFrom SDL_CreateSurfaceFrom #define PG_ConvertSurface SDL_ConvertSurface -#define PG_ConvertSurfaceFormat SDL_ConvertSurfaceFormat +#define PG_ConvertSurfaceFormat SDL_ConvertSurface + +#define PG_PixelFormatEnum SDL_PixelFormat #define PG_SurfaceHasRLE SDL_SurfaceHasRLE @@ -146,6 +148,8 @@ PG_UnlockMutex(SDL_mutex *mutex) #define PG_ConvertSurfaceFormat(src, pixel_format) \ SDL_ConvertSurfaceFormat(src, pixel_format, 0) +#define PG_PixelFormatEnum SDL_PixelFormatEnum + #define PG_SoftStretchNearest(src, srcrect, dst, dstrect) \ SDL_SoftStretch(src, srcrect, dst, dstrect) diff --git a/src_c/base.c b/src_c/base.c index 04379ba0f2..f42b045783 100644 --- a/src_c/base.c +++ b/src_c/base.c @@ -2075,25 +2075,25 @@ pg_SetDefaultWindowSurface(pgSurfaceObject *screen) pg_default_screen = screen; } -SDL_PixelFormat *pg_default_convert_format = NULL; +PG_PixelFormatEnum pg_default_convert_format = 0; -static SDL_PixelFormat * +static PG_PixelFormatEnum pg_GetDefaultConvertFormat(void) { if (pg_default_screen) { +#if SDL_VERSION_ATLEAST(3, 0, 0) return pg_default_screen->surf->format; +#else + return pg_default_screen->surf->format->format; +#endif } return pg_default_convert_format; } -static SDL_PixelFormat * -pg_SetDefaultConvertFormat(Uint32 format) +static void +pg_SetDefaultConvertFormat(PG_PixelFormatEnum format) { - if (pg_default_convert_format != NULL) { - SDL_FreeFormat(pg_default_convert_format); - } - pg_default_convert_format = SDL_AllocFormat(format); - return pg_default_convert_format; // returns for NULL error checking + pg_default_convert_format = format; } static int diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index 8158fe68df..b3548a66ee 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -184,10 +184,10 @@ typedef struct pg_bufferinfo_s { (*(int (*)(void))PYGAMEAPI_GET_SLOT(base, 23)) #define pg_GetDefaultConvertFormat \ - (*(SDL_PixelFormat * (*)(void)) PYGAMEAPI_GET_SLOT(base, 27)) + (*(PG_PixelFormatEnum(*)(void))PYGAMEAPI_GET_SLOT(base, 27)) #define pg_SetDefaultConvertFormat \ - (*(SDL_PixelFormat * (*)(Uint32)) PYGAMEAPI_GET_SLOT(base, 28)) + (*(void (*)(Uint32))PYGAMEAPI_GET_SLOT(base, 28)) #define import_pygame_base() IMPORT_PYGAME_MODULE(base) #endif /* ~PYGAMEAPI_BASE_INTERNAL */ diff --git a/src_c/meson.build b/src_c/meson.build index ca10cca737..fb43a584eb 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -1,7 +1,5 @@ # first the "required" modules -# TODO: support SDL3 -if sdl_api != 3 base = py.extension_module( 'base', 'base.c', @@ -10,7 +8,6 @@ base = py.extension_module( install: true, subdir: pg, ) -endif color = py.extension_module( 'color', diff --git a/src_c/surface.c b/src_c/surface.c index b9e3008ae3..d4a8eae2e9 100644 --- a/src_c/surface.c +++ b/src_c/surface.c @@ -1582,27 +1582,21 @@ surf_convert(pgSurfaceObject *self, PyObject *args) static SDL_Surface * pg_DisplayFormat(SDL_Surface *surface) { - SDL_PixelFormat *default_format = pg_GetDefaultConvertFormat(); + PG_PixelFormatEnum default_format = pg_GetDefaultConvertFormat(); if (!default_format) { SDL_SetError( "No convert format has been set, try display.set_mode()" " or Window.get_surface()."); return NULL; } - return PG_ConvertSurface(surface, default_format); + return PG_ConvertSurfaceFormat(surface, default_format); } static SDL_Surface * pg_DisplayFormatAlpha(SDL_Surface *surface) { - SDL_PixelFormat *dformat; - Uint32 pfe; - Uint32 amask = 0xff000000; - Uint32 rmask = 0x00ff0000; - Uint32 gmask = 0x0000ff00; - Uint32 bmask = 0x000000ff; - - dformat = pg_GetDefaultConvertFormat(); + PG_PixelFormatEnum pfe = SDL_PIXELFORMAT_ARGB8888; + PG_PixelFormatEnum dformat = pg_GetDefaultConvertFormat(); if (!dformat) { SDL_SetError( "No convert format has been set, try display.set_mode()" @@ -1610,38 +1604,32 @@ pg_DisplayFormatAlpha(SDL_Surface *surface) return NULL; } - switch (PG_FORMAT_BytesPerPixel(dformat)) { - case 2: - /* same behavior as SDL1 */ - if ((dformat->Rmask == 0x1f) && - (dformat->Bmask == 0xf800 || dformat->Bmask == 0x7c00)) { - rmask = 0xff; - bmask = 0xff0000; - } + switch (dformat) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + case SDL_PIXELFORMAT_XBGR1555: +#else + case SDL_PIXELFORMAT_BGR555: +#endif + case SDL_PIXELFORMAT_ABGR1555: + case SDL_PIXELFORMAT_BGR565: + case PG_PIXELFORMAT_XBGR8888: + case SDL_PIXELFORMAT_ABGR8888: + pfe = SDL_PIXELFORMAT_ABGR8888; break; - case 3: - case 4: - /* keep the format if the high bits are free */ - if ((dformat->Rmask == 0xff) && (dformat->Bmask == 0xff0000)) { - rmask = 0xff; - bmask = 0xff0000; - } - else if (dformat->Rmask == 0xff00 && - (dformat->Bmask == 0xff000000)) { - amask = 0x000000ff; - rmask = 0x0000ff00; - gmask = 0x00ff0000; - bmask = 0xff000000; - } + + case SDL_PIXELFORMAT_BGRX8888: + case SDL_PIXELFORMAT_BGRA8888: +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + case SDL_PIXELFORMAT_BGR24: +#else + case SDL_PIXELFORMAT_RGB24: +#endif + pfe = SDL_PIXELFORMAT_BGRA8888; break; - default: /* ARGB8888 */ + + default: break; } - pfe = SDL_MasksToPixelFormatEnum(32, rmask, gmask, bmask, amask); - if (pfe == SDL_PIXELFORMAT_UNKNOWN) { - SDL_SetError("unknown pixel format"); - return NULL; - } return PG_ConvertSurfaceFormat(surface, pfe); } diff --git a/src_c/window.c b/src_c/window.c index f2217cd20c..63b7270d06 100644 --- a/src_c/window.c +++ b/src_c/window.c @@ -157,12 +157,8 @@ window_get_surface(pgWindowObject *self, PyObject *_null) return RAISE(pgExc_SDLError, SDL_GetError()); } - if (pg_GetDefaultConvertFormat() == NULL) { - if (pg_SetDefaultConvertFormat(_surf->format->format) == NULL) { - /* This is very unlikely, I think only would happen if SDL runs - * out of memory when allocating the format. */ - return RAISE(pgExc_SDLError, SDL_GetError()); - } + if (pg_GetDefaultConvertFormat() == 0) { + pg_SetDefaultConvertFormat(_surf->format->format); } if (self->surf == NULL) { From 5ec1d20b5b02877cf0e364886f047b4a7345b75e Mon Sep 17 00:00:00 2001 From: Starbuck5 <46412508+Starbuck5@users.noreply.github.com> Date: Sat, 2 Nov 2024 01:13:49 -0700 Subject: [PATCH 27/36] Fix window docs --- docs/reST/ref/window.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reST/ref/window.rst b/docs/reST/ref/window.rst index 246bc5c44c..7c78de9dc0 100644 --- a/docs/reST/ref/window.rst +++ b/docs/reST/ref/window.rst @@ -59,10 +59,10 @@ pygame.quit() raise SystemExit - Event behavior if multiple ``Window``s are created: When the close button is + Event behavior if multiple ``Window``\ s are created: When the close button is pressed, a ``WINDOWCLOSE`` event is sent. You need to explicitly destroy - the window. Note that the event ``QUIT`` will only be sent if all ``Window``s - have been destroyed. + the window. Note that the event ``QUIT`` will only be sent if all + ``Window``\ s have been destroyed. .. code-block:: python From 96c033c048ed1506450119151d2c8300ad7c2a15 Mon Sep 17 00:00:00 2001 From: Ankith Date: Sat, 2 Nov 2024 13:59:09 +0530 Subject: [PATCH 28/36] Port constants.c to SDL3 --- src_c/_pygame.h | 4 ++++ src_c/meson.build | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src_c/_pygame.h b/src_c/_pygame.h index 46fe2d966d..07f236149a 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -284,6 +284,10 @@ typedef enum { SDL_ACTIVEEVENT = SDL_USEREVENT, SDL_VIDEORESIZE, SDL_VIDEOEXPOSE, +#if SDL_VERSION_ATLEAST(3, 0, 0) + /* SDL_SYSWMEVENT removed in SDL3, define it here for compat */ + SDL_SYSWMEVENT, +#endif PGE_MIDIIN, PGE_MIDIOUT, diff --git a/src_c/meson.build b/src_c/meson.build index fb43a584eb..792e699594 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -18,8 +18,6 @@ color = py.extension_module( subdir: pg, ) -# TODO: support SDL3 -if sdl_api != 3 constants = py.extension_module( 'constants', 'constants.c', @@ -28,7 +26,6 @@ constants = py.extension_module( install: true, subdir: pg, ) -endif # TODO: support SDL3 if sdl_api != 3 From 2afed5428b2b7cd821a45f9b8836e0d69a7f4577 Mon Sep 17 00:00:00 2001 From: Ankith Date: Sat, 2 Nov 2024 13:59:56 +0530 Subject: [PATCH 29/36] Port surflock.c to SDL3 --- src_c/meson.build | 2 -- src_c/surflock.c | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src_c/meson.build b/src_c/meson.build index 792e699594..78ae34b06c 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -144,7 +144,6 @@ surface = py.extension_module( endif # TODO: support SDL3 -if sdl_api != 3 surflock = py.extension_module( 'surflock', 'surflock.c', @@ -153,7 +152,6 @@ surflock = py.extension_module( install: true, subdir: pg, ) -endif # TODO: support SDL3 if sdl_api != 3 diff --git a/src_c/surflock.c b/src_c/surflock.c index 62cd3acdbd..60f3d953ec 100644 --- a/src_c/surflock.c +++ b/src_c/surflock.c @@ -99,7 +99,11 @@ pgSurface_LockBy(pgSurfaceObject *surfobj, PyObject *lockobj) if (surf->subsurface != NULL) { pgSurface_Prep(surfobj); } +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (!SDL_LockSurface(surf->surf)) { +#else if (SDL_LockSurface(surf->surf) == -1) { +#endif PyErr_SetString(PyExc_RuntimeError, "error locking surface"); return 0; } From 9ecb01bd04863aa20ee1e169f07269963f6e6cb0 Mon Sep 17 00:00:00 2001 From: Ankith Date: Sat, 2 Nov 2024 14:15:10 +0530 Subject: [PATCH 30/36] Run import pygame test on SDL3 CI --- .github/workflows/build-sdl3.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build-sdl3.yml b/.github/workflows/build-sdl3.yml index 6f442d58e5..f6107af8e0 100644 --- a/.github/workflows/build-sdl3.yml +++ b/.github/workflows/build-sdl3.yml @@ -91,6 +91,11 @@ jobs: -Csetup-args=-Dmixer=disabled -Csetup-args=-Dfont=disabled + # eventually we need to run all tests, but for now test that importing pygame + # works + - name: Test import works + run: python3 -c 'import pygame' + # - name: Run tests # env: # SDL_VIDEODRIVER: "dummy" From 176649335d3e71739f0529286b215f6223e0ba2f Mon Sep 17 00:00:00 2001 From: Ankith Date: Sat, 2 Nov 2024 15:02:22 +0530 Subject: [PATCH 31/36] Port time.c to SDL3 --- src_c/meson.build | 3 --- src_c/time.c | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src_c/meson.build b/src_c/meson.build index 78ae34b06c..07189d6180 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -153,8 +153,6 @@ surflock = py.extension_module( subdir: pg, ) -# TODO: support SDL3 -if sdl_api != 3 time = py.extension_module( 'time', 'time.c', @@ -163,7 +161,6 @@ time = py.extension_module( install: true, subdir: pg, ) -endif # TODO: support SDL3 if sdl_api != 3 diff --git a/src_c/time.c b/src_c/time.c index 66dc4fc6f3..a44d859209 100644 --- a/src_c/time.c +++ b/src_c/time.c @@ -276,8 +276,13 @@ _pg_clear_event_timer_type(int ev_type) /* Timer callback function * TODO: This needs better error handling and a way to report to the user */ +#if SDL_VERSION_ATLEAST(3, 0, 0) +static Uint32 +timer_callback(void *param, SDL_TimerID timerID, Uint32 interval) +#else static Uint32 timer_callback(Uint32 interval, void *param) +#endif { pgEventTimer *evtimer; PG_LOCK_TIMER_MUTEX @@ -316,12 +321,14 @@ accurate_delay(Sint64 ticks) if (ticks <= 0) return 0; +#if !SDL_VERSION_ATLEAST(3, 0, 0) if (!SDL_WasInit(SDL_INIT_TIMER)) { if (SDL_InitSubSystem(SDL_INIT_TIMER)) { PyErr_SetString(pgExc_SDLError, SDL_GetError()); return -1; } } +#endif funcstart = PG_GetTicks(); if (ticks >= WORST_CLOCK_ACCURACY) { @@ -342,8 +349,10 @@ accurate_delay(Sint64 ticks) static PyObject * time_get_ticks(PyObject *self, PyObject *_null) { +#if !SDL_VERSION_ATLEAST(3, 0, 0) if (!SDL_WasInit(SDL_INIT_TIMER)) return PyLong_FromLong(0); +#endif return PyLong_FromUnsignedLongLong(PG_GetTicks()); } @@ -371,11 +380,13 @@ time_wait(PyObject *self, PyObject *arg) if (!PyLong_Check(arg)) return RAISE(PyExc_TypeError, "wait requires one integer argument"); +#if !SDL_VERSION_ATLEAST(3, 0, 0) if (!SDL_WasInit(SDL_INIT_TIMER)) { if (SDL_InitSubSystem(SDL_INIT_TIMER)) { return RAISE(pgExc_SDLError, SDL_GetError()); } } +#endif ticks = PyLong_AsLongLong(arg); if (ticks < 0) @@ -455,6 +466,7 @@ time_set_timer(PyObject *self, PyObject *args, PyObject *kwargs) goto end; } +#if !SDL_VERSION_ATLEAST(3, 0, 0) /* just doublecheck that timer is initialized */ if (!SDL_WasInit(SDL_INIT_TIMER)) { if (SDL_InitSubSystem(SDL_INIT_TIMER)) { @@ -462,6 +474,7 @@ time_set_timer(PyObject *self, PyObject *args, PyObject *kwargs) goto end; } } +#endif ecode = _pg_add_event_timer(ev_type, ev_dict, loops); if (ecode != PG_TIMER_NO_ERROR) { @@ -522,12 +535,14 @@ clock_tick_base(pgClockObject *self, PyObject *arg, int use_accurate_delay) self->rawpassed = PG_GetTicks() - self->last_tick; delay = endtime - self->rawpassed; +#if !SDL_VERSION_ATLEAST(3, 0, 0) /*just doublecheck that timer is initialized*/ if (!SDL_WasInit(SDL_INIT_TIMER)) { if (SDL_InitSubSystem(SDL_INIT_TIMER)) { return RAISE(pgExc_SDLError, SDL_GetError()); } } +#endif if (use_accurate_delay) delay = accurate_delay(delay); @@ -639,11 +654,13 @@ clock_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) return NULL; } +#if !SDL_VERSION_ATLEAST(3, 0, 0) if (!SDL_WasInit(SDL_INIT_TIMER)) { if (SDL_InitSubSystem(SDL_INIT_TIMER)) { return RAISE(pgExc_SDLError, SDL_GetError()); } } +#endif pgClockObject *self = (pgClockObject *)(type->tp_alloc(type, 0)); self->fps_tick = 0; From 06866f450f99f05fe1a0fbe2469be30443c7f2eb Mon Sep 17 00:00:00 2001 From: Ankith Date: Wed, 23 Oct 2024 11:40:03 +0530 Subject: [PATCH 32/36] Add `dev.py` implementing dev command shorthands --- dev.py | 481 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 481 insertions(+) create mode 100644 dev.py diff --git a/dev.py b/dev.py new file mode 100644 index 0000000000..c3f27a00b8 --- /dev/null +++ b/dev.py @@ -0,0 +1,481 @@ +""" +This script is aimed at making development more convenient by having all useful +development commands under one place. + +For help on how to use this, do `python dev.py -h` to get a general overview +and `python dev.py [subcommand] -h` to get subcommand specific help. +""" + +import argparse +import os +import re +import subprocess +import sys +from pathlib import Path +from typing import Any, Union +from enum import Enum + +MOD_NAME = "pygame-ce" +DIST_DIR = "dist" + +VENV_NAME = "dev_venv" + +source_tree = Path(__file__).parent +venv_path = source_tree / VENV_NAME +pyproject_path = source_tree / "pyproject.toml" + +SDL3_ARGS = [ + "-Csetup-args=-Dsdl_api=3", + "-Csetup-args=-Dimage=disabled", + "-Csetup-args=-Dmixer=disabled", + "-Csetup-args=-Dfont=disabled", +] +COVERAGE_ARGS = ["-Csetup-args=-Dcoverage=true"] + +# We assume this script works with any pip version above this. +PIP_MIN_VERSION = "23.1" + + +class Colors(Enum): + RESET = "\033[0m" + RED = "\033[31m" + GREEN = "\033[32m" + YELLOW = "\033[33m" + BLUE = "\033[34m" + MAGENTA = "\033[35m" + CYAN = "\033[36m" + WHITE = "\033[37m" + + +# logic based on https://docs.python.org/3.13/using/cmdline.html#controlling-color +def has_color(): + # highest precedence + python_colors = os.environ.get("PYTHON_COLORS", "").strip() + if python_colors == "1": + return True + + if python_colors == "0": + return False + + # second highest precedence + if "NO_COLOR" in os.environ: + return False + + # third highest precedence + if "FORCE_COLOR" in os.environ: + return True + + # lowest precedence + return os.environ.get("TERM", "").strip().lower() != "dumb" + + +def pprint(arg: str, col: Colors = Colors.YELLOW): + do_col = has_color() + start = Colors.BLUE.value if do_col else "" + mid = col.value if do_col else "" + end = Colors.RESET.value if do_col else "" + print(f"{start}[dev.py] {mid}{arg}{end}", flush=True) + + +def cmd_run( + cmd: list[Union[str, Path]], + capture_output: bool = False, + error_on_output: bool = False, +) -> str: + if error_on_output: + capture_output = True + + norm_cmd = [str(i) for i in cmd] + pprint(f"> {' '.join(norm_cmd)}", Colors.CYAN) + try: + ret = subprocess.run( + norm_cmd, + stdout=subprocess.PIPE if capture_output else sys.stdout, + stderr=subprocess.STDOUT, + text=capture_output, + cwd=source_tree, + ) + except FileNotFoundError: + pprint(f"{norm_cmd[0]}: command not found", Colors.RED) + sys.exit(1) + + if ret.stdout: + print(ret.stdout, end="", flush=True) + + if (error_on_output and ret.stdout) and not ret.returncode: + # Convert success code to failure code if we have stdout and need to + # error + ret.returncode = 1 + + ret.check_returncode() + return ret.stdout + + +def pip_install(py: Path, args: list[str]): + return cmd_run([py, "-m", "pip", "install", "-v", *args]) + + +def get_pyproject_list_param(section: str, key: str) -> list[str]: + with open(pyproject_path, "r", encoding="utf-8") as f: + content = f.read() + if sys.version_info >= (3, 11): + import tomllib + + cur = tomllib.loads(content) + for i in section.split("."): + cur = cur[i] + + return cur[key] + + # hacky solution, because we don't have tomllib in stdlib on older + # python versions + import ast + import re + + # this regex only works to extract a list, nothing else + pattern = rf"\[{section}\].*\n\s*{key}\s*=\s*(\[.*?\])" + match = re.search(pattern, content, re.DOTALL) + if not match: + return [] + + return ast.literal_eval(match.group(1).strip()) + + +def get_build_deps(): + return set(get_pyproject_list_param("build-system", "requires")) + + +def get_cibw_setup_args(): + return [ + f"-Csetup-args={i}" + for i in get_pyproject_list_param( + "tool.cibuildwheel.config-settings", "setup-args" + ) + ] + + +def show_diff_and_suggest_fix(parent: str): + try: + cmd_run(["git", "status", "--porcelain"], error_on_output=True) + except subprocess.CalledProcessError: + try: + cmd_run(["git", "diff"]) + finally: + pprint(f"Running '{parent}' caused changes") + pprint(f"You need to run `python3 dev.py {parent}` and commit the changes") + pprint( + "Alternatively, you may run `python3 dev.py all` to catch more issues" + ) + raise + + +def check_version_atleast(version: str, min_version: str): + try: + version_tup = tuple(int(i.strip()) for i in version.split(".")) + min_version_tup = tuple(int(i.strip()) for i in min_version.split(".")) + except (AttributeError, TypeError, ValueError): + return False + + return version_tup >= min_version_tup + + +def check_module_in_constraint(mod: str, constraint: str): + constraint_mod = re.match(r"[a-z0-9._-]*", constraint.lower().strip()) + if not constraint_mod: + return False + + return mod.lower().strip() == constraint_mod[0] + + +class Dev: + def __init__(self) -> None: + self.py: Path = Path(sys.executable) + self.args: dict[str, Any] = {} + + self.deps: dict[str, set[str]] = { + "build": get_build_deps(), + "docs": get_build_deps(), + "test": {"numpy"}, + "lint": {"pylint==3.3.0", "numpy"}, + "stubs": {"mypy==1.11.2", "numpy"}, + "format": {"pre-commit==3.8.0"}, + } + self.deps["all"] = set() + for k in self.deps.values(): + self.deps["all"] |= k + + def cmd_build(self): + wheel_dir = self.args.get("wheel", DIST_DIR) + debug = self.args.get("debug", False) + lax = self.args.get("lax", False) + sdl3 = self.args.get("sdl3", False) + coverage = self.args.get("coverage", False) + if wheel_dir and coverage: + pprint("Cannot pass --wheel and --coverage together", Colors.RED) + sys.exit(1) + + build_suffix = "" + if debug: + build_suffix += "-dbg" + if lax: + build_suffix += "-lax" + if sdl3: + build_suffix += "-sdl3" + if coverage: + build_suffix += "-cov" + install_args = [ + "--no-build-isolation", + f"-Cbuild-dir=.mesonpy-build{build_suffix}", + ] + + if not wheel_dir: + # editable install + install_args.append("--editable") + + install_args.append(".") + + if debug: + install_args.append("-Csetup-args=-Dbuildtype=debug") + + if not lax: + # use the same flags as CI + install_args.extend(get_cibw_setup_args()) + + if sdl3: + install_args.extend(SDL3_ARGS) + + if coverage: + install_args.extend(COVERAGE_ARGS) + + info_str = f"with {debug=}, {lax=}, {sdl3=}, and {coverage=}" + if wheel_dir: + pprint(f"Building wheel at '{wheel_dir}' ({info_str})") + cmd_run( + [self.py, "-m", "pip", "wheel", "-v", "-w", wheel_dir, *install_args] + ) + pprint("Installing wheel") + pip_install( + self.py, ["--no-index", "--force", "--find-links", wheel_dir, MOD_NAME] + ) + else: + pprint(f"Installing in editable mode ({info_str})") + pip_install(self.py, install_args) + + def cmd_docs(self): + full = self.args.get("full", False) + + pprint(f"Generating docs (with {full=})") + extra_args = ["full_generation"] if full else [] + cmd_run([self.py, "buildconfig/make_docs.py", *extra_args]) + + if "CI" in os.environ: + show_diff_and_suggest_fix("docs") + + def cmd_lint(self): + pprint("Linting code (with pylint)") + cmd_run([self.py, "-m", "pylint", "src_py", "docs"]) + + def cmd_stubs(self): + pprint("Generating and testing type stubs (with mypy)") + cmd_run([self.py, "buildconfig/stubs/gen_stubs.py"]) + if "CI" in os.environ: + show_diff_and_suggest_fix("stubs") + + cmd_run([self.py, "buildconfig/stubs/stubcheck.py"]) + + def cmd_format(self): + pre_commit = self.py.parent / "pre-commit" + + pprint("Formatting code (with pre-commit)") + try: + cmd_run( + [ + pre_commit if pre_commit.exists() else "pre-commit", + "run", + "--all-files", + ] + ) + except subprocess.CalledProcessError: + # pre_commit may set error code when it modifies a file, ignore it + pass + + if "CI" in os.environ: + show_diff_and_suggest_fix("format") + + def cmd_test(self): + mod = self.args.get("mod", []) + + if mod: + pprint(f"Running tests (with module(s): {' '.join(mod)})") + for i in mod: + cmd_run([self.py, "-m", f"pygame.tests.{i}_test"]) + else: + pprint("Running tests (with all modules)") + cmd_run([self.py, "-m", "pygame.tests"]) + + def cmd_all(self): + self.cmd_format() + self.cmd_docs() + self.cmd_build() + self.cmd_stubs() + self.cmd_lint() + self.cmd_test() + + def parse_args(self): + parser = argparse.ArgumentParser( + description=( + "Build commands for the project. " + "For more info on any subcommand you can run -h/--help on it like: " + "dev.py build -h" + ) + ) + subparsers = parser.add_subparsers(dest="command", required=True) + + parser.add_argument( + "--venv", + action="store_true", + help="Make and use a venv (recommended, but not default)", + ) + parser.add_argument( + "--ignore-dep", action="append", help="Dependency to ignore in pip install" + ) + + # Build command + build_parser = subparsers.add_parser("build", help="Build the project") + build_parser.add_argument( + "--wheel", + nargs="?", + const=DIST_DIR, # Used if argument is provided without a value + default="", # Used if argument is not provided at all + help=( + "Generate a wheel and do a regular install from it. By default, this " + "value is empty in which case the script does an 'editable' install. " + "A value can passed optionally, to indicate the directory to place the " + f"wheel (if not passed, '{DIST_DIR}' is used)" + ), + ) + build_parser.add_argument( + "--debug", + action="store_true", + help="Install in debug mode (optimizations disabled and debug symbols enabled)", + ) + build_parser.add_argument( + "--lax", + action="store_true", + help="Be lax about build warnings, allow the build to succeed with them", + ) + build_parser.add_argument( + "--sdl3", + action="store_true", + help="Build against SDL3 instead of the default SDL2", + ) + build_parser.add_argument( + "--coverage", + action="store_true", + help=( + "Do a coverage build. To generate a test coverage report, you need " + "to compile pygame with this flag and run tests. This flag is only " + "supported if the underlying compiler supports the --coverage argument" + ), + ) + + # Docs command + docs_parser = subparsers.add_parser("docs", help="Generate docs") + docs_parser.add_argument( + "--full", + action="store_true", + help="Force a full regeneration of docs, ignoring previous build cache", + ) + + # Test command + test_parser = subparsers.add_parser("test", help="Run tests") + test_parser.add_argument( + "mod", + nargs="*", + help=( + "Name(s) of sub-module(s) to test. If no args are given all are tested" + ), + ) + + # Lint command + subparsers.add_parser("lint", help="Lint code") + + # Stubs command + subparsers.add_parser("stubs", help="Generate and test type stubs") + + # Format command + subparsers.add_parser("format", help="Format code") + + # All command + subparsers.add_parser( + "all", + help=( + "Run all the subcommands. This is handy for checking that your work is " + "ready to be submitted" + ), + ) + + args = parser.parse_args() + self.args = vars(args) + + def prep_env(self): + if self.args["venv"]: + if venv_path.is_dir(): + pprint(f"Using existing virtual environment '{venv_path}'") + else: + cmd_run([sys.executable, "-m", "venv", VENV_NAME]) + pprint(f"Virtual environment '{venv_path}' created") + + bin = venv_path / "Scripts" if os.name == "nt" else venv_path / "bin" + self.py = bin / "python" + else: + pprint(f"Using python '{self.py}'") + + # set PATH to give high priority to executables in the python bin folder + # this is where the binaries for meson/ninja/cython/sphinx/etc are installed + os.environ["PATH"] = f"{self.py.parent}{os.pathsep}{os.environ.get('PATH', '')}" + + pprint("Checking pip version") + pip_v = cmd_run([self.py, "-m", "pip", "-V"], capture_output=True) + try: + pip_version = pip_v.split()[1] + except (AttributeError, IndexError): + pip_version = "UNKNOWN" + + pprint(f"Determined pip version: {pip_version}") + if not check_version_atleast(pip_version, PIP_MIN_VERSION): + pprint("pip version is too old or unknown, attempting pip upgrade") + pip_install(self.py, ["-U", "pip"]) + + deps = self.deps.get(self.args["command"]) + ignored_deps = self.args["ignore_dep"] + deps_filtered = deps.copy() + if ignored_deps: + for constr in deps: + for dep in ignored_deps: + if check_module_in_constraint(dep, constr): + deps_filtered.remove(constr) + break + + if deps: + pprint("Installing dependencies") + pip_install(self.py, list(deps_filtered)) + + def run(self): + self.parse_args() + self.prep_env() + try: + func = getattr(self, f"cmd_{self.args['command']}") + func() + except subprocess.CalledProcessError as e: + pprint(f"Process exited with error code {e.returncode}", Colors.RED) + sys.exit(e.returncode) + except KeyboardInterrupt: + pprint("Got KeyboardInterrupt, exiting", Colors.RED) + sys.exit(1) + + pprint("Process exited successfully", Colors.GREEN) + + +if __name__ == "__main__": + Dev().run() From a44143ca9a0999042039c8c4a57801614f126d95 Mon Sep 17 00:00:00 2001 From: Ankith Date: Sun, 3 Nov 2024 16:53:03 +0530 Subject: [PATCH 33/36] Update CI, setup.py and docs to use dev.py --- .github/workflows/build-sdl3.yml | 6 +- .github/workflows/build-ubuntu-coverage.yml | 7 +-- .github/workflows/build-ubuntu-sdist.yml | 3 +- .github/workflows/dev-check.yml | 42 +++++++++++++ .github/workflows/format-lint.yml | 65 --------------------- docs/README.md | 5 +- setup.py | 10 +--- 7 files changed, 50 insertions(+), 88 deletions(-) create mode 100644 .github/workflows/dev-check.yml delete mode 100644 .github/workflows/format-lint.yml diff --git a/.github/workflows/build-sdl3.yml b/.github/workflows/build-sdl3.yml index 6f442d58e5..403141b51a 100644 --- a/.github/workflows/build-sdl3.yml +++ b/.github/workflows/build-sdl3.yml @@ -85,11 +85,7 @@ jobs: sudo cmake --install . --config Release - name: Build with SDL3 - run: > - python3 -m pip install . -v -Csetup-args=-Dsdl_api=3 - -Csetup-args=-Dimage=disabled - -Csetup-args=-Dmixer=disabled - -Csetup-args=-Dfont=disabled + run: python3 dev.py build --sdl3 # - name: Run tests # env: diff --git a/.github/workflows/build-ubuntu-coverage.yml b/.github/workflows/build-ubuntu-coverage.yml index 29260ccefb..699448770e 100644 --- a/.github/workflows/build-ubuntu-coverage.yml +++ b/.github/workflows/build-ubuntu-coverage.yml @@ -61,22 +61,17 @@ jobs: - uses: actions/checkout@v4.2.2 - name: Install deps - # install numpy from pip and not apt because the one from pip is newer, - # and has typestubs # https://github.com/actions/runner-images/issues/7192 # https://github.com/orgs/community/discussions/47863 run: | sudo apt-get update --fix-missing sudo apt-get install lcov -y sudo apt-get install libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev libfreetype6-dev libportmidi-dev python3-dev -y - pip3 install --upgrade pip - pip3 install meson-python ninja cython "sphinx<=7.2.6" # because we are doing --no-build-isolation - pip3 install numpy>=1.21.0 - name: Build with coverage hooks and install id: build run: | - pip3 install -e . --no-build-isolation -Cbuild-dir=./.mesonpy-rel -Csetup-args=-Dcoverage=true + python3 dev.py build --coverage - name: Run tests env: diff --git a/.github/workflows/build-ubuntu-sdist.yml b/.github/workflows/build-ubuntu-sdist.yml index ad0ab48eef..c58b9d8a6c 100644 --- a/.github/workflows/build-ubuntu-sdist.yml +++ b/.github/workflows/build-ubuntu-sdist.yml @@ -48,7 +48,7 @@ jobs: strategy: fail-fast: false # if a particular matrix build fails, don't skip the rest matrix: - os: [ubuntu-24.04, ubuntu-22.04] + os: [ubuntu-22.04] env: # Pip now forces us to either make a venv or set this flag, so we will do @@ -89,7 +89,6 @@ jobs: # We upload the generated files under github actions assets - name: Upload sdist - if: matrix.os == 'ubuntu-24.04' # upload sdist only once uses: actions/upload-artifact@v4 with: name: pygame-wheels-sdist diff --git a/.github/workflows/dev-check.yml b/.github/workflows/dev-check.yml new file mode 100644 index 0000000000..83d546df84 --- /dev/null +++ b/.github/workflows/dev-check.yml @@ -0,0 +1,42 @@ +name: python3 dev.py all + +# Run CI on changes to main branch, or any PR to main. Do not run CI on +# any other branch. +# Run on changes to all files. +on: + push: + branches: main + + pull_request: + branches: main + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-dev-check + cancel-in-progress: true + +jobs: + dev-check: + runs-on: ubuntu-24.04 + + env: + # Pip now forces us to either make a venv or set this flag, so we will do + # this + PIP_BREAK_SYSTEM_PACKAGES: 1 + + # We are using dependencies installed from apt + PG_DEPS_FROM_SYSTEM: 1 + + # environment variables to set while testing + SDL_VIDEODRIVER: "dummy" + SDL_AUDIODRIVER: "disk" + + steps: + - uses: actions/checkout@v4.2.2 + + - name: Install deps + run: | + sudo apt-get update --fix-missing + sudo apt-get install libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev libfreetype6-dev libportmidi-dev python3-dev + + - name: Check dev.py all + run: python3 dev.py all diff --git a/.github/workflows/format-lint.yml b/.github/workflows/format-lint.yml deleted file mode 100644 index 2030d0bf4f..0000000000 --- a/.github/workflows/format-lint.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: python3 setup.py lint - -# Run lint CI on changes to main branch, or any PR to main. Do not run CI on -# any other branch. -# Run only if there are changes on files that are linted (C, Python and rst files) -on: - push: - branches: main - paths: - - '**.h' - - '**.c' - - '**.py' - - '**.rst' - - '.pre-commit-config.yaml' - - pull_request: - branches: main - paths: - - '**.h' - - '**.c' - - '**.py' - - '**.rst' - - '.pre-commit-config.yaml' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-format-lint - cancel-in-progress: true - -jobs: - pre-commit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4.2.2 - - uses: actions/setup-python@v5 - with: - python-version: 3.x - - uses: pre-commit/action@v3.0.1 - - format-lint-code-check: - runs-on: ubuntu-24.04 - - env: - # Pip now forces us to either make a venv or set this flag, so we will do - # this - PIP_BREAK_SYSTEM_PACKAGES: 1 - - steps: - - uses: actions/checkout@v4.2.2 - - - name: Install deps - run: python3 -m pip install pylint sphinx"<7.2.0" - - - name: Check code linting - run: pylint src_py docs - - - name: Check docs changes are checked in - run: | - python3 buildconfig/make_docs.py - if [[ `git status --porcelain` ]]; then - echo "Generating docs caused changes. Please check them in." - echo "You may need to run: python3 buildconfig/make_docs.py full_generation" - # Run git status again, so people can see what changed. - git status --porcelain - exit 1 - fi diff --git a/docs/README.md b/docs/README.md index 349849b658..337938d68e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,9 +9,8 @@ but the documentation can also be launched with `python -m pygame.docs` Steps: -- Install Sphinx (`pip install Sphinx`) - Fork the pygame-ce repository, download and navigate to it in the terminal -- Run `python -m buildconfig docs` +- Run `python dev.py docs` - If you are using the legacy `python setup.py docs` (which is now deprecated): - (Run `python -m pip install -U pip setuptools` first if `ModuleNotFoundError: No module named setuptools` occurs) @@ -30,7 +29,7 @@ is useful when editing the theme CSS. --- **INSTEAD USE** --- -There is also `python -m buildconfig docs full_generation` for regenerating +There is also `python dev.py docs --full` for regenerating everything regardless of whether Sphinx thinks it should be regenerated. This is useful when editing the theme CSS. diff --git a/setup.py b/setup.py index 47648be978..cbad740727 100644 --- a/setup.py +++ b/setup.py @@ -807,11 +807,9 @@ def run(self): runs Sphinx to build the docs. ''' import subprocess - command_line = [ - sys.executable, "-m", "buildconfig", "docs" - ] + command_line = [sys.executable, "dev.py", "docs"] if self.fullgeneration: - command_line.append('full_generation') + command_line.append('--full') print("WARNING: This command is deprecated and will be removed in the future.") print(f"Please use the following replacement: `{' '.join(command_line)}`\n") @@ -834,9 +832,7 @@ def run(self): runs mypy to build the docs. ''' import subprocess - command_line = [ - sys.executable, os.path.join("buildconfig", "stubs", "stubcheck.py") - ] + command_line = [sys.executable, "dev.py", "stubs"] print("WARNING: This command is deprecated and will be removed in the future.") print(f"Please use the following replacement: `{' '.join(command_line)}`\n") result = subprocess.run(command_line) From f295ce5c2c602cdb6cfaa8782c4601a5c7bb1636 Mon Sep 17 00:00:00 2001 From: Ankith Date: Tue, 5 Nov 2024 23:55:08 +0530 Subject: [PATCH 34/36] Move brace out of conditional blocks Co-authored-by: gresm <78505251+gresm@users.noreply.github.com> --- src_c/surflock.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src_c/surflock.c b/src_c/surflock.c index 60f3d953ec..0786d0fe66 100644 --- a/src_c/surflock.c +++ b/src_c/surflock.c @@ -100,10 +100,11 @@ pgSurface_LockBy(pgSurfaceObject *surfobj, PyObject *lockobj) pgSurface_Prep(surfobj); } #if SDL_VERSION_ATLEAST(3, 0, 0) - if (!SDL_LockSurface(surf->surf)) { + if (!SDL_LockSurface(surf->surf)) #else - if (SDL_LockSurface(surf->surf) == -1) { + if (SDL_LockSurface(surf->surf) == -1) #endif + { PyErr_SetString(PyExc_RuntimeError, "error locking surface"); return 0; } From 2fdcf73ba5a86febf1073db037f598c8417362a0 Mon Sep 17 00:00:00 2001 From: XORandom <40043238+XORandom@users.noreply.github.com> Date: Tue, 5 Nov 2024 22:14:51 +0300 Subject: [PATCH 35/36] Add Russian readme (#3138) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update README.rst * Create README.ru.rst Added a translation to Russian. * Update README.es.rst Добавлены ссылки на ru.rst * Update README.ru.rst * Update README.ja.rst Added links to ru. rst * Added links to en README * Added links to ru. rst * Added links to ru. rst * Added links to ru. rst * Update README.zh-cn.rst * Update README.fr.rst * Update README.fa.rst * Update README.es.rst * Fixed non-clickable links Fixed non-clickable links to English README and incorrect paths to other README's * Update README.ru.rst * fix incorrect links to other readme's * fix formatting * Corrected the sentence to make it sound better. * Removed extra newline * Update README.ru.rst add `Italiano` * Update README.it.rst * Fix formatting --------- Co-authored-by: Dan Lawrence Co-authored-by: Ankith --- README.rst | 3 +- docs/readmes/README.es.rst | 4 +- docs/readmes/README.fa.rst | 4 +- docs/readmes/README.fr.rst | 4 +- docs/readmes/README.it.rst | 3 +- docs/readmes/README.ja.rst | 13 +- docs/readmes/README.ru.rst | 226 ++++++++++++++++++++++++++++++++++ docs/readmes/README.zh-cn.rst | 4 +- 8 files changed, 250 insertions(+), 11 deletions(-) create mode 100644 docs/readmes/README.ru.rst diff --git a/README.rst b/README.rst index e9c952c6a4..72b6cea133 100644 --- a/README.rst +++ b/README.rst @@ -8,7 +8,7 @@ |PyPiVersion| |PyPiLicense| |Python3| |GithubCommits| |BlackFormatBadge| -**English** `简体中文`_ `繁體中文`_ `Français`_ `فارسی`_ `Español`_ `日本語`_ `Italiano`_ +**English** `简体中文`_ `繁體中文`_ `Français`_ `فارسی`_ `Español`_ `日本語`_ `Italiano`_ `Русский`_ --------------------------------------------------------------------------------------------------- Pygame_ is a free and open-source cross-platform library @@ -221,3 +221,4 @@ See docs/licenses for licenses of dependencies. .. _Español: ./docs/readmes/README.es.rst .. _日本語: ./docs/readmes/README.ja.rst .. _Italiano: ./docs/readmes/README.it.rst +.. _Русский: ./docs/readmes/README.ru.rst diff --git a/docs/readmes/README.es.rst b/docs/readmes/README.es.rst index 9c78006fe2..69d55ea896 100644 --- a/docs/readmes/README.es.rst +++ b/docs/readmes/README.es.rst @@ -7,7 +7,8 @@ |PyPiVersion| |PyPiLicense| |Python3| |GithubCommits| |BlackFormatBadge| -`English`_ `简体中文`_ `繁體中文`_ `Français`_ `فارسی`_ **Español** `日本語`_ `Italiano`_ +`English`_ `简体中文`_ `繁體中文`_ `Français`_ `فارسی`_ **Español** `日本語`_ `Italiano`_ `Русский`_ + --------------------------------------------------------------------------------------------------------------------------------------------------- `Pygame`_ es una biblioteca multiplataforma, gratuita y de código abierto @@ -171,3 +172,4 @@ Consulta docs/licenses para ver las licencias de dependencia. .. _Français: README.fr.rst .. _日本語: README.ja.rst .. _Italiano: README.it.rst +.. _Русский: README.ru.rst diff --git a/docs/readmes/README.fa.rst b/docs/readmes/README.fa.rst index e41ebb3ea8..bb83cd0733 100644 --- a/docs/readmes/README.fa.rst +++ b/docs/readmes/README.fa.rst @@ -7,7 +7,8 @@ |PyPiVersion| |PyPiLicense| |Python3| |GithubCommits| |BlackFormatBadge| -`English`_ `简体中文`_ `繁體中文`_ `Français`_ **فارسی** `Español`_ `日本語`_ `Italiano`_ +`English`_ `简体中文`_ `繁體中文`_ `Français`_ **فارسی** `Español`_ `日本語`_ `Italiano`_ `Русский`_ + --------------------------------------------------------------------------------------------------- کتابخانه Pygame_ @@ -257,3 +258,4 @@ LGPL-2.1-or-later **شناسه مجوز:** .. _Español: README.es.rst .. _日本語: README.ja.rst .. _Italiano: README.it.rst +.. _Русский: README.ru.rst diff --git a/docs/readmes/README.fr.rst b/docs/readmes/README.fr.rst index e546df1afe..72155e294b 100644 --- a/docs/readmes/README.fr.rst +++ b/docs/readmes/README.fr.rst @@ -7,7 +7,8 @@ |PyPiVersion| |PyPiLicense| |Python3| |GithubCommits| |BlackFormatBadge| -`English`_ `简体中文`_ `繁體中文`_ **Français** `فارسی`_ `Español`_ `日本語`_ `Italiano`_ +`English`_ `简体中文`_ `繁體中文`_ **Français** `فارسی`_ `Español`_ `日本語`_ `Italiano`_ `Русский`_ + --------------------------------------------------------------------------------------------------------------------------------------------------- `Pygame`_ est une bibliothèque multi-plateforme, libre et open-source @@ -211,3 +212,4 @@ Voir les docs/licences pour les licences des dépendances. .. _Español: README.es.rst .. _日本語: README.ja.rst .. _Italiano: README.it.rst +.. _Русский: README.ru.rst diff --git a/docs/readmes/README.it.rst b/docs/readmes/README.it.rst index df7dcddb58..0a7f366297 100644 --- a/docs/readmes/README.it.rst +++ b/docs/readmes/README.it.rst @@ -8,7 +8,7 @@ |PyPiVersion| |PyPiLicense| |Python3| |GithubCommits| |BlackFormatBadge| -`English`_ `简体中文`_ `繁體中文`_ `Français`_ `فارسی`_ `Español`_ `日本語`_ **Italiano** +`English`_ `简体中文`_ `繁體中文`_ `Français`_ `فارسی`_ `Español`_ `日本語`_ **Italiano** `Русский`_ --------------------------------------------------------------------------------------------------- Pygame_ è una libreria open source gratuita e multipiattaforma @@ -226,3 +226,4 @@ Controlla docs/licenses per le licenze dei requisiti. .. _Español: README.es.rst .. _日本語: README.ja.rst .. _Italiano: README.it.rst +.. _Русский: README.ru.rst diff --git a/docs/readmes/README.ja.rst b/docs/readmes/README.ja.rst index 7774b97a1d..bc4c0e63ab 100644 --- a/docs/readmes/README.ja.rst +++ b/docs/readmes/README.ja.rst @@ -8,7 +8,8 @@ |PyPiVersion| |PyPiLicense| |Python3| |GithubCommits| |BlackFormatBadge| -`English` `简体中文`_ `繁體中文`_ `Français`_ `فارسی`_ `Español`_ **日本語** `Italiano`_ +`English` `简体中文`_ `繁體中文`_ `Français`_ `فارسی`_ `Español`_ **日本語** `Italiano`_ `Русский`_ + --------------------------------------------------------------------------------------------------- Pygame_ は、Pythonを使ってビデオゲームのようなマルチメディアアプリケーションを @@ -232,9 +233,11 @@ gfxdraw には SDL_gfx の埋め込みバージョンが含まれています。 .. _Pygame Community Discord Server: https://discord.gg/pygame .. _wiki pages: https://github.com/pygame-community/pygame-ce/wiki -.. _简体中文: ./docs/readmes/README.zh-cn.rst +.. _English: ./../../README.rst +.. _简体中文: README.zh-cn.rst .. _繁體中文: README.zh-tw.rst -.. _Français: ./docs/readmes/README.fr.rst -.. _فارسی: ./docs/readmes/README.fa.rst -.. _Español: ./docs/readmes/README.es.rst +.. _Français: README.fr.rst +.. _فارسی: README.fa.rst +.. _Español: README.es.rst .. _Italiano: README.it.rst +.. _Русский: README.ru.rst diff --git a/docs/readmes/README.ru.rst b/docs/readmes/README.ru.rst new file mode 100644 index 0000000000..e6e099775f --- /dev/null +++ b/docs/readmes/README.ru.rst @@ -0,0 +1,226 @@ +.. image:: https://raw.githubusercontent.com/pygame-community/pygame-ce/main/docs/reST/_static/pygame_ce_logo.svg + :width: 800 + :alt: pygame + :target: https://pyga.me/ + + +|DocsStatus| +|PyPiVersion| |PyPiLicense| +|Python3| |GithubCommits| |BlackFormatBadge| + +`English`_ `简体中文`_ `繁體中文`_ `Français`_ `فارسی`_ `Español`_ `日本語`_ `Italiano`_ **Русский** +--------------------------------------------------------------------------------------------------- + +Pygame_ - бесплатная кроссплатформенная библиотека с открытым исходным кодом +для разработки мультимедийных приложений, таких как видеоигры, с использованием Python. +Он использует `Simple DirectMedia Layer library`_ и несколько других популярных библиотек +для абстрагирования наиболее распространенных функций, +что делает написание этих программ более интуитивно понятной задачей. + + +Этот дистрибутив называется **'pygame - Community Edition'** (сокращённо 'pygame-ce'). + +Это ответвление исходного проекта pygame от его бывших главных разработчиков и было создано после того, как непреодолимые +трудности помешали им продолжить разработку исходного проекта. +Новый дистрибутив призван предлагать более частые выпуски, постоянные исправления и усовершенствования, +а также более демократичную модель управления. + +Новые участники приветствуются! + + +Установка +------------ + +:: + + pip install pygame-ce + + +Справка +---- + +Если вы только начинаете работать с pygame, вы сможете приступить к работе довольно быстро. +Pygame поставляется с множеством руководств и введений. +Также имеется полная справочная документация по всей библиотеке. +Просмотрите документацию на страниц `docs page`_. +Вы также можете просмотреть документацию локально, запустив +``python -m pygame.docs`` в Вашем терминале. Если документы не найдены +локально, вместо этого будет запущен онлайн-сайт. + +Интерактивная документация соответствует версии pygame для разработки на github. +Она может быть немного новее, чем версия pygame, которую вы используете. +Чтобы перейти на последнюю выпущенную версию, запустите +``pip install pygame-ce --upgrade`` в Вашем терминале. + +Лучше всего то, что в каталоге examples есть множество воспроизводимых небольших программ, +которые помогут вам сразу начать работу с кодом. + + +Сборка из исходного кода +-------------------- + +Если вы хотите использовать функции, которые в настоящее время находятся в разработке, +или вы хотите внести свой вклад в pygame-ce, +вам нужно будет создать pygame-ce локально из его исходного кода, а не устанавливать его pip. + +Установка из исходного кода довольно автоматизирована. +Основная работа будет включать компиляцию и установку всех зависимостей pygame. +Как только это будет сделано, запустите сценарий ``setup.py``, +который попытается автоматически настроить, собрать и установить pygame. + +Гораздо больше информации об установке и компиляции доступно +на `Compilation wiki page`_. + + +Заслуги +------- + +Спасибо всем, кто помог внести свой вклад в эту библиотеку. +Также уместна особая благодарность. + +* Marcus Von Appen: many changes, and fixes, 1.7.1+ freebsd maintainer +* Lenard Lindstrom: the 1.8+ windows maintainer, many changes, and fixes +* Brian Fisher for svn auto builder, bug tracker and many contributions +* Rene Dudfield: many changes, and fixes, 1.7+ release manager/maintainer +* Phil Hassey for his work on the pygame.org website +* DR0ID for his work on the sprite module +* Richard Goedeken for his smoothscale function +* Ulf Ekström for his pixel perfect collision detection code +* Pete Shinners: original author +* David Clark for filling the right-hand-man position +* Ed Boraas and Francis Irving: Debian packages +* Maxim Sobolev: FreeBSD packaging +* Bob Ippolito: macOS and OS X porting (much work!) +* Jan Ekhol, Ray Kelm, and Peter Nicolai: putting up with early design ideas +* Nat Pryce for starting our unit tests +* Dan Richter for documentation work +* TheCorruptor for his incredible logos and graphics +* Nicholas Dudfield: many test improvements +* Alex Folkner for pygame-ctypes + +Спасибо тем, кто присылает патчи и исправления: Niki Spahiev, Gordon +Tyler, Nathaniel Pryce, Dave Wallace, John Popplewell, Michael Urman, +Andrew Straw, Michael Hudson, Ole Martin Bjoerndalen, Herve Cauwelier, +James Mazer, Lalo Martins, Timothy Stranex, Chad Lester, Matthias +Spiller, Bo Jangeborg, Dmitry Borisov, Campbell Barton, Diego Essaya, +Eyal Lotem, Regis Desgroppes, Emmanuel Hainry, Randy Kaelber, +Matthew L Daniel, Nirav Patel, Forrest Voight, Charlie Nolan, +Frankie Robertson, John Krukoff, Lorenz Quack, Nick Irvine, +Michael George, Saul Spatz, Thomas Ibbotson, Tom Rothamel, Evan Kroske, +Cambell Barton. + +И наши охотники за багами выше всяких похвал: Angus, Guillaume Proux, Frank +Raiser, Austin Henry, Kaweh Kazemi, Arturo Aldama, Mike Mulcheck, +Michael Benfield, David Lau + +Есть еще много людей, которые предоставили полезные идеи, +поддержали этот проект и, по сути, упростили нам жизнь. Спасибо! + +Большое спасибо людям, которые комментируют документацию и добавляют в +`pygame documentation`_ и `pygame-ce documentation`_. + +Также большое спасибо за людей, создающих игры и размещающих их на веб-сайте +pygame.org, чтобы другие могли учиться и получать удовольствие. + +Огромное спасибо James Paige за хостинг pygame bugzilla. + +Также большое спасибо Roger Dingledine и команде SEUL.ORG за наш +отличный хостинг. + + +Зависимости +------------ + +Pygame, очевидно, сильно зависит от SDL и Python. Он также +ссылается на несколько других библиотек меньшего размера и встраивает их. Модуль font +использует SDL_ttf, который зависит от freetype. Модули mixer +(и mixer.music) зависят от SDL_mixer. Модуль image +зависит от SDL_image. Transform.rotozoom имеет встроенную версию +SDL_rotozoom, а gfxdraw имеет встроенную версию SDL_gfx. +Версии зависимостей: + + ++----------+------------------------+ +| CPython | >= 3.8 (Or use PyPy3) | ++----------+------------------------+ +| SDL | >= 2.0.10 | ++----------+------------------------+ +| SDL_mixer| >= 2.0.4 | ++----------+------------------------+ +| SDL_image| >= 2.0.4 | ++----------+------------------------+ +| SDL_ttf | >= 2.0.15 | ++----------+------------------------+ + +Как внести свой вклад +----------------- +Прежде всего, спасибо, что согласились внести свой вклад в pygame-ce! Именно такие люди, как вы, делают pygame-ce отличной библиотекой. Пожалуйста, выполните следующие действия, чтобы начать: + +1. Read the `Contribution Guidelines`_ and the `Many Ways to Contribute`_ wiki pages. +2. Read the documentataion on `Opening A Pull Request`_ and `Opening a Great Pull Request`_. +3. Read how to `label and link reported issues`_. +4. Check the `issue tracker`_ for open issues that interest you or open a new issue to start a discussion about your idea. + +There are many more resources throughout the `wiki pages`_ that can help you get started. + +If you have any questions, please feel free to ask in the `Pygame Community Discord Server`_ or open an issue. + +License +------- +**License Identifier:** LGPL-2.1-or-later + +Эта библиотека распространяется под лицензией `GNU LGPL version 2.1`_, которую можно +найти в файле ``docs/LGPL.txt``. Мы оставляем за собой право размещать +будущие версии этой библиотеки под другой лицензией. + +По сути, это означает, что вы можете использовать pygame в любом проекте, который захотите, +но если вы вносите какие-либо изменения или дополнения в саму pygame, они +должны быть выпущены с совместимой лицензией (preferably submitted +back to the pygame-ce project). Игры с закрытым исходным кодом и коммерческие игры - это нормально. + +Программы в подкаталоге ``examples`` находятся в открытом доступе. + +Смотрите docs/licenses, чтобы узнать лицензии на зависимости. + + +.. |PyPiVersion| image:: https://img.shields.io/pypi/v/pygame-ce.svg?v=1 + :target: https://pypi.python.org/pypi/pygame-ce + +.. |PyPiLicense| image:: https://img.shields.io/pypi/l/pygame-ce.svg?v=1 + :target: https://pypi.python.org/pypi/pygame-ce + +.. |Python3| image:: https://img.shields.io/badge/python-3-blue.svg?v=1 + +.. |GithubCommits| image:: https://img.shields.io/github/commits-since/pygame-community/pygame-ce/2.4.1.svg + :target: https://github.com/pygame-community/pygame-ce/compare/2.4.1...main + +.. |DocsStatus| image:: https://img.shields.io/website?down_message=offline&label=docs&up_message=online&url=https%3A%2F%2Fpyga.me%2Fdocs%2F + :target: https://pyga.me/docs/ + +.. |BlackFormatBadge| image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + +.. _Pygame: https://pyga.me +.. _pygame-ce documentation: https://pyga.me/docs/ +.. _pygame documentation: https://www.pygame.org/docs/ +.. _Simple DirectMedia Layer library: https://www.libsdl.org +.. _Compilation wiki page: https://github.com/pygame-community/pygame-ce/wiki#compiling +.. _docs page: https://pyga.me/docs +.. _GNU LGPL version 2.1: https://www.gnu.org/copyleft/lesser.html +.. _Contribution Guidelines: https://github.com/pygame-community/pygame-ce/wiki/Contribution-guidelines +.. _Many Ways to Contribute: https://github.com/pygame-community/pygame-ce/wiki/Many-ways-to-contribute +.. _Opening A Pull Request: https://github.com/pygame-community/pygame-ce/wiki/Opening-a-pull-request +.. _Opening a Great Pull Request: https://github.com/pygame-community/pygame-ce/wiki/Opening-a-great-pull-request +.. _issue tracker: https://github.com/pygame-community/pygame-ce/issues +.. _label and link reported issues: https://github.com/pygame-community/pygame-ce/wiki/Labelling-&-linking-reported-issues +.. _Pygame Community Discord Server: https://discord.gg/pygame +.. _wiki pages: https://github.com/pygame-community/pygame-ce/wiki + +.. _English: ./../../README.rst +.. _简体中文: README.zh-cn.rst +.. _繁體中文: README.zh-tw.rst +.. _Français: README.fr.rst +.. _فارسی: README.fa.rst +.. _Español: README.es.rst +.. _日本語: README.ja.rst +.. _Italiano: README.it.rst diff --git a/docs/readmes/README.zh-cn.rst b/docs/readmes/README.zh-cn.rst index 7816284e70..6a21668243 100644 --- a/docs/readmes/README.zh-cn.rst +++ b/docs/readmes/README.zh-cn.rst @@ -7,7 +7,8 @@ |PyPiVersion| |PyPiLicense| |Python3| |GithubCommits| |BlackFormatBadge| -`English`_ **简体中文** `繁體中文`_ `Français`_ `فارسی`_ `Español`_ `日本語`_ `Italiano`_ +`English`_ **简体中文** `繁體中文`_ `Français`_ `فارسی`_ `Español`_ `日本語`_ `Italiano`_ `Русский`_ + ---- Pygame_ 是一款自由且开源的跨平台库,用于开发电子游戏等多媒体应用。Pygame基于 `Simple DirectMedia Layer library`_ 以及其他几个广受欢迎的库,汲取其中最常见的函数,让编写游戏成为更加符合直觉的事情。 @@ -161,3 +162,4 @@ pygame显然依赖于SDL和Python。此外pygame还嵌入了几个较小的库 .. _Español: README.es.rst .. _日本語: README.ja.rst .. _Italiano: README.it.rst +.. _Русский: README.ru.rst From fac1c39c973a29c8ebbe95cc503b6ea6aeeb36ef Mon Sep 17 00:00:00 2001 From: Ankith Date: Sun, 3 Nov 2024 19:22:51 +0530 Subject: [PATCH 36/36] Raise minimum supported SDL2 to 2.0.14 --- README.rst | 2 +- docs/reST/ref/event.rst | 2 +- docs/reST/ref/joystick.rst | 2 +- docs/reST/ref/sdl2_controller.rst | 8 ++----- docs/reST/ref/system.rst | 5 +--- docs/readmes/README.es.rst | 2 +- docs/readmes/README.fa.rst | 2 +- docs/readmes/README.fr.rst | 2 +- docs/readmes/README.it.rst | 2 +- docs/readmes/README.ja.rst | 2 +- docs/readmes/README.ru.rst | 2 +- docs/readmes/README.zh-cn.rst | 2 +- src_c/_camera.c | 2 +- src_c/_pygame.h | 40 ------------------------------- src_c/_sdl2/controller.c | 6 ----- src_c/constants.c | 8 ------- src_c/display.c | 19 ++++----------- src_c/event.c | 12 ---------- src_c/font.c | 2 +- src_c/include/pgcompat.h | 18 +------------- src_c/pixelcopy.c | 2 +- src_c/surface.c | 2 +- src_c/system.c | 11 +-------- 23 files changed, 23 insertions(+), 132 deletions(-) diff --git a/README.rst b/README.rst index 72b6cea133..a0347341e7 100644 --- a/README.rst +++ b/README.rst @@ -141,7 +141,7 @@ Dependency versions: +----------+------------------------+ | CPython | >= 3.8 (Or use PyPy3) | +----------+------------------------+ -| SDL | >= 2.0.10 | +| SDL | >= 2.0.14 | +----------+------------------------+ | SDL_mixer| >= 2.0.4 | +----------+------------------------+ diff --git a/docs/reST/ref/event.rst b/docs/reST/ref/event.rst index b6c8349948..186fa37717 100644 --- a/docs/reST/ref/event.rst +++ b/docs/reST/ref/event.rst @@ -154,7 +154,7 @@ pygame 2 also supports controller hot-plugging CLIPBOARDUPDATE RENDER_TARGETS_RESET RENDER_DEVICE_RESET - LOCALECHANGED (SDL backend >= 2.0.14) + LOCALECHANGED Also in this version, ``instance_id`` attributes were added to joystick events, and the ``joy`` attribute was deprecated. diff --git a/docs/reST/ref/joystick.rst b/docs/reST/ref/joystick.rst index 0e89c13dcf..555c549489 100644 --- a/docs/reST/ref/joystick.rst +++ b/docs/reST/ref/joystick.rst @@ -338,7 +338,7 @@ variable. See :ref:`environment variables ` for more deta playing, then it will be overwritten. Returns True if the rumble was played successfully or False if the - joystick does not support it or :meth:`pygame.version.SDL` is below 2.0.9. + joystick does not support it. .. versionaddedold:: 2.0.2 diff --git a/docs/reST/ref/sdl2_controller.rst b/docs/reST/ref/sdl2_controller.rst index c5e61e4d9f..e6ff3ef4bd 100644 --- a/docs/reST/ref/sdl2_controller.rst +++ b/docs/reST/ref/sdl2_controller.rst @@ -19,11 +19,7 @@ always the leftmost button of the 4 buttons on the right. Controllers can generate the following events:: CONTROLLERAXISMOTION, CONTROLLERBUTTONDOWN, CONTROLLERBUTTONUP, - CONTROLLERDEVICEREMAPPED, CONTROLLERDEVICEADDED, CONTROLLERDEVICEREMOVED - -Additionally if pygame is built with SDL 2.0.14 or higher the following events can also be generated -(to get the version of sdl pygame is built with use :meth:`pygame.version.SDL`):: - + CONTROLLERDEVICEREMAPPED, CONTROLLERDEVICEADDED, CONTROLLERDEVICEREMOVED, CONTROLLERTOUCHPADDOWN, CONTROLLERTOUCHPADMOTION, CONTROLLERTOUCHPADUP These events can be enabled/disabled by :meth:`pygame._sdl2.controller.set_eventstate` @@ -274,7 +270,7 @@ events related to controllers. playing, then it will be overwritten. Returns True if the rumble was played successfully or False if the - controller does not support it or :meth:`pygame.version.SDL` is below 2.0.9. + controller does not support it. .. versionaddedold:: 2.0.2 diff --git a/docs/reST/ref/system.rst b/docs/reST/ref/system.rst index eb1450f9e3..de5cb55daf 100644 --- a/docs/reST/ref/system.rst +++ b/docs/reST/ref/system.rst @@ -43,10 +43,7 @@ 'LASX': False } - .. Note:: The value of ``ARMSIMD`` will be always False if - SDL version < 2.0.12. - - The values of ``LSX`` and ``LASX`` will be always False if + .. Note:: The values of ``LSX`` and ``LASX`` will be always False if SDL version < 2.24.0. .. versionadded:: 2.3.1 diff --git a/docs/readmes/README.es.rst b/docs/readmes/README.es.rst index 69d55ea896..d1ca1fd6c2 100644 --- a/docs/readmes/README.es.rst +++ b/docs/readmes/README.es.rst @@ -119,7 +119,7 @@ Versiones de dependencia: +----------+-----------------------------+ | CPython | >= 3.8 (Ou utiliser PyPy3) | +----------+-----------------------------+ -| SDL | >= 2.0.10 | +| SDL | >= 2.0.14 | +----------+-----------------------------+ | SDL_mixer| >= 2.0.4 | +----------+-----------------------------+ diff --git a/docs/readmes/README.fa.rst b/docs/readmes/README.fa.rst index bb83cd0733..b3b7229b33 100644 --- a/docs/readmes/README.fa.rst +++ b/docs/readmes/README.fa.rst @@ -191,7 +191,7 @@ Dependencies (وابستگی ها) +----------+------------------------+ | CPython | >= 3.8 (Or use PyPy3) | +----------+------------------------+ -| SDL | >= 2.0.10 | +| SDL | >= 2.0.14 | +----------+------------------------+ | SDL_mixer| >= 2.0.4 | +----------+------------------------+ diff --git a/docs/readmes/README.fr.rst b/docs/readmes/README.fr.rst index 72155e294b..c17d701fa9 100644 --- a/docs/readmes/README.fr.rst +++ b/docs/readmes/README.fr.rst @@ -148,7 +148,7 @@ Versions des dépendances: +----------+-----------------------------+ | CPython | >= 3.8 (Ou utiliser PyPy3) | +----------+-----------------------------+ -| SDL | >= 2.0.10 | +| SDL | >= 2.0.14 | +----------+-----------------------------+ | SDL_mixer| >= 2.0.4 | +----------+-----------------------------+ diff --git a/docs/readmes/README.it.rst b/docs/readmes/README.it.rst index 0a7f366297..f660b2c3cc 100644 --- a/docs/readmes/README.it.rst +++ b/docs/readmes/README.it.rst @@ -142,7 +142,7 @@ Le versioni dei requisiti: +----------+------------------------+ | CPython | >= 3.8 (Or use PyPy3) | +----------+------------------------+ -| SDL | >= 2.0.10 | +| SDL | >= 2.0.14 | +----------+------------------------+ | SDL_mixer| >= 2.0.4 | +----------+------------------------+ diff --git a/docs/readmes/README.ja.rst b/docs/readmes/README.ja.rst index bc4c0e63ab..502cd98e8e 100644 --- a/docs/readmes/README.ja.rst +++ b/docs/readmes/README.ja.rst @@ -153,7 +153,7 @@ gfxdraw には SDL_gfx の埋め込みバージョンが含まれています。 +----------+------------------------+ | CPython | >= 3.8 (Or use PyPy3) | +----------+------------------------+ -| SDL | >= 2.0.10 | +| SDL | >= 2.0.14 | +----------+------------------------+ | SDL_mixer| >= 2.0.4 | +----------+------------------------+ diff --git a/docs/readmes/README.ru.rst b/docs/readmes/README.ru.rst index e6e099775f..cdcbd37fc7 100644 --- a/docs/readmes/README.ru.rst +++ b/docs/readmes/README.ru.rst @@ -143,7 +143,7 @@ SDL_rotozoom, а gfxdraw имеет встроенную версию SDL_gfx. +----------+------------------------+ | CPython | >= 3.8 (Or use PyPy3) | +----------+------------------------+ -| SDL | >= 2.0.10 | +| SDL | >= 2.0.14 | +----------+------------------------+ | SDL_mixer| >= 2.0.4 | +----------+------------------------+ diff --git a/docs/readmes/README.zh-cn.rst b/docs/readmes/README.zh-cn.rst index 6a21668243..63745b8edb 100644 --- a/docs/readmes/README.zh-cn.rst +++ b/docs/readmes/README.zh-cn.rst @@ -107,7 +107,7 @@ pygame显然依赖于SDL和Python。此外pygame还嵌入了几个较小的库 +----------+------------------------+ | CPython | >= 3.8 (或 PyPy3) | +----------+------------------------+ -| SDL | >= 2.0.10 | +| SDL | >= 2.0.14 | +----------+------------------------+ | SDL_mixer| >= 2.0.4 | +----------+------------------------+ diff --git a/src_c/_camera.c b/src_c/_camera.c index 8bf528b559..3776e9fa68 100644 --- a/src_c/_camera.c +++ b/src_c/_camera.c @@ -425,7 +425,7 @@ camera_get_image(pgCameraObject *self, PyObject *arg) return NULL; if (!surfobj) { - surf = PG_CreateSurface(width, height, PG_PIXELFORMAT_XRGB8888); + surf = PG_CreateSurface(width, height, SDL_PIXELFORMAT_XRGB8888); } else { surf = pgSurface_AsSurface(surfobj); diff --git a/src_c/_pygame.h b/src_c/_pygame.h index 07f236149a..45ac03e341 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -188,47 +188,7 @@ PG_UnlockMutex(SDL_mutex *mutex) #define PG_INIT_TIMER SDL_INIT_TIMER -#if SDL_VERSION_ATLEAST(2, 0, 14) #define PG_SurfaceHasRLE SDL_HasSurfaceRLE -#else -// vendored in until our lowest SDL version is 2.0.14 -typedef struct { - Uint8 *src; - int src_w, src_h; - int src_pitch; - int src_skip; - Uint8 *dst; - int dst_w, dst_h; - int dst_pitch; - int dst_skip; - SDL_PixelFormat *src_fmt; - SDL_PixelFormat *dst_fmt; - Uint8 *table; - int flags; - Uint32 colorkey; - Uint8 r, g, b, a; -} SDL_InternalBlitInfo; - -struct SDL_BlitMap { - SDL_Surface *dst; - int identity; - SDL_blit blit; - void *data; - SDL_InternalBlitInfo info; - - /* the version count matches the destination; mismatch indicates - an invalid mapping */ - Uint32 dst_palette_version; - Uint32 src_palette_version; -}; -#define SDL_COPY_RLE_DESIRED 0x00001000 - -#define PG_SurfaceHasRLE(surface) \ - (((surface) == NULL) \ - ? 0 \ - : ((surface)->map->info.flags & SDL_COPY_RLE_DESIRED)) - -#endif #endif diff --git a/src_c/_sdl2/controller.c b/src_c/_sdl2/controller.c index 6425aa4f51..331ffd876d 100644 --- a/src_c/_sdl2/controller.c +++ b/src_c/_sdl2/controller.c @@ -367,7 +367,6 @@ controller_rumble(pgControllerObject *self, PyObject *args, PyObject *kwargs) return RAISE(pgExc_SDLError, "Controller is not initalized"); } -#if SDL_VERSION_ATLEAST(2, 0, 9) // rumble takes values in range 0 to 0xFFFF (65535) low_freq = MAX(MIN(low_freq, 1.0f), 0.0f) * 65535; high_freq = MAX(MIN(high_freq, 1.0f), 0.0f) * 65535; @@ -376,9 +375,6 @@ controller_rumble(pgControllerObject *self, PyObject *args, PyObject *kwargs) (Uint16)high_freq, duration); return PyBool_FromLong(success == 0); -#else - Py_RETURN_FALSE; -#endif } static PyObject * @@ -388,9 +384,7 @@ controller_stop_rumble(pgControllerObject *self, PyObject *_null) if (!self->controller) { return RAISE(pgExc_SDLError, "Controller is not initalized"); } -#if SDL_VERSION_ATLEAST(2, 0, 9) SDL_GameControllerRumble(self->controller, 0, 0, 1); -#endif Py_RETURN_NONE; } diff --git a/src_c/constants.c b/src_c/constants.c index f9eb244007..771aefca5a 100644 --- a/src_c/constants.c +++ b/src_c/constants.c @@ -317,19 +317,11 @@ MODINIT_DEFINE(constants) DEC_CONST(CONTROLLERDEVICEADDED); DEC_CONST(CONTROLLERDEVICEREMOVED); DEC_CONST(CONTROLLERDEVICEREMAPPED); -#if SDL_VERSION_ATLEAST(2, 0, 14) DEC_CONST(CONTROLLERTOUCHPADDOWN); DEC_CONST(CONTROLLERTOUCHPADMOTION); DEC_CONST(CONTROLLERTOUCHPADUP); DEC_CONST(CONTROLLERSENSORUPDATE); DEC_CONST(LOCALECHANGED); -#else - DEC_CONSTS(CONTROLLERTOUCHPADDOWN, -1); - DEC_CONSTS(CONTROLLERTOUCHPADMOTION, -1); - DEC_CONSTS(CONTROLLERTOUCHPADUP, -1); - DEC_CONSTS(CONTROLLERSENSORUPDATE, -1); - DEC_CONSTS(LOCALECHANGED, -1); -#endif DEC_CONST(JOYDEVICEADDED); DEC_CONST(JOYDEVICEREMOVED); diff --git a/src_c/display.c b/src_c/display.c index af7e268cbc..3ff35d4fa0 100644 --- a/src_c/display.c +++ b/src_c/display.c @@ -688,7 +688,7 @@ pg_ResizeEventWatch(void *userdata, SDL_Event *event) int h = event->window.data2; pgSurfaceObject *display_surface = pg_GetDefaultWindowSurface(); SDL_Surface *surf = - PG_CreateSurface(w, h, PG_PIXELFORMAT_XRGB8888); + PG_CreateSurface(w, h, SDL_PIXELFORMAT_XRGB8888); SDL_FreeSurface(display_surface->surf); display_surface->surf = surf; @@ -1156,7 +1156,7 @@ pg_set_mode(PyObject *self, PyObject *arg, PyObject *kwds) So we make a fake surface. */ - surf = PG_CreateSurface(w, h, PG_PIXELFORMAT_XRGB8888); + surf = PG_CreateSurface(w, h, SDL_PIXELFORMAT_XRGB8888); newownedsurf = surf; } else { @@ -1265,7 +1265,7 @@ pg_set_mode(PyObject *self, PyObject *arg, PyObject *kwds) pg_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h); } - surf = PG_CreateSurface(w, h, PG_PIXELFORMAT_XRGB8888); + surf = PG_CreateSurface(w, h, SDL_PIXELFORMAT_XRGB8888); newownedsurf = surf; } else { @@ -1571,7 +1571,7 @@ pg_list_modes(PyObject *self, PyObject *args, PyObject *kwds) } /* use reasonable defaults (cf. SDL_video.c) */ if (!mode.format) - mode.format = PG_PIXELFORMAT_XRGB8888; + mode.format = SDL_PIXELFORMAT_XRGB8888; if (!mode.w) mode.w = 640; if (!mode.h) @@ -2803,9 +2803,7 @@ pg_message_box(PyObject *self, PyObject *arg, PyObject *kwargs) return NULL; } -#if SDL_VERSION_ATLEAST(2, 0, 12) msgbox_data.flags |= SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT; -#endif if (parent_window == Py_None) { msgbox_data.window = NULL; @@ -2896,12 +2894,7 @@ pg_message_box(PyObject *self, PyObject *arg, PyObject *kwargs) buttons_data = malloc(sizeof(SDL_MessageBoxButtonData) * num_buttons); for (Py_ssize_t i = 0; i < num_buttons; i++) { -#if SDL_VERSION_ATLEAST(2, 0, 12) PyObject *btn_name_obj = PySequence_GetItem(buttons, i); -#else - PyObject *btn_name_obj = - PySequence_GetItem(buttons, num_buttons - i - 1); -#endif if (!btn_name_obj) goto error; @@ -2916,11 +2909,7 @@ pg_message_box(PyObject *self, PyObject *arg, PyObject *kwargs) goto error; buttons_data[i].text = btn_name; -#if SDL_VERSION_ATLEAST(2, 0, 12) buttons_data[i].buttonid = (int)i; -#else - buttons_data[i].buttonid = (int)(num_buttons - i - 1); -#endif buttons_data[i].flags = 0; if (return_button_index == buttons_data[i].buttonid) buttons_data[i].flags |= diff --git a/src_c/event.c b/src_c/event.c index 59132e3330..4af65354f7 100644 --- a/src_c/event.c +++ b/src_c/event.c @@ -342,12 +342,10 @@ _pg_pgevent_proxify_helper(Uint32 type, Uint8 proxify) _PG_HANDLE_PROXIFY(CONTROLLERDEVICEADDED); _PG_HANDLE_PROXIFY(CONTROLLERDEVICEREMOVED); _PG_HANDLE_PROXIFY(CONTROLLERDEVICEREMAPPED); -#if SDL_VERSION_ATLEAST(2, 0, 14) _PG_HANDLE_PROXIFY(CONTROLLERTOUCHPADDOWN); _PG_HANDLE_PROXIFY(CONTROLLERTOUCHPADMOTION); _PG_HANDLE_PROXIFY(CONTROLLERTOUCHPADUP); _PG_HANDLE_PROXIFY(CONTROLLERSENSORUPDATE); -#endif _PG_HANDLE_PROXIFY(DOLLARGESTURE); _PG_HANDLE_PROXIFY(DOLLARRECORD); _PG_HANDLE_PROXIFY(DROPFILE); @@ -367,9 +365,7 @@ _pg_pgevent_proxify_helper(Uint32 type, Uint8 proxify) _PG_HANDLE_PROXIFY(JOYBUTTONUP); _PG_HANDLE_PROXIFY(JOYDEVICEADDED); _PG_HANDLE_PROXIFY(JOYDEVICEREMOVED); -#if SDL_VERSION_ATLEAST(2, 0, 14) _PG_HANDLE_PROXIFY(LOCALECHANGED); -#endif _PG_HANDLE_PROXIFY(MOUSEMOTION); _PG_HANDLE_PROXIFY(MOUSEBUTTONDOWN); _PG_HANDLE_PROXIFY(MOUSEBUTTONUP); @@ -756,10 +752,8 @@ _pg_name_from_eventtype(int type) return "KeyUp"; case SDL_KEYMAPCHANGED: return "KeyMapChanged"; -#if SDL_VERSION_ATLEAST(2, 0, 14) case SDL_LOCALECHANGED: return "LocaleChanged"; -#endif case SDL_MOUSEMOTION: return "MouseMotion"; case SDL_MOUSEBUTTONDOWN: @@ -828,7 +822,6 @@ _pg_name_from_eventtype(int type) return "JoyDeviceAdded"; case SDL_JOYDEVICEREMOVED: return "JoyDeviceRemoved"; -#if SDL_VERSION_ATLEAST(2, 0, 14) case SDL_CONTROLLERTOUCHPADDOWN: return "ControllerTouchpadDown"; case SDL_CONTROLLERTOUCHPADMOTION: @@ -837,7 +830,6 @@ _pg_name_from_eventtype(int type) return "ControllerTouchpadUp"; case SDL_CONTROLLERSENSORUPDATE: return "ControllerSensorUpdate"; -#endif /*SDL_VERSION_ATLEAST(2, 0, 14)*/ case SDL_AUDIODEVICEADDED: return "AudioDeviceAdded"; case SDL_AUDIODEVICEREMOVED: @@ -1215,7 +1207,6 @@ dict_from_event(SDL_Event *event) _pg_insobj(dict, "instance_id", PyLong_FromLong(event->jdevice.which)); break; -#if SDL_VERSION_ATLEAST(2, 0, 14) case SDL_CONTROLLERTOUCHPADDOWN: case SDL_CONTROLLERTOUCHPADMOTION: case SDL_CONTROLLERTOUCHPADUP: @@ -1230,7 +1221,6 @@ dict_from_event(SDL_Event *event) _pg_insobj(dict, "pressure", PyFloat_FromDouble(event->ctouchpad.pressure)); break; -#endif /*SDL_VERSION_ATLEAST(2, 0, 14)*/ #ifdef WIN32 case SDL_SYSWMEVENT: @@ -1318,14 +1308,12 @@ dict_from_event(SDL_Event *event) window = SDL_GetWindowFromID(event->button.windowID); break; } -#if SDL_VERSION_ATLEAST(2, 0, 14) case SDL_FINGERMOTION: case SDL_FINGERDOWN: case SDL_FINGERUP: { window = SDL_GetWindowFromID(event->tfinger.windowID); break; } -#endif default: { return dict; } diff --git a/src_c/font.c b/src_c/font.c index cae985f1cc..8530bcd3e1 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -612,7 +612,7 @@ font_render(PyObject *self, PyObject *args, PyObject *kwds) if (strlen(astring) == 0) { /* special 0 string case */ int height = TTF_FontHeight(font); - surf = PG_CreateSurface(0, height, PG_PIXELFORMAT_XRGB8888); + surf = PG_CreateSurface(0, height, SDL_PIXELFORMAT_XRGB8888); } else { /* normal case */ if (antialias && bg_rgba_obj == Py_None) { diff --git a/src_c/include/pgcompat.h b/src_c/include/pgcompat.h index 7c89877d78..aa7a2e37e1 100644 --- a/src_c/include/pgcompat.h +++ b/src_c/include/pgcompat.h @@ -27,29 +27,13 @@ typedef uint8_t Uint8; * warning without this check here, which is very weird. */ #ifdef SDL_VERSION_ATLEAST -// SDL_PIXELFORMAT_XRGB8888 and SDL_PIXELFORMAT_XBGR8888 are new names -// in SDL 2.0.14, the macros below let us use the new (less confusing) -// naming while still building on old versions. - -#if SDL_VERSION_ATLEAST(2, 0, 14) -#define PG_PIXELFORMAT_XRGB8888 SDL_PIXELFORMAT_XRGB8888 -#else -#define PG_PIXELFORMAT_XRGB8888 SDL_PIXELFORMAT_RGB888 -#endif - -#if SDL_VERSION_ATLEAST(2, 0, 14) -#define PG_PIXELFORMAT_XBGR8888 SDL_PIXELFORMAT_XBGR8888 -#else -#define PG_PIXELFORMAT_XBGR8888 SDL_PIXELFORMAT_BGR888 -#endif - // SDL does not provide endian independent names for 32 bit formats without // alpha channels the way they do for ones with alpha channels. // E.g. SDL_PIXELFORMAT_RGBA32. This macro allows us the convenience of the // endian independent name. #if SDL_BYTEORDER == SDL_LIL_ENDIAN -#define PG_PIXELFORMAT_RGBX32 PG_PIXELFORMAT_XBGR8888 +#define PG_PIXELFORMAT_RGBX32 SDL_PIXELFORMAT_XBGR8888 #else #define PG_PIXELFORMAT_RGBX32 SDL_PIXELFORMAT_RGBX8888 #endif diff --git a/src_c/pixelcopy.c b/src_c/pixelcopy.c index 751ed25124..a964b9f373 100644 --- a/src_c/pixelcopy.c +++ b/src_c/pixelcopy.c @@ -1160,7 +1160,7 @@ make_surface(PyObject *self, PyObject *arg) pixelformat = SDL_PIXELFORMAT_INDEX8; } else { - pixelformat = PG_PIXELFORMAT_XRGB8888; + pixelformat = SDL_PIXELFORMAT_XRGB8888; } sizex = (int)view_p->shape[0]; sizey = (int)view_p->shape[1]; diff --git a/src_c/surface.c b/src_c/surface.c index d4a8eae2e9..1850ebc19f 100644 --- a/src_c/surface.c +++ b/src_c/surface.c @@ -1612,7 +1612,7 @@ pg_DisplayFormatAlpha(SDL_Surface *surface) #endif case SDL_PIXELFORMAT_ABGR1555: case SDL_PIXELFORMAT_BGR565: - case PG_PIXELFORMAT_XBGR8888: + case SDL_PIXELFORMAT_XBGR8888: case SDL_PIXELFORMAT_ABGR8888: pfe = SDL_PIXELFORMAT_ABGR8888; break; diff --git a/src_c/system.c b/src_c/system.c index 8794a95993..4e7c21162a 100644 --- a/src_c/system.c +++ b/src_c/system.c @@ -35,12 +35,7 @@ pg_system_get_cpu_instruction_sets(PyObject *self, PyObject *_null) INSERT_INSTRUCTIONSET_INFO("AVX2", SDL_HasAVX2); INSERT_INSTRUCTIONSET_INFO("AVX512F", SDL_HasAVX512F); INSERT_INSTRUCTIONSET_INFO("NEON", SDL_HasNEON); -#if SDL_VERSION_ATLEAST(2, 0, 12) INSERT_INSTRUCTIONSET_INFO("ARMSIMD", SDL_HasARMSIMD); -#else - if (PyDict_SetItemString(instruction_sets, "ARMSIMD", Py_False)) - goto error; -#endif #if SDL_VERSION_ATLEAST(2, 24, 0) INSERT_INSTRUCTIONSET_INFO("LSX", SDL_HasLSX); INSERT_INSTRUCTIONSET_INFO("LASX", SDL_HasLASX); @@ -113,7 +108,7 @@ pg_system_get_pref_locales(PyObject *self, PyObject *_null) * information */ return ret_list; } -#elif SDL_VERSION_ATLEAST(2, 0, 14) +#else SDL_Locale *locales = SDL_GetPreferredLocales(); if (!locales) { /* Return an empty list if SDL function does not return any useful @@ -131,7 +126,6 @@ pg_system_get_pref_locales(PyObject *self, PyObject *_null) } #endif -#if SDL_VERSION_ATLEAST(2, 0, 14) for (int i = 0; i < num_locales; i++) { dict = PyDict_New(); if (!dict) { @@ -183,9 +177,6 @@ pg_system_get_pref_locales(PyObject *self, PyObject *_null) SDL_free(locales); Py_DECREF(ret_list); return NULL; -#else - return ret_list; -#endif } static PyObject *PowerState_class = NULL;