ProGraphx Toolbox tileset format
This file format is used by the ProGraphx Toolbox to store images used for map tiles in a game.
The ProGraphx Toolbox, written by Peder Jungck, is used by the following games:
- Dark Ages - DA3.EXE contains the string Version 1.0 EGA/VGAProGraphx EGA/VGA Toolbox (DA1.EXE and DA2.exe contain gibberish)
- Duke Nukem - DN1.EXE contains the string Version 1.0 EGA/VGAProGraphx EGA/VGA Toolbox
- Crystal Caves - CC1.EXE contains the string Version 1.5 320x200 PAN EGA/VGAProGraphx EGA/VGA Toolbox
- FBI Fred - FBIFRED.EXE contains the string Version 1.5 EGA/VGAProGraphx EGA/VGA Toolbox (c) 1990
- Secret Agent - SAM1.EXE contains the string ProGraphx EGA/VGA Toolbox Version 2.0 320x200 EGA/VGA Copyright 1991 by Peder Jungck
The file consists of a number of tilesets one after the other. Each tileset is made up of a collection of small images (usually 8×8 or 16×16, but the format supports up to 2040×255.)
In Secret Agent the files are encrypted with Secret Agent encryption. In the other games there is no encryption.
There is no signature, however careful processing of the header can be used to check whether the last tileset ends at exactly the end of the file (allowing for padding in some versions of the format.) If not, it is unlikely to be in this format. Be careful that files with zero values don't cause an endless loop when calculating offsets.
Each tileset begins with the following header.
|BYTE count||Number of sprites in this chunk (50 in most cases)|
|BYTE width||Sprite width, in bytes (not in pixels)|
|BYTE height||Sprite height, in pixels|
The image data for the tileset follows the header. After the image data either the next header begins, or the file ends.
Dark Ages: Each tileset is padded up to 8064 bytes, except for the last tileset which contains 2 sprites and is padded up to 384 bytes.
Duke Nukem: Each tileset is padded up to 8064 bytes, except for NUMBERS.DN? (7186 bytes) and the backdrop files (DROP*.DN?) which have no padding. The backdrop files also have all three header bytes set to zero. For these files, the number of sprites is always 130, the width is always 2 (bytes) and the height is always 16.
Crystal Caves: The file ends after the last tile's image data, there is no padding.
FBI Fred: Each tileset is padded up to 8064 bytes, except for the last tileset which contains 23 sprites and is padded up to 3712 bytes.
Secret Agent: Each tileset is padded up to 8064 bytes for 16×16 sprite files (SAM?01.GFX), and 2048 bytes for 8×8 sprite files (SAM?02.GFX).
For those files with padding at the end, be careful not to interpret the padding as the presence of more tiles.
The image data is in Byte-planar EGA format with five planes, so reading width × height × 5 bytes will read in enough data for a single image (one tile.) This value multiplied by the number of tiles (count) will yield the number of bytes in the entire tileset, which can be used to skip directly to the next tileset in the file (if any.)
The first byte in each tile's data is the transparency plane (1 == opaque, 0 == transparent), and the following four bytes/planes are blue, green, red and intensity. The MSB in each byte (10000000) is the first/left-most pixel, and the eighth pixel is the LSB (00000001). This means if the bits are processed in a loop, as the X direction increases to the right (0, 1, 2) the bit value decreases (0x80, 0x40, 0x20.)
- For at least Duke Nukem, the game seems to ignore the header of all files in this format. You can set the entire header of any tileset file to zero values and the game will still load them properly. This also means that you cannot use larger tilesets without modifying the executable.
This file format has been reverse engineered by many people over the years. K1n9_Duk3 discovered that Duke Nukem uses this format. Frenkel identified the similarities amongst all the games using the file format, and realised they all use the ProGraphx Toolbox. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)