SDL1.2 - Drawing transparent image to color-keyed surface

I'm working with SDL1.2 and have been trying to find a solution to this problem for some time. I have an image with some transparency done through the SDL_SetAlpha() function. I want to draw that image to a surface and then draw that surface to the screen. The surface that I'm drawing to is filled with magenta and has its color key set to magenta. When I draw the transparent image to the surface, it is drawn onto the magenta surface, so when the surface is drawn to the screen, the image has gained a pink tint but the rest of the magenta is skipped because of the color key. Is there any way to draw a transparent image to an empty surface and then the screen without picking up the color key?

Here's an image showing what I'm getting at:
http://i.imgur.com/RxbCAIi.jpg
You might want to use a surface with alpha channel instead of color key.
Yeah, that's what I figured. I'm just not sure how to do it.

Right now, I'm loading the color-keyed surface like this:

1
2
3
4
5
6
#define COLOR_KEY_HEX 0xFF00FF

SDL_Surface* surface = SDL_CreateRGBSurface(
		NULL, w, h, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
SDL_FillRect(surface, NULL, COLOR_KEY_HEX);
SDL_SetColorKey(surface, SDL_SRCCOLORKEY, COLOR_KEY_HEX);


I've been trying something like this, but I've had no luck. The surface is just black:

1
2
3
SDL_Surface* surface = SDL_CreateRGBSurface(
		SDL_SRCALPHA, w, h, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
SDL_SetAlpha(surface, NULL, SDL_ALPHA_TRANSPARENT);


What am I doing wrong and what should I be doing instead?
Doesn't it work without the color key?

 
SDL_Surface* surface = SDL_CreateRGBSurface(0, w, h, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);


I don't think you want to use SDL_SRCALPHA / SDL_SetAlpha because that is for having an alpha value per surface. You want an alpha value per pixel.
I now have this code:

1
2
3
4
SDL_Surface* load_surface = SDL_CreateRGBSurface(
		NULL, w, h, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
SDL_Surface* surface = SDL_DisplayFormatAlpha(load_surface);
SDL_FreeSurface(load_surface);


This produces a fully transparent surface, which is a start. But when I draw a partially-transparent image to the surface, the image gains a black tint and becomes opaque. The image is still blending with a black surface below it before the surface is drawn to the screen. How do I get it to not blend the image with the black? I guess I want the pixels on the surface replaced with the pixels in the image, and retain their partial transparency. I'm just using SDL_BlitSurface() to draw.
Last edited on
If you draw the same image multiple times at the same location the partially transparent areas will undoubtedly become more and more opaque. I'm not sure exactly what you want to happen or what the purpose of the transparent surface is. If you just want the image to show up on the screen why not draw it to the screen directly?
Last edited on
It's not becoming more opaque from redrawing the transparent image, it's gaining a black tint just like the pink tint in my image above.

The purpose of the transparent surface is a trail made of small dots that slowly fade out. I can draw them directly to the screen and that works fine, but there are some trails that I want to be permanent. Instead of drawing each dot in these permanent trails to the screen every frame, I want to draw them to a surface and then delete them to minimize the number of blit operations each frame.

Maybe it's just not possible to draw a transparent object to an intermediate surface and maintain transparency. But it would strike me as strange if you couldn't.
Are you using SDL_DisplayFormatAlpha on both surfaces?
I am.

Here's what is in the documentation:

RGBA->RGBA with SDL_SRCALPHA
The source is alpha-blended with the destination using the source alpha channel. The alpha channel in the destination surface is left untouched. SDL_SRCCOLORKEY is ignored.

RGBA->RGBA without SDL_SRCALPHA
The RGBA data is copied to the destination surface. If SDL_SRCCOLORKEY is set, only the pixels not matching the colorkey value are copied.


The second thing is what I want. When I draw a transparent bitmap to the surface, I want to replace the pixels on the surface with the pixels in the bitmap. I don't want to blend the transparent bitmap with the surface, which will make the bitmap opaque and give it a tint of the color key.
Ah, so that's how SDL_SRCALPHA works.

It seems like you need to turn off SDL_SRCALPHA explicitly so I guess you want to do this for the image but not for the surface.

1
2
// Disables SDL_SRCALPHA
SDL_SetAlpha(img, 0, 0);
Alright, I think I almost have it figured out. I looked a bit more closely into what SDL_DisplayFormatAlpha does:

This function can be used to convert a colorkey to an alpha channel, if the SDL_SRCCOLORKEY flag is set on the surface. The generated surface will then be transparent (alpha=0) where the pixels match the colorkey, and opaque (alpha=255) elsewhere.


So I'm now initializing my middle surface like this:

1
2
3
4
5
6
7
SDL_Surface* load_surface = SDL_CreateRGBSurface(
		SDL_HWSURFACE, w, h, 32, rmask, gmask, bmask, amask);
SDL_FillRect(load_surface, NULL, 0xFF00FF);
SDL_SetColorKey(load_surface, SDL_SRCCOLORKEY, 0xFF00FF);
SDL_Surface* surface = SDL_DisplayFormatAlpha(load_surface);
SDL_FreeSurface(load_surface);
return surface;


and initializing my bitmap like this:

1
2
3
4
SDL_Surface* bitmap = SDL_LoadBMP(filepath.c_str());
SDL_SetColorKey(bitmap , SDL_SRCCOLORKEY, 0xFF00FF);
SDL_SetAlpha(bitmap , SDL_SRCALPHA, alpha);
return bitmap;


By using SDL_DisplayFormatAlpha, I convert all the color key pixels in the surface to transparent pixels. Then I can draw the transparent bitmap to the surface without it blending with what was the pink color key. So now I can draw a partially-transparent bitmap to a fully-transparent surface, then to the screen or any other surface, without losing the bitmap's transparency or gaining a pink tint.

The only problem I'm having now is I haven't been able to convert the bitmap to display format without ruining the transparency, but I'll keep going ahead and see if I actually get any noticeable performance issues without display format. If I don't, I won't worry about it. I have the effect I want.

Thanks for your help Peter!
Last edited on
Topic archived. No new replies allowed.