diff --git a/src_c/_pygame.h b/src_c/_pygame.h index 7a2f069ef9..2d14b1e44c 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -72,6 +72,8 @@ #define PG_ConvertSurface SDL_ConvertSurface #define PG_ConvertSurfaceFormat SDL_ConvertSurfaceFormat +#define PG_SurfaceHasRLE SDL_SurfaceHasRLE + #else /* ~SDL_VERSION_ATLEAST(3, 0, 0)*/ #define PG_ShowCursor() SDL_ShowCursor(SDL_ENABLE) #define PG_HideCursor() SDL_ShowCursor(SDL_DISABLE) @@ -100,6 +102,44 @@ #define PG_ConvertSurface(src, fmt) SDL_ConvertSurface(src, fmt, 0) #define PG_ConvertSurfaceFormat(src, pixel_format) \ SDL_ConvertSurfaceFormat(src, pixel_format, 0) +#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 + +SDL_bool +PG_SurfaceHasRLE(SDL_Surface *surface); +#endif #endif diff --git a/src_c/rotozoom.c b/src_c/rotozoom.c index 787b5a8afd..88696d3d08 100644 --- a/src_c/rotozoom.c +++ b/src_c/rotozoom.c @@ -11,6 +11,23 @@ */ +#include "_pygame.h" + +#if !SDL_VERSION_ATLEAST(2, 0, 14) +SDL_bool +PG_SurfaceHasRLE(SDL_Surface *surface) +{ + if (surface == NULL) { + return SDL_FALSE; + } + + if (!(surface->map->info.flags & SDL_COPY_RLE_DESIRED)) { + return SDL_FALSE; + } + + return SDL_TRUE; +} +#endif #define NO_PYGAME_C_API #include "pygame.h" @@ -511,6 +528,7 @@ rotozoomSurface(SDL_Surface *src, double angle, double zoom, int smooth) int dstwidth, dstheight; int is32bit; int src_converted; + Uint32 colorkey; /* * Sanity check @@ -583,6 +601,17 @@ rotozoomSurface(SDL_Surface *src, double angle, double zoom, int smooth) * Target surface is 32bit with source RGBA/ABGR ordering */ rz_dst = PG_CreateSurface(dstwidth, dstheight, rz_src->format->format); + if (SDL_GetColorKey(src, &colorkey) == 0) { + if (SDL_SetColorKey(rz_dst, SDL_TRUE, colorkey) != 0) { + SDL_FreeSurface(rz_dst); + return NULL; + } + if (PG_SurfaceHasRLE(src) && + SDL_SetSurfaceRLE(rz_dst, SDL_TRUE) != 0) { + SDL_FreeSurface(rz_dst); + return NULL; + } + } /* * Lock source surface @@ -628,7 +657,19 @@ rotozoomSurface(SDL_Surface *src, double angle, double zoom, int smooth) /* * Target surface is 32bit with source RGBA/ABGR ordering */ + rz_dst = PG_CreateSurface(dstwidth, dstheight, rz_src->format->format); + if (SDL_GetColorKey(src, &colorkey) == 0) { + if (SDL_SetColorKey(rz_dst, SDL_TRUE, colorkey) != 0) { + SDL_FreeSurface(rz_dst); + return NULL; + } + if (PG_SurfaceHasRLE(src) && + SDL_SetSurfaceRLE(rz_dst, SDL_TRUE) != 0) { + SDL_FreeSurface(rz_dst); + return NULL; + } + } /* * Lock source surface diff --git a/src_c/transform.c b/src_c/transform.c index 5a5d10faa6..8bb3d9fe1a 100644 --- a/src_c/transform.c +++ b/src_c/transform.c @@ -891,6 +891,10 @@ surf_rotozoom(PyObject *self, PyObject *args, PyObject *kwargs) Py_BEGIN_ALLOW_THREADS; newsurf = rotozoomSurface(surf32, angle, scale, 1); Py_END_ALLOW_THREADS; + if (newsurf == NULL) { + PyErr_SetString(pgExc_SDLError, SDL_GetError()); + return NULL; + } if (surf32 == surf) pgSurface_Unlock(surfobj); diff --git a/test/transform_test.py b/test/transform_test.py index af1c6109d1..a976800f2e 100644 --- a/test/transform_test.py +++ b/test/transform_test.py @@ -1287,6 +1287,17 @@ def test_rotozoom(self): self.assertEqual(s1.get_rect(), pygame.Rect(0, 0, 0, 0)) self.assertEqual(s2.get_rect(), pygame.Rect(0, 0, 0, 0)) + def test_rotozoom_keeps_colorkey(self): + image = pygame.Surface((64, 64)) + image.set_colorkey("black") + pygame.draw.circle(image, "red", (32, 32), 32, width=0) + + no_rot = pygame.transform.rotozoom(image, 0, 1.1) + self.assertEqual(image.get_colorkey(), no_rot.get_colorkey()) + + with_rot = pygame.transform.rotozoom(image, 5, 1.1) + self.assertEqual(image.get_colorkey(), with_rot.get_colorkey()) + def test_invert(self): surface = pygame.Surface((10, 10), depth=32)