Drawing sprites using any colour as transparent

From HashVB
Jump to: navigation, search

One of the problems with the method that many sites will propose for drawing sprites is that you are forced to either use one particular colour for the mask colour, or have a separate picture stored for the mask. Or both. Unfortunately, this is often not very practical, and so you might think of using the conveniently existent TransparentBlt API. Annoyingly, the nice people at MS who wrote this function overlooked the fact that there's a horrible memory leak in it, and so it's a bad idea to use it. So what do you do? Well, you could either get the pixels using GetDIBits and 'blit' manually, or you can use several BitBlt calls and a couple of extra memory DCs to draw your image transparently.

Here's the code to do so:

   Private Sub TransparentBlt(ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal lTransparentColor As Long)
       Dim mDC As Long, mBmp As Long
       Dim hTmpDC As Long, hTmpBmp As Long
       Dim hMonoDC As Long, hMonoBmp As Long
       Dim lOldBkColor As Long
       mDC = CreateCompatibleDC(hDestDC)
       mBmp = CreateCompatibleBitmap(hDestDC, cx, cy)
       DeleteObject SelectObject(mDC, mBmp)
       hTmpDC = CreateCompatibleDC(hDestDC)
       hTmpBmp = CreateCompatibleBitmap(hDestDC, cx, cy)
       DeleteObject SelectObject(hTmpDC, hTmpBmp)
       hMonoDC = CreateCompatibleDC(hDestDC)
       hMonoBmp = CreateBitmap(cx, cy, 1, 1, ByVal 0&)
       DeleteObject SelectObject(hMonoDC, hMonoBmp)
       '-- Set the backcolor so we can get a monochrome bitmap of the source
       lOldBkColor = SetBkColor(hSrcDC, lTransparentColor)
       '-- Copy the source into our monochrome bitmap
       BitBlt hMonoDC, 0, 0, cx, cy, hSrcDC, xSrc, ySrc, vbSrcCopy
       '-- Set the backcolor back to its original value
       SetBkColor hSrcDC, lOldBkColor
       '-- Get the background and draw the mask onto the background transparently with maskblt
       MaskBlt mDC, 0, 0, cx, cy, hDestDC, x, y, hMonoBmp, 0, 0, vbSrcCopy
       '-- Invert the mask
       BitBlt hMonoDC, 0, 0, cx, cy, hMonoDC, 0, 0, vbNotSrcCopy
       '-- Get the foreground and draw the inverted mask onto it transparently with maskblt
       MaskBlt hTmpDC, 0, 0, cx, cy, hSrcDC, xSrc, ySrc, hMonoBmp, 0, 0, vbSrcCopy
       '-- XOR the two together
       BitBlt mDC, 0, 0, cx, cy, hTmpDC, 0, 0, vbSrcInvert
       '-- Output the result
       BitBlt hDestDC, x, y, cx, cy, mDC, 0, 0, vbSrcCopy
       DeleteObject hMonoBmp
       DeleteDC hMonoDC
       DeleteObject hTmpBmp
       DeleteDC hTmpDC
       DeleteObject mBmp
       DeleteDC mDC
   End Sub

The comments explain the code. If you don't understand the comments, tough.