Creating Masks


You can create masks with a bitmap editor. Just use Save As to copy the image, and then fill with black every pixel you want to be opaque and fill with white every pixel you want to be transparent. This works, but it isn’t a particularly good idea. First, it’s difficult to change the mask every time you change the image. Second, if you have a color image, you’ll end up with a color mask consisting of two colors, although you need only a monochrome mask. Depending on your video system, the color mask can take up a lot more memory than a monochrome mask.


It’s also possible to create a mask by looping through every pixel in a picture and setting all the colored pixels to black and all the background bits to white, but I don’t recommend it. Instead, you can sneak through the back door and create masks on the fly by copying them. Windows will automatically translate a color bitmap into a monochrome bitmap (and vice versa) when you copy it. Therefore, in order to get a monochrome mask, simply copy a color bitmap to a monochrome bitmap of the same size. All the nonwhite pixels will come out black. The trick is getting a monochrome bitmap. As it turns out, you get one by default when you create a memory DC and a bitmap to go into it.


A memory device context is just like any other device context except that it exists only in memory. You can’t see it, but you can copy it to the DC of a visible object such as a form, a picture box, or a printer. In other words, it’s like a picture box with Visible set to False—except that it takes up fewer resources. Memory DCs are handy because you can use them to mix masks and images out of sight and then, when everything is ready, copy the invisible DC to the visible one. This reduces the number of visible blits and thus reduces the amount of flicker during animation.


Here’s how Bit Blast creates a mask:

Private Sub cmdMask_Click()
Dim hdcMono As Long, hbmpMono As Long, hbmpOld As Long

‘ Create memory device context
hdcMono = CreateCompatibleDC(0)
‘ Create monochrome bitmap and select it into DC
hbmpMono = CreateCompatibleBitmap(hdcMono, dxBlt, dyBlt)
hbmpOld = SelectObject(hdcMono, hbmpMono)
‘ Copy color bitmap to DC to create mono mask
BitBlt hdcMono, 0, 0, dxBlt, dyBlt, pbSrc.hDC, 0, 0, SRCCOPY
‘ Copy mono memory mask to visible picture box
BitBlt pbDst.hDC, 0, 0, dxBlt, dyBlt, hdcMono, 0, 0, SRCCOPY
pbDst.Refresh
‘ Clean up
Call SelectObject(hdcMono, hbmpOld)
Call DeleteDC(hdcMono)
Call DeleteObject(hbmpMono)
End Sub

This code creates a mask in a memory DC and then copies that DC to the specified destination. The 0 passed to CreateCompatibleDC tells it to make the new DC compatible with the screen. You could pass it the HDC of something else (a printer, perhaps) to make it compatible with that object. Animation doesn’t work too well on printers, so the screen is usually a good choice. CreateCom­patibleBitmap creates a bitmap of the given size. At this point, the DC is an imaginary object with no size and no features; you must select something into it with SelectObject to make it real. You might ask (as I did) why a bitmap compatible with a DC compatible with a color screen comes out monochrome. Well, it’s just one of those things.


Once you have a monochrome bitmap of the correct size, simply copy and let Windows do the conversion. In Bit Blast, I copy the resulting mask back to a visible picture, but there’s usually no need to see the mask so you can leave it in memory. Finally you must clean up the mask when you’re done. In Bit Blast, you’re done as soon as you copy the mask, but in real life you’ll probably need to keep the mask around for the life of the image you’re animating. You can clean up in Form_Unload or Class_Terminate. Just be sure to do it. I can assure you from hard experience that the consequences of forgetting are unpleasant.