The format LC_LZ2 is a lossless compression technique used by Super Mario World and The Legend of Zelda: A Link to the Past for the Super Nintendo to compress graphics into a (sometimes) smaller format. The LC_LZ2 decompression routine is setup at SNES $00:B888. The decompression routine itself is located at SNES $00:B8DE. During the decompression, the decompressed chunks are outputted into a buffer which is either RAM or SRAM.
In the ROM class I've implemented a version of the format based on @Skarsnik sneshacking as well as @zarby89 ZScreamDungeon which both implement the format in C and C# respectively.
The ROM::Decompress method has been visually tested and confirmed to decompress the graphics in The Legend of Zelda: A Link to the Past, and now the goal is to implement compression as well. Given the editor is still early in development, I have no edited graphics or overworld tiles yet to compress or test (besides generating my own 3bpp snes tiles like in sneshacking) so I'm only using unit tests to confirm ROM::Compress.
The current pull request represents a transition from the C style buffers and pointers of @skarsnik sneshacking to a more idiomatic C++ smart pointers and container based implementation. The code makes use of the Google abseil-cpp library for string manipulation and error handling.
The header byte $FF marks the end of the data stream.
List of commands
%000 - "Direct Copy" - followed by (L+1) bytes of data
%001 - "Byte Fill" - followed by 1 byte to be repeated (L+1) times
%010 - "Word Fill" - Followed by two bytes. Output first byte, then second, then first, then second, etc. until (L+1) bytes has been outputted
%011 - "Increasing Fill" - Followed by one byte to be repeated (L+1) times, but the byte is increased by 1 after each write
%100 - "Repeat" - Followed by two bytes (big endian) containing address (in the output buffer) to copy (L+1) bytes from
%101 - Unused
%110 - Unused
%111 - "Long length" - This command has got a two-byte header:
111CCCLL LLLLLLLL
CCC: Real command
LLLLLLLLLL: Length
Normally you have 5 bits for the length, so the maximum value you can represent is 31 (which outputs 32 bytes). With the long length, you get 5 more bits for the length, so the maximum value you can represent becomes 1023, outputting 1024 bytes at a time.
The format
LC_LZ2
is a lossless compression technique used by Super Mario World and The Legend of Zelda: A Link to the Past for the Super Nintendo to compress graphics into a (sometimes) smaller format. TheLC_LZ2
decompression routine is setup at SNES$00:B888
. The decompression routine itself is located at SNES$00:B8DE
. During the decompression, the decompressed chunks are outputted into a buffer which is either RAM or SRAM.In the
ROM
class I've implemented a version of the format based on @Skarsnik sneshacking as well as @zarby89 ZScreamDungeon which both implement the format in C and C# respectively.The
ROM::Decompress
method has been visually tested and confirmed to decompress the graphics in The Legend of Zelda: A Link to the Past, and now the goal is to implement compression as well. Given the editor is still early in development, I have no edited graphics or overworld tiles yet to compress or test (besides generating my own 3bpp snes tiles like in sneshacking) so I'm only using unit tests to confirmROM::Compress
.The current pull request represents a transition from the C style buffers and pointers of @skarsnik sneshacking to a more idiomatic C++ smart pointers and container based implementation. The code makes use of the Google abseil-cpp library for string manipulation and error handling.
Further reading on LC_LZ2:
Credit to user @bonimy for the markdown explanation of the format.
LC_LZ2 Format
This format is identical to LZ1, except the repeat command's address is big endian.
The compressed stream consists of chunks, each starting with a 1 byte header.
The header byte
$FF
marks the end of the data stream.List of commands
%000
- "Direct Copy" - followed by (L+1) bytes of data%001
- "Byte Fill" - followed by 1 byte to be repeated (L+1) times%010
- "Word Fill" - Followed by two bytes. Output first byte, then second, then first, then second, etc. until (L+1) bytes has been outputted%011
- "Increasing Fill" - Followed by one byte to be repeated (L+1) times, but the byte is increased by 1 after each write%100
- "Repeat" - Followed by two bytes (big endian) containing address (in the output buffer) to copy (L+1) bytes from%101
- Unused%110
- Unused%111
- "Long length" - This command has got a two-byte header:Normally you have 5 bits for the length, so the maximum value you can represent is 31 (which outputs 32 bytes). With the long length, you get 5 more bits for the length, so the maximum value you can represent becomes 1023, outputting 1024 bytes at a time.