Color Keying in 16-bit

First off, I want to give credit where credit is due. I really can't take any credit for this tutorial, all I've done to get this code was paste it together from various other tutorials. So here it is, all credit goes to: Patrice Scribe, and Steven Blom (in that order). Also thanks to various people on various message boards, who pointed out that it is indeed BGR, and not RGB.

Okay, so what is this tutorial about? Well, if you have any experience with DirectDraw, you know about Color Keys. You probably also know that trying to key out colors in any other color mode than 24-bit (or 32) can be a pain. This tutorial deals with this problem for 16-bit mode. It shows, through code, how to take either an RGB Long, or three separate RGB components, and convert them to a 16-bit Long color code.

Let's start with the first step: Initialization. To be able to do our conversions, we need to get the color shift values. So we need some code to get these. Here's the two functions we'll need, along with a few public variables:


'COLOR SHIFT VALUES Public RedShiftLeft As Long Public RedShiftRight As Long Public GreenShiftLeft As Long Public GreenShiftRight As Long Public BlueShiftLeft As Long Public BlueShiftRight As Long
Public Sub GetColorShiftValues(PrimarySurface As DirectDrawSurface7) Dim PixelFormat As DDPIXELFORMAT PrimarySurface.GetPixelFormat PixelFormat MaskToShiftValues PixelFormat.lRBitMask, RedShiftRight, RedShiftLeft MaskToShiftValues PixelFormat.lGBitMask, GreenShiftRight, GreenShiftLeft MaskToShiftValues PixelFormat.lBBitMask, BlueShiftRight, BlueShiftLeft End Sub
Public Sub MaskToShiftValues(ByVal Mask As Long, ShiftRight As Long, ShiftLeft As Long) Dim ZeroBitCount As Long Dim OneBitCount As Long ' Count zero bits ZeroBitCount = 0 Do While (Mask And 1) = 0 ZeroBitCount = ZeroBitCount + 1 Mask = Mask \ 2 ' Shift right Loop ' Count one bits OneBitCount = 0 Do While (Mask And 1) = 1 OneBitCount = OneBitCount + 1 Mask = Mask \ 2 ' Shift right Loop ' Shift right 8-OneBitCount bits ShiftRight = 2 ^ (8 - OneBitCount) ' Shift left ZeroBitCount bits ShiftLeft = 2 ^ ZeroBitCount End Sub

Once we have these functions in place, all we need to do is call GetColorShiftValues once during our initialization (after creating the primary surface). This sets up our Shift variables for use later in the color conversion.

Now what we need is a function to take a red, green, and blue component, adjust them according to our shift values, and give us a properly formatted 16-bit Long color. We can make that with a single line of code:


Public Function DDRGB(Red As Long, Green As Long, Blue As Long) As Long DDRGB = (Red \ RedShiftRight) * RedShiftLeft + _ (Green \ GreenShiftRight) * GreenShiftLeft + _ (Blue \ BlueShiftRight) * BlueShiftLeft End Function

Yes, that's really just one line. :) So now we can pass our red, green, and blue values to this function, and get a 16-bit RGB Long all nicely formatted to work with DirectDraw. One last thing though, what happens if we already have a 24-bit RGB we want converted? Well, all we have to do is split it down into red, green, and blue components, and pass those to our DDRGB function. The following two functions will take care of it for us:


Public Sub GetRGBfromColor(ByVal Color As Long, ByRef Red As Long, ByRef Green As Long, ByRef Blue As Long) Dim HexadecimalValue As String 'This will store the Hexadecimal Value as a string 'This line will convert a Long decimal to Hexadecimal HexadecimalValue = Hex(Val(Color)) If Len(HexadecimalValue) < 6 Then HexadecimalValue = String(6 - Len(HexadecimalValue), "0") + HexadecimalValue End If Blue = CLng("&H" + Mid(HexadecimalValue, 1, 2)) Green = CLng("&H" + Mid(HexadecimalValue, 3, 2)) Red = CLng("&H" + Mid(HexadecimalValue, 5, 2)) End Sub
Public Function DDColor(RGBColor As Long) As Long Dim RedVal As Long Dim GreenVal As Long Dim BlueVal As Long GetRGBfromColor RGBColor, RedVal, GreenVal, BlueVal DDColor = DDRGB(RedVal, GreenVal, BlueVal) End Function

You'll notice in the GetRGBfromColor function that the colors are stored in the order, BGR, rather than RGB. That one had me stumped for a while. :) Anyway, there it is. You can use the two functions DDRGB and DDColor to get a 16-bit color. So now you can key out any color in 16-bit, and not just black, white, and magenta. :)

Once again, all code was written by Patrice Scribe, except for the function to split up colors from a single Long, which was written by Steven Blom. The only code I actually wrote here was the DDColor function. ;) I hope you found this tutorial helpful.

--MetalWarrior aka Jeff Smith