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.
DDPIXELFORMAT DDPixelFormat;
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 )
break;
TestMask <<= 1;
}
TestMask <<= 1;
for( *NumBits = 1; *NumBits < 32; ( *NumBits )++ )
{
if( !( Mask & TestMask ))
break;
TestMask <<= 1;
}
}
[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;
}
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 )
{
DDSURFACEDESC DDSurfDesc;
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: 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
Thanks,
Nathan Davies
References: DirectX SDKs, Microsoft, and Stan Trujillo's High Performance Windows Graphics Programming, Coriolis Group Books.