Please support our sponsor:
Welcome To DirectX 4 VB! Multimedia Visual Basic at its best...

DirectDraw: 16 bit Color Keys
By: Jeff Smith (aka MetalWarrior)
Written: September 2000

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:

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

    ' Count one bits

    OneBitCount = 0
    Do While (Mask And 1) = 1
        OneBitCount = OneBitCount + 1
        Mask = Mask \ 2 ' Shift right

    ' 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

DirectX 4 VB 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster
This site is hosted by Exhedra Solutions, Inc., the parent company of and