[Managed C#] masking using a paletted mask-map

Got questions? Got answers? Go here for both.

Moderator: MaxCoderz Staff

King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

[Managed C#] masking using a paletted mask-map

Post by King Harold »

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..
User avatar
kv83
Maxcoderz Staff
Posts: 2735
Joined: Wed 15 Dec, 2004 7:26 pm
Location: The Hague, Netherlands
Contact:

Post by kv83 »

I don't get your question. Can't you post the pictures and then post what the result should be?
Image
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

I have absolutely no idea what you're asking, sorry. Sample pictures, as kv requested, would be good :)
User avatar
tr1p1ea
Maxcoderz Staff
Posts: 4141
Joined: Thu 16 Dec, 2004 10:06 pm
Location: I cant seem to get out of this cryogenic chamber!
Contact:

Post by tr1p1ea »

I think he has one image that *may* be a combination of possible images to which can be achieved by applying a certain mask to show/remove any needed/unwanted elements?
"My world is Black & White. But if I blink fast enough, I see it in Grayscale."
Image
Image
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

tr1p is THE man! 8)

ok here are some pics that explain what i want:

the outside:
Image
its "build mask" (meaning that one of those colours is meant to be build first, and then the next, etc
Image
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

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:
  • 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.
User avatar
KermMartian
Calc Wizard
Posts: 549
Joined: Tue 05 Jul, 2005 11:28 pm
Contact:

Post by KermMartian »

I smell an AOE clone.
Image Image Image
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

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)
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

King Harold wrote:isn't that going to be terribly slow though?
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.

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.
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

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))
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

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.
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

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 :P

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..
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

I'm not sure what sort of code you're looking for, really.

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;
	
}
(Written without testing, standard disclaimers apply!)
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

looks ok, thanx loads! :D
wouldnt it blacken the pixels that havent been build yet though? (not that it matters, i can do something about it, no problem at all)
I'll try it as soon as i can.
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

King Harold wrote:looks ok, thanx loads! :D
wouldnt it blacken the pixels that havent been build yet though?
It shouldn't do - the Bitmap is locked as 32bpp ARGB, which means that 0 is completely transparent, not black.
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);
Post Reply