From 5c64387b6532e2c27e6ee608e79ef91be64c6f5f Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 24 Mar 2013 09:51:01 -0700 Subject: [PATCH] The palette unused value is treated as alpha and updated when setting the colorkey. This fixes issues loading palettized images that have a colorkey with the same RGB values as another entry in the palette (e.g. bug 1746) --- src/video/SDL_pixels.c | 17 ++++++++-------- src/video/SDL_pixels_c.h | 2 +- src/video/SDL_surface.c | 43 ++++++++++++++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c index 47843b034..b27520832 100644 --- a/src/video/SDL_pixels.c +++ b/src/video/SDL_pixels.c @@ -762,12 +762,12 @@ SDL_CalculatePitch(SDL_Surface * surface) * Match an RGB value to a particular palette index */ Uint8 -SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b) +SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a) { /* Do colorspace distance matching */ unsigned int smallest; unsigned int distance; - int rd, gd, bd; + int rd, gd, bd, ad; int i; Uint8 pixel = 0; @@ -776,7 +776,8 @@ SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b) rd = pal->colors[i].r - r; gd = pal->colors[i].g - g; bd = pal->colors[i].b - b; - distance = (rd * rd) + (gd * gd) + (bd * bd); + ad = pal->colors[i].unused - a; + distance = (rd * rd) + (gd * gd) + (bd * bd) + (ad * ad); if (distance < smallest) { pixel = i; if (distance == 0) { /* Perfect match! */ @@ -797,7 +798,7 @@ SDL_MapRGB(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b) | (g >> format->Gloss) << format->Gshift | (b >> format->Bloss) << format->Bshift | format->Amask; } else { - return SDL_FindColor(format->palette, r, g, b); + return SDL_FindColor(format->palette, r, g, b, SDL_ALPHA_OPAQUE); } } @@ -812,7 +813,7 @@ SDL_MapRGBA(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b, | (b >> format->Bloss) << format->Bshift | ((a >> format->Aloss) << format->Ashift & format->Amask); } else { - return SDL_FindColor(format->palette, r, g, b); + return SDL_FindColor(format->palette, r, g, b, a); } } @@ -858,7 +859,7 @@ SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormat * format, *r = format->palette->colors[pixel].r; *g = format->palette->colors[pixel].g; *b = format->palette->colors[pixel].b; - *a = SDL_ALPHA_OPAQUE; + *a = format->palette->colors[pixel].unused; } else { *r = *g = *b = *a = 0; } @@ -894,7 +895,7 @@ Map1to1(SDL_Palette * src, SDL_Palette * dst, int *identical) for (i = 0; i < src->ncolors; ++i) { map[i] = SDL_FindColor(dst, src->colors[i].r, src->colors[i].g, - src->colors[i].b); + src->colors[i].b, src->colors[i].unused); } return (map); } @@ -918,10 +919,10 @@ Map1toN(SDL_PixelFormat * src, Uint8 Rmod, Uint8 Gmod, Uint8 Bmod, Uint8 Amod, /* We memory copy to the pixel map so the endianness is preserved */ for (i = 0; i < pal->ncolors; ++i) { - Uint8 A = Amod; Uint8 R = (Uint8) ((pal->colors[i].r * Rmod) / 255); Uint8 G = (Uint8) ((pal->colors[i].g * Gmod) / 255); Uint8 B = (Uint8) ((pal->colors[i].b * Bmod) / 255); + Uint8 A = (Uint8) ((pal->colors[i].unused * Amod) / 255); ASSEMBLE_RGBA(&map[i * bpp], dst->BytesPerPixel, dst, R, G, B, A); } return (map); diff --git a/src/video/SDL_pixels_c.h b/src/video/SDL_pixels_c.h index 46b086c45..0b5d9a006 100644 --- a/src/video/SDL_pixels_c.h +++ b/src/video/SDL_pixels_c.h @@ -36,6 +36,6 @@ extern void SDL_FreeBlitMap(SDL_BlitMap * map); /* Miscellaneous functions */ extern int SDL_CalculatePitch(SDL_Surface * surface); extern void SDL_DitherColors(SDL_Color * colors, int bpp); -extern Uint8 SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b); +extern Uint8 SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a); /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c index 710508ed3..b496a1b86 100644 --- a/src/video/SDL_surface.c +++ b/src/video/SDL_surface.c @@ -187,7 +187,13 @@ SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key) if (flag) { surface->map->info.flags |= SDL_COPY_COLORKEY; surface->map->info.colorkey = key; + if (surface->format->palette) { + surface->format->palette->colors[surface->map->info.colorkey].unused = SDL_ALPHA_TRANSPARENT; + } } else { + if (surface->format->palette) { + surface->format->palette->colors[surface->map->info.colorkey].unused = SDL_ALPHA_OPAQUE; + } surface->map->info.flags &= ~SDL_COPY_COLORKEY; } if (surface->map->info.flags != flags) { @@ -843,14 +849,35 @@ SDL_ConvertSurface(SDL_Surface * surface, SDL_PixelFormat * format, SDL_COPY_RLE_ALPHAKEY)); surface->map->info.flags = copy_flags; if (copy_flags & SDL_COPY_COLORKEY) { - Uint8 keyR, keyG, keyB, keyA; - - SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR, - &keyG, &keyB, &keyA); - SDL_SetColorKey(convert, 1, - SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA)); - /* This is needed when converting for 3D texture upload */ - SDL_ConvertColorkeyToAlpha(convert); + SDL_bool set_colorkey_by_color = SDL_FALSE; + + if (surface->format->palette) { + if (format->palette && + surface->format->palette->ncolors <= format->palette->ncolors && + (SDL_memcmp(surface->format->palette->colors, format->palette->colors, + surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) { + /* The palette is identical, just set the same colorkey */ + SDL_SetColorKey(convert, 1, surface->map->info.colorkey); + } else if (format->Amask) { + /* The alpha was set in the destination from the palette */ + } else { + set_colorkey_by_color = SDL_TRUE; + } + } else { + set_colorkey_by_color = SDL_TRUE; + } + + if (set_colorkey_by_color) { + /* Set the colorkey by color, which needs to be unique */ + Uint8 keyR, keyG, keyB, keyA; + + SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR, + &keyG, &keyB, &keyA); + SDL_SetColorKey(convert, 1, + SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA)); + /* This is needed when converting for 3D texture upload */ + SDL_ConvertColorkeyToAlpha(convert); + } } SDL_SetClipRect(convert, &surface->clip_rect);