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.x*4;*

dpixels=(Uint8 *)dest->pixels+dest->pitch*(i+r2.y)+r2.x4;

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