In the following descriptions, 'uint16' is an unsigned 16 bit value and 'uint32' is an unsigned 32 bit value. Both are specified in little-endian format - i.e. the least significant byte is stored first (this is the same format used by the Pentium processor family).
The C16 format can be broken down into three sections:
1) a small file header
2) sprite headers
3) actual image data
1) FILE HEADER
- bit 0: RGB pixel format 0=555, 1=565
- bit 1: must be 1!
- bits 2 to 31 are unused and should be 0.
- The number of sprite images in the file.
2) SPRITE HEADER ARRAY
Then comes an array of sprite headers, one for each sprite in the file.
Each header has the following structure:
uint32: offset to beginning of first line (line 0) in the image data
uint16: width (in pixels)
uint16: height (in pixels)
uint32[height-1]: an array of offsets to remaining lines in image data (this does _not_ include the line 0 offset, because we already know it).
Note that offsets are measured from the beginning of the file.
3) IMAGE DATA
The image data itself follows after the array of sprite headers.
Each line of image data is individually compressed down into a set of 'runs'.
A run begins with a uint16 tag.
- Bit 0 of the tag gives the type of run: 0 = transparent run. 1 = colour run.
The remaining bits (1..15) specify the length of the run in pixels. This implies that a run can be up to 32767 pixels in length(!).
For a colour run, the tag will be followed by the given number of non-transparent pixels (pixels are uint16 values).
For a transparent run, no pixels follow the tag. Rather, the count specifies how many transparent (ie black) pixels are in the image at that point. So rather than storing a whole lot of transparent pixels in the image as the s16 format does, the c16 format simply stores a count saying how many there are. This has the dual advantages of saving memory and being quicker for the game to draw to the screen.
Each image line ends with a zero tag.
An extra zero uint16 is required at the end of each image.