Jazz Jackrabbit Sprite Format
Sprites for Jazz Jackrabbit are stored in SPRITES.xxx and MAINCHAR.000 files. SPRITES.xxx contains all sprites that belong to levels LEVELy.xxx with tileset BLOCKS.xxx. MAINCHAR.000 contains all standard sprites, such as Jazz's walking animations and such.
When a level is loaded, sprites are loaded into a 256-sprite array. First the MAINCHAR is read, then the level's SPRITES file. Both files contain 'holes' or null entries that can be filled by the other. (For example, MAINCHAR has holes between 23-48 and 238-255) If a sprite exists in both files, the SPRITES one is loaded. This produces a sprite array for each level containing 238-256 sprites, with a number of 'holes' that can also be used by events. (Nothing will appear, and this is used in several ingenious ways.)
Sprite files (Except MAINCHAR) have a header, followed by three different types of sprite 'entry'
Note that there is a sprite zero.
All sprite files except MAINCHAR.000 have a header, of variable size. (Maximum size 514 bytes, written as follows. First there is a word detailing size of the h and v segments. The header size is twice this plus two. Then there is the h and v offset segments. Each of these is [Size] bytes long, consisting of one-byte entries for each sprite loaded in-level including those in MAINCHAR.000 and 'null' sprites. The minimum size of this is thus 237 bytes. (Max 256)
These segments are used to 'align' sprites. This is because many sprites are different heights and widths, so when they animate they should 'line up' The two segments move an individual sprite frame right or down by a certain number of pixels (The value.) While the h offsets can often be ignored, the v offsets are crucial.
Note that the levels also control sprite frame positioning and the header was merely included as a space saving measure. While a lot of the header (For Jazz's animations.) is identical between files, the actual values used for each sprite depend on how it is used in a level.
BLANK: This consists of the word $FFFF, and means nothing is loaded. It acts as a placeholder for other sprites though and chaos will result if it is moved. Thus you will often encounter large blocks of $FF in a file.
UNMASKED: This is not actually 'unmasked' as such, but doesn't have a separate masked image, using instead a transparent color. It is very efficient compared to 'masked' sprites, size-wise. The format is as follows:
1 2 Sprite width \ 4 3 2 Sprite height 5 2 Image size, sprite is made out of FOUR of these images, interlaced 7 2 Size of mask data segment, zero. 9 2 Mask size, $FFFF to indicate sprite is 'unmasked' 11 x Image 1,2,3,4 The sprite is divided into columns, image 1 consists of columns 1,5,9..., image 2 consists of columns 2,6,10... and so on. This is quite common in Jazz. 1-byte values here are the color of each pixel, 254 being transparent and 255 being unuseable.
MASKED: This is used for sprites that may or may not have 'extra height', that is, blank space added to the bottom of the sprite that need not be encoded as graphics data in the sprite file. This wastes a lot of space. Format as follows:
1 2 Sprite width \ 4 3 2 Sprite height 5 2 Mask size, [Height] * [width] usually, if this is larger than we have 'extra height' which will be automatically added to the bottom of the sprite. 7 2 Size of mask data segment 9 2 Pixel data size, number of nonzero-value pixels in sprite mask, the total 'Pixel data' size will be four times this value. 11 x Mask data, 2 bytes per line of mask; notes the sum of how many masked pixels are in the mask so far. The last entry will thus be the same as the [Pixel data size] (Total number of masked pixels.) and the first entry will be pretty low. JAZZ doesn't read this, but it is (was) used by Epic to figure out the h\v offsets earlier. ? x Compressed sprite mask, each byte is worth four pixels of sprite. Values are between 0-15, with the last four bits of each byte controlling whether the four pixels are masked, and in what order. ? x Pixel data 1,2... The color of each pixel of the sprite. The decompressed mask is divided into columns, much like the 'unmasked' sprites above. This data then controls the color of each column. Since the mask has an entry for ever four pixels, this will occasionally need a color entry for a pixel that is not supposed to be masked color 254 is used for this. (However, zero value mask entries aren't given any data here.) This is difficult to envision without a diagram.
- One of the sprites in tileset 11 is Jill from Jill of the Jungle
- One of the MAINCHAR sprites is the Epic logo
This format was deciphered from the source of OpenJazz and elaborated by Levellord. 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!)