How can I manage transparency in SDL? I know how to use color keying, but of course this contrasts with anti-aliasing...
Buch, when you set up a surface in SDL I think you have to choose whether it uses color keying or alpha transparency. Then, when you draw it to another surface, the way it behaves depends on that combinations of source alpha vs. destination alpha settings.
If you're using SDL_image, when you load a file with RGBA (e.g. many PNG files) that surface will automatically have the correct alpha transparency settings, and if you draw them to the screen the edges wil work as expected.
For details, hit up the SDL documentation. Or, if you have a specific scenario, maybe I can point you to the right SDL doc you need.
Thanks for the suggestion! I found something in the documentation... there's a function in the library that allows me to enable alpha channel
As a warning: my understanding is that SDL does not handle per-pixel alpha very efficiently. If you use it too much, it'll have a noticeable framerate impact. I know, that contrasts with antialiasing, and I don't even have any alternatives to suggest, but just be aware.
Definitely about SDL performance with per-pixel alpha.
In OSARE I had to convert all the character sprites and tilesets to "magic pink" transparency for performance. I only use full alpha sprites for spell effects, where variable-level alpha transparency is a major part of the art.
Actually I'm just making some trials to learn SDL, but at the moment I haven't found any slow-down and I'm getting a much better result than with color keying...
I back that up too, if you use a lot of it it will get slow as hell. There was something called glSDL that used OpenGL as a rendering backend for SDL that avoided this slowdown but I don't know what's the current state of it. You might want to search the mailing lists.
You could try SFML it is not only more simple than SDL but it is also faster ;-) I have been using it since a few days now and it looks great (and does full transparency). It relies on OpenGL, you can see this as a huge advantage or huge drawback.
I'm having a problem still with transparency: when I use the function SDL_CreateRGBSurface to create an empty surface, how can I make it completely transparent? I tried changing the mask values: giving an alpha mask value of 0xFF000000 as suggested by the documentation creates an empty and transparent surface, but when I blit anything on it the surface remains empty.
I'm having a problem still with transparency: when I use the function SDL_CreateRGBSurface to create an empty surface, how can I make it completely transparent? I tried changing the mask values: giving an alpha mask value of 0xFF000000 as suggested by the documentation creates an empty and transparent surface, but when I blit anything on it the surface remains empty.
Buch, can you post your example code to e.g. pastebin?
It's a short piece of code , so I'll just post it here... Thanks for your interest
This is inside a class; frameWidth and frameHeight are the values of the size of the image; I've skipped the part where I blit images on the surface created because there is a lot of code there to choose which image blit and how to do it, but I'm pretty sure the problem is not there, because when I do it outside from this function on an image not made with SDL_CreateRGBSurface (such as the window) I don't have any problem.
SDL_Surface* image(){
SDL_Surface* result = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, frameWidth, frameHeight, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
//Here I just blit an image on the surface...
return result;
}
Note that what happens with the Alpha depends on both the source and destination surfaces.
From the SDL documentation:
The results of blitting operations vary greatly depending on whether SDL_SRCAPLHA is set or not. See SDL_SetAlpha for an explaination of how this affects your results. Colorkeying and alpha attributes also interact with surface blitting, as the following pseudo-code should hopefully explain.
if (source surface has SDL_SRCALPHA set) {
if (source surface has alpha channel (that is, format->Amask != 0))
blit using per-pixel alpha, ignoring any colour key
else {
if (source surface has SDL_SRCCOLORKEY set)
blit using the colour key AND the per-surface alpha value
else
blit using the per-surface alpha value
}
} else {
if (source surface has SDL_SRCCOLORKEY set)
blit using the colour key
else
ordinary opaque rectangular blit
}
The problem is not that blitting on the surface doesn't work properly, but that the surface created with SDL_CreateRGBSurface is black and opaque if amask is 0 or remains completely transparent (even if I blit something on it) if amask is 0xFF000000.
What I would like to do is creating a transparent surface (I mean that all pixels are transparent, not that the per-surface alpha is transparent).
I've tried this:
Uint32 background = SDL_MapRGBA(result->format, 0,0,0,SDL_ALPHA_TRANSPARENT);
SDL_FillRect(result, &result->clip_rect, background);
to make all the pixels transparent, but the per-pixel alpha doesn't change, while the color does (if I change the values of RGB the black rectangle becomes a colored rectangle).
Sorry if I can't explain this very well...
Thank you for your interest anyway
Problem solved (at least I think so...)
I had a look once more at the docs and found out that the SDL_BlitSurface function doesn't copy the alpha values from the source to the destination; then I wrote a function that copies pixel pixel from the source to the destination, including alpha values, and it works.
Thank you for your help.
Hey guys, I got a lot of insight from the discussion above. But there still a problem I am facing with my code. What I am doing is that I am creating a raw buffer through another code which decodes a PNG image and fills it into the buffer. Then I create a SDL_Surface over that buffer using SDL_CreateRGBSurfaceFrom function.
Now when I display the image on the screen I do not see the alpha values blending properly. Any Suggestions?
What I do is like:
void * ImgBuffer = ReadPNG("FILE.png"); // Creates a raw buffer with Decoded PNG.
SDL_Surface *image = SDL_CreateRGBSurfaceFrom(ImgBuffer, SWSURFACE, w, h, 32, w*4, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
SDL_Rect rect = {0, 0, 100, 100}; // since the image size is 100x100
SDL_BlitSurface(SDL_Screen /*Video Screen*/, NULL, image, &rect);
But this doesn't show the image properly with alpha blending
Any help would be great
You're not specifying an alpha mask. Despite what the documentation says (and it can be a bit confusing), if you don't specify an alpha mask, you won't get any alpha channel at all. Your call to SDL_CreateRGBSurfaceFrom should look like this:
Just a note on per-pixel alpha in SDL. I feel like there's some option where you can choose whether to render in hardware or in software, and (counterintuitively) software is way faster for per-pixel alpha.
(the following only applies to SDL 1.2 or earlier).
Note that in Flare we solved this issue by borrowing a function from SDL_gfx that correctly blits one alpha surface to another. The two files are:
The function name is SDL_gfxBlitRGBA. Note it's done in software so it's slow.