« on: September 12, 2016, 10:54:03 pm »
I managed to figure out the graphics compression for Digimon 02: Tag Tamers and wrote a simple decompressor script (super duper proud of myself). Now I need to find a way to cram my new changes back in... and I'm not quite sure how.
The graphics are 2BBP: 00 00 is a black line, FF FF is a white line, etc. The compressed image starts with some meta data (length/width/location, how many tiles will be drawn, etc).
The data is partitioned off with single opcodes that determine how much of its section is uncompressed. For instance, if the section starts with FF:
*Convert to binary, 1111 1111.
*Read from right to left
*If it's "1", the hex value at that position is uncompressed (read one byte)
*If it's "0", the hex value at that position is a compressed opcode (read two bytes)
An FF section reads in 8 bytes before the next section, a 00 section reads in 16, and anything in-between reads in 8 < x < 16 bytes.
If we hit an opcode, then we're repeating a certain amount of lines/hex codes that were already drawn.
In the opcode, the first byte multipled by 16 is how many bytes you go back to start repeating. The following byte is split in two; the first nybble can be used to go back an additional number of hex codes, and the second nybble tells us how many bytes to repeat... plus 3 (since a two byte hex code that only draws 1 or 2 is a waste of space, haha).
Example: 01 45 would go back (1 * 16) + 4 hex values, then redraw the next (5 + 3) hexcodes from there. If it hits the end of the drawn lines before it finishes, it'll loop back to the starting point and repeat the process (this usually only happens with a 00 opcode).
I've been able to use this information manually edit a few in-game graphics so far, but that way lies madness. I think I have an idea of how to write the recompression routine:
*[Fill array with all uncompressed data]
*Read in byte
*Start from index 0 of uncompressed hexcodes array and work our way to the current read position
--Find the longest matching sequence that starts with the current byte
--If greater than/equal to 3, create opcode
--Otherwise, add in byte as uncompressed
--When we have enough for a section, create the appropriate separator byte and add to "Output" array
*Read in next byte, and repeat until finished.
Not 100% sure this works, but it seems like it would.
I'm not too concerned with the efficency of the algorithm itself (although I don't mind any feedback there) so much as generating the smallest compressed output to fit back in.
Any suggestions or advice would be much appreciated!