I keep looking for old games with interesting animation formats and I’ve found another two, from Israeli companies this time.
First is the format used in Armed & Delirious. Since all of the files are in the custom archive (except for a single file with “please change CD” animation) I’m not going to support it, though I still documented it for posterity. Apparently it has two operating modes: updating some lines where each line can have its own coding mode (all are RLE variations) and updating tiles, now with each tile having its own coding mode. The only interesting thing is that tile coding operates on a sub-set of colours so it can use 3-6 bits for index. I remember some formats resorting to 16 colours and 4-bit indices but there are more variations here.
And then there’s VID format used in Soul Hunt and, apparently, some other games by the same company. It features DPCM-compressed audio and depending on version RLE- or JPEG-compressed images (and both versions are present in the game). That’s right, they use code (probably borrowed from libjpeg
but I’m not sure about that) to decode data in JPEG-like format (8×8 blocks, IDCT and such) and then use some large lookup table to convert it from YUV to paletted RGB. Of course there are video codecs with such built-in functionality like Cinepak or Indeo 3 but it’s still surprising to see such thing in a random codec.
Update from December 21st: I’ve looked at JPEG-inspired coding again and I have a better understanding what it does (so maybe I’ll even be able to support it eventually):
- there’s intra- and inter-coding, the former operates on 256×16 megablocks (consisting of 32×2 Y blocks and 16 U and V blocks each), the latter has a macroblock update mask and codes only updated macroblocks;
- there are two quantisation matrices sets used in intra and inter mode, the binary specifications calls them “good” and “bad” factors;
- the colour conversion code and IDCT seem to come from
libjpeg
while coefficient coding is their own invention; - coefficient coding seems to employ a rather simple set of codes:
xxx0
is used for -4..4 values (codes are LSB first),xxxxxx01
is used for larger values,xxxxxx11
is used to code zero runs andxxxxxxxx 11111111
is used to code large values; - DC prediction is present and works the following way: decode block, dequantise it, add last DC value (and update it afterwards), scale block DC value by 32.
Initially I was discouraged by the coefficient decoding routines being implemented as state machines with computed label, so Ghidra
cannot decompile it properly. I.e. it starts with “refill bit buffer” state, then moves to “decode new coefficient having 32 bits”, then it handles one of four cases listed above and moves to “decode new coefficient having 28 bits”, or “decode new coefficient having 24 bits”, or “decode new coefficient having 16 bits” state—unless it decoded the full block and saves that state to keep working from it the next time the function is called. Oh well, at least it turned out to be not that much complicated in the end.
Update from December 27th: I dug a bit more and while decoding macroblock data looks feasible, reconstructing it properly is bonkers, as the game reads quantisation matrices and scale factor for good/bad case from quants.ini
text file. So I’m not so sure it’s worth the effort…