Alpha Blending

Is there a way to blend colors that have an alpha < 256 prior blending it with the buffer?

Normally the process is Buffer<-PixelA<-PixelB<-PixelC

I want to do: PixelA<-PixelB<-PixelC then have Buffer<-PixelA (PixelA is now the blend of A+B+C).

Example usage:
Sorted furthest to nearest objects in 3D space, there are areas that are composed of similar overlapping areas (which have varying degrees of alpha). It is unknown what exists on the buffer, however, a drawing improvement can be made if I can compute the overlapped areas into a single Color, and then blend it with the buffer instead of having to recompute the order for every pixel.

Thanks in advance.
I once had someone make me a program, i doubt i could do it myself even now. I know the mathematics, but the drawing routines are beyond my programming at this point.

I don't have my text file that I had but let's see if i can repeat the process...

a color is made up of RGB values, each ranging from 0 to 255. Take each one seperately, subtract the smallest from the largest to get the difference.. multiply this difference by the opacy (0 to 1.00) and if the smallest was the back color, add the smallest. If the smallest was the forecolor, subtract this from the largest. or something like that.

Then repeat for green and blue.

It's beena while and I can't find my text file where I had it all figgured out, but play around with this in paint with a calculator and you'll figgure it out. I'm gonna try to find that text file.

Found it.
Let R = the value of Red. R1 is bottom color, R2 is top color
P = Percentage of R2 to show through R1.
1
2
3
4
If (R1 >= R2)
  R = (R1-R2) * (P*0.01) + R2;
else
  R = (R2-R1) * ((100-P)*0.01) + R1;

Repeat for G and B (green and blue)
Last edited on
I just happened to be working on alpha blending last month.
Here's a complete routine to blend two 32-bit surfaces of equal size without offset. It doesn't use costly integer-float conversion (that was kinda sloppy of you, Arkanaar). Written using SDL:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
Alpha Blending HowTo:

'src' is the upper layer and 'dst' is the lower layer.
The blend is performed downwards so that 'dst' will be the sum of both layers.
If several layers need to be blended, the best way to do this is to start with a
final layer which will be completely black and transparent and blend all layers
into it from the bottom up.
*/
void alphaBlending(SDL_Surface *src,SDL_Surface *dst){
    int w0=src->clip_rect.w,
        h0=src->clip_rect.h;
    SDL_LockSurface(src);
    SDL_LockSurface(dst);
    uchar *pos0=(uchar *)src->pixels;
    uchar *pos1=(uchar *)dst->pixels;
    uchar Roffset0=(src->format->Rshift)>>3;
    uchar Goffset0=(src->format->Gshift)>>3;
    uchar Boffset0=(src->format->Bshift)>>3;
    uchar Aoffset0=(src->format->Ashift)>>3;
    uchar Roffset1=(dst->format->Rshift)>>3;
    uchar Goffset1=(dst->format->Gshift)>>3;
    uchar Boffset1=(dst->format->Bshift)>>3;
    uchar Aoffset1=(dst->format->Ashift)>>3;
    unsigned advance0=src->format->BytesPerPixel;
    unsigned advance1=dst->format->BytesPerPixel;
    bool alpha0=(Aoffset0!=Roffset0 && Aoffset0!=Goffset0 && Aoffset0!=Boffset0);
    bool alpha1=(Aoffset1!=Roffset1 && Aoffset1!=Goffset1 && Aoffset1!=Boffset1);
    for (int y0=0;y0<h0;y0++){
        for (int x0=0;x0<w0;x0++){
            uchar r0=pos0[Roffset0];
            uchar g0=pos0[Goffset0];
            uchar b0=pos0[Boffset0];
            uchar *r1=pos1+Roffset1;
            uchar *g1=pos1+Goffset1;
            uchar *b1=pos1+Boffset1;
            //Here starts the actual alpha blending operation:
            //Check whether src has alpha (this doesn't mean that it's
            //transparent. It means it has no alpha channel, and is therefore
            //opaque and will simply block the layers beneath it).
            if (alpha0){
                uchar a0=pos0[Aoffset0];
                short deltar=r0-*r1;
                short deltag=g0-*g1;
                short deltab=b0-*b1;
                //Using integer-float-integer conversions here more than triples
                //execution time.
                (*r1)+=(deltar*a0)/255;
                (*g1)+=(deltag*a0)/255;
                (*b1)+=(deltab*a0)/255;
                if (alpha1){
                    uchar *a1=pos1+Aoffset1;
                    short temp=*a1+a0;
                    *a1=temp>255?255:temp;
                }
            }else{
                *r1=r0;
                *g1=g0;
                *b1=b0;
                /*
                Odd... Right now I feel I should have added
                
                if (alpha1)
                    pos1[Aoffset1]=255;
                
                If you get incorrect results, try adding that.
                */
            }
            //...And it ends here.
            pos0+=advance0;
            pos1+=advance1;
        }
    }
    SDL_UnlockSurface(dst);
    SDL_UnlockSurface(src);
}
Last edited on
Thanks people, I haven't had time to try these yet, but I will.
Helio,
Thanks, I did some more testing and found your method worked the best.
Last edited on
Topic archived. No new replies allowed.