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 :
- 0 filled : the bloc is filled with 0. A plain old memset is enough.
memset(out, 0, 32)
- 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; } }
- 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]; }
- 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; switch(current_bloc_encoding) { case 0: // zero filled. memset(out, 0, 32); break; case 1: // sparse. sparse_decode(out, data); break; case 2: // XOR sparse. sparse_decode(out, data); xor(out); break; case 3: // raw data. memcpy(out, data, 32); data += 32; break; } out += 32; }
- Source code for Märchen Maze, Obocchama Kun and Zipang.
- Source code for World Jockey.