The Incredible Machine Image Format

From ModdingWiki
Jump to navigation Jump to search
The Incredible Machine Image Format
There is no image of a tileset in this format — upload one!
Format typeTileset
HardwareEGA, VGA
Max tile count65535
PaletteShared
Tile names?No
Minimum tile size (pixels)1x1
Maximum tile size (pixels)65535×65535
Plane count1
Plane arrangementLinear
Transparent pixels?Yes
Hitmap pixels?No
Metadata?None
Supports sub-tilesets?No
Compressed tiles?Yes
Hidden data?Yes
Games

The Incredible Machine (TIM) bitmap images are stored in the RESOURCE.00? resource files as sub-files. They have the extension .BMP.

(For full-screen images (*.SCR), see Stellar 7 RES Format.)

Chunk format

The files are built up out of chunks, in the typical Dynamix chunk format: a 3-character ID, followed by a ':', followed by the chunk size in UINT32LE format. The highest bit of the chunk size value is not actually part of the chunk size: it is set to 1 if the chunk is a container-type chunk that contains more chunks inside itself. This chunk format is documented on the Stellar 7 RES Format page.

The BMP file is contained inside one BMP chunk. This is a container chunk. None of chunks types embedded inside it are container chunks.

The first chunk inside the BMP data is the INF chunk. Its data starts with a UINT16LE indicating the number of sub-images inside the file, followed by two UINT16LE arrays containing respectively the widths and heights of all images.

Based on the chunk type that contains the image data, there are two types of images:

SCN/OFF format

The majority of the image files in The Incredible Machine, including the graphics for puzzle parts, contain an SCN and an OFF chunk. The image data is stored in the SCN chunk, while the OFF chunk contains an index for each sub-image's data inside the SCN chunk. The SCN chunk has its own compression format, described in the next section.

The SCN chunk

The SCN chunk contains the pixel data for each sub-image. Basically, it has an extended code-based run-length encoding format with 2-bit commands. This gives four commands; the classic "repeat" and "copy" ones, and two extra commands to skip ahead. These "skips" should always treat the skipped space as transparent. If the output buffer is not cleared in advance, and the decompression is not meant to directly paint the new graphics onto an existing image in the buffer, these commands might need to specifically write 0-values to fill the skipped pixels.

The data for each sub-image starts with an addValue byte that has a special meaning: its value is added to all non-transparent pixel values. It normally corresponds to the lowest pixel value found in the resulting image. The value of this byte is set to 0xFF in some "empty" images that contain only a few transparent pixels. In 8-bit games, like Heart of China, the result may be an 8-bit image, meaning addValue, and the resulting pixel values, can be larger than 0x0F. The compression itself is based on storage of 4-bit pixels, though, so even on 8-bit images, the final data can only contain values from addValue up to addValue + 0x0F, plus the background colour. This special handling of transparency makes sure that the full range of the 4 bits can be used for colours, without the need to sacrifice one for transparency. This does make it difficult to convert to classic image formats without upgrading the image to at least 8-bit.

The actual RLE codes start after this byte. The command is made from the upper two bits, with the lower six bits serving as the value.

Note that this value always denotes a number of pixels, not bytes, which may be tricky to program for 4-bit images. An alternative approach could be to decompress the image to an 8-bit buffer, and post-process the result to compact it to 4-bit (unless the addValue makes the values too large for that, and it is intended to be 8-bit).

The four different commands are:

Command 0: Line skip

The command made from high bits 00 is meant to skip to the next line in the image. This command must be used to terminate a line in the image; the format does not seem to support automatic wraparound for progressing to a new line. This also means none of the other commands will ever write data that goes beyond the end of a line.

The line skip command will move the output pointer down one line on the image (ending up on the same X-coordinate on the next line), and then move back by the amount of pixels specified in value. With wraparound included, this means the operation simply jumps (or background-fills) to the position width - value pixels ahead of your current output write position.

There are some special cases in this, though. Since this should be able to move from the end of one line to the start of the next one, it needs to be able to address the entire width of the image, which, on large images, can't be done in one 6-bit value. Because of this, the data may contain two consecutive bytes with a 'line skip' command, and the values of both of these need to be taken together, with the second command providing the more significant seventh to twelfth bits to be added to the first read value, as value = value1 | (value2 << 6).

However, if an image has several empty lines in it, it can be unclear whether or not such commands should be taken together. Because of this, if the second command has a value of 0, the rule is to always treat it as separate command. To avoid all ambiguity in these cases, and because a value 00 code can be extended by one with a higher value, if the non-empty pixels on that later line start at an X-coordinate earlier than the end (start of the empty pixels) of that earlier line, the first line skip command will always align the X-coordinate with the point at which the data restarts after the gap, so that all commands following it can be non-ambiguous byte 00 full line skips. Note that if the pixel where the skip starts is at an identical or higher X-coordinate, all line skips can be done with 00 bytes, and any remaining distance can simply be filled up with 'short skip' commands (see below), which can perfectly be placed after the 00 bytes.

Command 1: Short skip

The command you get when the high bits are 01 will skip (or background-fill) the amount of pixels specified in value. Numbers greater than 0x3F will simply be encoded in multiple 'short skip' commands. A 'short skip' command with a value of 0, resulting in a Code byte 0x40, is used to indicate the end of the decompression of the current sub-image.

Command 2: Repeat

A command made up of bits 10 will create a sequence of pixels of the same color. The repeat count is specified by value. A single byte follows the Code byte, containing the pixel value. Since this is a 4-bit format, the most significant 4 bits of this byte are always zero. Note that the addValue from the start of the data needs to be added to this to get the real pixel value to repeat.

Command 3: Copy

The command from high bits 11 is the Copy command. This simply copies a sequence of pixel values to the output. The amount of pixels is specified in value.

Since the amount is in pixels, the number of bytes after the Code byte does not match the value. It can be calculated as (value + 1) >> 1. Each byte contains two pixels, with the color of the leftmost pixel stored in the most significant nibble. If the number of pixels is odd, the most significant 4 bits of the last byte contains the color of the last pixel, and the less significant nibble is zero. Note that since the addValue from the start of the data needs to be added to every pixel in this range, and the starting position to write pixels to may be an odd number at the start of the command, this operation requires treating all data as nibbles to process them correctly.

Terminator

Nearly all sub-images are "terminated" by the byte sequence 0x00 0x40; a full line skip, followed by an empty short skip command. However, there are a few exceptions, where it ends on 0x40 alone. Do note that while a 0x40 can always be considered a terminator command, since it has no real meaning on its own, a 0x00 is a perfectly valid full-line skip, and should never be treated as a signal to end the decompression.

The OFF chunk

The OFF chunk contains the offsets for each sub-image in the SCN chunk, as UINT32LE values. The first one should always be zero.

The end of the current sub-image's compressed data in the SCN chunk can be determined from the start of the next offset in the list, or the length of the SCN chunk, if it's the final image. In practice, though, the data itself will always indicate the end with the 0x40 terminator value.

Format quirks

Since the 'line skip' command is the only valid way to progress to a new line, and this can only address up to 12 bits, images in this format are technically restricted to a width of up to 4095 pixels.

BIN format

The remaining files in The Incredible Machine use a BIN chunk (e.g. MOUSE.BMP, PARTBIN.BMP).

The BIN chunk has a small header of one byte to indicate the compression algorithm, followed by a UINT32LE giving the uncompressed size. It supports the same compression algorithms as Dynamix fonts. The header is immediately followed by the compressed 4bpp pixel data.

This format is the 4 bit per pixel version of the BIN/VGA-containing BMP format found in several 8-bit Dynamix games.

Tools

The following tools are able to work with files in this format.

Name PlatformView images in this format? Convert/export to another file/format? Import from another file/format? Access hidden data? Edit metadata? Notes
The Incredible Machine level/image resource viewer (VOGONS) Windows, LinuxYesYesNoNoN/A
The Incredible Machine image resource reader Windows, LinuxYesYesNoNoN/A Outdated version.
Engie File Converter WindowsYesYesYesNoN/A Supports SCN/OFF files with a high addValue byte, treating them as 8-bit.

Credits

The SCN compression was reverse engineered by Knt47, with further detail research conducted by Nyerguds. 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!)