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