Reputation: 8408
I'm trying to blit a surface created by IMG_Load
(SDL_image) onto one created via SDL_CreateRGBSurface
. When both surfaces are loaded with IMG_Load
, this works fine, but not when the target surface was created using SDL_CreateRGBSurface
.
By experimentation, I figured out that if I call SDL_SetAlpha
on the source surface, it suddenly works fine. The documentation is a bit lacking, but how I understand it, the way I call it below should clear the SDL_SRCALPHA
flag, presumably set by IMG_Load
. It seems like the alpha flag of the source surface is what matters when blitting, so I guess this turns off alpha blending altogether.
The big question is: Why is this SDL_SetAlpha
necessary in the first place? And is this really the right way to do it?
Here's code that reproduces this:
#include <SDL/SDL.h>
#include <SDL_image/SDL_image.h>
SDL_Surface* copy_surface(SDL_Surface* source)
{
SDL_Surface *target;
target = SDL_CreateRGBSurface(0, source->w, source->h,
source->format->BitsPerPixel,
source->format->Rmask, source->format->Gmask,
source->format->Bmask, source->format->Amask);
/*
* I really don't understand why this is necessary. This is supposed to
* clear the SDL_SRCALPHA flag presumably set by IMG_Load. But why wouldn't
* blitting work otherwise?
*/
SDL_SetAlpha(source, 0, 0);
SDL_BlitSurface(source, 0, target, 0);
return target;
}
int main(int argc, char* argv[])
{
SDL_Event event;
SDL_Surface *copy, *screen, *source;
SDL_Init(SDL_INIT_VIDEO);
screen = SDL_SetVideoMode(800, 600, 0, 0);
SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0xff, 0xff, 0xff));
source = IMG_Load("source.png");
if (!source) {
fprintf(stderr, "Unable to load source image\n");
return 1;
}
copy = copy_surface(source);
SDL_BlitSurface(copy, 0, screen, 0);
SDL_Flip(screen);
while (SDL_WaitEvent(&event))
if (event.type == SDL_QUIT
|| (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_ESCAPE))
break;
SDL_Quit();
return 0;
}
You'll need source.png. I'm using a 400x400 transparent PNG with some black scribbling.
Upvotes: 0
Views: 4146
Reputation: 18409
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsetalpha.html describes blitting for each possible pixel format combination.
When alpha blending is performed, standard formula is SRC_COLOUR * SRC_ALPHA + DST_COLOUR * (1 - SRC_ALPHA)
. Destination alpha isn't used in here.
If alpha blending is enabled, and SRCALPHA flag is enabled for source surface, source alpha is used to re-calculate (blend) updated destination colours, but alpha channel of destination is left untouched. Next time this 'dst' used as source of blitting, its alpha would be used.
To avoid your problem, there are several possible ways:
memcpy
would be enough. This will overwrite contents of destination, not blend it. It also would be noticeably faster than blend. If dimensions do not match - depending on pitch
parameter you probably would need number_of_rows memcpy
's. If pixel formats do not match - copying is problematic, you need to decode each pixel from source pixel format and encode it to destination pixel format.SDL_ConvertSurface(source, source->format, 0)
. It will create new surface with the same contents. I think this way is preferred. Don't forget to free new surface later.SDL_ConvertSurface
, but converts surface to display format, not source surface's one. It is no longer available in SDL2.Also note that (4), (5) and (6) are only ways I see that allows you to keep source alpha. All blitting operations discarding source alpha, leaving destination with its own alpha values - as blitting never updates destination alpha.
Upvotes: 1