diff --git a/src_c/meson.build b/src_c/meson.build index d56d6b014d..077b5512d9 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -249,8 +249,6 @@ bufferproxy = py.extension_module( subdir: pg, ) -# TODO: support SDL3 -if sdl_api != 3 pixelarray = py.extension_module( 'pixelarray', 'pixelarray.c', @@ -259,7 +257,6 @@ pixelarray = py.extension_module( install: true, subdir: pg, ) -endif math = py.extension_module( 'math', diff --git a/src_c/pixelarray.c b/src_c/pixelarray.c index f13c604553..1486031de6 100644 --- a/src_c/pixelarray.c +++ b/src_c/pixelarray.c @@ -23,6 +23,7 @@ #include "pygame.h" #include "pgcompat.h" +#include #include "doc/pixelarray_doc.h" @@ -971,6 +972,13 @@ _array_assign_array(pgPixelArrayObject *array, Py_ssize_t low, Py_ssize_t high, return -1; } + PG_PixelFormat *surf_format = PG_GetSurfaceFormat(surf); + PG_PixelFormat *val_surf_format = PG_GetSurfaceFormat(val_surf); + if (surf_format == NULL || val_surf_format == NULL) { + PyErr_SetString(pgExc_SDLError, SDL_GetError()); + return -1; + } + /* If we reassign the same array, we need to copy the pixels * first. */ if (SURFACE_EQUALS(array, val)) { @@ -1021,20 +1029,23 @@ _array_assign_array(pgPixelArrayObject *array, Py_ssize_t low, Py_ssize_t high, } break; case 3: { +// Note: +// Why is the 24 bit case pixelformat aware but none of the rest are? +// - Starbuck, jan. 2025 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN) - Uint32 Roffset = surf->format->Rshift >> 3; - Uint32 Goffset = surf->format->Gshift >> 3; - Uint32 Boffset = surf->format->Bshift >> 3; - Uint32 vRoffset = val_surf->format->Rshift >> 3; - Uint32 vGoffset = val_surf->format->Gshift >> 3; - Uint32 vBoffset = val_surf->format->Bshift >> 3; + Uint32 Roffset = surf_format->Rshift >> 3; + Uint32 Goffset = surf_format->Gshift >> 3; + Uint32 Boffset = surf_format->Bshift >> 3; + Uint32 vRoffset = val_surf_format->Rshift >> 3; + Uint32 vGoffset = val_surf_format->Gshift >> 3; + Uint32 vBoffset = val_surf_format->Bshift >> 3; #else - Uint32 Roffset = 2 - (surf->format->Rshift >> 3); - Uint32 Goffset = 2 - (surf->format->Gshift >> 3); - Uint32 Boffset = 2 - (surf->format->Bshift >> 3); - Uint32 vRoffset = 2 - (val_surf->format->Rshift >> 3); - Uint32 vGoffset = 2 - (val_surf->format->Gshift >> 3); - Uint32 vBoffset = 2 - (val_surf->format->Bshift >> 3); + Uint32 Roffset = 2 - (surf_format->Rshift >> 3); + Uint32 Goffset = 2 - (surf_format->Gshift >> 3); + Uint32 Boffset = 2 - (surf_format->Bshift >> 3); + Uint32 vRoffset = 2 - (val_surf_format->Rshift >> 3); + Uint32 vGoffset = 2 - (val_surf_format->Gshift >> 3); + Uint32 vBoffset = 2 - (val_surf_format->Bshift >> 3); #endif for (y = 0; y < dim1; ++y) { pixel_p = pixelrow; @@ -1076,7 +1087,6 @@ _array_assign_sequence(pgPixelArrayObject *array, Py_ssize_t low, Py_ssize_t high, PyObject *val) { SDL_Surface *surf = pgSurface_AsSurface(array->surface); - SDL_PixelFormat *format; Py_ssize_t dim0 = ABS(high - low); Py_ssize_t dim1 = array->shape[1]; Py_ssize_t stride0 = high >= low ? array->strides[0] : -array->strides[0]; @@ -1097,8 +1107,13 @@ _array_assign_sequence(pgPixelArrayObject *array, Py_ssize_t low, return -1; } - format = surf->format; - bpp = PG_FORMAT_BytesPerPixel(format); + PG_PixelFormat *surf_format = PG_GetSurfaceFormat(surf); + if (surf_format == NULL) { + PyErr_SetString(pgExc_SDLError, SDL_GetError()); + return -1; + } + + bpp = PG_FORMAT_BytesPerPixel(surf_format); if (!dim1) { dim1 = 1; @@ -1150,13 +1165,13 @@ _array_assign_sequence(pgPixelArrayObject *array, Py_ssize_t low, break; case 3: { #if (SDL_BYTEORDER == SDL_LIL_ENDIAN) - Uint32 Roffset = surf->format->Rshift >> 3; - Uint32 Goffset = surf->format->Gshift >> 3; - Uint32 Boffset = surf->format->Bshift >> 3; + Uint32 Roffset = surf_format->Rshift >> 3; + Uint32 Goffset = surf_format->Gshift >> 3; + Uint32 Boffset = surf_format->Bshift >> 3; #else - Uint32 Roffset = 2 - (surf->format->Rshift >> 3); - Uint32 Goffset = 2 - (surf->format->Gshift >> 3); - Uint32 Boffset = 2 - (surf->format->Bshift >> 3); + Uint32 Roffset = 2 - (surf_format->Rshift >> 3); + Uint32 Goffset = 2 - (surf_format->Gshift >> 3); + Uint32 Boffset = 2 - (surf_format->Bshift >> 3); #endif for (y = 0; y < dim1; ++y) { pixel_p = pixelrow; @@ -1206,7 +1221,13 @@ _array_assign_slice(pgPixelArrayObject *array, Py_ssize_t low, Py_ssize_t high, Py_ssize_t x; Py_ssize_t y; - bpp = PG_SURF_BytesPerPixel(surf); + PG_PixelFormat *surf_format = PG_GetSurfaceFormat(surf); + if (surf_format == NULL) { + PyErr_SetString(pgExc_SDLError, SDL_GetError()); + return -1; + } + + bpp = PG_FORMAT_BytesPerPixel(surf_format); if (!dim1) { dim1 = 1; @@ -1241,13 +1262,13 @@ _array_assign_slice(pgPixelArrayObject *array, Py_ssize_t low, Py_ssize_t high, } break; case 3: { #if (SDL_BYTEORDER == SDL_LIL_ENDIAN) - Uint32 Roffset = surf->format->Rshift >> 3; - Uint32 Goffset = surf->format->Gshift >> 3; - Uint32 Boffset = surf->format->Bshift >> 3; + Uint32 Roffset = surf_format->Rshift >> 3; + Uint32 Goffset = surf_format->Gshift >> 3; + Uint32 Boffset = surf_format->Bshift >> 3; #else - Uint32 Roffset = 2 - (surf->format->Rshift >> 3); - Uint32 Goffset = 2 - (surf->format->Gshift >> 3); - Uint32 Boffset = 2 - (surf->format->Bshift >> 3); + Uint32 Roffset = 2 - (surf_format->Rshift >> 3); + Uint32 Goffset = 2 - (surf_format->Gshift >> 3); + Uint32 Boffset = 2 - (surf_format->Bshift >> 3); #endif Uint8 r = (Uint8)(color >> 16); Uint8 g = (Uint8)(color >> 8); @@ -1352,6 +1373,12 @@ _pxarray_ass_item(pgPixelArrayObject *array, Py_ssize_t index, PyObject *value) dim1 = 1; } + PG_PixelFormat *surf_format = PG_GetSurfaceFormat(surf); + if (surf_format == NULL) { + PyErr_SetString(pgExc_SDLError, SDL_GetError()); + return -1; + } + Py_BEGIN_ALLOW_THREADS; /* Single value assignment. */ switch (bpp) { @@ -1369,13 +1396,13 @@ _pxarray_ass_item(pgPixelArrayObject *array, Py_ssize_t index, PyObject *value) break; case 3: { #if (SDL_BYTEORDER == SDL_LIL_ENDIAN) - Uint32 Roffset = surf->format->Rshift >> 3; - Uint32 Goffset = surf->format->Gshift >> 3; - Uint32 Boffset = surf->format->Bshift >> 3; + Uint32 Roffset = surf_format->Rshift >> 3; + Uint32 Goffset = surf_format->Gshift >> 3; + Uint32 Boffset = surf_format->Bshift >> 3; #else - Uint32 Roffset = 2 - (surf->format->Rshift >> 3); - Uint32 Goffset = 2 - (surf->format->Gshift >> 3); - Uint32 Boffset = 2 - (surf->format->Bshift >> 3); + Uint32 Roffset = 2 - (surf_format->Rshift >> 3); + Uint32 Goffset = 2 - (surf_format->Gshift >> 3); + Uint32 Boffset = 2 - (surf_format->Bshift >> 3); #endif for (y = 0; y < dim1; ++y) { pixel_p[Roffset] = (Uint8)(color >> 16); diff --git a/src_c/pixelarray_methods.c b/src_c/pixelarray_methods.c index a11be9ab71..97725c5f38 100644 --- a/src_c/pixelarray_methods.c +++ b/src_c/pixelarray_methods.c @@ -28,6 +28,18 @@ wb * (b1 - b2) * (b1 - b2)) / \ 255.0) +#define PXM_GET_PIXELVALS(_sR, _sG, _sB, _sA, px, fmt, palette, ppa) \ + PG_GetRGBA(px, fmt, palette, &(_sR), &(_sG), &(_sB), &(_sA)); \ + if (!ppa) { \ + _sA = 255; \ + } + +#define PXM_GET_PIXELVALS_1(sr, sg, sb, sa, _src, _palette) \ + sr = _palette->colors[*((Uint8 *)(_src))].r; \ + sg = _palette->colors[*((Uint8 *)(_src))].g; \ + sb = _palette->colors[*((Uint8 *)(_src))].b; \ + sa = 255; + #define WR_NTSC 0.299 #define WG_NTSC 0.587 #define WB_NTSC 0.114 @@ -339,7 +351,6 @@ _replace_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) PyObject *delcolor = 0; PyObject *replcolor = 0; SDL_Surface *surf; - SDL_PixelFormat *format; Py_ssize_t dim0 = array->shape[0]; Py_ssize_t dim1 = array->shape[1]; Py_ssize_t stride0 = array->strides[0]; @@ -372,8 +383,13 @@ _replace_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) "distance must be in the range from 0.0 to 1.0"); } - format = surf->format; - bpp = PG_SURF_BytesPerPixel(surf); + PG_PixelFormat *format; + SDL_Palette *palette; + if (!PG_GetSurfaceDetails(surf, &format, &palette)) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + + bpp = PG_FORMAT_BytesPerPixel(format); if (!_get_color_from_object(delcolor, surf, &dcolor) || !_get_color_from_object(replcolor, surf, &rcolor)) { @@ -385,7 +401,7 @@ _replace_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) } if (distance != 0.0) { - SDL_GetRGB(dcolor, format, &r1, &g1, &b1); + PG_GetRGB(dcolor, format, palette, &r1, &g1, &b1); } if (!dim1) { @@ -403,7 +419,7 @@ _replace_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) for (x = 0; x < dim0; ++x) { px_p = pixel_p; if (distance != 0.0) { - GET_PIXELVALS_1(r2, g2, b2, a2, px_p, format); + PXM_GET_PIXELVALS_1(r2, g2, b2, a2, px_p, palette); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { *px_p = (Uint8)rcolor; @@ -427,8 +443,8 @@ _replace_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) for (x = 0; x < dim0; ++x) { px_p = (Uint16 *)pixel_p; if (distance != 0.0) { - GET_PIXELVALS(r2, g2, b2, a2, (Uint32)*px_p, format, - ppa); + PXM_GET_PIXELVALS(r2, g2, b2, a2, (Uint32)*px_p, + format, palette, ppa); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { *px_p = (Uint16)rcolor; @@ -463,7 +479,8 @@ _replace_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) ((Uint32)pixel_p[Goffset] << 8) + ((Uint32)pixel_p[Boffset])); if (distance != 0.0) { - GET_PIXELVALS(r2, g2, b2, a2, pxcolor, format, ppa); + PXM_GET_PIXELVALS(r2, g2, b2, a2, pxcolor, format, + palette, ppa); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { pixel_p[Roffset] = (Uint8)(rcolor >> 16); @@ -484,15 +501,16 @@ _replace_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) default: /* case 4: */ { Uint32 *px_p; - int ppa = (SDL_ISPIXELFORMAT_ALPHA(format->format) && - surf->format->Amask); + int ppa = + (SDL_ISPIXELFORMAT_ALPHA(format->format) && format->Amask); for (y = 0; y < dim1; ++y) { pixel_p = pixelrow; for (x = 0; x < dim0; ++x) { px_p = (Uint32 *)pixel_p; if (distance != 0.0) { - GET_PIXELVALS(r2, g2, b2, a2, *px_p, format, ppa); + PXM_GET_PIXELVALS(r2, g2, b2, a2, *px_p, format, + palette, ppa); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { *px_p = rcolor; @@ -530,7 +548,6 @@ _extract_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) Py_ssize_t y; PyObject *surface; SDL_Surface *surf; - SDL_PixelFormat *format; pgPixelArrayObject *new_array; Py_ssize_t dim0; Py_ssize_t dim1; @@ -570,16 +587,23 @@ _extract_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) } surf = pgSurface_AsSurface(surface); - format = surf->format; - bpp = PG_SURF_BytesPerPixel(surf); + + PG_PixelFormat *format; + SDL_Palette *palette; + if (!PG_GetSurfaceDetails(surf, &format, &palette)) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + + bpp = PG_FORMAT_BytesPerPixel(format); + dim0 = new_array->shape[0]; dim1 = new_array->shape[1]; stride0 = new_array->strides[0]; stride1 = new_array->strides[1]; pixels = new_array->pixels; - black = SDL_MapRGBA(format, 0, 0, 0, 255); - white = SDL_MapRGBA(format, 255, 255, 255, 255); + black = PG_MapRGBA(format, palette, 0, 0, 0, 255); + white = PG_MapRGBA(format, palette, 255, 255, 255, 255); if (!_get_color_from_object(excolor, surf, &color)) { Py_DECREF(new_array); @@ -587,7 +611,7 @@ _extract_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) } if (distance != 0.0) { - SDL_GetRGB(color, format, &r1, &g1, &b1); + PG_GetRGB(color, format, palette, &r1, &g1, &b1); } if (!dim1) { @@ -605,7 +629,7 @@ _extract_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) for (x = 0; x < dim0; ++x) { px_p = pixel_p; if (distance != 0.0) { - GET_PIXELVALS_1(r2, g2, b2, a2, px_p, format); + PXM_GET_PIXELVALS_1(r2, g2, b2, a2, px_p, palette); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { *px_p = (Uint8)white; @@ -632,8 +656,8 @@ _extract_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) for (x = 0; x < dim0; ++x) { px_p = (Uint16 *)pixel_p; if (distance != 0.0) { - GET_PIXELVALS(r2, g2, b2, a2, (Uint32)*px_p, format, - ppa); + PXM_GET_PIXELVALS(r2, g2, b2, a2, (Uint32)*px_p, + format, palette, ppa); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { *px_p = (Uint16)white; @@ -677,7 +701,8 @@ _extract_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) ((Uint32)pixel_p[Goffset] << 8) + ((Uint32)pixel_p[Boffset])); if (distance != 0.0) { - GET_PIXELVALS(r2, g2, b2, a2, pxcolor, format, ppa); + PXM_GET_PIXELVALS(r2, g2, b2, a2, pxcolor, format, + palette, ppa); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { pixel_p[Roffset] = white_r; @@ -716,7 +741,8 @@ _extract_color(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) for (x = 0; x < dim0; ++x) { px_p = (Uint32 *)pixel_p; if (distance != 0.0) { - GET_PIXELVALS(r2, g2, b2, a2, *px_p, format, ppa); + PXM_GET_PIXELVALS(r2, g2, b2, a2, *px_p, format, + palette, ppa); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { *px_p = white; @@ -745,11 +771,9 @@ _compare(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) Py_ssize_t dim0 = array->shape[0]; Py_ssize_t dim1 = array->shape[1]; SDL_Surface *surf; - SDL_PixelFormat *format; pgPixelArrayObject *other_array; PyObject *weights = 0; SDL_Surface *other_surf; - SDL_PixelFormat *other_format; Py_ssize_t other_stride0; Py_ssize_t other_stride1; Uint8 *other_pixels; @@ -767,7 +791,6 @@ _compare(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) Py_ssize_t y; pgPixelArrayObject *new_array; PyObject *new_surface; - SDL_PixelFormat *new_format; Py_ssize_t stride0; Py_ssize_t stride1; Uint8 *pixels; @@ -800,10 +823,18 @@ _compare(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) return 0; } - format = surf->format; - bpp = PG_SURF_BytesPerPixel(surf); other_surf = pgSurface_AsSurface(other_array->surface); - other_format = other_surf->format; + + PG_PixelFormat *format, *other_format; + SDL_Palette *palette, *other_palette; + if (!PG_GetSurfaceDetails(surf, &format, &palette)) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + if (!PG_GetSurfaceDetails(other_surf, &other_format, &other_palette)) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + + bpp = PG_SURF_BytesPerPixel(surf); if (PG_FORMAT_BytesPerPixel(other_format) != bpp) { /* bpp do not match. We cannot guarantee that the padding and co @@ -828,13 +859,12 @@ _compare(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) return 0; } - new_format = surf->format; stride0 = new_array->strides[0]; stride1 = new_array->strides[1]; pixels = new_array->pixels; - black = SDL_MapRGBA(format, 0, 0, 0, 255); - white = SDL_MapRGBA(format, 255, 255, 255, 255); + black = PG_MapRGBA(format, palette, 0, 0, 0, 255); + white = PG_MapRGBA(format, palette, 255, 255, 255, 255); Py_BEGIN_ALLOW_THREADS; if (!dim1) { @@ -855,9 +885,9 @@ _compare(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) pixel_p = byte_p; other_pixel_p = other_byte_p; if (distance != 0.0) { - GET_PIXELVALS_1(r1, g1, b1, a1, pixel_p, new_format); - GET_PIXELVALS_1(r2, g2, b2, a2, other_pixel_p, - other_format); + PXM_GET_PIXELVALS_1(r1, g1, b1, a1, pixel_p, palette); + PXM_GET_PIXELVALS_1(r2, g2, b2, a2, other_pixel_p, + other_palette); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { *pixel_p = (Uint8)white; @@ -892,10 +922,11 @@ _compare(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) pixel_p = (Uint16 *)byte_p; other_pixel_p = (Uint16 *)other_byte_p; if (distance != 0.0) { - GET_PIXELVALS(r1, g1, b1, a1, (Uint32)*pixel_p, format, - ppa); - GET_PIXELVALS(r2, g2, b2, a2, (Uint32)*other_pixel_p, - other_format, other_ppa); + PXM_GET_PIXELVALS(r1, g1, b1, a1, (Uint32)*pixel_p, + format, palette, ppa); + PXM_GET_PIXELVALS(r2, g2, b2, a2, + (Uint32)*other_pixel_p, other_format, + other_palette, other_ppa); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { *pixel_p = (Uint16)white; @@ -995,9 +1026,11 @@ _compare(pgPixelArrayObject *array, PyObject *args, PyObject *kwds) pixel_p = (Uint32 *)byte_p; other_pixel_p = (Uint32 *)other_byte_p; if (distance != 0.0) { - GET_PIXELVALS(r1, g1, b1, a1, *pixel_p, format, ppa); - GET_PIXELVALS(r2, g2, b2, a2, *other_pixel_p, - other_format, other_ppa); + PXM_GET_PIXELVALS(r1, g1, b1, a1, *pixel_p, format, + palette, ppa); + PXM_GET_PIXELVALS(r2, g2, b2, a2, *other_pixel_p, + other_format, other_palette, + other_ppa); if (COLOR_DIFF_RGB(wr, wg, wb, r1, g1, b1, r2, g2, b2) <= distance) { *pixel_p = white;