Riven tBMP resources
Riven | |||
Mohawk | Overview | ||
BLST | CARD | FLST | HSPT |
MLST | NAME | PLST | RMAP |
SFXE | SLST | tBMP | tMOV |
tWAV | VARS | VERS | ZIPS |
Scripts | Variables | ||
External commands |
This page shows the structure of Riven tBMP resources, which store game bitmaps.
Contents
General tBMP structure
tBMP resources store 8-bit and 24-bit bitmaps, which can be plain or compressed. Everything is in big-endian order. Each resource begins with this structure:
unsigned short | bitmap width (pixels) |
unsigned short | bitmap height (pixels) |
unsigned short | bytes per row |
unsigned char | compression flag |
unsigned char | truecolor flag |
If the truecolor flag is 4 then the bitmap is a 24-bit image, and the structure goes on with height rows, each row following this structure:
width*3 unsigned chars | pixel values (BGR, BGR, BGR...) |
width unsigned chars | unknown (zero) |
Note that there is only one 24-bit bitmap in the whole game! It's tBMP 24 in b2_data.mhk, and it's a secret image.
If the truecolor flag is not 4 the tBMP is a normal 8-bit bitmap and after the initial fields we find:
unsigned long | unknown (seems always 0x030418ff) |
256*3 unsigned chars | color table (BGR, BGR, BGR...) |
If the compression flag is 0, the bitmap is uncompressed: pixel data follows immediately as a simple block of pixels. Each pixel is a byte representing an index in the color table. Rows may be padded with filling bytes to reach the specified number of bytes per row; just discard those extra bytes. Otherwise, if the compression flag is 4 then the bitmap is compressed with a proprietary format (explained below); the compressed data block follows immediately.
Compression details
In compressed tBMP bitmaps, pixels are encoded as a data stream made of variable length commands. Pixels are always decoded in duplets: each command generates at least 2 pixels. The encoding is heavily based on what comes before each command, so even a little decoding bug can cripple the whole image. The commands can appear in any order inside the data stream. The first 4 bytes of the data stream are unknown and can be ignored. Many thanks to Arthur Muller for his precious help in decoding this format. Main commands
They are all 1-byte commands, followed by a variable number of arguments.
Command | Action |
---|---|
0x00 | End of stream: when reaching it, the decoding is complete. No additional bytes follow. I think some bitmaps don't have this, so just stop when you have decoded enough pixels to fill the image. |
0x01 -0x3f | Output n pixel duplets, where n is the command value itself. Pixel data comes immediately after the command as 2*n bytes representing direct indices in the 8-bit color table. |
0x40-0x7f | Repeat last 2 pixels n times, where n = command_value & 0x3F. No additional bytes follow. |
0x80-0xbf | Repeat last 4 pixels n times, where n = command_value & 0x3F. No additional bytes follow. |
0xc0-0xff | Begin of a subcommand stream. This is like the main command stream, but contains another set of commands which are somewhat more specific and a bit more complex. This command says that command_value & 0x3F subcommands will follow. It doesn't generate pixels itself. |
Subcommands, part 1: arithmetic operations
Subcommands are not simply 1-byte values, but are somewhat mixed with their arguments, so the full byte pattern is reported.
Command | Byte pattern | Action |
---|---|---|
0x01-0x0f | 0000mmmm | Repeat duplet at relative position -m, where m is given in duplets. So if m=1, repeat the last duplet. |
0x10 | 0x10 p | Repeat last duplet, but change second pixel to p. |
0x11-0x1f | 0001mmmm | Output the first pixel of last duplet, then pixel at relative position -m. m is given in pixels. |
0x20-0x2f | 0010xxxx | Repeat last duplet, but add x to second pixel. |
0x30-0x3f | 0011xxxx | Repeat last duplet, but subtract x to second pixel. |
0x40 | 0x40 p | Repeat last duplet, but change first pixel to p. |
0x41-0x4f | 0100mmmm | Output pixel at relative position -m, then second pixel of last duplet. |
0x50 | 0x50 p1 p2 | Output two absolute pixel values, p1 and p2. |
0x51-0x57 | 01010mmm p | Output pixel at relative position -m, then absolute pixel value p. |
0x59-0x5f | 01011mmm p | Output absolute pixel value p, then pixel at relative position -m. |
0x60-0x6f | 0110xxxx p | Output absolute pixel value p, then (second pixel of last duplet) + x. |
0x70-0x7f | 0111xxxx p | Output absolute pixel value p, then (second pixel of last duplet) - x. |
0x80-0x8f | 1000xxxx | Repeat last duplet adding x to the first pixel. |
0x90-0x9f | 1001xxxx p | Output (first pixel of last duplet) + x, then absolute pixel value p. |
0xa0 | 0xa0 xxxxyyyy | Repeat last duplet, adding x to the first pixel and y to the second. |
0xb0 | 0xb0 xxxxyyyy | Repeat last duplet, adding x to the first pixel and subtracting y from the second. |
0xc0-0xcf | 1100xxxx | Repeat last duplet subtracting x from first pixel. |
0xd0-0xdf | 1101xxxx p | Output (first pixel of last duplet) - x, then absolute pixel value p. |
0xe0 | 0xe0 xxxxyyyy | Repeat last duplet, subtracting x from first pixel and adding y to second. |
0xf0 and 0xff | 0xfx xxxxyyyy | Repeat last duplet, subtracting x from first pixel and y from second. |
Subcommands, part 2: repeat operations
Command | Byte pattern | Action | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
various | 1x1xxxmm mmmmmmmm |
Repeat n duplets from relative position -m (given in pixels, not duplets). If r is 0, another byte follows and the last pixel is set to that value. n and r come from the table on the right. | ||||||||||||||||||||||||||||||||||||
0xfc | 0xfc nnnnnrmm mmmmmmmm (p) | Repeat n+2 duplets from relative position -m (given in pixels, not duplets). If r is 0, another byte p follows and the last pixel is set to absolute value p. |