Inverted Masks with BitBlt


      First off, what is BitBlt? It is a graphical API that lets you copy one image to another place with a bunch of different options. You can make the object non-square, with a mask, or you can flip it, rotate it, or stretch it with a bunch of it's "sister" APIs. This is the syntax of declaration as of VB6 SP4:

Declare Function BitBlt Lib "gdi32" Alias "BitBlt" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long

      I will now explain each variable in depth. hDestDC is the hDC of the destination. This means you can use a form, a picturebox, or anything with an hDC. EX. Picture1.hDC. The second one, X, is where you want the left of the image to be on the destination. This value is in PIXELS, not twips. The third value (Y) is where you want the top of the image. This is also a pixel value. nWidth is how large the image is, horizontally in PIXELS. If you specify the wrong width, it will not stretch, however, it will copy too much or too little. The height is the same as nWidth, except for the fact that it is called nHeight. hSrcDC is the hDC of the source, where you are getting the image from. xSrc is where you want the left of the image to be on the source. This is also a PIXEL value. ySrc is where you want the top of the image on the source to begin. Once again, this is a PIXEL value. We will be explaining dwRop in a second. Another term for the laster constant is a RASTER OPERATION FLAG.

      So now you know what BitBlt is. But how do you use it? There are several different styles, using different RASTER OPERATION flags each. But how do you know what ones do what? Here is a list of the ones I use:

  • SRCCOPY = &HCC0020 - Copys the RECTANGULAR Source Region to the Destination Region.
  • SRCAND = &H8800C6 - Used for MASKS, ANDS the Source and Destination Regions together.
  • SRCPAINT = &HEE0086 - Used for SPRITES with MASKS, Paints the SPRITE onto the Non-Transparent Regions specified by the MASK.
  • MERGEPAINT = &HBB0226 - Used for when the Background of a SPRITE is not BLACK. Use this instead of SRCAND and use SRCAND instead of SRCPAINT.

          Copy the BitBlt declaration into your project. Make sure to add a public to the start if this is in a module, and a private if it is in a form. Add const to the start of each raster operation and add public/private as necessary for forms and modules. Now you're ready to code. I always find it better to make a "wrapper" function for the API calls, depending on what you want to do. This makes it, in the end, easier to code. The next code snippet is my own function for the SRCCOPY raster command.

    Function sCopy(SrcDC as Long, DstDC as Long, dW as Long, dH as Long, X as Long, Y as Long) as Long
       sCopy = BitBlt(DstDC, X, Y, dW, dH, SrcDC, 0, 0, SRCCOPY
    End Function


          Alright, let's look at what I've coded. It calls for only 6 out of the 9 variables needed to call BitBlt. But my function has a fault. Can you see it? It only blits pictures that have the starting point of 0, 0 on the source picture. You can change this by adding the variables sX and sY, both longs, to the function call parameters, and erasing 0, 0 and putting in sX, sY into the appropriate places.

          What this particular function does is call BitBlt always with SRCCOPY. This function is more "user-friendly" then BITBLT, so that is why I use a call like this. So, try to add two picture boxes, one with a picture, one without a picture, and "blit" the one with a picture onto the other. It works! Now try adding a timer, and adding the cls statement to the picturebox we're blitting to before the sCopy command. Here's our first problem: we need a backbuffer.

    Private Sub Timer1_Timer()
    Dim ret As Long
       Picture1.Cls
       ret = sCopy(Picture1.hDC,0,0,32,32,Picture2.hDC,0,0) 'note: the last two 0, 0s are only needed if you modified the sCopy routine
    End Sub


          You can see that when added to a timer, this code blits the picture correctly, but it flickers. The way we can get around this is to add a BACKBUFFER. A backbuffer is where we do all of the drawing, but then blit it onto a VISIBLE buffer, which is the front buffer, or drawing surface. The backbuffer is always invisible and must have AUTOREDRAW set to true to work.

    Private Sub Timer1_Timer()
    Dim ret As Long
       Picture3.Cls
       ret = sCopy(Picture3.hDC,0,0,32,32,Picture2.hDC,0,0) 'note: the last two 0, 0s are only needed if you modified the sCopy routine
       ret = sCopy(Picture1.hDC,0,0,32,32,Picture3.hDC,0,0)
    End Sub


          This last code snippet has a backbuffer, Picture3. It first refreshes Picture3, then blits the picture onto Picture3, and then "flips" the drawing from Picture3 to Picture1. BitBlt, however, does NOT erase sprites when they are blitted, working somewhat like the Copy and Paste commands in notepad.

          Now you know how to use a backbuffer and BitBlt, to a certain extent. Now you probably want to blit a mask and a sprite down, making a non-square picture onto the destination. This is almost as easy as the former. I will explain something called "colour dipping."

          Colour Dipping, as I call it, is the process of colouring a sprite. To do this, I recommend having a fresh project to work from. Make six pictureboxes. Name them: picMask(0), picMask(1), BB, picDip, picBlack, and Surface. Make sure all are invisible and have autoredraw set to true except for Surface. Save the following pictures to disk and load them into picMask(0), and picMask(1), respectively.

    Save to disk and load into picMask(0).Save to disk and load into picMask(1).

          Make picBlack's background pure black (RGB 0, 0, 0) and picDip's background any colour you want (this colour will be the colour of the sprite). Now here is the sequence of blitting, I will not put down any code for the rest.

  • Blit picMask(0) onto picDip using srcAnd.
  • Blit picBlack onto picDip using srcPaint.
  • Refresh BB using the CLS command.
  • Blit picMask(1) onto BB using srcAnd.
  • Blit picDip onto BB using srcPaint.
  • Blit BB onto Surface using srcCopy.

    When I have time to revise this tutorial, I shall, however this is how it will stay for now. Date: Friday, March 15, 2001.

    Send Sastraxi an Email