[Managed C#] masking using a paletted mask-map
Moderator: MaxCoderz Staff
-
- Calc King
- Posts: 1513
- Joined: Sat 05 Aug, 2006 7:22 am
[Managed C#] masking using a paletted mask-map
I know the title is a little cryptic so I'll try to explain the problem.
Basically there are 2 pictures involved, one with the actual picture data and one with "multiple" masks. Multiple because its in P8 format (8 bit pallet). The point is to have several masks in 1 picture. Why? no idea. I just dont want to convert them all to Black/White masks because i would have to do that for 64 pictures and that would take some time.
the actual Point of this is to first mask out everything and then add elements of the picture by changing the mask to "disclude" a certain colour so that more of the real picture is shown.
unfortunately i have no idea how to actually code this..
Basically there are 2 pictures involved, one with the actual picture data and one with "multiple" masks. Multiple because its in P8 format (8 bit pallet). The point is to have several masks in 1 picture. Why? no idea. I just dont want to convert them all to Black/White masks because i would have to do that for 64 pictures and that would take some time.
the actual Point of this is to first mask out everything and then add elements of the picture by changing the mask to "disclude" a certain colour so that more of the real picture is shown.
unfortunately i have no idea how to actually code this..
-
- Calc King
- Posts: 1513
- Joined: Sat 05 Aug, 2006 7:22 am
- benryves
- Maxcoderz Staff
- Posts: 3087
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Is the initial image going to used indexed colours too, or not?
I cannot think of any automatic way of doing it. Personally, I'd do this:
I cannot think of any automatic way of doing it. Personally, I'd do this:
- Lock both Bitmaps (using Bitmap.LockBits); the top one as 32 bit ARGB and the lower one as 8-bit indexed. ReadWrite access is required for the top one, Read for the lower.
- Copy both to arrays using Marshal.Copy - an int[] array for the upper one, a byte[] array for the lower.
- Have a for-loop that cycles through each byte in the mask's pixel data. If the byte isn't <colour you want to mask by>, set the corresponding int in the upper image's array to 0.
- Marshal.Copy the int data back into the first bitmap.
- Unlock both Bitmaps, then dispose the lower one.
- KermMartian
- Calc Wizard
- Posts: 549
- Joined: Tue 05 Jul, 2005 11:28 pm
- Contact:
-
- Calc King
- Posts: 1513
- Joined: Sat 05 Aug, 2006 7:22 am
isn't that going to be terribly slow though?
@kerm: then obviously you do not play AOE because this building doesnt even remotely look like an AOE building. AOE buildings are rotated 45 degrees. AND AOE buildings are build in an idiotic way (you see no change for a long time and then.. POOF the building is finished)
@kerm: then obviously you do not play AOE because this building doesnt even remotely look like an AOE building. AOE buildings are rotated 45 degrees. AND AOE buildings are build in an idiotic way (you see no change for a long time and then.. POOF the building is finished)
- benryves
- Maxcoderz Staff
- Posts: 3087
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Not really. The only slow thing you can do is use SetPixel/GetPixel as they need to lock/unlock the entire Bitmap each time, rather than just locking it once and dumping the data to and from an array.King Harold wrote:isn't that going to be terribly slow though?
If speed is really an issue; Clone the Bitmap and build up/cache the various stages in memory the first time you load the images.
-
- Calc King
- Posts: 1513
- Joined: Sat 05 Aug, 2006 7:22 am
well i'll first try it the slower way and i'll see how fast it will be. I can't really accept framerates under 30 FPS and i may need up to 10 of those things displayed at the same time (more is possible but not realistic). Finished buildings shouldnt slow anything down at all.
(I had to pre-load the map data though, that was the real bottleneck, but it runs at 55 FPS now (in release mode))
(I had to pre-load the map data though, that was the real bottleneck, but it runs at 55 FPS now (in release mode))
- benryves
- Maxcoderz Staff
- Posts: 3087
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Sorry, I had assumed you were doing this as a one-off conversion thing. Regenerating the mask each frame is rather silly.
I also thought that you needed to only return data from the upper image based on a single mask from the lower image.
A faster way of doing this is quite simple - as long as the palette is ordered correctly, just cycle through the pixels in the upper image, and if the corresponding palette index in the mask is > the desired built amount, blank it out.
I also thought that you needed to only return data from the upper image based on a single mask from the lower image.
A faster way of doing this is quite simple - as long as the palette is ordered correctly, just cycle through the pixels in the upper image, and if the corresponding palette index in the mask is > the desired built amount, blank it out.
-
- Calc King
- Posts: 1513
- Joined: Sat 05 Aug, 2006 7:22 am
yes i was thinking along those lines.. there is a huge problem though, the pallete is messed up almost randomly, im going to have to figure out the formula.. silly artists.. but without them i couldnt do a thing
edit: sorry artists.. its ordered but i was thinking chaotically..
it may sound stupid, but.. how do i actually do this? it all sounds so simple.. but i think i need some tips..
edit: sorry artists.. its ordered but i was thinking chaotically..
it may sound stupid, but.. how do i actually do this? it all sounds so simple.. but i think i need some tips..
- benryves
- Maxcoderz Staff
- Posts: 3087
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
I'm not sure what sort of code you're looking for, really.
(Written without testing, standard disclaimers apply!)
Code: Select all
private Bitmap CreatePartiallyBuiltCastle(Bitmap sourceImage, Bitmap sourceMask, int buildLevel) {
// Clone the input bitmap to have something to work with
Bitmap Output = (Bitmap)sourceImage.Clone();
// Get width/height
int Width = Output.Width;
int Height = Output.Height;
// Create two arrays to dump the pixel data into
int[] SourceImageArray = new int[Width * Height];
byte[] SourceMaskArray = new int[Width * Height];
// A rectangle to cover the entire image
Rectangle FrameRectangle = new Rectangle(0, 0, Width, Height);
// Lock source
BitmapData SourceImageData = sourceImage.LockBits(FrameRectangle, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
// Dump into array
Marshal.Copy(SourceImageData.Scan0, SourceImageArray, 0, Width * Height);
// Unlock
sourceImage.UnlockBits(SourceImageData);
// Lock mask
BitmapData SourceMaskData = sourceMask.LockBits(FrameRectangle, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
// Dump into array
Marshal.Copy(SourceMaskData.Scan0, SourceMaskArray, 0, Width * Height);
// Unlock
sourceMask.UnlockBits(SourceMaskData);
// Process!
// Go through each pixel, and blank it out if the mask colour is greater/equal to the build level.
// This assumes that colour #0 is the first to be drawn, #1 is the second and so on.
for (int i = 0; i < Width * Height; ++i) {
if (SourceMaskArray[i] >= buildLevel) SourceImageArray[i] = 0;
}
// Write to our output image
BitmapData OutputData = Output.LockBits(FrameRectangle, ImageLockMode.WriteOnly, PixelFormat.32bppArgb);
// Dump from array
Marshal.Copy(SourceImageArray, 0, OutputData.Scan0, Width * Height);
// Unlock
Output.UnlockBits(OutputData);
// Return!
return Output;
}
-
- Calc King
- Posts: 1513
- Joined: Sat 05 Aug, 2006 7:22 am
- benryves
- Maxcoderz Staff
- Posts: 3087
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
It shouldn't do - the Bitmap is locked as 32bpp ARGB, which means that 0 is completely transparent, not black.King Harold wrote:looks ok, thanx loads!
wouldnt it blacken the pixels that havent been build yet though?
If, of course, the loaded image isn't 32bpp ARGB, instead of using the Clone part it might be better to just to -
Code: Select all
Bitmap Output = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);