Jump to content

Sprite decompression (Generation I): Difference between revisions

(Added an attribution section for now for Kagamiin's discovery, since the corresponding description above may need some significant revision.)
 
(3 intermediate revisions by 2 users not shown)
Line 39:
For glitch Pokémon, those two sizes often mismatch. The size indicated first byte of the compressed data stream is often called the '''actual sprite size''', and the size indicated by the byte in the base stats data structure is often called the '''base stats sprite size'''. The front and back sprites for a glitch Pokémon each has its own actual sprite size, but there is only one base stats sprite size for the front sprite. Pokémon from the same [[family]] always share the same base stats sprite size, but their sprites may be different since those sprite data may be in different banks (even though they share the same two-byte pointer), in which case each sprite will have its own actual size.
 
The actual sprite size determines whether the sprite causes memory corruption, and how much. For an actual sprite size of ''w''×''h'', the sprite decompression routine will always read data from the input stream until it has output (''w''×8)×(''h''×8) bits, i.e., ''w''×''h''×8 bytes, for each of the two bit planes. Each bit plane is written to a contiguous region in the memory, starting from <code>sSpriteBuffer1</code> and <code>sSpriteBuffer2</code> respectively, meaning that they will overlap each other if ''w''×''h'' > 49. Then the bit planes are unpacked by operating on the same memory regions. Both decoding and unpacking are handled with double loops, and both ''w'' and ''h'' must be in the range of 0–15 since they are nybbles, so the only relevant possibility of arithmetic overflow is that when (''w''×8) and/or (''h''×8) are 0, they are usually treated as if they were 256, or equivalently that '''when ''w'' and/or ''h'' are 0, they are usually treated as if they were 32.'''
 
However, there is a single exception to this special treatment of 0: The delta decoding procedure, which is one of the two major subroutines of the unpacking procedure, actually uses arithmetic (i.e. adding the ''h''×8 to the pointer) to move the pointer to the next column<ref>[https://github.com/pret/pokered/blob/e076ee0a40b2a21183e2cc535519e64b706b5407/home/uncompress.asm#L347-L350 The lines of code to move to the next column in the delta decoding procedure]</ref>, instead of increasing the pointer for each row in the sprite. This means that, when ''h'' is 0, this procedure would be unable to move to the next column (since it keeps adding 0 to the pointer), and instead keep decoding bytes corresponding to the first column of the sprite buffer. This special behavior is particularly important because the other major subroutine of the unpacking procedure, XOR unpacking, does not happen for unpacking mode 0, whereas delta decoding is guaranteed to happen at least once.
Since the distance between <code>sSpriteBuffer2</code> and the start of the Hall of Fame data is 392+256 = 648, Hall of Fame corruption will happen when ''w''×''h''×8 > 648, i.e., ''w''×''h'' > 81. Meanwhile, WRAM corruption will only happen when ''w''×''h'' > 926, which is only possible for a sprite with actual size 0×0 (e.g., Yellow [[MissingNo.]]), where both ''w'' and ''h'' are treated as 32. If WRAM corruption does happen, it will affect WRAM addresses up to $C30F, which contain variables used by the sound engine as well as some sprite data<ref>[https://github.com/pret/pokered/blob/bbb0e7e82deb6741f75a12b48f81076d92f5d9dc/ram/wram.asm#L1-L149 The range of WRAM addresses that can be affected by sprite corruption], up to and including the entire 4-byte structure <code>wShadowOAMSprite03</code></ref>. Corruption of those data is the causes of [[Pokémon_sprite_corruptions#Sound_and/or_sound_bank_corruption|sound and/or sound bank corruption]] and the [[walking characters effect]] respectively.
 
Since the distance between <code>sSpriteBuffer2</code> and the start of the Hall of Fame data is 392+256 = 648, Hall of Fame corruption will happen when ''w''×''h''×8 > 648, i.e., ''w''×''h'' > 81. Meanwhile, WRAM corruption will only happen when ''w''×''h'' > 926, which is only possible for a sprite with actual size 0×0 (e.g., Yellow [[MissingNo.]]), where both ''w'' and ''h'' are treated as 32. If WRAM corruption does happen, it will be able to affect WRAM addresses up to $C30F, which contain variables used by the sound engine as well as some sprite data<ref>[https://github.com/pret/pokered/blob/bbb0e7e82deb6741f75a12b48f81076d92f5d9dc/ram/wram.asm#L1-L149 The range of WRAM addresses that can be affected by sprite corruption], up to and including the entire 4-byte structure <code>wShadowOAMSprite03</code></ref>. Corruption of those data is the causes of [[Pokémon_sprite_corruptions#Sound_and/or_sound_bank_corruption|sound and/or sound bank corruption]] and the [[walking characters effect]] respectively.
 
A subtle point is that, even though the actual size of a sprite determines the memory region it may affect, its actual corruption effect will depend on both the detailed sprite data and the state of that memory region before corruption. In particular, some 0×0 sprites may not be able to touch certain WRAM addresses (e.g. the sound bank) due to a combination of several factors:
* The run-length decoding procedure writes bits to the memory with bitwise OR, so if the bits it is supposed to write to a byte happen to be all zeros, it would not affect that byte. This is made more likely by the fact that the run-length decoding procedure is designed so that it is easier (i.e. more likely on random inputs) to produce zeros than ones.
* The delta decoding procedure, as mentioned above, only affects the first column (i.e. first 256 bytes) of each sprite buffer when the sprite height is 0, meaning that it would not touch the WRAM in this case.
* The XOR unpacking procedure may not happen at all if the unpacking mode (determined by the sprite data) happens to be 0.
 
== Run-length decoding ==
Line 81 ⟶ 88:
* [https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g Retro Game Mechanics Explained] uploaded multiple YouTube videos (see above) that analyzed sprite decompression in detail, which formed one of the earliest publicly available documentations on this topic.
* Kagamiin discovered that the delta decoding procedure (but not the XOR unpacking procedure) uses pointer arithmetic when moving to the next column, which does ''not'' treat a sprite height of 0 as 256, resulting in a "special" behavior for sprites with height 0.
 
== See also ==
*[[Sprite compression (Generation I)]]
 
==External links==
*[https://rgmechex.com/tech/gen1decompress.html Retro Game Mechanics Explained's tool to compress and decompress sprites online (supports PNGs)]
*"Sprite import tools for RBY" can be downloaded within Evie's Google Sites backup [https://drive.google.com/drive/folders/1DAVPYay9sAuXwi4qXbDQfPU2sIDI_mXH?usp=sharing here]. It is based on the previous work of the GB Dev (for .2bpp encoding) and Skeetendo (for sprite compression) communities.
 
== References ==
Cookies help us deliver our services. By using our services, you agree to our use of cookies.