The SG asset pipeline
Every sprite in Caesar III, Pharaoh, Zeus and Emperor comes through this pair of files: an .sg2 or .sg3 index describing images, and one or more .555 files holding their pixels. Getting art out of these games, or new art in, means reading both.
Used by Caesar III Pharaoh Zeus Emperor
An SG file contains no pixels. It is an index: a fixed header, a lookup table, one record per source bitmap, and one record per image. The pixels live in .555 files, and every image record points into one by byte offset.
The split is what makes the format tractable. You can read the whole catalogue of a game's art — names, dimensions, animation frames, which building a sprite belongs to — without decoding a single pixel.
Header
80 bytes, at the start of the file. All integers are little-endian.
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 0 | 4 | int32 | file_size | Size of this SG file. |
| 4 | 4 | int32 | version | Format version. See the table below. |
| 8 | 4 | — | unknown | Purpose not established. |
| 12 | 4 | int32 | num_image_records | Total image records present. |
| 16 | 4 | int32 | num_images | Image records actually in use. |
| 20 | 4 | int32 | num_bitmap_records | Bitmap records present. |
| 24 | 4 | int32 | unknown | Bitmap-related; purpose not established. |
| 28 | 4 | int32 | total_filesize | Total size of the image data. |
| 32 | 4 | int32 | filesize_555 | Size of the internal .555 file. |
| 36 | 4 | int32 | filesize_external | Combined size of the external .555 files. |
| 40 | 40 | — | unknown | Purpose not established. |
Version codes
Read from offset 4. The version decides the size of an image record, which makes it the first thing a parser needs.
- 211
- SG2 — Caesar III.
- 213
- SG3 — Pharaoh, Zeus, Emperor.
- 214
- SG3 with an alpha mask. Image records grow from 64 to 72 bytes.
Index
600 bytes, immediately after the header.
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 80 | 600 | uint16[300] | image_ids | Maps a stable game-facing group ID to the position of an image record. The indirection is the point: artists could reorder or re-export images without the game code having to change. |
Bitmap record
200 bytes each, following the index. One per source bitmap — the artist's original file, which may hold many game images.
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 0 | 65 | char[] | filename | Null-terminated source filename, e.g. a .bmp name. |
| 65 | 51 | char[] | comment | Null-terminated description. |
| 116 | 4 | int32 | width | Width of the external bitmap. |
| 120 | 4 | int32 | height | Height of the external bitmap. |
| 124 | 4 | int32 | num_images | How many images come from this bitmap. |
| 128 | 4 | int32 | start_index | First image index belonging to it. |
| 132 | 4 | int32 | end_index | Last image index belonging to it. |
| 136 | 64 | int32[16] | unknown | Purpose not established. |
Image record
64 bytes below version 214, 72 bytes at 214 and above. Offsets are relative to the start of the record.
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 0 | 4 | int32 | offset_555 | Byte offset of this image's pixel data within its .555 file. |
| 4 | 4 | int32 | length | Length of the stored data. |
| 8 | 4 | int32 | uncompressed_length | Length once expanded. |
| 12 | 4 | — | zero | Always zero. |
| 16 | 4 | int32 | invert_offset | Offset of the image this one mirrors. SG3 only. |
| 20 | 2 | uint16 | width | Image width in pixels. |
| 22 | 2 | uint16 | height | Image height in pixels. |
| 24 | 6 | — | unknown | Three shorts; purpose not established. |
| 30 | 2 | uint16 | num_animation_sprites | Frames in this animation. |
| 32 | 2 | uint16 | unknown | Purpose not established. |
| 34 | 2 | int16 | sprite_offset_x | Horizontal animation offset. |
| 36 | 2 | int16 | sprite_offset_y | Vertical animation offset. |
| 38 | 10 | — | unknown | Purpose not established. |
| 48 | 1 | uint8 | can_reverse | Whether the animation plays back and forth. |
| 49 | 1 | — | unknown | Purpose not established. |
| 50 | 1 | uint8 | type | Image type. See below. |
| 51 | 1 | uint8 | fully_compressed | The whole image is run-length compressed. |
| 52 | 1 | uint8 | external | Pixels live in an external .555 file rather than the internal one. |
| 53 | 1 | uint8 | part_compressed | Isometric image with a compressed top section. |
| 54 | 2 | — | unknown | Purpose not established. |
| 56 | 1 | uint8 | bitmap_id | Which bitmap record this image came from. |
| 57 | 1 | — | unknown | Purpose not established. |
| 58 | 1 | uint8 | animation_speed_id | Playback speed selector. |
| 59 | 1 | — | unknown | Purpose not established. |
| 60 | 4 | — | zero | Always zero. |
| 64 | 4 | int32 | alpha_offset | Alpha mask offset. Version 214 only. |
| 68 | 4 | int32 | alpha_length | Alpha mask length. Version 214 only. |
Image types
Read from offset 50 of an image record.
- 0
- Plain image that may carry transparency.
- 1, 10, 12, 13, 20
- Plain images.
- 30
- Isometric — a building or terrain tile, stored differently. See below.
How pixels are stored
Three storage modes, chosen per image by the flags at offsets 51 to 53.
Uncompressed images are raw pixels, row by row, top to bottom and left to right.
Compressed images are run-length encoded, and only for transparency. A control byte of 255 means "the next byte is a count of transparent pixels"; any other value is a count of coloured pixels that follow. There is no compression of the colours themselves.
Isometric images come in two parts. The base is a set of uncompressed diamond tiles — 58×30 pixels in Caesar III, Pharaoh and Zeus, and 78×40 in Emperor — laid out row by row for multi-tile buildings. Anything standing above the ground plane follows as a compressed "top" section.
The .555 files and colour
Pixels are two bytes each, little-endian, five bits per channel in R-G-B order. The single value 0xF81F is the transparency key rather than a colour, which is why it never appears as magenta in-game.
Most images live in the internal .555 file, which shares the SG file's name. Some live in external ones, flagged at offset 52 of the image record and named after the bitmap record's filename with the extension changed to .555. Pharaoh in particular spreads its art across several external files.