The tBMP images stored in Riven Mohawk archives are 8-bpp (256-color) palettized bitmaps. Each image file contains a header, a color table, and bitmap data, which is usually compressed.
Home | Exile Movie Index | Saavedro’s Journal | Riven Image Viewer |
The tBMP images stored in Riven Mohawk archives are 8-bpp (256-color) palettized bitmaps. Each image file contains a header, a color table, and bitmap data, which is usually compressed.
The header specifies the dimensions and format of the image:
Offset | Size | Description |
---|---|---|
0x0000 | Word | The width of the image in pixels. |
0x0002 | Word | The height of the image in pixels. |
0x0004 | Word | The number of bytes per row of pixels. |
0x0006 | Word | 0x000A if the bitmap data is uncompressed; 0x040A if the bitmap data is compressed. |
0x0008 | Word | The value 0x0304 . (Perhaps this is the offset of the bitmap data relative to this field.) |
0x000A | Word | The value 0x18FF . (Unknown) |
Note: “Word” and “double word” denote two- and four-byte big-endian integers.
The color table is an array of 256 red-green-blue triplets that specify the colors used in the image:
Offset | Size | Description |
---|---|---|
0x000C | Byte | Color 0: Blue. |
0x000D | Byte | Color 0: Green. |
0x000E | Byte | Color 0: Red. |
0x000F | Byte | Color 1: Blue. |
0x0010 | Byte | Color 1: Green. |
0x0011 | Byte | Color 1: Red. |
. . . | ||
0x0309 | Byte | Color 255: Blue. |
0x030A | Byte | Color 255: Green. |
0x030B | Byte | Color 255: Red. |
When uncompressed, the bitmap data consists of the color-table index for each pixel in the bitmap, in order from left to right and top to bottom. Each index is one byte. If necessary, up to three zero-valued bytes pad every row of indexes so that each row ends on a four-byte boundary.
For uncompressed images, the bitmap data immediately follows the color table:
Offset | Size | Description |
---|---|---|
0x030C | Byte | The first byte of uncompressed bitmap data (the color-table index for the top-left pixel in the bitmap). |
For compressed images, a four-byte value precedes the compressed bitmap data:
Offset | Size | Description |
---|---|---|
0x030C | DWord | (Unknown) |
0x0310 | Byte | The first byte of compressed bitmap data (the opcode of the first instruction). |
When compressed, the bitmap data is a series of variable-length “instructions”. Each instruction consists of a one-byte opcode followed by zero or more operands. There are many different opcodes; each opcode specifies an operation that outputs one or more words of uncompressed data (color-table indexes and padding).
The Riven image decompressor uses two distinct sets of opcodes, which are documented in the sections below. Initially, the decompressor uses Instruction Set 1. It uses Instruction Set 2 when directed to do so.
The instruction set tables use the following conventions:
Symbol | Description |
---|---|
N, X, Y | Represents a value ranging from 0x00 to 0xFF . |
[n] | Represents a byte with the value n. |
<n> | Represents the value of the n-th previous output byte, counting bytes already output by the current instruction. For example, <1> represents the value of the last byte that was output. |
{n} | Indicates that the previous term is repeated n times. For example, [<4>]{2} stands for [<4>] [<4>]. |
.. | Indicates a range of consecutive values. For example, 1..3 represents the values 1, 2, and 3. |
Instruction | Output Bytes | Description |
---|---|---|
[0x00 ] | None | Stop. (This instruction terminates the compressed bitmap data.) |
[0x00 +n] [X1] ... [X2n]; n=2..31 | [X1] ... [X2n] | Output n words of raw data. |
[0x40 +n]; n=1..31 | [<2>]{2n} | Copy the last word n times. |
[0x80 +n]; n=1..31 | [<4>]{4n} | Copy the last two words n times. |
[0xC0 +n]; n=1..63 | Execute the next n instructions using Instruction Set 2. |
The remaining opcodes (0x01, 0x20–0x40, 0x60–0x80, and 0xA0–0xC0) are unused.
In the following table, the variables n, r, and s represent hexadecimal digits ranging from 1 to F.
Instruction | Output Bytes | Description |
---|---|---|
[0x00 ] | (Unused) | |
[0x0 n] | [<2n>] [<2n>] | Copy the n-th previous word. |
[0x10 ] [X] | [<2>] [X] | Copy the last word; replace its second byte by X. |
[0x1 n] | [<2>] [<n>] | Copy the last word; replace its second byte by the n-th previous byte. |
[0x20 ] | (Unused) | |
[0x2 s] | [<2>] [<2>+s] | Copy the last word; increment its second byte by s. |
[0x30 ] | (Unused) | |
[0x3 s] | [<2>] [<2>−s] | Copy the last word; decrement its second byte by s. |
[0x40 ] [X] | [X] [<2>] | Copy the last word; replace its first byte by X. |
[0x4 n] | [<n>] [<2>] | Copy the last word; replace its first byte by the n-th previous byte. |
[0x50 ] [X] [Y] | [X] [Y] | Output X and Y. |
[0x50 +k] [X]; k=1..7 | [<k>] [X] | Copy the k-th previous byte and output X. |
[0x58 ] | (Unused) | |
[0x58 +k] [X]; k=1..7 | [X] [<k>] | Output X and copy the k-th previous byte. |
[0x60 ] | (Unused) | |
[0x6 s] [X] | [X] [<2>+s] | Copy the last word; replace its first byte by X and increment its second byte by s. |
[0x70 ] | (Unused) | |
[0x7 s] [X] | [X] [<2>−s] | Copy the last word; replace its first byte by X and decrement its second byte by s. |
[0x80 ] | (Unused) | |
[0x8 r] | [<2>+r] [<2>] | Copy the last word; increment its first byte by r. |
[0x90 ] | (Unused) | |
[0x9 r] [X] | [<2>+r] [X] | Copy the last word; increment its first byte by r and replace its second byte by X. |
[0xA0 ] [rs] | [<2>+r] [<2>+s] | Copy the last word; increment its first byte by r and increment its second byte by s. |
[0xA1 ][ 0xA2 ][ 0xA3 ] | (Unused) | |
[0xA4 +k] [N] [X]; k=0..3 | [<N+256k>]{3} [X] | Copy 3 bytes starting at the (N + 256k)-th previous byte. Then output X. |
[0xA8 +k] [N]; k=0..3 | [<N+256k>]{4} | Copy 4 bytes starting at the (N + 256k)-th previous byte. |
[0xAC +k] [N] [X]; k=0..3 | [<N+256k>]{5} [X] | Copy 5 bytes starting at the (N + 256k)-th previous byte. Then output X. |
[0xB0 ] [rs] | [<2>+r] [<2>−s] | Copy the last word; increment its first byte by r and decrement its second byte by s. |
[0xB1 ][ 0xB2 ][ 0xB3 ] | (Unused) | |
[0xB4 +k] [N]; k=0..3 | [<N+256k>]{6} | Copy 6 bytes starting at the (N + 256k)-th previous byte. |
[0xB8 +k] [N] [X]; k=0..3 | [<N+256k>]{7} [X] | Copy 7 bytes starting at the (N + 256k)-th previous byte. Then output X. |
[0xBC +k] [N]; k=0..3 | [<N+256k>]{8} | Copy 8 bytes starting at the (N + 256k)-th previous byte. |
[0xC0 ] | (Unused) | |
[0xC r] | [<2>−r] [<2>] | Copy the last word; decrement its first byte by r. |
[0xD0 ] | (Unused) | |
[0xD r] [X] | [<2>−r] [X] | Copy the last word; decrement its first byte by r and replace its second byte by X. |
[0xE0 ] [rs] | [<2>−r] [<2>+s] | Copy the last word; decrement its first byte by r and increment its second byte by s. |
[0xE1 ][ 0xE2 ][ 0xE3 ] | (Unused) | |
[0xE4 +k] [N] [X]; k=0..3 | [<N+256k>]{9} [X] | Copy 9 bytes starting at the (N + 256k)-th previous byte. Then output X. |
[0xE8 +k] [N]; k=0..3 | [<N+256k>]{10} | Copy 10 bytes starting at the (N + 256k)-th previous byte. |
[0xEC +k] [N] [X]; k=0..3 | [<N+256k>]{11} [X] | Copy 11 bytes starting at the (N + 256k)-th previous byte. Then output X. |
[0xF0 ] [rs] | [<2>−r] [<2>−s] | Copy the last word; decrement its first byte by r and decrement its second byte by s. |
[0xF1 ][ 0xF2 ][ 0xF3 ] | (Unused) | |
[0xF4 +k] [N]; k=0..3 | [<N+256k>]{12} | Copy 12 bytes starting at the (N + 256k)-th previous byte. |
[0xF8 +k] [N] [X]; k=0..3 | [<N+256k>]{13} [X] | Copy 13 bytes starting at the (N + 256k)-th previous byte. Then output X. |
[0xFC ] [8m+k] [N] [X]; m=0..31, k=0..3 | [<N+256k>]{2m+3} [X] | Copy (2m + 3) bytes starting at the (N + 256k)-th previous byte. Then output X. |
[0xFC ] [8m+k+4] [N]; m=0..31, k=0..3 | [<N+256k>]{2m+4} | Copy (2m + 4) bytes starting at the (N + 256k)-th previous byte. |
[0xFD ][ 0xFE ][ 0xFF ] | (Unused) |
Bytes are incremented and decremented modulo 256. For example, 0xFF + 1 = 0x00, and 0x00 − 1 = 0xFF.
Some opcodes are unused because equivalent opcodes exist:
© 2004–2006 Rising Productions. Last updated: February 22, 2006.