Compositing surfaces

Hello,

I’m using SDL to create a simple windowing system. Each window has a
client surface and a decoration surface. These two are composited to a
third surface which is then drawn to the screen. The composition is
stored and can be drawn whenever needed without having to recomposite
each time.

The composition isn’t working as I would expect.

All surfaces are 32 bit and have an alpha channel (alpha mask is set and
the surfaces are created with SDL_SRCALPHA). The first thing I do when I
composite is to clear the composition surface with SDL_FillRect, passing
black with 0 alpha so that the surface is now transparent. Then I
SDL_BitSurface first the decoration surface and then the client surface
onto the composition surface. Both of these surfaces contain alpha
channels (as described above) but these seem to be ignored and the alpha
channel of the final composition is still 0, so the whole thing is
invisible.

If I clear with opaque black at the start the final composition becomes
visible. Likewise, if I will with black with an alpha of 0x88, that’s
the opacity of the final surface.

Why when I SD_BltSurface isn’t the alpha channel being copied accross?

Thanks

Chris Seaton

Hi,

Chris Seaton wrote:

All surfaces are 32 bit and have an alpha channel (alpha mask is set
and the surfaces are created with SDL_SRCALPHA). The first thing I do
when I composite is to clear the composition surface with
SDL_FillRect, passing black with 0 alpha so that the surface is now
transparent. Then I SDL_BitSurface first the decoration surface and
then the client surface onto the composition surface. Both of these
surfaces contain alpha channels (as described above) but these seem to
be ignored and the alpha channel of the final composition is still 0,
so the whole thing is invisible.

This sounds sooo familiar :wink:

When blitting from an alpha surface to an alpha surface, SDL doesn’t
copy the alpha channel. What I eventually did was copy pygame’s
alphablit function (http://pygame.org/). Some say that there is a way to
make SDL do the correct blits, but I’ve never managed that. Also, the
docs for SDL_SetAlpha() say:

“Note that RGBA->RGBA blits (with SDL_SRCALPHA set) keep the alpha of
the destination surface. This means that you cannot compose two
arbitrary RGBA surfaces this way and get the result you would expect
from “overlaying” them; the destination alpha will work as a mask.”

Have a nice holiday,
Sebastian

SDL does’nt handle alpha->alpha blits correctly, it’s a known issue. The
only option short of not trying to composite surfaces together that you have
is to write your own blitter than can handle this case.> ----- Original Message -----

From: chris@chrisseaton.com (Chris Seaton)
To:
Sent: Wednesday, December 24, 2003 10:02 AM
Subject: [SDL] Compositing surfaces

Hello,

I’m using SDL to create a simple windowing system. Each window has a
client surface and a decoration surface. These two are composited to a
third surface which is then drawn to the screen. The composition is
stored and can be drawn whenever needed without having to recomposite
each time.

The composition isn’t working as I would expect.

All surfaces are 32 bit and have an alpha channel (alpha mask is set and
the surfaces are created with SDL_SRCALPHA). The first thing I do when I
composite is to clear the composition surface with SDL_FillRect, passing
black with 0 alpha so that the surface is now transparent. Then I
SDL_BitSurface first the decoration surface and then the client surface
onto the composition surface. Both of these surfaces contain alpha
channels (as described above) but these seem to be ignored and the alpha
channel of the final composition is still 0, so the whole thing is
invisible.

If I clear with opaque black at the start the final composition becomes
visible. Likewise, if I will with black with an alpha of 0x88, that’s
the opacity of the final surface.

Why when I SD_BltSurface isn’t the alpha channel being copied accross?

Thanks

Chris Seaton


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

I wrote a message some moths ago with a blitting routine that corrects
this. With this function, you can composite various Surfaces, and then
blit them to the final surface having a good behavior with the alpha
channel. I include here again the message I sent:

For sure that some of you have noticed that if you have 3 surfaces: A, B
and C, and you do the following:

1.- blit (blit C over B) A, i.e. blit C over B, and then blit the result
over A

or

2.- blit C over (blit B over A), i.e. blit B over A, and then blit C
over the result

You obtain different results if you have some alpha values different
than 0 or 255.
However, this is a problem sometimes, since if B and C are fixed, you
are making 2 blits every time you redraw your screen. To solve this
problem, I’ve made a function that blits a surface over another that
acomplished the asociative property, i.e. “blit (blit C over B) A” is
equal to “blit C over (blit B over A)”. So, you can blit C over B, and
at each frame just blit this result over A. Resulting in a single blit
per frame.

I don’t know if some one is interested in such a function. But it’s been
very usefull to me.
I include the source code here (It’s completely unoptimized, but it does
the work). Notice that I’ve divided by 255 instead of 256 to normalize
the alpha values. But this is because the alpha values are between 0 and
255 and not between 0 and 256. I just wanted EXACT calculations.

void surface_blit_rightalpha(SDL_Surface *orig,SDL_Rect *or,SDL_Surface
*dest,SDL_Rect *dr)
{
int i,j;
SDL_Rect r1,r2;
Uint8 *opixels,*dpixels;
int a1,a2;
int ap,app;

if (orig->format->BytesPerPixel!=4 ||
dest->format->BytesPerPixel!=4) return;

if (or!=0) {
r1=or;
} else {
r1.x=0;
r1.y=0;
r1.w=orig->w;
r1.h=orig->h;
} /
if */

if (dr!=0) {
r2=dr;
} else {
r2.x=0;
r2.y=0;
} /
if */

if (r1.x<0) {
r1.w+=r1.x;
r1.x=0;
} /* if /
if (r1.x>=dest->w) return;
if (r1.y<0) {
r1.h+=r1.y;
r1.y=0;
} /
if */
if (r1.y>=dest->h) return;

if (r2.x<0) {
r1.w+=r2.x;
r2.x=0;
} /* if /
if (r2.x>=dest->w) return;
if (r2.y<0) {
r1.h+=r2.y;
r2.y=0;
} /
if */
if (r2.y>=dest->h) return;
if (r1.w<0) return;
if (r2.x+r1.w>dest->w) r1.w=dest->w-r2.x;
if (r1.h<0) return;
if (r2.y+r1.h>dest->h) r1.h=dest->h-r2.y;

SDL_LockSurface(orig);
SDL_LockSurface(dest);

for(i=0;i<r1.h;i++) {
opixels=(Uint8 )orig->pixels+orig->pitch(i+r1.y)+r1.x4;
dpixels=(Uint8 )dest->pixels+dest->pitch(i+r2.y)+r2.x
4;
for(j=0;j<r1.w;j++,opixels+=4,dpixels+=4) {
a2=opixels[AOFFSET];
if (a2!=0) {
a1=dpixels[AOFFSET];

           ap=a1+a2-(a1*a2)/255;
           if (ap>255) ap=255;
           if (ap<0) ap=0;

           if (a2==0) app=0;
                 else app=(-a2*255)/(((a1*a2)/255)-a1-a2);
           if (app>255) app=255;
           if (app<0) app=0;

dpixels[ROFFSET]=(opixels[ROFFSET]app+dpixels[ROFFSET](255-app))/255;

dpixels[GOFFSET]=(opixels[GOFFSET]app+dpixels[GOFFSET](255-app))/255;

dpixels[BOFFSET]=(opixels[BOFFSET]app+dpixels[BOFFSET](255-app))/255;
dpixels[AOFFSET]=ap;
} /* if /
} /
for /
} /
for */

SDL_UnlockSurface(orig);
SDL_UnlockSurface(dest);
} /* surface_blit_rightalpha */_______________________________________________
SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl