|Reading and displaying PCX files|
|Phil Inch, Game Developers Magazine|
DOWNLOAD ... The example files mentioned in this article are contained in the file PCX-SHOW.ZIP (12,091 bytes) which can be downloaded by clicking this disk icon.
Of all the formats available for storing pictures, the .PCX format is one of the best known and most accessible from a programmers point of view, and there are a plethora of "paint" programs with which you can create your own PCX files. There are also plenty of PCX files on bulletin boards which you can download and experiment with.
This article will show you how to load and display PCX files which are up to 320x200 in 256 colours - that is, which are designed for the same video mode (mode 13h) as the other graphics articles you've been reading in the magazine.
For simplicity we won't cover the details of PCX files constructed for other video modes - we'll return to these in later issues when we've learnt how to use other video modes.
So please note, ALL of the following text assumes that the file in question is a 256 colour VGA PCX file.
You'll also see references to using the AND function. Basically AND is used to selectively turn off certain bits within a byte, so that we can isolate certain bits we are interested in. The manual which comes with your programming language should have a more detailed description of the AND function.
In Basic and Assembler, the function is AND. In C it's the operator '&'. In Pascal, ... anyone?
(If you're unfamiliar with the VGA palette, please read the article on the VGA palette before proceeding).
DESCRIPTION LENGTH COMMENTS Manufacturer 1 Byte Varies, not very useful Version 1 Byte '5' for 256 colour files Encoding 1 Byte Usually set to '1' Bits per pixel 1 Byte '8' for 256 colour files XMin 2 Bytes Top left X co-ordinate YMin 2 Bytes Top left Y co-ordinate Width 2 Bytes Width of image - 1 Height 2 Bytes Height of image - 1 Horizontal Res 2 Bytes Horizontal resolution Vertical Res 2 Bytes Vertical resolution EGA Palette 48 Bytes EGA palette values (not used) 1 Byte (not currently used) Colour planes 1 Byte Number of colour planes Bytes per line 2 Bytes Number of bytes in 1 line Palette Type 2 Bytes '2' for colour palette (not used) 58 Bytes (not currently used)As you can see, only some of the information in the header is useful. For example, the EGA palette is not used at all in a VGA image, and some of the other values are constant.
I have noted in the comments column the sorts of values we expect when we're dealing with a mode 13h (320x200) 256-colour PCX file.
You may be surprised to see that the PCX file header contains an "upper left" (x,y) co-ordinate and a width and height specifier. This allows you to display an image smaller than 320x200 and at an offset with regard to the top left hand corner of the screen (320x200). The routine we'll write will account for this.
This compression is achieved by storing "runs" of pixels (repeated pixels with the same colour value) as an encoded series of bytes which represents that run.
This is done by storing two bytes. The first byte consists of two "nibbles" (a nibble is half a byte, or four bits). The "high nibble" (first four bits) contain the value 0Ch (12 decimal).
This can be tested for by ANDing the byte with the value C0h (192 decimal) and checking to see if the result is 192, or more simply by seeing if the byte is >= 192.
The "low nibble" (second 4 bits) contain the length of the run.
The following byte in the file contains the value (colour) of the pixel in the run.
You may wonder, then, how it stores a "real" colour code which is greater than 192. The answer is that it's encoded as a run of length 1. This means that colour codes >= 192 take two bytes each to store. For some files, this is wasteful, and for others, it's not.
1) Read the header. From the header, remove the information which you need, such as the top left (x,y) and the width and height. Remember that the width and height values are actually 1 less than the real width and height ... ie a full-screen image returns width and height values of 319 and 199 instead of 320 and 200.
2) Go to the end of the file, skip back 769 bytes, and check that the byte at that location is 0Ch (12 decimal). This is the double check to ensure that this is a 256-colour PCX file.
3) Read the remaining 768 bytes in the file, which are the colour values for the entire VGA palette.
4) Divide all of these bytes by 4, to bring them into the range 0 - 63. I don't know why they're not already in the range 0 - 63. (I'm sure the spec probably tells you but I haven't looked that deeply into it.)
5) Use these values to reprogram the VGA palette.
6) Skip back to the 129th byte in the file (ie: the byte immediately following the header).
7) Set up a couple of temporary variables to hold the "current" x and y positions. Their initial values should be the "top left" x and y values specified in the header.
8) Read a byte. Check if the two high bits are set, either by ANDing the byte with C0h (192 dec) and seeing if the result is C0h (192 dec), or by checking if the byte is >= 192. If this is NOT the case, go to step 11.
9) You have detected a run. Get the value in the low nibble of the byte by ANDing the byte with 3Fh (63 dec). The resulting value is the run length.
10) Read another byte from the file. This is the colour value of all of the pixels in the run. Note that as we're already in a run this byte will be a "real" colour number.
11) Set the current pixel position, as defined by your working variables, to the specified colour.
12) Increment the temporary position variables according to the width and height specified in the header. If you've exceeded the maximum height, the image is finished so skip to step 14.
13) If you're plotting a run, take one from the run length and return to step 11 until the run length reaches zero. If not, or if the run length has reached zero, go to step 8.
14) The picture is now displayed! Remember to close the PCX file!
It does do some checking to make sure that the file can be correctly displayed in mode 13h, and it detects this by looking at the "Version" byte to check for a 256 colour file, and by looking at the top left (x,y) and width and height values to ensure the image will fit on the screen.
The program will not attempt to display an image which will not display correctly in mode 13h, but instead aborts with an error.
You can also use VGA palette programming examples in the VGA palette programming article to create effects such as "fading in" and "fading out" a PCX image, which is a great looking effect for title screens.
And, if you're really feeling like a challenge, why don't you try to write a routine which takes an existing image on the screen and writes it out as a PCX file? Remember, you'll have to write the header correctly, do the encoding correctly, and get the palette values too!
Next issue, we'll use our PCX file knowledge to learn how to move sprites across a background image without destroying that image!