Riven tBMP resources

From A look inside The Link @ wiki
Revision as of 02:01, 6 February 2008 by Di gama (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

This page shows the structure of Riven tBMP resources, which store game bitmaps.

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
Command n r
0xa4 - 0xa7 2 0
0xa8 - 0xab 2 1
0xac - 0xaf 3 0
0xb4 - 0xb7 3 1
0xb8 - 0xbb 4 0
0xbc - 0xbf 4 1
0xe4 - 0xe7 5 0
0xe8 - 0xeb 5 1
0xec - 0xef 6 0
0xf4 - 0xf7 6 1
0xf8 - 0xfb 7 0

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.