Alpha Channel

Hello people,

I have a question about correctly using the alpha channel in 32bpp: How

do I make the per-pixel alpha work, instead of the per-surface alpha?
Thing is, I correctly read the 32bpp TGA files - that is, I get
all the pixel components right, and use SDL_MapRGBA to fill in the image
buffer. I then use SDL_CreateRGBSurfaceFrom to create the SDL surface.
Well, if I call SDL_SetAlpha for that surface, the entire surface gets
affected, instead of a per-pixel effect. Any pointers here? BTW, the
SDL_CreateRGBSurfaceFrom is being called with all the color masks set to
0.

Thanks in advance,
Miguel Osorio.

   Thing is, I correctly read the 32bpp TGA files - that is, I get

all the pixel components right, and use SDL_MapRGBA to fill in the image
buffer. I then use SDL_CreateRGBSurfaceFrom to create the SDL surface.
Well, if I call SDL_SetAlpha for that surface, the entire surface gets
affected, instead of a per-pixel effect. Any pointers here? BTW, the
SDL_CreateRGBSurfaceFrom is being called with all the color masks set to
0.

If you pass 0 as the colour masks in calls to SDL_CreateRGBSurface[From]
then some default masks will be used with no alpha channel (Amask=0).
In general, always specify the colour masks for non-palettized surfaces

the TGA loader will create surfaces with an alpha channel if and only if
the file had an alpha channel

The per-surface alpha will only be used if the surface doesn’t have an
alpha channel

Mattias Engdeg?rd wrote:

   Thing is, I correctly read the 32bpp TGA files - that is, I get

all the pixel components right, and use SDL_MapRGBA to fill in the image
buffer. I then use SDL_CreateRGBSurfaceFrom to create the SDL surface.
Well, if I call SDL_SetAlpha for that surface, the entire surface gets
affected, instead of a per-pixel effect. Any pointers here? BTW, the
SDL_CreateRGBSurfaceFrom is being called with all the color masks set to
0.

If you pass 0 as the colour masks in calls to SDL_CreateRGBSurface[From]
then some default masks will be used with no alpha channel (Amask=0).
In general, always specify the colour masks for non-palettized surfaces

the TGA loader will create surfaces with an alpha channel if and only if
the file had an alpha channel

The per-surface alpha will only be used if the surface doesn’t have an
alpha channel

Aha! I found out what was the problem: I was calling SDL_MapRGBA

passing the screen surface’s format as the format argument (by screen
surface I refer to the SDL_Surface* returned by the SDL_SetVideoMode
call). Thing is, the screen format had it’s masks set as the following:
R: 0xFF0000, G: 0x00FF00, B: 0x0000FF, A: 0. Well, what I did was create
a dummy (SDL_Surface *dummy) surface, with masks 0xFF000000, 0x00FF0000,
0x0000FF00 and 0x000000FF respectively, and then passed dummy->format as
the format argument for the SDL_MapRGBA call - it worked.
Ok, but here’s the catch: this whole dummy-surface thing doesn’t look
like the most elegant thing to do, so I was wondering: is there a way to
specify the screen surface’s masks ?

Thanks for any help,
Miguel Osorio.

Ok, but here’s the catch: this whole dummy-surface thing doesn’t look
like the most elegant thing to do, so I was wondering: is there a way to
specify the screen surface’s masks ?

No, since that’s defined by the hardware and it is usually not changeable.

It is unclear what you are trying to do, but the easiest way to read image
files (TGA or any other format) is to use IMG_Load() from SDL_image, and
then convert them to a format quickly blittable to the screen by calling
SDL_DisplayFormat() or SDL_DisplayFormatAlpha()

Hi,

I have a bmp image with a nice object and around the object is the color
0x10FF16, which I want to use as alpha channel.

I have a SDL_Surface shown to the user and know I want to blit my bmp image
to this screen, but use the alpha information as well.

SDL_Surface * alpha_img;
SDL_Surface * bmp = SDL_LoadBMP(filename);
screen = SDL_AllocSurface(bmp->flags,
200, 200,
bmp->format->BitsPerPixel,
bmp->format->Rmask,
bmp->format->Gmask,
bmp->format->Bmask,
0);
SDL_SetAlpha(screen, 0, 0);
SDL_SetColorKey(bmp, SDL_RLEACCEL, SDL_MapRGB(bmp->format, 0x10, 0xFF, 0x16));
SDL_SetAlpha(bmp, SDL_RLEACCEL, 128);
alpha_img = SDL_DisplayFormatAlpha(bmp);
SDL_BlitSurface(alpha_img, &src, screen, &dst);

But alpha information is completly ignored. The alpha_img is completely
added to the screen.

What is going wrong? Maybe I have to note that SDL_SWSURFACE is enabled.

Steinchen–
http://www.hpfsc.de/ - die Seite rund um:
Assembler, Bundeswehr, TFT LCDs, Halle/Saale, Fahrradtouren,
Wanderstaat Mauma, Raumschiff USS Nathan, Enemy Room, MLCAD Tutorial

Sebastian Stein wrote:

Hi,

I have a bmp image with a nice object and around the object is the
color 0x10FF16, which I want to use as alpha channel.

I have a SDL_Surface shown to the user and know I want to blit my bmp
image to this screen, but use the alpha information as well.

SDL_Surface * alpha_img;
SDL_Surface * bmp = SDL_LoadBMP(filename);
screen = SDL_AllocSurface(bmp->flags,
200, 200,
bmp->format->BitsPerPixel,
bmp->format->Rmask,
bmp->format->Gmask,
bmp->format->Bmask,
0);
SDL_SetAlpha(screen, 0, 0);
SDL_SetColorKey(bmp, SDL_RLEACCEL, SDL_MapRGB(bmp->format, 0x10,
0xFF, 0x16)); SDL_SetAlpha(bmp, SDL_RLEACCEL, 128);
alpha_img = SDL_DisplayFormatAlpha(bmp);
SDL_BlitSurface(alpha_img, &src, screen, &dst);

But alpha information is completly ignored. The alpha_img is
completely added to the screen.

I have a similar problem, which I posted about a few days ago. It seems
like SDL_DisplayFormatAlpha messes things up.

If I just call SetAlpha on a colour-keyed surface (for instance, to set
it to 50% opacity), it works and blends it accordingly. If I
subsequently call SDL_DisplayFormatAlpha on that surface, the idea being
to speed it up, the colour-key information is preserved but there is no
alpha blending and the image is drawn at 100% opacity (apart from the
colourkey which is 0%). If I move the SetAlpha call to after the
DisplayFormatAlpha, it has absolutely no effect (ie. it is drawn as an
opaque yet colourkeyed surface). Behaviour seems to be the same in
hardware and software mode, although obviously software is more
authoritative as it’s not limited by capabilities, only the library
code.

I am inclined to think that there’s some bugs in the whole alpha
routines, but it may just be that there’s a lot of special cases which
aren’t fully documented.–
Kylotan

SDL_Surface * bmp = SDL_LoadBMP(filename);
SDL_SetColorKey(bmp, SDL_RLEACCEL, SDL_MapRGB(bmp->format, 0x10, 0xFF, 0x16));
SDL_SetAlpha(bmp, SDL_RLEACCEL, 128);
alpha_img = SDL_DisplayFormatAlpha(bmp);
SDL_BlitSurface(alpha_img, &src, screen, &dst);

But alpha information is completly ignored. The alpha_img is completely
added to the screen.

This was a bug. Thanks to Kylotan’s great little test program, I’ve fixed
the problem in CVS: http://www.libsdl.org/cvs.php

Note that this fix changes the semantics of a blit from RGB to RGBA
without SDL_SRCALPHA set. Where before the destination alpha is set
opaque, the destination alpha is now taken from the per-surface alpha.
This is a more correct interpretation and matches the semantics of
blitting RGBA to RGBA with SDL_SRCALPHA unset.

Also, I noticed it isn’t mentioned in the docs, but the ‘alpha’ parameter
of SDL_SetAlpha() is ignored when using the function on surfaces with an
alpha channel. For these surfaces the function simply enables and disables
blending in blits.

See ya!
-Sam Lantinga, Software Engineer, Blizzard Entertainment

Kylotan [020802 03:52]:

I have a similar problem, which I posted about a few days ago. It seems
like SDL_DisplayFormatAlpha messes things up.

I am inclined to think that there’s some bugs in the whole alpha
routines, but it may just be that there’s a lot of special cases which
aren’t fully documented.

I can’t say the reason. But the SDL documentation is sometimes very short. I
solved the problem for me by writing my own alpha blending function. But I
think this is not the best way because some freaks would it do better. And
my function works only for 24bpp.

Steinchen

void BlitAlphaSurface(SDL_Surface * src, SDL_Rect * srcrect,
SDL_Surface * dst, SDL_Rect * dstrect)
{
int x, y;

Uint8 * pdst;
Uint8 * psrc;

/* alpha values from a global definition */
unsigned short r = ALPHA_CHANNEL_R;
unsigned short g = ALPHA_CHANNEL_G;
unsigned short b = ALPHA_CHANNEL_B;

/* loop through all pixels */
for (y = 0; y < dstrect->w; y++)
{
for (x = 0; x < dstrect->h; x++)
{
psrc = (Uint8 *)src->pixels
+ (y + srcrect->y)*src->pitch
+ (x + srcrect->x)*src->format->BytesPerPixel;

     /* test if the pixel has the alpha value */
     if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
     {
        if ((unsigned short) *psrc == r
            && (unsigned short) *(psrc + 1) == g
            && (unsigned short) *(psrc + 2) == b)
           continue; // yes
     } else {
        if ((unsigned short) *psrc == b
            && (unsigned short) *(psrc + 1) == g
            && (unsigned short) *(psrc + 2) == r)
           continue; // yes
     }
     /* no, so copy value from source to destination */
     pdst = (Uint8 *)dst->pixels
                 + (y + dstrect->y)*dst->pitch
                       + (x + dstrect->x)*dst->format->BytesPerPixel;
     (* (Uint32 *) pdst) = (* (Uint32 *) psrc);
  }

}

return;
}–
http://www.hpfsc.de/ - die Seite rund um:
Assembler, Bundeswehr, TFT LCDs, Halle/Saale, Fahrradtouren,
Wanderstaat Mauma, Raumschiff USS Nathan, Enemy Room, MLCAD Tutorial

I can’t say the reason. But the SDL documentation is sometimes very short. I
solved the problem for me by writing my own alpha blending function. But I
think this is not the best way because some freaks would it do better. And
my function works only for 24bpp.

There are a lot of significant optimization you can make in this code,
here I suggest only the obvious ones, like don’t recalculate the bitmap
position for each pixel, compare to constants instead that with
variables and use an #if instead of if for the endianness of the system
since it’s very unlikely that will change at runtime :slight_smile:

int delta_src_pitch = src->pitch - dstrect->w;
int delta_dst_pitch = dest->pitch - dstrect->w;

Uint32 *psrc = ((Uint8 *)src->pixels
+ (y + srcrect->y)*src->pitch
+ (x + srcrect->x)*src->format->BytesPerPixel);

Uint32 *pdst = ((Uint8 *)dst->pixels
+ (y + dstrect->y)*src->pitch
+ (x + dstrect->x)*src->format->BytesPerPixel);

for (y = 0; y < dstrect->h; y++) {
for (x = 0; x < dstrect->w; x++) {
/* test if the pixel has the alpha value /
#if SDL_BYTEORDER == SDL_BIG_ENDIAN)
if (
((Uint8 *)psrc) != ALPHA_CHANNEL_R
|| *( (Uint8 *)psrc + 1) != ALPHA_CHANNEL_G
|| *( (Uint8 )psrc + 2) != ALPHA_CHANNEL_B)
#else
if (
((Uint8 *)psrc) != ALPHA_CHANNEL_B
|| *( (Uint8 *)psrc + 1) != ALPHA_CHANNEL_G
|| *( (Uint8 *)psrc + 2) != ALPHA_CHALLER_R)
#endif
*pdst++ = psrc++; // this is the IF clause
/
only works with bpp == 4, best thing is anyway a different
function for each bpp since a check for every pixel will slow
down the algorithm a lot, another chance is something like this:
{
*pdst = *psrc;

	((Uint8 *)psrc)+= src->format->BytesPerPixel;
	((Uint8 *)pdst)+= src->format->BytesPerPixel;
        }

that should work with 24/32 bpp.
*/
}
pdst+=delta_dst_pitch;
psrc+=delta_src_pitch;
}On Fri, 2002-08-02 at 03:58, Sebastian Stein wrote:

void BlitAlphaSurface(SDL_Surface * src, SDL_Rect * srcrect,
SDL_Surface * dst, SDL_Rect * dstrect)
{
int x, y;

Uint8 * pdst;
Uint8 * psrc;

/* alpha values from a global definition */
unsigned short r = ALPHA_CHANNEL_R;
unsigned short g = ALPHA_CHANNEL_G;
unsigned short b = ALPHA_CHANNEL_B;

/* loop through all pixels */
for (y = 0; y < dstrect->w; y++)
{
for (x = 0; x < dstrect->h; x++)
{
psrc = (Uint8 *)src->pixels
+ (y + srcrect->y)*src->pitch
+ (x + srcrect->x)*src->format->BytesPerPixel;

     /* test if the pixel has the alpha value */
     if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
     {
        if ((unsigned short) *psrc == r
            && (unsigned short) *(psrc + 1) == g
            && (unsigned short) *(psrc + 2) == b)
           continue; // yes
     } else {
        if ((unsigned short) *psrc == b
            && (unsigned short) *(psrc + 1) == g
            && (unsigned short) *(psrc + 2) == r)
           continue; // yes
     }
     /* no, so copy value from source to destination */
     pdst = (Uint8 *)dst->pixels
                 + (y + dstrect->y)*dst->pitch
                       + (x + dstrect->x)*dst->format->BytesPerPixel;
     (* (Uint32 *) pdst) = (* (Uint32 *) psrc);
  }

}

Gabriele Greco [020805 16:51]:

here I suggest only the obvious ones, like don’t recalculate the bitmap
position for each pixel,

Yes, in my first version I allready had this, but it didn’t worked at all
and so I took it back to have a better overview.

compare to constants instead that with
variables and use an #if instead of if for the endianness of the system
since it’s very unlikely that will change at runtime :slight_smile:

Yes, ok I see.

I hope the fix is included in the next stable release so that I don’t have
to use my function any more. In some cases SDL_BlitSurface and before a
setColorkey works as expected.

Steinchen–
http://www.hpfsc.de/ - die Seite rund um:
Assembler, Bundeswehr, TFT LCDs, Halle/Saale, Fahrradtouren,
Wanderstaat Mauma, Raumschiff USS Nathan, Enemy Room, MLCAD Tutorial