diff --git a/src_c/_pygame.h b/src_c/_pygame.h index 07f236149a..70fae7450a 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -26,6 +26,8 @@ #ifndef _PYGAME_INTERNAL_H #define _PYGAME_INTERNAL_H +#include + #include "pgplatform.h" /* If PY_SSIZE_T_CLEAN is defined before including Python.h, length is a @@ -78,6 +80,15 @@ #define PG_ConvertSurfaceFormat SDL_ConvertSurface #define PG_PixelFormatEnum SDL_PixelFormat +#define PG_PixelFormat const SDL_PixelFormatDetails +#define PG_PixelFormatMut SDL_PixelFormatDetails +#define PG_SurfaceFormatEnum(surf) (surf)->format +#define PG_GetSurfaceFormat(surf) \ + SDL_GetPixelFormatDetails(PG_SurfaceFormatEnum(surf)) +#define PG_GetSurfacePalette SDL_GetSurfacePalette +#define PG_SurfaceMapRGBA(surf, r, g, b, a) \ + SDL_MapSurfaceRGBA(surf, r, g, b, a) +#define PG_GetSurfaceClipRect SDL_GetSurfaceClipRect #define PG_SurfaceHasRLE SDL_SurfaceHasRLE @@ -100,6 +111,8 @@ PG_UnlockMutex(SDL_mutex *mutex) return 0; } +#define PG_FillRect SDL_FillSurfaceRect + #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 @@ -149,6 +162,17 @@ PG_UnlockMutex(SDL_mutex *mutex) SDL_ConvertSurfaceFormat(src, pixel_format, 0) #define PG_PixelFormatEnum SDL_PixelFormatEnum +#define PG_PixelFormat SDL_PixelFormat +#define PG_PixelFormatMut SDL_PixelFormat +#define PG_SurfaceFormatEnum(surf) (surf)->format->format +#define PG_GetSurfaceFormat(surf) (surf)->format +#define PG_GetSurfacePalette(surf) (surf)->format->palette +#define PG_SurfaceMapRGBA(surf, r, g, b, a) \ + SDL_MapRGBA(PG_GetSurfaceFormat(surf), r, g, b, a) +#define PG_GetSurfaceClipRect(surf, rect) \ + { \ + rect = &surf->clip_rect; \ + } #define PG_SoftStretchNearest(src, srcrect, dst, dstrect) \ SDL_SoftStretch(src, srcrect, dst, dstrect) @@ -165,6 +189,12 @@ PG_UnlockMutex(SDL_mutex *mutex) return SDL_UnlockMutex(mutex); } +static inline bool +PG_FillRect(SDL_Surface *dst, const SDL_Rect *rect, Uint32 color) +{ + return SDL_FillRect(dst, rect, color) != -1; +} + #define PG_SURF_BitsPerPixel(surf) surf->format->BitsPerPixel #define PG_SURF_BytesPerPixel(surf) surf->format->BytesPerPixel #define PG_FORMAT_BitsPerPixel(format) format->BitsPerPixel diff --git a/src_c/surface.c b/src_c/surface.c index d4a8eae2e9..e1cf2fff90 100644 --- a/src_c/surface.c +++ b/src_c/surface.c @@ -481,7 +481,7 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds) int bpp; Uint32 Rmask, Gmask, Bmask, Amask; SDL_Surface *surface; - SDL_PixelFormat default_format; + PG_PixelFormatMut default_format; char *kwids[] = {"size", "flags", "depth", "masks", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iOO", kwids, &size, &flags, @@ -507,8 +507,6 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds) return -1; } - default_format.palette = NULL; - surface_cleanup(self); if (depth && masks) { /* all info supplied, most errorchecking @@ -602,23 +600,30 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds) } } else { /* no depth or surface */ - SDL_PixelFormat *pix; - if (depth && pgSurface_Check(depth)) - pix = ((pgSurfaceObject *)depth)->surf->format; + PG_PixelFormatMut *pix; + if (depth && pgSurface_Check(depth)) { + /* For SDL3 PG_GetSurfaceFormat returns (const PG_PixelFormat *) + * and not (PG_PixelFormat *), but it's not an issue here, as in + * this case pix is not mutated. */ + pix = (PG_PixelFormatMut *)PG_GetSurfaceFormat( + ((pgSurfaceObject *)depth)->surf); + } else if (pg_GetDefaultWindowSurface()) - pix = pgSurface_AsSurface(pg_GetDefaultWindowSurface())->format; + pix = (PG_PixelFormatMut *)PG_GetSurfaceFormat( + pgSurface_AsSurface(pg_GetDefaultWindowSurface())); else { pix = &default_format; -#if SDL_VERSION_ATLEAST(3, 0, 0) - pix->bits_per_pixel = 32; -#else - pix->BitsPerPixel = 32; -#endif + PG_FORMAT_BitsPerPixel(pix) = 32; pix->Amask = 0; pix->Rmask = 0xFF0000; pix->Gmask = 0xFF00; pix->Bmask = 0xFF; } + + if (pix == NULL) { + RAISERETURN(pgExc_SDLError, SDL_GetError(), -1); + } + bpp = PG_FORMAT_BitsPerPixel(pix); if (flags & PGS_SRCALPHA) { @@ -682,14 +687,14 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds) */ if (Amask != 0) { SDL_FillRect(surface, NULL, - SDL_MapRGBA(surface->format, 0, 0, 0, 255)); + PG_SurfaceMapRGBA(surface, 0, 0, 0, 255)); } } - if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) { + if (SDL_ISPIXELFORMAT_INDEXED(PG_SurfaceFormatEnum(surface))) { /* Give the surface something other than an all white palette. * */ - if (SDL_SetPaletteColors(surface->format->palette, + if (SDL_SetPaletteColors(PG_GetSurfacePalette(surface), default_palette_colors, 0, default_palette_size - 1) != 0) { PyErr_SetString(pgExc_SDLError, SDL_GetError()); @@ -712,7 +717,7 @@ static PyObject * surf_get_at(PyObject *self, PyObject *position) { SDL_Surface *surf = pgSurface_AsSurface(self); - SDL_PixelFormat *format = NULL; + PG_PixelFormat *format = NULL; Uint8 *pixels = NULL; int x, y; Uint32 color; @@ -729,7 +734,10 @@ surf_get_at(PyObject *self, PyObject *position) if (x < 0 || x >= surf->w || y < 0 || y >= surf->h) return RAISE(PyExc_IndexError, "pixel index out of range"); - format = surf->format; + format = PG_GetSurfaceFormat(surf); + + if (format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); if (PG_FORMAT_BytesPerPixel(format) < 1 || PG_FORMAT_BytesPerPixel(format) > 4) @@ -743,11 +751,11 @@ surf_get_at(PyObject *self, PyObject *position) switch (PG_FORMAT_BytesPerPixel(format)) { case 1: color = (Uint32) * ((Uint8 *)pixels + y * surf->pitch + x); - SDL_GetRGB(color, format, rgba, rgba + 1, rgba + 2); + PG_SurfaceGetRGB(color, surf, rgba, rgba + 1, rgba + 2); break; case 2: color = (Uint32) * ((Uint16 *)(pixels + y * surf->pitch) + x); - SDL_GetRGBA(color, format, rgba, rgba + 1, rgba + 2, rgba + 3); + PG_SurfaceGetRGBA(color, surf, rgba, rgba + 1, rgba + 2, rgba + 3); break; case 3: pix = ((Uint8 *)(pixels + y * surf->pitch) + x * 3); @@ -756,12 +764,12 @@ surf_get_at(PyObject *self, PyObject *position) #else color = (pix[2]) + (pix[1] << 8) + (pix[0] << 16); #endif - SDL_GetRGB(color, format, rgba, rgba + 1, rgba + 2); + PG_SurfaceGetRGB(color, surf, rgba, rgba + 1, rgba + 2); break; default: /* case 4: */ assert(PG_FORMAT_BytesPerPixel(format) == 4); color = *((Uint32 *)(pixels + y * surf->pitch) + x); - SDL_GetRGBA(color, format, rgba, rgba + 1, rgba + 2, rgba + 3); + PG_SurfaceGetRGBA(color, surf, rgba, rgba + 1, rgba + 2, rgba + 3); break; } if (!pgSurface_Unlock((pgSurfaceObject *)self)) @@ -775,12 +783,13 @@ surf_set_at(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { SDL_Surface *surf = pgSurface_AsSurface(self); SURF_INIT_CHECK(surf) - SDL_PixelFormat *format = NULL; + PG_PixelFormat *format = NULL; Uint8 *pixels; int x, y; Uint32 color; PyObject *rgba_obj; Uint8 *byte_buf; + SDL_Rect *clip_rect; if (nargs != 2) { return PyErr_Format(PyExc_TypeError, @@ -795,13 +804,22 @@ surf_set_at(PyObject *self, PyObject *const *args, Py_ssize_t nargs) rgba_obj = args[1]; - format = surf->format; + format = PG_GetSurfaceFormat(surf); + + if (format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); + if (PG_FORMAT_BytesPerPixel(format) < 1 || PG_FORMAT_BytesPerPixel(format) > 4) return RAISE(PyExc_RuntimeError, "invalid color depth for surface"); - if (x < surf->clip_rect.x || x >= surf->clip_rect.x + surf->clip_rect.w || - y < surf->clip_rect.y || y >= surf->clip_rect.y + surf->clip_rect.h) { + PG_GetSurfaceClipRect(surf, clip_rect); + + if (clip_rect == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); + + if (x < clip_rect->x || x >= clip_rect->x + clip_rect->w || + y < clip_rect->y || y >= clip_rect->y + clip_rect->h) { /* out of clip area */ Py_RETURN_NONE; } @@ -854,7 +872,7 @@ static PyObject * surf_get_at_mapped(PyObject *self, PyObject *position) { SDL_Surface *surf = pgSurface_AsSurface(self); - SDL_PixelFormat *format = NULL; + PG_PixelFormat *format = NULL; Uint8 *pixels = NULL; int x, y; Sint32 color; @@ -870,7 +888,10 @@ surf_get_at_mapped(PyObject *self, PyObject *position) if (x < 0 || x >= surf->w || y < 0 || y >= surf->h) return RAISE(PyExc_IndexError, "pixel index out of range"); - format = surf->format; + format = PG_GetSurfaceFormat(surf); + + if (format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); if (PG_FORMAT_BytesPerPixel(format) < 1 || PG_FORMAT_BytesPerPixel(format) > 4) @@ -918,7 +939,7 @@ surf_map_rgb(PyObject *self, PyObject *args) SURF_INIT_CHECK(surf) - color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]); + color = PG_SurfaceMapRGBA(surf, rgba[0], rgba[1], rgba[2], rgba[3]); return PyLong_FromLong(color); } @@ -936,10 +957,10 @@ surf_unmap_rgb(PyObject *self, PyObject *arg) } SURF_INIT_CHECK(surf) - if (SDL_ISPIXELFORMAT_ALPHA(surf->format->format)) - SDL_GetRGBA(col, surf->format, rgba, rgba + 1, rgba + 2, rgba + 3); + if (SDL_ISPIXELFORMAT_ALPHA(PG_SurfaceFormatEnum(surf))) + PG_SurfaceGetRGBA(col, surf, rgba, rgba + 1, rgba + 2, rgba + 3); else { - SDL_GetRGB(col, surf->format, rgba, rgba + 1, rgba + 2); + PG_SurfaceGetRGB(col, surf, rgba, rgba + 1, rgba + 2); rgba[3] = 255; } @@ -1029,7 +1050,7 @@ surf_get_palette(PyObject *self, PyObject *_null) SURF_INIT_CHECK(surf) - pal = surf->format->palette; + pal = PG_GetSurfacePalette(surf); if (!pal) return RAISE(pgExc_SDLError, "Surface has no palette to get\n"); @@ -1068,7 +1089,7 @@ surf_get_palette_at(PyObject *self, PyObject *args) return NULL; SURF_INIT_CHECK(surf) - pal = surf->format->palette; + pal = PG_GetSurfacePalette(surf); if (!pal) return RAISE(pgExc_SDLError, "Surface has no palette to set\n"); @@ -1107,9 +1128,9 @@ surf_set_palette(PyObject *self, PyObject *seq) if (!PySequence_Check(seq)) return RAISE(PyExc_ValueError, "Argument must be a sequence type"); - pal = surf->format->palette; + pal = PG_GetSurfacePalette(surf); - if (!SDL_ISPIXELFORMAT_INDEXED(surf->format->format)) + if (!SDL_ISPIXELFORMAT_INDEXED(PG_SurfaceFormatEnum(surf))) return RAISE(pgExc_SDLError, "Surface colors are not indexed\n"); if (!pal) @@ -1164,10 +1185,10 @@ surf_set_palette_at(PyObject *self, PyObject *args) return NULL; } - if (!SDL_ISPIXELFORMAT_INDEXED(surf->format->format)) + if (!SDL_ISPIXELFORMAT_INDEXED(PG_SurfaceFormatEnum(surf))) return RAISE(pgExc_SDLError, "Surface colors are not indexed\n"); - pal = surf->format->palette; + pal = PG_GetSurfacePalette(surf); if (!pal) { return RAISE(pgExc_SDLError, "Surface is not palettized\n"); @@ -1248,10 +1269,10 @@ surf_get_colorkey(pgSurfaceObject *self, PyObject *_null) SDL_GetColorKey(surf, &mapped_color); - if (SDL_ISPIXELFORMAT_ALPHA(surf->format->format)) - SDL_GetRGBA(mapped_color, surf->format, &r, &g, &b, &a); + if (SDL_ISPIXELFORMAT_ALPHA(PG_SurfaceFormatEnum(surf))) + PG_SurfaceGetRGBA(mapped_color, surf, &r, &g, &b, &a); else - SDL_GetRGB(mapped_color, surf->format, &r, &g, &b); + PG_SurfaceGetRGB(mapped_color, surf, &r, &g, &b); return Py_BuildValue("(bbbb)", r, g, b, a); } @@ -1305,6 +1326,9 @@ surf_set_alpha(pgSurfaceObject *self, PyObject *args) pgSurface_Prep(self); result = SDL_SetSurfaceRLE(surf, (flags & PGS_RLEACCEL) ? SDL_TRUE : SDL_FALSE); + +#if !SDL_VERSION_ATLEAST(3, 0, 0) + // TODO: is it fine to ignore this part for SDL3? /* HACK HACK HACK */ if ((surf->flags & SDL_RLEACCEL) && (!(flags & PGS_RLEACCEL))) { /* hack to strip SDL_RLEACCEL flag off surface immediately when @@ -1314,11 +1338,12 @@ surf_set_alpha(pgSurfaceObject *self, PyObject *args) sdlrect.h = 0; sdlrect.w = 0; - surface = PG_CreateSurface(1, 1, surf->format->format); + surface = PG_CreateSurface(1, 1, PG_SurfaceFormatEnum(surf)); SDL_LowerBlit(surf, &sdlrect, surface, &sdlrect); SDL_FreeSurface(surface); } +#endif /* HACK HACK HACK */ if (result == 0) result = SDL_SetSurfaceAlphaMod(surf, alpha); @@ -1411,11 +1436,10 @@ surf_convert(pgSurfaceObject *self, PyObject *args) if ((has_colorkey = SDL_HasColorKey(surf))) { SDL_GetColorKey(surf, &colorkey); - if (SDL_ISPIXELFORMAT_ALPHA(surf->format->format)) - SDL_GetRGBA(colorkey, surf->format, &key_r, &key_g, &key_b, - &key_a); + if (SDL_ISPIXELFORMAT_ALPHA(PG_SurfaceFormatEnum(surf))) + PG_SurfaceGetRGBA(colorkey, surf, &key_r, &key_g, &key_b, &key_a); else - SDL_GetRGB(colorkey, surf->format, &key_r, &key_g, &key_b); + PG_SurfaceGetRGB(colorkey, surf, &key_r, &key_g, &key_b); } if (argobject) { @@ -1428,9 +1452,13 @@ surf_convert(pgSurfaceObject *self, PyObject *args) */ int bpp = 0; SDL_Palette *palette = SDL_AllocPalette(default_palette_size); - SDL_PixelFormat format; + PG_PixelFormatMut format; + PG_PixelFormat *surf_format = PG_GetSurfaceFormat(surf); + + if (surf_format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); - memcpy(&format, surf->format, sizeof(format)); + memcpy(&format, surf_format, sizeof(format)); if (pg_IntFromObj(argobject, &bpp)) { Uint32 Rmask, Gmask, Bmask, Amask; @@ -1524,19 +1552,33 @@ surf_convert(pgSurfaceObject *self, PyObject *args) format.BitsPerPixel = (Uint8)bpp; format.BytesPerPixel = (bpp + 7) / 8; #endif - if (PG_FORMAT_BitsPerPixel((&format)) > 8) - /* Allow a 8 bit source surface with an empty palette to be + if (PG_FORMAT_BitsPerPixel((&format)) > 8) { + /* Allow an 8 bit source surface with an empty palette to be * converted to a format without a palette (pygame-ce issue * #146). If the target format has a non-NULL palette pointer * then SDL_ConvertSurface checks that the palette is not * empty-- that at least one entry is not black. */ +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_FreePalette(palette); + palette = NULL; +#else format.palette = NULL; +#endif + } + if (SDL_ISPIXELFORMAT_INDEXED(SDL_MasksToPixelFormatEnum( PG_FORMAT_BitsPerPixel((&format)), format.Rmask, format.Gmask, format.Bmask, format.Amask))) { - if (SDL_ISPIXELFORMAT_INDEXED(surf->format->format)) { - SDL_SetPixelFormatPalette(&format, surf->format->palette); + if (SDL_ISPIXELFORMAT_INDEXED(PG_SurfaceFormatEnum(surf))) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (palette) + SDL_FreePalette(palette); + palette = PG_GetSurfacePalette(surf); +#else + SDL_SetPixelFormatPalette(&format, + PG_GetSurfacePalette(surf)); +#endif } else { /* Give the surface something other than an all white @@ -1544,12 +1586,24 @@ surf_convert(pgSurfaceObject *self, PyObject *args) */ SDL_SetPaletteColors(palette, default_palette_colors, 0, default_palette_size); +#if !SDL_VERSION_ATLEAST(3, 0, 0) SDL_SetPixelFormatPalette(&format, palette); +#endif } } +#if SDL_VERSION_ATLEAST(3, 0, 0) + PG_PixelFormatEnum format_enum = SDL_GetPixelFormatForMasks( + format.bits_per_pixel, format.Rmask, format.Gmask, + format.Bmask, format.Amask); + newsurf = SDL_ConvertSurfaceAndColorspace( + surf, format_enum, palette, SDL_GetSurfaceColorspace(surf), + SDL_GetSurfaceProperties(surf)); +#else newsurf = PG_ConvertSurface(surf, &format); +#endif SDL_SetSurfaceBlendMode(newsurf, SDL_BLENDMODE_NONE); - SDL_FreePalette(palette); + if (palette) + SDL_FreePalette(palette); } } else { @@ -1563,7 +1617,7 @@ surf_convert(pgSurfaceObject *self, PyObject *args) } if (has_colorkey) { - colorkey = SDL_MapRGBA(newsurf->format, key_r, key_g, key_b, key_a); + colorkey = PG_SurfaceMapRGBA(newsurf, key_r, key_g, key_b, key_a); if (SDL_SetColorKey(newsurf, SDL_TRUE, colorkey) != 0) { PyErr_SetString(pgExc_SDLError, SDL_GetError()); SDL_FreeSurface(newsurf); @@ -1709,9 +1763,15 @@ static PyObject * surf_get_clip(PyObject *self, PyObject *_null) { SDL_Surface *surf = pgSurface_AsSurface(self); + SDL_Rect *clip_rect; SURF_INIT_CHECK(surf) - return pgRect_New(&surf->clip_rect); + PG_GetSurfaceClipRect(surf, clip_rect); + + if (clip_rect == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); + + return pgRect_New(clip_rect); } static PyObject * @@ -2480,7 +2540,11 @@ surf_scroll(PyObject *self, PyObject *args, PyObject *keywds) } } - clip_rect = &surf->clip_rect; + PG_GetSurfaceClipRect(surf, clip_rect); + + if (clip_rect == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); + SDL_Rect surf_rect = {0, 0, surf->w, surf->h}; // In SDL3, SDL_IntersectRect is renamed to SDL_GetRectIntersection @@ -2498,9 +2562,8 @@ surf_scroll(PyObject *self, PyObject *args, PyObject *keywds) 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; + if (!PG_FillRect(surf, NULL, 0)) { + return RAISE(pgExc_SDLError, SDL_GetError()); } } Py_RETURN_NONE; @@ -2530,7 +2593,12 @@ static int _PgSurface_SrcAlpha(SDL_Surface *surf) { SDL_BlendMode mode; - if (SDL_GetSurfaceBlendMode(surf, &mode) < 0) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (!SDL_GetSurfaceBlendMode(surf, &mode)) +#else + if (SDL_GetSurfaceBlendMode(surf, &mode) < 0) +#endif + { PyErr_SetString(pgExc_SDLError, SDL_GetError()); return -1; } @@ -2569,7 +2637,11 @@ surf_get_flags(PyObject *self, PyObject *_null) flags |= PGS_PREALLOC; if (PG_SurfaceHasRLE(surf)) flags |= PGS_RLEACCELOK; +#if SDL_VERSION_ATLEAST(3, 0, 0) // TODO: is there a better solution? + if (PG_SurfaceHasRLE(surf)) +#else if ((sdl_flags & SDL_RLEACCEL)) +#endif flags |= PGS_RLEACCEL; if (is_window_surf) { if (window_flags & PG_WINDOW_FULLSCREEN_INCLUSIVE) @@ -2693,10 +2765,16 @@ static PyObject * surf_get_masks(PyObject *self, PyObject *_null) { SDL_Surface *surf = pgSurface_AsSurface(self); + PG_PixelFormat *format; SURF_INIT_CHECK(surf) - return Py_BuildValue("(IIII)", surf->format->Rmask, surf->format->Gmask, - surf->format->Bmask, surf->format->Amask); + format = PG_GetSurfaceFormat(surf); + + if (format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); + + return Py_BuildValue("(IIII)", format->Rmask, format->Gmask, format->Bmask, + format->Amask); } static PyObject * @@ -2709,10 +2787,16 @@ static PyObject * surf_get_shifts(PyObject *self, PyObject *_null) { SDL_Surface *surf = pgSurface_AsSurface(self); + PG_PixelFormat *format; SURF_INIT_CHECK(surf) - return Py_BuildValue("(iiii)", surf->format->Rshift, surf->format->Gshift, - surf->format->Bshift, surf->format->Ashift); + format = PG_GetSurfaceFormat(surf); + + if (format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); + + return Py_BuildValue("(iiii)", format->Rshift, format->Gshift, + format->Bshift, format->Ashift); } static PyObject * @@ -2721,21 +2805,33 @@ surf_set_shifts(PyObject *self, PyObject *args) return RAISE(PyExc_TypeError, "The surface shifts are read-only in SDL2"); } +// TODO: deprecation and implementation of surf_get_bits. static PyObject * surf_get_losses(PyObject *self, PyObject *_null) { SDL_Surface *surf = pgSurface_AsSurface(self); + PG_PixelFormat *format; SURF_INIT_CHECK(surf) - return Py_BuildValue("(iiii)", surf->format->Rloss, surf->format->Gloss, - surf->format->Bloss, surf->format->Aloss); + format = PG_GetSurfaceFormat(surf); + + if (format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); + +#if SDL_VERSION_ATLEAST(3, 0, 0) + return Py_BuildValue("(iiii)", 8 - format->Rbits, 8 - format->Gbits, + 8 - format->Bbits, 8 - format->Abits); +#else + return Py_BuildValue("(iiii)", format->Rloss, format->Gloss, format->Bloss, + format->Aloss); +#endif } static PyObject * surf_subsurface(PyObject *self, PyObject *args) { SDL_Surface *surf = pgSurface_AsSurface(self); - SDL_PixelFormat *format; + PG_PixelFormat *format; SDL_Rect *rect, temp; SDL_Surface *sub; PyObject *subobj; @@ -2745,7 +2841,11 @@ surf_subsurface(PyObject *self, PyObject *args) SURF_INIT_CHECK(surf) - format = surf->format; + format = PG_GetSurfaceFormat(surf); + + if (format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); + if (!(rect = pgRect_FromObject(args, &temp))) return RAISE(PyExc_ValueError, "invalid rectstyle argument"); if (rect->x < 0 || rect->y < 0 || rect->x + rect->w > surf->w || @@ -2768,10 +2868,11 @@ surf_subsurface(PyObject *self, PyObject *args) return RAISE(pgExc_SDLError, SDL_GetError()); /* copy the colormap if we need it */ - if (SDL_ISPIXELFORMAT_INDEXED(surf->format->format) && - surf->format->palette) { - SDL_Color *colors = surf->format->palette->colors; - int ncolors = surf->format->palette->ncolors; + if (SDL_ISPIXELFORMAT_INDEXED(PG_SurfaceFormatEnum(surf)) && + PG_GetSurfacePalette(surf)) { + SDL_Palette *surf_pallete = PG_GetSurfacePalette(surf); + SDL_Color *colors = surf_pallete->colors; + int ncolors = surf_pallete->ncolors; SDL_Palette *pal = SDL_AllocPalette(ncolors); if (!pal) { @@ -2931,7 +3032,8 @@ surf_get_bounding_rect(PyObject *self, PyObject *args, PyObject *kwargs) #endif PyObject *rect; SDL_Surface *surf = pgSurface_AsSurface(self); - SDL_PixelFormat *format = NULL; + PG_PixelFormat *format = NULL; + SDL_Palette *palette; Uint8 *pixels = NULL; Uint8 *pixel; int x, y; @@ -2955,11 +3057,15 @@ surf_get_bounding_rect(PyObject *self, PyObject *args, PyObject *kwargs) if (!pgSurface_Lock((pgSurfaceObject *)self)) return RAISE(pgExc_SDLError, "could not lock surface"); - format = surf->format; + format = PG_GetSurfaceFormat(surf); + palette = PG_GetSurfacePalette(surf); + + if (format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); if ((has_colorkey = SDL_HasColorKey(surf))) { SDL_GetColorKey(surf, &colorkey); - SDL_GetRGBA(colorkey, surf->format, &keyr, &keyg, &keyb, &a); + PG_GetRGBA(colorkey, format, palette, &keyr, &keyg, &keyb, &a); } pixels = (Uint8 *)surf->pixels; @@ -2989,7 +3095,7 @@ surf_get_bounding_rect(PyObject *self, PyObject *args, PyObject *kwargs) assert(PG_FORMAT_BytesPerPixel(format) == 4); value = *(Uint32 *)pixel; } - SDL_GetRGBA(value, surf->format, &r, &g, &b, &a); + PG_GetRGBA(value, format, palette, &r, &g, &b, &a); if ((a >= min_alpha && has_colorkey == 0) || (has_colorkey != 0 && (r != keyr || g != keyg || b != keyb))) { found_alpha = 1; @@ -3022,7 +3128,7 @@ surf_get_bounding_rect(PyObject *self, PyObject *args, PyObject *kwargs) assert(PG_FORMAT_BytesPerPixel(format) == 4); value = *(Uint32 *)pixel; } - SDL_GetRGBA(value, surf->format, &r, &g, &b, &a); + PG_GetRGBA(value, format, palette, &r, &g, &b, &a); if ((a >= min_alpha && has_colorkey == 0) || (has_colorkey != 0 && (r != keyr || g != keyg || b != keyb))) { found_alpha = 1; @@ -3056,7 +3162,7 @@ surf_get_bounding_rect(PyObject *self, PyObject *args, PyObject *kwargs) assert(PG_FORMAT_BytesPerPixel(format) == 4); value = *(Uint32 *)pixel; } - SDL_GetRGBA(value, surf->format, &r, &g, &b, &a); + PG_GetRGBA(value, format, palette, &r, &g, &b, &a); if ((a >= min_alpha && has_colorkey == 0) || (has_colorkey != 0 && (r != keyr || g != keyg || b != keyb))) { found_alpha = 1; @@ -3089,7 +3195,7 @@ surf_get_bounding_rect(PyObject *self, PyObject *args, PyObject *kwargs) assert(PG_FORMAT_BytesPerPixel(format) == 4); value = *(Uint32 *)pixel; } - SDL_GetRGBA(value, surf->format, &r, &g, &b, &a); + PG_GetRGBA(value, format, palette, &r, &g, &b, &a); if ((a >= min_alpha && has_colorkey == 0) || (has_colorkey != 0 && (r != keyr || g != keyg || b != keyb))) { found_alpha = 1; @@ -3163,7 +3269,7 @@ static PyObject * surf_get_view(PyObject *self, PyObject *args) { SDL_Surface *surface = pgSurface_AsSurface(self); - SDL_PixelFormat *format; + PG_PixelFormat *format; Uint32 mask = 0; SurfViewKind view_kind = VIEWKIND_2D; getbufferproc get_buffer = 0; @@ -3174,7 +3280,11 @@ surf_get_view(PyObject *self, PyObject *args) SURF_INIT_CHECK(surface) - format = surface->format; + format = PG_GetSurfaceFormat(surface); + + if (format == NULL) + return RAISE(pgExc_SDLError, SDL_GetError()); + switch (view_kind) { /* This switch statement is exhaustive over the SurfViewKind enum */ @@ -3517,6 +3627,12 @@ static int _get_buffer_3D(PyObject *obj, Py_buffer *view_p, int flags) { SDL_Surface *surface = pgSurface_AsSurface(obj); + PG_PixelFormat *format = PG_GetSurfaceFormat(surface); + + if (format == NULL) { + RAISERETURN(pgExc_SDLError, SDL_GetError(), -1); + } + int pixelsize = PG_SURF_BytesPerPixel(surface); char *startpixel = (char *)surface->pixels; @@ -3548,7 +3664,7 @@ _get_buffer_3D(PyObject *obj, Py_buffer *view_p, int flags) view_p->shape[2] = 3; view_p->strides[0] = pixelsize; view_p->strides[1] = surface->pitch; - switch (surface->format->Rmask) { + switch (format->Rmask) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN case 0xffU: view_p->strides[2] = 1; @@ -3594,29 +3710,49 @@ _get_buffer_3D(PyObject *obj, Py_buffer *view_p, int flags) static int _get_buffer_red(PyObject *obj, Py_buffer *view_p, int flags) { - return _get_buffer_colorplane(obj, view_p, flags, "red", - pgSurface_AsSurface(obj)->format->Rmask); + PG_PixelFormat *format = PG_GetSurfaceFormat(pgSurface_AsSurface(obj)); + + if (format == NULL) { + RAISERETURN(pgExc_SDLError, SDL_GetError(), -1); + } + + return _get_buffer_colorplane(obj, view_p, flags, "red", format->Rmask); } static int _get_buffer_green(PyObject *obj, Py_buffer *view_p, int flags) { - return _get_buffer_colorplane(obj, view_p, flags, "green", - pgSurface_AsSurface(obj)->format->Gmask); + PG_PixelFormat *format = PG_GetSurfaceFormat(pgSurface_AsSurface(obj)); + + if (format == NULL) { + RAISERETURN(pgExc_SDLError, SDL_GetError(), -1); + } + + return _get_buffer_colorplane(obj, view_p, flags, "green", format->Gmask); } static int _get_buffer_blue(PyObject *obj, Py_buffer *view_p, int flags) { - return _get_buffer_colorplane(obj, view_p, flags, "blue", - pgSurface_AsSurface(obj)->format->Bmask); + PG_PixelFormat *format = PG_GetSurfaceFormat(pgSurface_AsSurface(obj)); + + if (format == NULL) { + RAISERETURN(pgExc_SDLError, SDL_GetError(), -1); + } + + return _get_buffer_colorplane(obj, view_p, flags, "blue", format->Bmask); } static int _get_buffer_alpha(PyObject *obj, Py_buffer *view_p, int flags) { - return _get_buffer_colorplane(obj, view_p, flags, "alpha", - pgSurface_AsSurface(obj)->format->Amask); + PG_PixelFormat *format = PG_GetSurfaceFormat(pgSurface_AsSurface(obj)); + + if (format == NULL) { + RAISERETURN(pgExc_SDLError, SDL_GetError(), -1); + } + + return _get_buffer_colorplane(obj, view_p, flags, "alpha", format->Amask); } static int @@ -3878,7 +4014,12 @@ surface_do_overlap(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, int x, y; int w = srcrect->w, h = srcrect->h; int maxw, maxh; - SDL_Rect *clip = &dst->clip_rect; + SDL_Rect *clip; + PG_GetSurfaceClipRect(dst, clip); + + if (clip == NULL) + return -1; + int span; int dstoffset; @@ -4004,50 +4145,70 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj, owner is locked. */ dst->pixels == src->pixels && srcrect != NULL && - surface_do_overlap(src, srcrect, dst, dstrect))) { + (result = surface_do_overlap(src, srcrect, dst, dstrect)) && + result != -1)) { /* Py_BEGIN_ALLOW_THREADS */ result = pygame_Blit(src, srcrect, dst, dstrect, blend_flags); /* Py_END_ALLOW_THREADS */ } /* can't blit alpha to 8bit, crashes SDL */ else if (PG_SURF_BytesPerPixel(dst) == 1 && - (SDL_ISPIXELFORMAT_ALPHA(src->format->format) || + (SDL_ISPIXELFORMAT_ALPHA(PG_SurfaceFormatEnum(src)) || ((SDL_GetSurfaceAlphaMod(src, &alpha) == 0 && alpha != 255)))) { /* Py_BEGIN_ALLOW_THREADS */ if (PG_SURF_BytesPerPixel(src) == 1) { result = pygame_Blit(src, srcrect, dst, dstrect, 0); } else { - SDL_PixelFormat *fmt = src->format; - SDL_PixelFormat newfmt; + PG_PixelFormat *fmt = PG_GetSurfaceFormat(src); + PG_PixelFormatMut newfmt; - newfmt.palette = 0; /* Set NULL (or SDL gets confused) */ + if (fmt == NULL) { + result = -1; + } + else { #if SDL_VERSION_ATLEAST(3, 0, 0) - newfmt.bits_per_pixel = fmt->bits_per_pixel; - newfmt.bytes_per_pixel = fmt->bytes_per_pixel; + newfmt.bits_per_pixel = fmt->bits_per_pixel; + newfmt.bytes_per_pixel = fmt->bytes_per_pixel; #else - newfmt.BitsPerPixel = fmt->BitsPerPixel; - newfmt.BytesPerPixel = fmt->BytesPerPixel; + newfmt.palette = 0; /* Set NULL (or SDL gets confused) */ + newfmt.BitsPerPixel = fmt->BitsPerPixel; + newfmt.BytesPerPixel = fmt->BytesPerPixel; #endif - newfmt.Amask = 0; - newfmt.Rmask = fmt->Rmask; - newfmt.Gmask = fmt->Gmask; - newfmt.Bmask = fmt->Bmask; - newfmt.Ashift = 0; - newfmt.Rshift = fmt->Rshift; - newfmt.Gshift = fmt->Gshift; - newfmt.Bshift = fmt->Bshift; - newfmt.Aloss = 0; - newfmt.Rloss = fmt->Rloss; - newfmt.Gloss = fmt->Gloss; - newfmt.Bloss = fmt->Bloss; - src = PG_ConvertSurface(src, &newfmt); - if (src) { - result = SDL_BlitSurface(src, srcrect, dst, dstrect); - SDL_FreeSurface(src); - } - else { - result = -1; + newfmt.Amask = 0; + newfmt.Rmask = fmt->Rmask; + newfmt.Gmask = fmt->Gmask; + newfmt.Bmask = fmt->Bmask; + newfmt.Ashift = 0; + newfmt.Rshift = fmt->Rshift; + newfmt.Gshift = fmt->Gshift; + newfmt.Bshift = fmt->Bshift; +#if SDL_VERSION_ATLEAST(3, 0, 0) + newfmt.Abits = 0; + newfmt.Rbits = fmt->Rbits; + newfmt.Gbits = fmt->Gbits; + newfmt.Bbits = fmt->Bbits; +#else + newfmt.Aloss = 0; + newfmt.Rloss = fmt->Rloss; + newfmt.Gloss = fmt->Gloss; + newfmt.Bloss = fmt->Bloss; +#endif +#if SDL_VERSION_ATLEAST(3, 0, 0) + PG_PixelFormatEnum format_enum = SDL_GetPixelFormatForMasks( + newfmt.bits_per_pixel, newfmt.Rmask, newfmt.Gmask, + newfmt.Bmask, newfmt.Amask); + src = SDL_ConvertSurface(src, format_enum); +#else + src = PG_ConvertSurface(src, &newfmt); +#endif + if (src) { + result = SDL_BlitSurface(src, srcrect, dst, dstrect); + SDL_FreeSurface(src); + } + else { + result = -1; + } } } /* Py_END_ALLOW_THREADS */ @@ -4057,9 +4218,12 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj, (PG_SURF_BytesPerPixel(dst) == 4 || PG_SURF_BytesPerPixel(dst) == 2) && _PgSurface_SrcAlpha(src) && - (SDL_ISPIXELFORMAT_ALPHA(src->format->format)) && - !PG_SurfaceHasRLE(src) && !PG_SurfaceHasRLE(dst) && - !(src->flags & SDL_RLEACCEL) && !(dst->flags & SDL_RLEACCEL)) { + (SDL_ISPIXELFORMAT_ALPHA(PG_SurfaceFormatEnum(src))) && + !PG_SurfaceHasRLE(src) && !PG_SurfaceHasRLE(dst) +#if !SDL_VERSION_ATLEAST(3, 0, 0) + && !(src->flags & SDL_RLEACCEL) && !(dst->flags & SDL_RLEACCEL) +#endif + ) { /* If we have a 32bit source surface with per pixel alpha and no RLE we'll use pygame_Blit so we can mimic how SDL1 behaved */ diff --git a/src_c/surface.h b/src_c/surface.h index 4009579d1d..8a43dacb8a 100644 --- a/src_c/surface.h +++ b/src_c/surface.h @@ -342,6 +342,31 @@ } while (0) #endif +#if SDL_VERSION_ATLEAST(3, 0, 0) + +#define PG_SurfaceGetRGBA(colorkey, surf, r, g, b, a) \ + SDL_GetRGBA(colorkey, PG_GetSurfaceFormat(surf), \ + PG_GetSurfacePalette(surf), r, g, b, a) +#define PG_SurfaceGetRGB(colorkey, surf, r, g, b) \ + SDL_GetRGB(colorkey, PG_GetSurfaceFormat(surf), \ + PG_GetSurfacePalette(surf), r, g, b) + +#define PG_GetRGBA SDL_GetRGBA + +#else /* ~SDL_VERSION_ATLEAST(3, 0, 0) */ +#define PG_SurfaceGetRGBA(colorkey, surf, r, g, b, a) \ + SDL_GetRGBA(colorkey, PG_GetSurfaceFormat(surf), r, g, b, a) +#define PG_SurfaceGetRGB(colorkey, surf, r, g, b) \ + SDL_GetRGB(colorkey, PG_GetSurfaceFormat(surf), r, g, b) + +static inline void +PG_GetRGBA(Uint32 pixel, const SDL_PixelFormat *format, SDL_Palette *palette, + Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a) +{ + SDL_GetRGBA(pixel, format, r, g, b, a); +} +#endif + int surface_fill_blend(SDL_Surface *surface, SDL_Rect *rect, Uint32 color, int blendargs);