pokefirered/src/decompress.c

208 lines
5.7 KiB
C

#include "global.h"
#include "gflib.h"
#include "decompress.h"
#include "pokemon.h"
EWRAM_DATA ALIGNED(4) u8 gDecompressionBuffer[0x4000] = {0};
void LZDecompressWram(const void *src, void *dest)
{
LZ77UnCompWram(src, dest);
}
void LZDecompressVram(const void *src, void *dest)
{
LZ77UnCompVram(src, dest);
}
// Checks if `ptr` is likely LZ77 data
// Checks word-alignment, min/max size, and header byte
// Returns uncompressed size if true, 0 otherwise
u32 IsLZ77Data(const void *ptr, u32 minSize, u32 maxSize)
{
const u8 *data = ptr;
u32 size;
// Compressed data must be word aligned
if (((u32)ptr) & 3)
return 0;
// Check LZ77 header byte
// See https://problemkaputt.de/gbatek.htm#biosdecompressionfunctions
if (data[0] != 0x10)
return 0;
// Read 24-bit uncompressed size
size = data[1] | (data[2] << 8) | (data[3] << 16);
if (size >= minSize && size <= maxSize)
return size;
return 0;
}
u16 LoadCompressedSpriteSheet(const struct CompressedSpriteSheet *src)
{
struct SpriteSheet dest;
LZ77UnCompWram(src->data, gDecompressionBuffer);
dest.data = gDecompressionBuffer;
dest.size = src->size;
dest.tag = src->tag;
return LoadSpriteSheet(&dest);
}
// This can be used for either compressed or uncompressed sprite sheets
u16 LoadCompressedSpriteSheetByTemplate(const struct SpriteTemplate *template, s32 offset)
{
struct SpriteTemplate myTemplate;
struct SpriteFrameImage myImage;
u32 size;
// Check for LZ77 header and read uncompressed size, or fallback if not compressed (zero size)
if ((size = IsLZ77Data(template->images->data, TILE_SIZE_4BPP, sizeof(gDecompressionBuffer))) == 0)
return LoadSpriteSheetByTemplate(template, 0, offset);
LZ77UnCompWram(template->images->data, gDecompressionBuffer);
myImage.data = gDecompressionBuffer;
myImage.size = size + offset;
myTemplate.images = &myImage;
myTemplate.tileTag = template->tileTag;
return LoadSpriteSheetByTemplate(&myTemplate, 0, offset);
}
void LoadCompressedSpriteSheetOverrideBuffer(const struct CompressedSpriteSheet *src, void *buffer)
{
struct SpriteSheet dest;
LZ77UnCompWram(src->data, buffer);
dest.data = buffer;
dest.size = src->size;
dest.tag = src->tag;
LoadSpriteSheet(&dest);
}
void LoadCompressedSpritePalette(const struct CompressedSpritePalette *src)
{
struct SpritePalette dest;
LZ77UnCompWram(src->data, gDecompressionBuffer);
dest.data = (void *) gDecompressionBuffer;
dest.tag = src->tag;
LoadSpritePalette(&dest);
}
void LoadCompressedSpritePaletteWithTag(const u32 *pal, u16 tag)
{
struct SpritePalette dest;
LZ77UnCompWram(pal, gDecompressionBuffer);
dest.data = (void *) gDecompressionBuffer;
dest.tag = tag;
LoadSpritePalette(&dest);
}
void LoadCompressedSpritePaletteOverrideBuffer(const struct CompressedSpritePalette *src, void *buffer)
{
struct SpritePalette dest;
LZ77UnCompWram(src->data, buffer);
dest.data = buffer;
dest.tag = src->tag;
LoadSpritePalette(&dest);
}
void DecompressPicFromTable(const struct CompressedSpriteSheet *src, void *buffer)
{
LZ77UnCompWram(src->data, buffer);
}
void HandleLoadSpecialPokePic(bool32 isFrontPic, void *dest, s32 species, u32 personality)
{
LoadSpecialPokePic(dest, species, personality, isFrontPic);
}
void LoadSpecialPokePic(void *dest, s32 species, u32 personality, bool8 isFrontPic)
{
species = SanitizeSpeciesId(species);
if (species == SPECIES_UNOWN)
species = GetUnownSpeciesId(personality);
if (isFrontPic)
{
#if P_GENDER_DIFFERENCES
if (gSpeciesInfo[species].frontPicFemale != NULL && IsPersonalityFemale(species, personality))
LZ77UnCompWram(gSpeciesInfo[species].frontPicFemale, dest);
else
#endif
if (gSpeciesInfo[species].frontPic != NULL)
LZ77UnCompWram(gSpeciesInfo[species].frontPic, dest);
else
LZ77UnCompWram(gSpeciesInfo[SPECIES_NONE].frontPic, dest);
}
else
{
#if P_GENDER_DIFFERENCES
if (gSpeciesInfo[species].backPicFemale != NULL && IsPersonalityFemale(species, personality))
LZ77UnCompWram(gSpeciesInfo[species].backPicFemale, dest);
else
#endif
if (gSpeciesInfo[species].backPic != NULL)
LZ77UnCompWram(gSpeciesInfo[species].backPic, dest);
else
LZ77UnCompWram(gSpeciesInfo[SPECIES_NONE].backPic, dest);
}
DrawSpindaSpots(species, personality, dest, isFrontPic);
}
bool8 LoadCompressedSpriteSheetUsingHeap(const struct CompressedSpriteSheet *src)
{
struct SpriteSheet dest;
void *buffer;
buffer = AllocZeroed(src->data[0] >> 8);
LZ77UnCompWram(src->data, buffer);
dest.data = buffer;
dest.size = src->size;
dest.tag = src->tag;
LoadSpriteSheet(&dest);
Free(buffer);
return FALSE;
}
bool8 LoadCompressedSpritePaletteUsingHeap(const struct CompressedSpritePalette *src)
{
struct SpritePalette dest;
void *buffer;
buffer = AllocZeroed(src->data[0] >> 8);
LZ77UnCompWram(src->data, buffer);
dest.data = buffer;
dest.tag = src->tag;
LoadSpritePalette(&dest);
Free(buffer);
return FALSE;
}
bool8 LoadCompressedSpritePaletteUsingHeapWithTag(const u32 *pal, u16 tag)
{
struct SpritePalette dest;
void *buffer;
buffer = AllocZeroed(*((u32 *)pal) >> 8);
if (!buffer)
return TRUE;
LZ77UnCompWram(pal, buffer);
dest.data = buffer;
dest.tag = tag;
LoadSpritePalette(&dest);
Free(buffer);
return FALSE;
}
u32 GetDecompressedDataSize(const u32 *ptr)
{
const u8 *ptr8 = (const u8 *)ptr;
return (ptr8[3] << 16) | (ptr8[2] << 8) | (ptr8[1]);
}