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.
- 1,2,4 and 8 bit “indexed” modes (8 bit is the most popular and is better known as “256-color mode”).
- 16-bit (64K colors) “high-color” modes
- 24-bit (16.7M colors) “true-color” modes
- 32-bit RGBA modes. The first 3 bytes are used the same as in 24-bit modes; the A byte is for an “alpha-channel”, which provides information about the opacity (transparency) of the pixel.
These modes are available, typically, in the following resolutions:
- 1600×1200 (drool)
with 640×480 being probably the most common mode for running games in at the moment.
Monitor’s generally have a width that is 4/3 times their height (called the aspect ratio); 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, and thus be physically square. 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 320×200 pixels are actually stretched to be taller than they are wide.
There are a number of different ways that colors can be represented, known as “color models”. The most common one is probably RGB (Red,Green,Blue). Nearly all possible visible colors can be produced by combining, in various proportions, the three primary colors red, green and blue. These are commonly stored as three bytes – each byte represents the relative intensity of each primary color as a value from 0 to 255 inclusive. Pure bright red, for example, would be RGB(255,0,0). Purple would be RGB(255,0,255), grey would be RGB(150,150,150), and so on.
Here is an example of some C code that you might use for representing RGB colors.
SColor make_rgb( int r, int g, int b )
ret.r = r;
ret.g = g;
ret.b = b;
Alternatively you may want to store an RGB color in an unsigned 32-bit integer. Bits 0 to 7 are used to store the blue value, bits 8 to 15 for the green and so on.
typedef unsigned int rgb_color;
#define MAKE_RGB(r,g,b) ( ((r) << 16) | ((g) << 8) | (b) )
Anyway, I’m rambling now.
There are other color models, such as HSV (Hue, Saturation, Luminance), but I won’t be going into them here. The book “Computer Graphics, principles and practise” by Foley & van Dam (often referred to as The Computer Graphics Bible) explains color modes in some detail, and how to convert between color modes.
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.
Palette-based, or “indexed” modes
Indexed color modes use the notion of a color “look up table” (LUT). The most common of these modes is 8-bit, better known as 256 color mode. Each pixel on the screen is represented by a single byte, which means that up to 28 can be displayed on the screen at once. The colors assigned to each of these 256 indexes are stored as 3 byte RGB values in the LUT, and these colors are used by the graphics hardware to determine what color to display on the screen.
Creating an application using indexed modes can be a pain, especially for the graphics artist, but there are sometimes advantages to using indexed modes:
- Less memory is required to store the information in bitmaps and on the screen.
- Because less memory is required, drawing routines can be made faster, since there are fewer bytes to transfer.
- Some interesting “palette animation” tricks, that would be quite difficult to do in a normal mode, can be done quite easily in indexed modes. By changing the values in the LUT, you can change the colors on the screen without modifying screen memory at all. For example, a fade-out can be done by fading the RGB values in the LUT to zero.
- Some 3D accelerators support indexed modes for textures, which can be useful if (for example) you have a very large texture that takes up a lot of memory.
ModeX is a special type of VGA 256 color mode in which the contents of graphics memory (i.e. what appears on the screen) is stored in a somewhat complex planar format. The resolution of ModeX modes isn’t very high. 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 is allowed to create ModeX surfaces. These days you probably want to avoid ModeX.
Even though the screen resolution might be, say, 640x480x32, this does not necessarily mean that each row of pixels will take up 640*4 bytes in memory. For speed reasons, graphics cards often store surfaces wider than their logical width (a trade-off of memory for speed.) For example, a graphics card that supports a maximum of 1024×768 might store all modes from 320×200 up to 1024×768 as 1024×768 internally. This leaves a “margin” on the right side of a surface. This actual allocated width for a surface is known as the pitch or stride of the surface. It is important to know the pitch of any surface whose memory you are going to write into, whether it is a 2D DirectDraw surface or a texture map. The pitch of a surface can be queried using DirectDraw.
Text diagram illustrating pitch:
| | |
| -- screen width -------- | |
| | |
| -- pitch/stride ---------------------- |
| | |
| | |
| | |
| | |
| | |