8bit archeology returns

While working on Märchen Maze translation I checked if other Namcot games use the same image encoding format. It appears that not only some Namcot games use it but there are Pack-In-Video games as well. Maybe the same subcontractor studio was involved.
Anyway, here is the list of the games I checked so far.

The encoding is pretty simple. The image is split in 32 bytes blocs. Each bloc can be encoded using one of he following 4 techniques :

  1. 0 filled : the bloc is filled with 0. A plain old memset is enough.
    memset(out, 0, 32)
  2. Sparse : the bloc contains 0 bytes. The first 4 bytes indicates if the corresponding bloc byte is 0 or read from the data buffer.
    uint8_t *input; // pointer to encoded input data.
    uint8_t *out;   // pointer to output data.
    // ...
    // sparse_decode
    int i, j;
    uint8_t *header = input;
    uint8_t *data   = input+4;
    uint8_t  bit;
    for(i=0; i<4; i++)
        bit = header[i];
        for(j=0; j<8; j++)
            *out++ = (bit & 1) ? *data++ : 0x00;
            bit >>= 1;
  3. XOR Sparse : Just like the “sparse” encoding but the bloc was previously processed using a sequence of xor on each consecutive 16 bytes in order to increase the number of 0 in the bloc.
    sparse_decode(out, input);
    // xor
    for(i=0; i<16; i+=2)
        out[i+0x02] ^= out[i+0x00];
        out[i+0x03] ^= out[i+0x01];
        out[i+0x12] ^= out[i+0x10];
        out[i+0x13] ^= out[i+0x11];
  4. Raw : the bloc data is stored unencoded, just call
    memcpy(out, data, 32)

The encoding type is packed in 4 bits stored separately from the image data. This means that a byte stores the encoding type for 4 blocs.

The pseudo code for the whole decoding routine looks like this.

uint8_t *encoding; // pointer to the bloc encoding type array.
uint8_t *data;     // pointer to the encoded image data.
uint8_t *out;      // pointer to the output image data.
size_t bloc_count;
uint8_t current_bloc_encoding;
int i;

for(i=0; i<bloc_count; i++)
    current_bloc_encoding = (encoding[i/4] >> (i%4)) & 0x03;
        case 0: // zero filled.
            memset(out, 0, 32);
        case 1: // sparse.
            sparse_decode(out, data);
        case 2: // XOR sparse.
            sparse_decode(out, data);
        case 3: // raw data.
            memcpy(out, data, 32);
            data += 32;
    out += 32;
Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

What is 8 + 13 ?
Please leave these two fields as-is:
IMPORTANT! To be able to proceed, you need to solve the following simple math (so we know that you are a human) :-)