Skip to content

Commit

Permalink
Fix transform.hsl() to work on any Surface (pygame-community#2948)
Browse files Browse the repository at this point in the history
* fixes transform.hsl when calling .convert_alpha() onto the surface to transform

* more fixes

* add test

* fix
  • Loading branch information
itzpr3d4t0r authored Jun 23, 2024
1 parent cca42ca commit 8535cfe
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 7 deletions.
19 changes: 12 additions & 7 deletions src_c/transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -2289,13 +2289,6 @@ HSL_to_RGB(float h, float s, float l, Uint8 *r, Uint8 *g, Uint8 *b)
static void
modify_hsl(SDL_Surface *surf, SDL_Surface *dst, float h, float s, float l)
{
int x, y;
Uint8 r, g, b, a;
float s_h = 0, s_s = 0, s_l = 0;
SDL_PixelFormat *fmt = surf->format;
Uint8 *srcp8 = (Uint8 *)surf->pixels;
Uint8 *dstp8 = (Uint8 *)dst->pixels;

int surf_locked = 0;
if (SDL_MUSTLOCK(surf)) {
if (SDL_LockSurface(surf) == 0) {
Expand All @@ -2309,6 +2302,13 @@ modify_hsl(SDL_Surface *surf, SDL_Surface *dst, float h, float s, float l)
}
}

int x, y;
Uint8 r, g, b, a;
float s_h = 0, s_s = 0, s_l = 0;
SDL_PixelFormat *fmt = surf->format;
Uint8 *srcp8 = (Uint8 *)surf->pixels;
Uint8 *dstp8 = (Uint8 *)dst->pixels;

if (PG_FORMAT_BytesPerPixel(fmt) == 4 ||
PG_FORMAT_BytesPerPixel(fmt) == 3) {
const int src_skip =
Expand All @@ -2320,10 +2320,12 @@ modify_hsl(SDL_Surface *surf, SDL_Surface *dst, float h, float s, float l)
const int Ridx = fmt->Rshift >> 3;
const int Gidx = fmt->Gshift >> 3;
const int Bidx = fmt->Bshift >> 3;
const int Aidx = fmt->Ashift >> 3;
#else
const int Ridx = 3 - (fmt->Rshift >> 3);
const int Gidx = 3 - (fmt->Gshift >> 3);
const int Bidx = 3 - (fmt->Bshift >> 3);
const int Aidx = 3 - (fmt->Ashift >> 3);
#endif

int height = surf->h;
Expand Down Expand Up @@ -2353,6 +2355,8 @@ modify_hsl(SDL_Surface *surf, SDL_Surface *dst, float h, float s, float l)
dstp8[Ridx] = r;
dstp8[Gidx] = g;
dstp8[Bidx] = b;
if (fmt->Amask)
dstp8[Aidx] = srcp8[Aidx];

srcp8 += PG_FORMAT_BytesPerPixel(fmt);
dstp8 += PG_FORMAT_BytesPerPixel(fmt);
Expand Down Expand Up @@ -2462,6 +2466,7 @@ surf_hsl(PyObject *self, PyObject *args, PyObject *kwargs)
if (src->format->Rmask != dst->format->Rmask ||
src->format->Gmask != dst->format->Gmask ||
src->format->Bmask != dst->format->Bmask ||
src->format->Amask != dst->format->Amask ||
PG_SURF_BytesPerPixel(src) != PG_SURF_BytesPerPixel(dst)) {
return RAISE(PyExc_ValueError,
"Source and destination surfaces need the same format.");
Expand Down
44 changes: 44 additions & 0 deletions test/transform_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,50 @@ def test_hsl(self):
for v1, v2 in zip(expected_rgb, actual_rgb):
self.assertAlmostEqual(v1, v2, delta=1)

surf = pygame.Surface((1, 1), flags=pygame.SRCALPHA)
dest = pygame.Surface((1, 1), flags=pygame.SRCALPHA)

alpha_colors = [
(0, 0, 0, 0),
(255, 255, 255, 255),
(255, 0, 0, 255),
(0, 255, 0, 255),
(0, 0, 255, 255),
(127, 127, 127, 127),
(11, 23, 34, 255),
(1, 0, 1, 255),
]

for color in alpha_colors:
c_a = color[3]
for h in range(0, 360, 10):
for s in range(0, 100, 10):
for l in range(0, 100, 10):
surf.fill(color)
ns = s / 100.0
nl = l / 100.0

hsl_surf = pygame.transform.hsl(surf, h, ns, nl)
pygame.transform.hsl(surf, h, ns, nl, dest_surface=dest)

nh = h / 360.0
modified_hsl = modify_hsl(*rgb_to_hsl(color[:3]), nh, ns, nl)
expected_rgb = hsl_to_rgb(modified_hsl)

# without destination
actual_color = hsl_surf.get_at((0, 0))
actual_rgb = actual_color.rgb
for v1, v2 in zip(expected_rgb, actual_rgb):
self.assertAlmostEqual(v1, v2, delta=1)
self.assertEqual(c_a, actual_color.a)

# with destination
actual_color = dest.get_at((0, 0))
actual_rgb = actual_color.rgb
for v1, v2 in zip(expected_rgb, actual_rgb):
self.assertAlmostEqual(v1, v2, delta=1)
self.assertEqual(c_a, actual_color.a)

def test_grayscale_simd_assumptions(self):
# The grayscale SIMD algorithm relies on the destination surface pitch
# being exactly width * 4 (4 bytes per pixel), for maximum speed.
Expand Down

0 comments on commit 8535cfe

Please sign in to comment.