Alpha-blending is the process of using an extra value (alpha) to
combine color values (like partial transparency) instead of just
replacing one with the other. Commonly in SDL, this is done with
entire surfaces. One surface, the 'source', is blitted (drawn)
onto another 'destination' surface (also 'dest'). Now, there are
a few ways to do this and several of them are, sadly, not possible
through SDL's built-in blitter (accessible through
SDL_BlitSurface). I'll cover the readily possible ones first,
then get to the ones that you need either Sprig or some other software
for.
There are three paths to transparency: Path 1: Colorkeying (aka CK) Path 2: Per-Surface Alpha (PSA) Path 3: Per-Pixel Alpha (PPA)
All
three of these can be used in various combinations to acheive visual
awesomeness, with the exception that in SDL, per-pixel alpha takes
priority over per-surface alpha.
Colorkeying is your first
choice. If you use RGB surfaces (no alpha channel) and you want
some areas to be transparent and others not, then this is the way to
go. First, load an image with one particular color as the
background (very often people choose bright pink: RGB=255,0,255).
Now, we can use SDL_SetColorKey (note the capital K)...
// You can see why Sprig has a convenience function for this: // Using Sprig and SDL_ColorDef (new version) SPG_SetColorkey(mySurface, RGB_BRIGHTPINK(mySurface));
// Here's how to disable it SDL_SetColorKey(mySurface, 0, mySurface->format->colorkey); // I used the surface's current colorkey just so I'm not throwing away info that I might use later
Colorkeying
has advantages in that it is easy to use and it is processed
quickly. It can only give you either full transparency or full
opacity, however.
The second option is per-surface alpha.
This is a nice feature of SDL that allows you to control the alpha
value of the entire surface all at once. This is great for
certain fading effects and runs faster than per-pixel alpha. In
SDL, alpha is a measure of opacity (how opaque something is). It
ranges from 0 to 255 (n.b. 256 different values), 0 being fully
transparent, and 255 being fully opaque. You can use SDL_SetAlpha
to control your per-surface alpha...
// To disable PSA (and PPA for that matter): SDL_SetAlpha(mySurface, 0, mySurface->format->alpha); // Again, I'm saving the PSA value for later
Per-pixel
alpha is found as an extra color channel on true-color surfaces, those
that store color information in each pixel rather than in a
palette. This is the real alpha-blending that you might normally
think of. PNG (Portable Network Graphics) and TGA (Truevision
Graphics Adapter, commonly 'Targa') are two common image file formats
that support per-pixel alpha. There is a surprising lack of
simple utilities that help you to work well with the alpha channel in
images... I'm hoping to pop out one if someone doesn't beat me to
it. You can load these formats with the SDL_Image library.
Now you have a few more choices... The SDL documentation has a list of the options, but a table would do much better...
Type
SDL_SRCALPHA
SDL_SRCCOLORKEY
Per-pixel blend?
Per-surface blend?
Colorkey?
RGB->RGB(A)
On
On
->
No
Yes
Yes
RGB->RGB(A)
On
Off
->
No
Yes
No
RGB->RGB(A)
Off
On
->
No
No
Yes
RGB->RGB(A)
Off
Off
->
No
No
No
RGBA->RGB
On
On
->
Yes
No
No
RGBA->RGB
On
Off
->
Yes
No
No
RGBA->RGB
Off
On
->
No
No
No
RGBA->RGB
Off
Off
->
No
No
No
RGBA->RGBA
On
On
->
Yes
No
No
RGBA->RGBA
On
Off
->
Yes
No
No
RGBA->RGBA
Off
On
->
No
No
Yes
RGBA->RGBA
Off
Off
->
No
No
No
Wow!
There it is! Good job, self. This summarizes what you can
do with transparency in SDL. There are
waaay too many 'No's up there... No wonder I thought the Sprig
blitter was a good idea. Look at the three columns on the right
for what you want to do, then apply the appropriate flags to the source
surface. Keep in mind that when performing
alpha-blending in SDL, there is no way to blend the destination alpha
(see Sprig).
To round things out, we should chat about creating
surfaces. This is done with two functions:
SDL_CreateRGBSurface and SDL_CreateRGBSurfaceFrom. The first one
makes a surface from scratch. The second one takes some existing
pixel data and creates a new surface with it.
// Now a 32-bit 50x70 surface from memory SDL_Surface* surf2 = SDL_CreateRGBSurfaceFrom(myPixelArray, 50, 70, 32, 50*4, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
Now
the picky stuff comes in... See all those hexidecimal values I
threw in there? Those are the masks for each color channel,
RGBA. Surfaces can come in all different configurations, so these
values tell the blitter how to handle the data I throw at it.
Each pair of characters represents 8 bits and has a max value of
255. So you can look at a single 32-bit color value like
so: 0xAABBGGRR (or ABGR). I know, it looks backwards, but
that's how these are represented in little endian format. Don't
get me started on that. If you don't want to mess with endianess,
then just use SPG_CreateAlphaSurface (again with the
convenience!). You can look into SPG_CreateAlphaSurface in
sprig_inline.h to see how I deal with it (or check the SDL docs).
I only really mess with 32-bit images, so if you use a different
format, make sure that your color masks isolate their respective color
with a bit-wise AND (&). The spot where I put '50*4' is the
pitch of the image. That is the number of bytes that total one
horizontal scanline. In this case, 32 bits means 4 bytes, so I'm
just multiplying the width by that number. The way that SDL
determines if a particular surface has an alpha channel or not is by
looking at its alpha mask. So, to disable the alpha channel...
Okay.
That's it for built-in SDL stuff. Sprig (slowly) implements a few
(slow) more (slow!) options. By pushing a flag onto the blending
stack, we can change the mode of the Sprig blitter and the Sprig
primitives. Oh, by the way, the blitter can be a little slow
sometimes. These effects are not good for real-time usage.
You should render them once before you need them, then use them
wherever.
// Set it SPG_PushBlend(SPG_COMBINE_ALPHA);
// Do it SPG_Blit(mySurf, NULL, screen, NULL);
// Restore the old one so nobody else is messed up SPG_PopBlend();
The
SPG_COMBINE_ALPHA flag makes the blitter perform alpha-blending on the
destination alpha channel as well as the other color channels.
This is an 'overlay' effect. You can apply a partially
transparent surface to a fully opaque surface and get a partially
transparent result. You can apply a surface to a fully
transparent dest and get a visible result. A nice set of flags
are the SPG_COPY_ALPHA_ONLY and SPG_COMBINE_ALPHA_ONLY flags. You
can mess with the transparency and leave the colors untouched.
Check out the Sprig documentation for more.
Sweet. If you want to talk more alpha to me, go ahead.