Sprites, wall patches, the status bar, the menus and the title screen are all kept in
one picture format, which the Doom source calls patch_t. It stores a picture
column by column, because the engine draws walls and sprites as vertical strips. Each
column holds only its opaque pixels, in runs called posts; the rows between posts are
transparent. Each pixel is one byte, an index into the
palette.
0Header width, height, left offset, top offset8 bytes8Column offsets one for each column4 bytes × width…Columns each a run of posts, thenFFvaries
Header
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 2 | i16 | width | The width in pixels: the number of columns. |
| 2 | 2 | i16 | height | The height in pixels. |
| 4 | 2 | i16 | leftoffset | How far left of its position the picture is drawn. For a sprite, the distance from its left edge to the thing’s centre. |
| 6 | 2 | i16 | topoffset | How far above its position it is drawn. For a sprite, how high its top is above the floor. |
Screen pictures use the offsets too: the status bar and menu pieces are placed by them. Wall patches usually have offsets that the game ignores, since a texture gives their place.
Column offsets
After the header come width unsigned 32-bit numbers, one for each column
from left to right: where the column’s posts start, counted from the start of the lump.
Columns usually follow one another in order, but nothing requires it. Two identical
columns may point at the same bytes.
Posts
| Offset | Size | Name | Description |
|---|---|---|---|
| 0 | 1 | topdelta | The row the post starts at, from the top. FF here ends the column instead. |
| 1 | 1 | length | The number of pixels in the post. |
| 2 | 1 | unused | Not drawn. Usually a copy of the first pixel. |
| 3 | length | pixels | Palette indexes, top to bottom. |
| 3 + length | 1 | unused | Not drawn. Usually a copy of the last pixel. |
The unused bytes are there because the engine’s column drawer could read one pixel
beyond each end of a post. A column with no opaque pixels is the single byte
FF.
0Header03 00 04 00 01 00 04 00: 3 × 4, offsets 1 and 48 bytes8Column offsets14 00 00 00,20 00 00 00,14 00 00 0012 bytes20Column 0 post00 02 0A 0A 0B 0B, post03 01 0C 0C 0C,FF12 bytes32Column 1FF: all transparent1 byte
Compression
The format’s only compression is that transparent pixels take no bytes. An opaque
pixel costs one byte, each post four more, and each column five (its offset and its
FF). A full-screen picture with no transparency, such as a title screen,
is therefore a little larger than its raw pixels; a sprite with much empty space round
it is smaller. The explorer lists every post with the rows it covers, and picking a
pixel of the picture selects its byte.
Tall pictures
A topdelta of one byte cannot reach rows beyond 254. Later tools and source
ports, beginning with the DeePsea editor, read a topdelta that is not more
than the one before it as counted from that post instead of from the top. In a picture
whose posts are in order and below row 255 this changes nothing, so the explorer always
reads it that way. Doom itself does not.