Jump to content
  • Advertisement
  • 07/31/99 02:02 AM
    Sign in to follow this  

    Plotting Pixels in Non-Palettized DirectDraw Surfaces

    Graphics and GPU Programming

    Myopic Rhino
    Plotting Pixels in Non-palettized Direct Draw Surfaces To plot a pixel in an 8-bit surface is simple. Lock the surface to get the surface pointer and equate the point you're working with to the colour supplied. SurfPtr[ X + Y * SurfacePitch ] = Colour.

    But plotting a pixel to a non-palettized surface takes a little more work and thought. First you need to know what the pixel format of the surface is. The pixel format is just a way of saying what bits represent Red/Green/Blue in the surface. For example, common 16-bit surfaces include 0555 and 565, where in the first, the first bit is 0, and the remaining 15 bits represent red/green/blue, with 5 bits used for each. Because of the varying pixel formats, and the fact that you should handle all formats, it's useful to find this information during DirectDraw Initialization and store it for easy access any time you need to plot a pixel or draw a line, etc...

    [size="5"]Finding the Pixel Format:

    // These variables are set in StorePixelFormat and should be defined
    // elsewhere(global, member variable, etc...)
    WORD NumberRedBits, NumberGreenBits, NumberBlueBits;
    WORD LowRedBit, LowGreenBit, LowBlueBit;

    BOOL StorePixelFormat()
    // Define a PixelFormat variable, clear it and set the dwSize variable, as usual.
    ZeroMemory( &DDPixelFormat, sizeof( DDPixelFormat ));
    DDPixelFormat.dwSize = sizeof( DDPixelFormat );

    // Fill the PixelFormat from the information for the Primary Surface
    if( FAILED( PrimarySurface->GetPixelFormat( &DDPixelFormat)))
    // Fatal error. The program should exit nicely
    return FALSE;

    // Save the Low Bit and Number of Bits
    ProcessBits( DDPixelFormat.dwRBitMask, &LowRedBit, &NumberRedBits);
    ProcessBits( DDPixelFormat.dwGBitMask, &LowGreenBit, &NumberGreenBits);
    ProcessBits( DDPixelFormat.dwBBitMask, &LowBlueBit, &NumberBlueBits);

    return TRUE;

    // Small utility function to find the LowBit and Number of Bits in a supplied Mask
    void ProcessBits( DWORD Mask, WORD* LowBit, WORD* NumBits )
    DWORD TestMask = 1;
    for( *LowBit = 0; *LowBit < 32; ( *LowBit )++ )
    if( Mask & TestMask )
    TestMask <<= 1;

    TestMask <<= 1;
    for( *NumBits = 1; *NumBits < 32; ( *NumBits )++ )
    if( !( Mask & TestMask ))
    TestMask <<= 1;
    You might wonder why I would want to save the Low Bit and Number of Bits for each colour. Well that's so that we can convert an RGB value to a Colour value with This function.

    [size="5"]Converting RGB Values to Pixel Formatted Colour:

    // Converts the supplied RGB values to a DWORD Pixel Formatted Colour
    DWORD RGBToColour( DWORD Red, DWORD Green, DWORD Blue )
    // Supplied Values(0 - 255) are converted to Pixel Formatted Values
    // If 565 format and Red = 128, RedVal will become 16 since 128 / 256 == 16 / 32(5 bits)
    DWORD RedVal = ( Red * ( 1 << NumRedBits )) / 256;
    DWORD GreenVal = ( Green * ( 1 << NumGreenBits )) / 256;
    DWORD BlueVal = ( Blue * ( 1 << NumBlueBits )) / 256;

    // Convert the Values to the appropriate Location in the returned colour value
    RedVal <<= LowRedBit;
    GreenVal <<= LowGreenBit;
    BlueVal <<= LowBlueBit;

    return RedVal | GreenVal | BlueVal;
    The RGBToColour function first converts a value from 0 - 255 to 0 - ( 1 << NumColourBits ). This is used most for 16 bit colour and possibly an alpha version of a 24-bit format. In a 24-bit 888 Pixel Format this is totally unnecessary since it would be converting from 0 - 255 to 0 - 255.

    NOTE: I read on a mailing list that there might exist a 32-bit format such as 11-12-11. I have no idea if such a format exists, but it's possible. This function would not handle such a case howerver.

    And now on to the whole point of this article, the plotting of the pixel. Since all this setup has given us a way to determine the colour to output, given an RGB value, the plotting is simple. To plot the pixel you need to lock a surface, change the value of a pixel and unlock the surface.

    [size="5"]Plotting a Pixel:

    void PutPixel( LPDIRECTDRAWSURFACE TempSurf, int X, int Y, int Red, int Green, int Blue )
    BYTE* SurfPtr;

    ZeroMemory( &DDSurfDesc, sizeof( DDSurfDesc ));
    DDSurfDesc.dwSize = sizeof( DDSurfDesc );

    TempSurf->Lock( 0, &DDSurfDesc, DDLOCK_WAIT, 0 );
    SurfPtr = ( BYTE* )DDSurfDesc.lpSurface;

    SurfPtr[ X + Y * DDSurfDesc.lPitch ] = RGBToColour( Red, Green, Blue );

    TempSurf->Unlock( SurfPtr );
    NOTE/RANT: This method is VERY slow and wasteful. Some, but not all reasons include the following. Locking/unlocking can be slow and should be done as few times as possible. You could lock/unlock outside this function and supply the surface pointer instead. If you are doing this, and using a separate function that is also wasteful, since the only line in the function would be the SurfPtr[ ... ] = Colour line. Just throw it in your code instead. Lastly, if your colour is not changing with every new pixel, don't calculate it with every new pixel. If you use a similiar method for a line, you would only need one colour(supposedly).

    NOTE: To change this to work with newer versions of DirectDraw, just change the Structures accordingly. For example, DX6 uses LPDIRECTDRAWSURFACE4 and DDSURFACEDESC2.

    Well I hope this has helped someone. I've seen a bunch of newsgroup and mailing list messages about this topic and decided to put this together to help anyone that might be having problems. If you notice anything wrong with this example, or you have comments, let me know at alamar@netinc.ca

    Nathan Davies

    References: DirectX SDKs, Microsoft, and Stan Trujillo's High Performance Windows Graphics Programming, Coriolis Group Books.

      Report Article
    Sign in to follow this  

    User Feedback

    There are no comments to display.

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!