Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Simple ChessBoard Graphics

0.00/5 (No votes)
8 Sep 2015 1  
A simple ChessBoard graphics using GDI32

Introduction

In this tip, we will learn how to draw a chessboard using the Windows GDI32. The goal of this tip is not only to show how to draw a chessboard, but also to give some knowledge about GDI32.

Background

This tip will assume that you are familiar with pure Win32 programming.

Windows GDI32

At first, we will know very little information about the GDI32 so it will be easier for a novice programmer to understand this post.

The GDI

GDI means Graphical Device Interface and it is used for drawing on Windows. Pen, Brush are GDI objects used for defining how the drawing will be look like. Font is another GDI object used for describing how the text will appear.

The DC

DC means device context. Device context is a structure that defines a set of graphic objects. The graphic objects can be a Pen, a Brush or a Bitmap.

The WM_PAINT

In Windows, all GDI drawings are usually done inside the WM_PAINT message handler.  Inside the WM_PAINT event handler, an application can call BeginPaint function of GDI32 to retrieve the display device context for the client area. After completing the drawing operations, the application calls the EndPaint function of GDI32 to release the display device context.

Including the GDI32 Library into Project

For including GDI32 library header file, all you have to do is just add this simple line at the beginning of your C++ source file if you have not done this already:

#include <windows.h>

This will include not only the GDI functions prototype but also all the necessary Windows functions prototype into your source code that you will need to do Win32 GUI programming. In fact, the windows.h file itself actually includes all the necessary Windows library header files.

Do not forget to add 'Gdi32.Lib' import library into your project.

Drawing the Chessboard

For drawing a Chessboard, we will create a Bitmap, will change the Bitmap pixel data/color and then draw it later inside the WM_PAINT event.

At first, we need to know how a bitmap can be created in GDI. Though GDI has got various functions for that, but here, we will use the CreateDIBSection function of GDI32 library.

The MSDN library says:

The CreateDIBSection function creates a DIB that applications can write to directly. The function gives you a pointer to the location of the bitmap bit values. You can supply a handle to a file-mapping object that the function will use to create the bitmap, or you can let the system allocate the memory for the bitmap.

That means using this function, you can easily create Device-Independent Bitmap (DIB). This is the prototype of the function:

HBITMAP CreateDIBSection(
  HDC hdc,                 // handle to DC
  CONST BITMAPINFO *pbmi,  // bitmap data
  UINT iUsage,             // data type indicator
  VOID **ppvBits,          // bit values
  HANDLE hSection,         // handle to file mapping object
  DWORD dwOffset           // offset to bitmap bit values
);

So let's create a 24-bit bitmap using the function. We will do this after creating the drawing window.

We can use the GetClientRect function to get the size of the client area of the drawing window to use it as our bitmap size.

RECT rc;
::GetClientRect(hWnd, &rc);

int nBitmapWidth = rc.right;
int nBitmapHeight = rc.bottom;

As we can see, the CreateDIBSection function takes a structure of the BITMAPINFO type as its second parameter. So let's create the structure and fill-up its member variables using the necessary value.

const int nColorBit = 24;
BYTE* pPixel = NULL;

const int nHeaderSize = sizeof(BITMAPINFOHEADER) + 16;

BYTE* temp_buf = new BYTE[(size_t)nHeaderSize];
ZeroMemory(temp_buf, nHeaderSize);

BITMAPINFO* pInfo = (BITMAPINFO*)&temp_buf[0];
pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pInfo->bmiHeader.biWidth = nBitmapWidth;
pInfo->bmiHeader.biHeight = nBitmapHeight;
pInfo->bmiHeader.biPlanes = 1;
pInfo->bmiHeader.biBitCount = (WORD)nColorBit;

nBitmapWidth and nBitmapHeight variables hold the bitmap size though I have used the drawing window client size as their value but you may want to use your own value.

At this point, we have all the information that will be needed for CreateDIBSection function parameters value. So call the function to create the bitmap:

g_hbmp = ::CreateDIBSection(NULL, pInfo, DIB_RGB_COLORS, (VOID**) &pPixel, NULL, 0);

Now, we have a 24-bit bitmap on memory and a pointer to its pixel data. The pPixel variable is now pointed to bitmap pixel data.

Let's clear the data:

const int nPitch = 4 * ((nBitmapWidth * nColorBit + 31) / 32); 
ZeroMemory(pPixel, nPitch * nBitmapHeight);

This code will make the bitmap black.

Then loop through the bitmap pixels:

for(int y = 0;y < nBoardSize;y++)
{
	xOffset = 0; 

	for(int x = 0;x < nBoardSize;x++)
	{
		Index = yOffset + xOffset;
		...

For checking whether it should be a black or white (the common two colors for a chessboard) block pixel, we will use a % operator:

int nX = x / nBlockSize;
int nY = y / nBlockSize;

if ( ((nX + nY) % 2 == 0) )
{
	pPixel[Index] = 255; // Blue
	pPixel[Index+1] = 255; // Green
	pPixel[Index+2] = 255; // Red
}
else
{
	pPixel[Index] = 0; // Blue
	pPixel[Index+1] = 0; // Green
	pPixel[Index+2] = 0; // Red
}

Now, all that remains is to draw the bitmap, and we will do it using BitBlt function of GDI32 library inside the WM_PAINT event:

HDC tmpDC = ::CreateCompatibleDC(NULL) ;
HGDIOBJ tmpOBJ = ::SelectObject(tmpDC, g_hbmp);

::BitBlt(hdc, 0, 0, nBitmapWidth, nBitmapHeight, tmpDC, 0, 0, SRCCOPY);

::SelectObject (tmpDC, tmpOBJ);
::DeleteDC(tmpDC);

g_hbmp ( global variable ) is the handle of the bitmap that we have created using the CreateDIBSection function.

Points of Interest

I think drawing a chessboard programmatically is more interesting than drawing it in any other way. You can easily change the size of blocks and its color during run-time. So I hope it will be interesting for those who want to create a chess game and also for those who want to learn more about GDI32.

Conclusion

You may think that I could simply use the SetPixel function of GDI32 library inside the WM_PAINT message for drawing the chessboard. But using the SetPixel function, it will be very very slow and will take several seconds for every redraw.

So, you may not want to use this.

At last, I want to say that if you find anything wrong in the tip or if you want to say anything about this post, please comment to help me improve my tip.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here