Sign in to follow this  
Albrektson

Allegro Masking... (bitmap - bitmap = masked bitmap?)

Recommended Posts

Albrektson    122
Probably one of those stupid allegro-questions, but here goes: http://www.systemsgo.se/masking/index.html I just need to know if it's possible and in any case how to have one bitmap (in my case a PNG-file with full alpha transparency - mostly for antialiasing-reasons) overlap another (any jpeg-file), thus masking the underlying content (the jpeg-file) resulting in a masked surface. (A basic feature found in Macromedia Flash for instance). In case I wasn't clear enough, I posted a graphic instance of what I want to achieve on the URL above. Just for further clarification, I want to use allegro with directX-support (so if I'm not mistaken, an openGL-solution - which probably won't be necessary in this case, won't work - right?)... Example code would be great! Best, John

Share this post


Link to post
Share on other sites
nefthy    184
I don't realy know how alegro does stuff. But I would do it like this:

load both images replace the colors of the transparent one with the colors of the other (don't tuch the alpha) and your done. If you substract the colors of the transparent image you will get some some effects, but I don't think this is what you want to do.

Share this post


Link to post
Share on other sites
23yrold3yrold    941
To be honest, I keep getting told Allegro can do this, but I've never seen it done in practice. You could probably write your own function to do this with the Allegro bitmaps, and if you're good it wouldn't even be that slow. [smile] If you want to use Allegro with DirectX, maybe try using DirectX to do this if that's easier, too. I've never tried DirectX though, so I won't comment.

Share this post


Link to post
Share on other sites
konForce    592
Is the PNG mask only used as a 1-bit black/white masking image? If so, you could use XOR drawing mode with rectfill to accomplish this.

I cannot tell by the images on the link you posted, but it looks like you want anti-aliased edges by what you said.

[Edited by - konForce on June 3, 2005 9:14:24 PM]

Share this post


Link to post
Share on other sites
markr    1692
Create an Allegro bitmap of depth 32 bits (create_bitmap_ex).

Then blit the solid bitmap into this memory bitmap.

Then copy the alpha channel from the other image - you might need to do this pixel by pixel, or there might be an Allegro blender function which just takes the alpha channel, or you could write your own.

Either way, this is a piece of precalculation that you only need to do once, or occasionally, right, so it doesn't matter if it takes a while.

Even for a big bitmap like this, it's still only going to take 100ms probably on a slowish machine, so it's not a problem provided you only do this once per level, or occasionally.

Mark

Share this post


Link to post
Share on other sites
konForce    592
Here is a demo that illustrates how to do it: mask.zip

In short, you need to:

  • create a 32-bit bitmap for the RGBA image
  • create an 8-bit bitmap for the mask. (Color #255 is 0% transparent, Color #0 is 100% transparent.)
  • call set_write_alpha_blender() to enable the alpha layer writing
  • use draw_trans_sprite() to apply the mask on top of the 32-bit RGBA image.
  • call set_alpha_blender() to enable the alpha blitting
  • use draw_trans_sprite() to draw the 32-bit RGBA picture to another bitmap, using the alpha layer to determine opacity.

It does exactly what you want to do, except that your PNG mask file needs to be replaced with an 8-bit image that represents the mask.

Share this post


Link to post
Share on other sites
Albrektson    122
Everyone - Seriously great! Thank you! - especially nefthy - looks great. I'll just optimize it for my needs and that's one less thing to worry about ;)

Again, big thanks!

Share this post


Link to post
Share on other sites
Albrektson    122
Updated question:
I'm currently testing things with the source code provided by nefthy... (available in the mask.zip above - or posted as text below)

Now, the question is: if I want to display a different background-image instead of the black which is produced by the mask-file (how do I do this?

In other words, still the same as before (circle reveals the yellow/orange picture, but instead of black surrounding, I want another image (lets say a sky-theme)... how?


_______________________________________

ORIGINAL SOURCE:


#include <allegro.h>

int main(void)
{
BITMAP *pic, *mask; // image picture and 8-bit image mask
BITMAP *buffer; // screen buffer
int x = 0, y = 0; // coords of where to draw the mask
int k=0; // used for the key code
int mx,my; // old mouse x and y values

allegro_init();
set_color_depth(32);
set_gfx_mode(GFX_AUTODETECT_WINDOWED,800,600,0,0);
install_keyboard();
install_mouse();

buffer = create_bitmap(SCREEN_W, SCREEN_H);

// the image with alpha support *must* be 32-bit
// by default, this picture will be converted to 32-bit because
// that is what the current color depth is
pic = load_bmp("layer1.bmp", NULL);

// the mask needs to stay 8-bit, so we must disable color conversion
set_color_conversion(COLORCONV_NONE);
mask = load_bmp("mask.bmp", NULL);

if (!pic || !mask) exit(1);

// center the mask
x = pic->w/2 - mask->w/2;
y = pic->h/2 - mask->h/2;

// set up initial mouse stuff
show_mouse(screen);
poll_mouse();
mx = mouse_x;
my = mouse_y;

do
{
// move mask coords with mouse
poll_mouse();
if (mx != mouse_x || my != mouse_y)
{
x = (mx = mouse_x) - mask->w / 2;
y = (my = mouse_y) - mask->h / 2;
}

// set up the masking
set_write_alpha_blender(); // used for 'draw_trans_sprite()'
drawing_mode(DRAW_MODE_TRANS, NULL, 0,0); // used for 'rectfill()'

// set all the alpha values to 0 (transparent)
// this works because we set the drawing mode to DRAW_MODE_TRANS
rectfill(pic, 0,0,pic->w,pic->h, 0);

// update the alpha values based on the image mask
// this works because we enabled the "write alpha blender"
draw_trans_sprite(pic, mask, x,y);

// reset the drawing mode to solid and draw a rectangle around the image
drawing_mode(DRAW_MODE_SOLID, NULL, 0,0);
clear(buffer);
rect(buffer, 0,0, pic->w+1, pic->h+1, makecol(255,255,255));

// set the blender to alpha drawing
set_alpha_blender();
draw_trans_sprite(buffer, pic, 1,1); // draw the picture with its alpha

// blit buffer to screen
blit(buffer, screen, 0,0, 0,0, SCREEN_W, SCREEN_H);

// move the mask coords with keys
if (keypressed())
{
k = readkey() >> 8;
if (k == KEY_LEFT) x--;
if (k == KEY_RIGHT) x++;
if (k == KEY_UP) y--;
if (k == KEY_DOWN) y++;
}
} while (k != KEY_ESC && !mouse_b);

destroy_bitmap(buffer);
destroy_bitmap(mask);
destroy_bitmap(pic);
return 0;
}
END_OF_MAIN()

Share this post


Link to post
Share on other sites
konForce    592
Quote:
In other words, still the same as before (circle reveals the yellow/orange picture, but instead of black surrounding, I want another image (lets say a sky-theme)... how?


You need to blit the sky theme to the buffer before drawing the alpha sprite to the buffer.


// reset the drawing mode to solid
drawing_mode(DRAW_MODE_SOLID, NULL, 0,0);
clear(buffer);

// blit the sky-theme image to the buffer
blit(sky, buffer, 0,0, 0,0, sky->w,sky->h);

// set the blender to alpha drawing
set_alpha_blender();
draw_trans_sprite(buffer, pic, 1,1); // draw the picture with its alpha


Share this post


Link to post
Share on other sites
Albrektson    122
Thx! works perfectly...

one more thing I can't figure out: I can define the X and Y coordinates of both the mask and the sky-theme - but I can't figure out how to define the X and Y of the image shown through the mask (in my case the orange/yellow image).

Let's say I want to displace this (nudge it upwards along the Y-axis about 40 pixels), without displacing the sky-image (let's call this the background image) or the mask itself.

is there some ...0,0 (x,y)... I have yet to define to do this?

Note that this may seem trivial using the images, etc I've posted as example-files in the beginning of this thread - but is vital to the effect itself, using multiple maskinglayers and other images.

Please help! ;)

Share this post


Link to post
Share on other sites
konForce    592
If you want to show a different part of the Alpha image, then you need to adjust the x,y values of:

draw_trans_sprite(pic, mask, x,y);

This will put the mask at a different location, causing a differnet part of the picture to show.

If you want to put the alpha picture itself at a different location, then just adjust the x,y values of:

draw_trans_sprite(buffer, pic, x,y);

If you always draw the background picture (sky, etc) at 0,0 of the buffer, then moving the x,y in the above draw_trans_sprite() will cause the alpha picture to move around relative to the background.

Share this post


Link to post
Share on other sites
Albrektson    122
Heh... tried that same thing yesterday but for some strange reason (probably lack of sleep) is wouldn't work then. Today however, grand success ;) Thanks!


One more thing however: right now, every image and mask used is .bmp-files (32-/24- or 8-bit). Well... that's great, since everything works great, only: bmp's take a lot of diskspace compared to lets say jpegs...

... so how do I use for instance jpegs (and/or PNG-files) to do the same thing in this code? i downloaded libJPEG and linked the libJPEG.dll.a to the project - but just exchanging the .bmp to .jpg in code (and of course new jpeg-images in the dir), just didn't to it.

Help...?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this