Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Transparency and translucency together

Credits go to Dustin Dettmer for helping out!
This thread is locked; no one can reply to it. rss feed Print
Transparency and translucency together
Nathan Holts
Member #8,442
March 2007

First off, my apologies for bothering you folk with what may well be a ridiculously simple problem. I'm sure there's an obvious solution that I just keep overlooking, but I can't for the life of me see it.

Alright, so I have a sprite('A'), which has a pure magenta (transparency) background. I want to draw another image ('B') over it translucently, in such a way as to only draw over the non-transparent pixels in A, whilst leaving the transparent pixels their current colour.

I can't think of a clearer way to word that, so perhaps an example would be better.

http://img293.imageshack.us/img293/8356/examplewh7.png
(please excuse the atrocious placeholder graphics, they're just for example's sake)

A is the original sprite, B the image I want to draw over it. When I use draw_trans_sprite to do this, I get C as a result, whilst the result I want is labelled D.

If anyone can please tell me how I can get that result, short of writing my own blitting function, I'd be grateful.

Onewing
Member #6,152
August 2005
avatar

My guess is your solution is in

drawing_mode.

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Matt Smith
Member #783
November 2000

drawing_mode won't help. I think you'll need your own blitting function.
e.g (untested)

1 
2 bitmap * bmp_a, * bmp_b, * bmp_d; //all same size. OK if *bmp_d==*bmp_a or *bmp_d==*bmp_b;
3 int d_alpha = 0 to 255
4 int color_a,color_b; //temp vars used to store pixel colors
5 
6 for (y=0; y<bmp_d->height; y++)
7 for (x=0 ;x< bmp_d->width; x++)
8 if ((color_a = _getpixel(bmp_a,x,y))!=bitmap_mask_color(bmp_a))
9 {
10 color_b = _getpixel(bmp_b, x, y);
11 
12 r = (getr(color_a) * d_alpha + getr(color_b) * (255 - d_alpha)) /255;
13 g = (getg(color_a) * d_alpha + getg(color_b) * (255 - d_alpha)) /255;
14 b = (getb(color_a) * d_alpha + getb(color_b) * (255 - d_alpha)) /255;
15
16 _putpixel(bmp_d, x, y, makecol(r,g,b);
17 } else _putpixel(bmp_d, x, y, color_a); //saves need to pre-clear bmp_d;

HardTranceFan
Member #7,317
June 2006
avatar

Or create a mask of image A (making all none-magenta colours transparent), resulting in B, combine it with C to create D, and use that on A to produce E?

591633

--
"Shame your mind don't shine like your possessions do" - Faithless (I want more part 1)

Nathan Holts
Member #8,442
March 2007

One Wing: Thanks but I'd already tried this one (asuming you're thinking the same way I am), it seems it wont work with sprites taller than 64 pixels (mine are 80).

Matt Smith: That's what I was afraid of... My main concern with a custom blit function being one of speed.

HardTranceFan: This is what I was originally thinking, but am stuck on combining B and C. I can't figure out how to make the white transparent instead of magenta, or is there another way to do this? (again, my apologies if this is really simple, I've checked the documentation and couldn't see anything, but then again I'm not sure exactly what I'm looking for)

Matt Smith
Member #783
November 2000

Surprisingly, a custom blit function written like that isn't too slow. It can be optimised somewhat (usually at the expense of having seperate versions for each color depth) but this is basically what all allegro's blit functions do anyway. As it is, it is roughly half the speed of the best possible software solution.

Dustin Dettmer
Member #3,935
October 2003
avatar

A custom blit function is overkill. Heres one idea:

1static unsigned long reverseTransBlender24(int x, int y, int n)
2{
3 unsigned long ret = y;
4 
5 if(y != makecol24(255, 0, 255))
6 ret = makecol24(
7 getr24(x) * n + getr24(y) * (255 - n),
8 getg24(x) * n + getg24(y) * (255 - n),
9 getb24(x) * n + getb24(y) * (255 - n));
10 
11 return ret;
12}
13 
14...
15 
16 
17BITMAP *theGuy, *thePattern;
18 
19set_blender_mode(0, 0, reverseTransBlender24, 255, 255, 255, 127);
20 
21draw_trans_sprite(theGuy, thePattern, 0, 0);
22blit(theGuy, screen, ... );

Kris Asick
Member #1,424
July 2001

HardTranceFan's got the right idea, but there's a simpler method than his, and it takes advantage of Allegro's ability to blit 8-bit images onto images of a higher bit depth.

You will end up with four bitmaps. All of which should be truecolour, except B, which should be 8-bit:

A: Base, Masked Image
B: Mask for A
C: Transparent Image
D: Final Bitmap

Image B should have the transparent area of A set to a palleted magic pink and the non-transparent area set to colour index 0.

Then, all you do:

Step 1: Blit C to D.
Step 2: Blit A translucently to D.
Step 3: Use draw_sprite() to blit B to D.

Done! (NOTE: You can also swap A and C between steps 1 and 2. It depends on how you want to control the translucency.)

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Nathan Holts
Member #8,442
March 2007

Dustin Dettmer: I couldn't get the code you supplied to work, even after tinkering for a while, but it did point me in the right direction. I wouldn't have even thought of a custom blender (alright, I didn't even know they existed, I've been learning this stuff as it comes up), but I've now managed to get one working that does what I needed it to. Many thanks for your help.

orz
Member #565
August 2000

AASTR2 will happily do that sort of thing. It's reasonably fast if you disable the anti-aliasing part.

Dustin Dettmer
Member #3,935
October 2003
avatar

Nathan said:

... but I've now managed to get one working that does what I needed it to. Many thanks for your help.

Awesome :)

Go to: