1.2 SDL_BlitSurface and colorkeying

The behaviour of color key blitting seems to have changed slightly in
1.2.

I have an application where I load palettized images for which palette
color 0 should be transparent. I used to use code like this to
set per-pixel alpha=0 for indexed-color 0, and alpha=1 for all other
pixels.

SDL_Surface *orig, *rgba;

orig = IMG_Load(filename);
rgba = SDL_CreateRGBSurface(SDL_SWSURFACE, orig->w, orig->h, 32,
			rmask, bmask, gmask, amask);

/* Palettized images have color index 0 transparent.  We set the
 * color key (transparent color) here, and fill the alpha channel
 * in the dest with 0.  When we do the blit the color key pixels
 * aren't copied and retain the 0 alpha value. */
if (orig->format->palette != NULL) {
    SDL_SetColorKey(orig, SDL_SRCCOLORKEY, 0);
    SDL_FillRect(rgba, NULL, SDL_MapRGBA(rgba->format, 0, 0, 0, 0));
}
SDL_BlitSurface(orig, NULL, rgba, NULL);

Unfortunately this doesn’t seem to work in 1.2 – the alpha=0 remains
for all pixels, and is not overwritten by the SDL_BlitSurface() over
the top.

Is this a bug? A feature? Can someone suggest an alternative way of
doing what I was doing (preferably without having to code my own
pixel-test-and-set loops)?

  • Mike

SDL_Surface *orig, *rgba;

orig = IMG_Load(filename);
rgba = SDL_CreateRGBSurface(SDL_SWSURFACE, orig->w, orig->h, 32,
rmask, bmask, gmask, amask);

/* Palettized images have color index 0 transparent. We set the
* color key (transparent color) here, and fill the alpha channel
* in the dest with 0. When we do the blit the color key pixels
* aren’t copied and retain the 0 alpha value. */
if (orig->format->palette != NULL) {
SDL_SetColorKey(orig, SDL_SRCCOLORKEY, 0);
SDL_FillRect(rgba, NULL, SDL_MapRGBA(rgba->format, 0, 0, 0, 0));
}
SDL_BlitSurface(orig, NULL, rgba, NULL);

Unfortunately this doesn’t seem to work in 1.2 – the alpha=0 remains
for all pixels, and is not overwritten by the SDL_BlitSurface() over
the top.

Some more info, here is the surface format of “orig” (on x86 Linux):

(gidb) print *orig
$1 = {flags = 4096, format = 0x9a66cc0, w = 640, h = 480, pitch = 640,
pixels = 0x49c17008, offset = 0, hwdata = 0x0, clip_rect = {x = 0, y = 0,
w = 640, h = 480}, unused1 = 4279704868, locked = 0, map = 0x8ed8da0,
format_version = 0, refcount = 1}
(gdb) print *orig->format
$3 = {palette = 0x8eccc60, BitsPerPixel = 8 ‘\b’, BytesPerPixel = 1 ‘\001’,
Rloss = 8 ‘\b’, Gloss = 8 ‘\b’, Bloss = 8 ‘\b’, Aloss = 8 ‘\b’,
Rshift = 0 ‘\000’, Gshift = 0 ‘\000’, Bshift = 0 ‘\000’, Ashift = 0 ‘\000’,
Rmask = 0, Gmask = 0, Bmask = 0, Amask = 0, colorkey = 0, alpha = 255 ‘?’}
(gdb) print *orig->format->palette
$4 = {ncolors = 16, colors = 0x9a66cf0}

  • Mike

Unfortunately this doesn’t seem to work in 1.2 – the alpha=0 remains
for all pixels, and is not overwritten by the SDL_BlitSurface() over
the top.

this seems to be a bug for indexed images. Please try the patch below.
Also try SDL_DisplayFormatAlpha(); in 1.2, it converts colourkeyed
images to alpha-channel ones as you would expect

Index: SDL_pixels.c===================================================================
RCS file: /cvs/SDL12/src/video/SDL_pixels.c,v
retrieving revision 1.2
diff -u -r1.2 SDL_pixels.c
— SDL_pixels.c 2001/04/26 16:50:18 1.2
+++ SDL_pixels.c 2001/06/04 15:33:18
@@ -464,7 +464,6 @@
Uint8 *map;
int i;
int bpp;

  • unsigned alpha;

    bpp = ((dst->BytesPerPixel == 3) ? 4 : dst->BytesPerPixel);
    map = (Uint8 )malloc(src->ncolorsbpp);
    @@ -473,12 +472,11 @@
    return(NULL);
    }

  • alpha = dst->Amask ? SDL_ALPHA_OPAQUE : 0;
    /* We memory copy to the pixel map so the endianness is preserved */
    for ( i=0; incolors; ++i ) {
    ASSEMBLE_RGBA(&map[i*bpp], dst->BytesPerPixel, dst,
    src->colors[i].r, src->colors[i].g,

  •   	      src->colors[i].b, alpha);
    
  •   	      src->colors[i].b, SDL_ALPHA_OPAQUE);
    
    }
    return(map);
    }

The behaviour of color key blitting seems to have changed slightly in
1.2.

I have an application where I load palettized images for which palette
color 0 should be transparent. I used to use code like this to
set per-pixel alpha=0 for indexed-color 0, and alpha=1 for all other
pixels.

[deleted]

Unfortunately this doesn’t seem to work in 1.2 – the alpha=0 remains
for all pixels, and is not overwritten by the SDL_BlitSurface() over
the top.

Okay, turns out that wasn’t the problem in the end, the problem was that
the destination surface now has SDL_SRCALPHA set where previously it
didn’t. I’m not sure I understand the reasoning, but hey, problem solved.

  • Mike

Okay, turns out that wasn’t the problem in the end, the problem was that
the destination surface now has SDL_SRCALPHA set where previously it
didn’t. I’m not sure I understand the reasoning, but hey, problem solved.

oh no, don’t think you’ll get away that easily :slight_smile:

SDL_SRCALPHA should have no bearing on the result when set on the
destination surface, or there is a bug in SDL. Did you try my patch,
or using DisplayFormatAlpha?