[ Home | Chapter 1 | Chapter 2 | Chapter 3 | Chapter 4 | Chapter 5 ]

David Joffe's Guide to Programming Games with DirectX

Chapter 2: Palettes, Gaming concepts, double buffering etc

2.1 Video Modes

Screen modes come in several flavours, based on how many bits are used to store the color of each pixel on the screen. Naturally, the more bits you use per pixel, the more colours you can display at once; but there is more data to move into graphics memory to update the screen.

These modes are available, typically, in the following resolutions:

with 320x200 and 640x480 being the two most popular modes for games at the moment. Monitor's generally have a width 4/3 times their height, so with modes where the number of pixels along the width is 4/3 times the number of pixels along the height, the pixels will have an aspect ratio of 1. That is to say, 100 pixels in one direction should then be the same physical length as 100 pixels in a perpendicular direction. Note that 320/200 does not have this property; so in 320x200 pixels are actually stretched to be taller than they are wide.

2.2 Color theory

Every possible visible color can be made by combining in various proportions the three primary colours Red, Green and Blue. This system is called the RGB system. The Red, Green and Blue values are normally specified in the range 0 to 255 inclusive. So pure bright red would be RGB(255,0,0); purple would be RGB(255,0,255); grey is RGB(150,150,150); black is RGB(0,0,0), etc.

2.2.1 High-color and true-color modes

In high-color and true-color modes, the pixels on the screen are stored in video memory as their corresponding RGB make-up values. For example, if the top left pixel on the screen was green, then (in true-color mode) the first three bytes in video memory would be 0, 255 and 0.

In high-color modes the RGB values are specified using (if I remember correctly) 5, 6 and 5 bits for red, green and blue respectively, so in the above example the first two bytes in video memory would be, in binary: 00000111 11100000.

2.2.2 Palette-based, or "indexed" modes

Urgh.

In the most common of these modes, that is, 8-bit, the programmer has a choice of 28 = 256 different colors that can be displayed on the screen at once. The RGB make-up values for each of these 256 colors are stored in a table of RGB records, each 3 bytes long. Thus, each pixel takes one byte in video memory, and the value of that byte specifies an index into the table (called the "palette") which is used to look up the RGB values to generate the pixel on the screen.

Creating an application around this palette is a pain. But using a palette offers several advantages, which include:

2.2.3 ModeX

ModeX is a special type of mode in which the contents of graphics memory (i.e. what appears on the screen) is stored in a somewhat complex planar format. DirectDraw knows how to write to ModeX surfaces, but the Windows GDI doesn't, so be careful when trying to mix GDI and DirectDraw ModeX surfaces. When setting the DirectDraw fullscreen mode, it is possible to choose whether or not DirectDraw may create ModeX surfaces.

2.3 A few gaming concepts you'll need to know to write games

2.3.1 Bitmaps and sprites

A bitmap is an image on the computer that is stored as an array of pixel values. That's a pretty crappy description. Basically, a bitmap is any picture on the computer. That little "home" picture at the bottom of this page is a bitmap. A sprite is the same thing as a bitmap, except normally it means a bitmap that has transparent areas. Sprites are an extremely important component of games. They have a million and one uses. For example, your mouse cursor qualifies as a sprite. The monsters in DOOM are also sprites. They are flat images with transparent areas that always face you. Note that the sprite always faces you - this doesn't mean the monster is facing you. Anyway, enough said about bitmaps and sprites, I think.

2.3.2 Double buffering and page flipping

Double-buffering is a rather nifty technique that is very important in acheiving fast, smooth animation in your application. It's not the only thing you'll need to achieve this, but it's definitely one of the more important ones. Basically, it works like this. Your game draws what the user is meant to see on the screen onto an off-screen surface. The upshot of this is that the user doesn't have to *watch* the elements of the screen being drawn, as this causes all sorts of icky artefacts, like flickering. Now, only when the image is ready for viewing (or "finished rendering", if you want to speak a bit more technically) is it shown to the user. There are two basic ways of getting this image from the off-screen surface, and onto the screen. The first is to copy the contents from the off-screen surface, into the screen memory. The other is to use hardware page-flipping, which means that you instruct the graphics hardware to refresh the screen from that point on from a different point in memory - typically you let it point to your off-screen surface. Now the area in memory that the screen *was* drawing from becomes your off-screen surface, and when you've drawn to that, you do the page-flip again.

A problem that can arise from this technique is "tearing". Your monitor redraws the image on the screen fairly frequently, normally at around 70 times per second (or 70 Hertz). It normally draws from top to bottom. Now, it can happen that the screen has only drawn half of its image, when you decide to instruct it to start drawing something else, using any one of the two techniques described above. When you do this, the bottom half of the screen is drawn using the new image. This is called tearing, or shearing. A solution exists, however. It is possible to time your page flipping to co-incide with the end of a screen refresh. I'll stop here though, having let you know that it is possible.

2.4 Clipping and DirectDraw clippers

Clipping is the name given to the technique of preventing drawing routines from drawing off the edge of the screen or other rectangular bounding area such as a window. If not performed, the general result could best be described as a mess. In DirectDraw, for example, when using windowed mode; Windows basically gives DirectDraw the right to draw anywhere on the screen that it wants to. However, a well-behaved DirectDraw application would normally only draw into it's own window. DirectX has an object called a "clipper" that can be attached to a DirectDraw surface to prevent it drawing outside of the window.

2.5 DirectDraw surfaces

DirectDraw uses "surfaces" to access any section of memory, either video memory or system memory, that is used to store (normally) bitmaps, texture maps, sprites, and the current contents of the screen or a window.

DirectDraw also provides support for "overlays"; a special type of sprite. An overlay is normally a surface that houses a bitmap with transparent sections that will be "overlaid" on a scene. For example, a racing car game might use an overlay for the image of the cockpit controls and window frame.

The memory a DirectDraw surface uses can be lost in some circumstances, because DirectDraw has to share resources with the GDI. It is necessary for you application to check regularly that this hasn't happened, and to restore the surfaces if it has.

2.6 DirectX return values and error-checking

DirectX functions return an HRESULT as an error-code. Since DirectX objects are based on the COM architecture, the correct way to check if a DirectX function has failed is to use the macros SUCCEEDED() and FAILED(), with the HRESULT as the parameter. It is not merely sufficient to check if, for example, your DirectDraw HRESULT is equal to DD_OK, since it is possible for COM objects to have multiple return values as success values.

2.6 DirectX debugging

When you install the DirectX SDK you get a choice of whether to install the retail version of the libraries, or the debug version. The debug version will actually write diagnostic messages to your Visual C++ TRACE output window, which is very useful. If you want to mainly play DirectX games, install the retail version. If you want to do mainly DirectX development, install the debug version.

Article updated: 2 September 1997


Article by David Joffe
http://www.geocities.com/SoHo/Lofts/2018/