diff --git a/src/spriteloader/grf.cpp b/src/spriteloader/grf.cpp --- a/src/spriteloader/grf.cpp +++ b/src/spriteloader/grf.cpp @@ -22,6 +22,15 @@ extern const byte _palmap_w2d[]; +/** The different colour components a sprite can have. */ +enum SpriteColourComponent { + SCC_RGB = 1 << 0, ///< Sprite has RGB. + SCC_ALPHA = 1 << 1, ///< Sprite has alpha. + SCC_PAL = 1 << 2, ///< Sprite has palette data. + SCC_MASK = SCC_RGB | SCC_ALPHA | SCC_PAL, ///< Mask of valid colour bits. +}; +DECLARE_ENUM_AS_BIT_SET(SpriteColourComponent) + /** * We found a corrupted sprite. This means that the sprite itself * contains invalid data or is too small for the given dimensions. @@ -176,7 +185,7 @@ bool DecodeSingleSprite(SpriteLoader::Sp return true; } -bool SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type) +bool LoadSpriteV1(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type) { /* Open the right file and go to the correct position */ FioSeekToFile(file_slot, file_pos); @@ -199,3 +208,59 @@ bool SpriteLoaderGrf::LoadSprite(SpriteL return DecodeSingleSprite(sprite, file_slot, file_pos, sprite_type, num, type); } + +bool LoadSpriteV2(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type) +{ + /* Is the sprite not present/stripped in the GRF? */ + if (file_pos == SIZE_MAX) return false; + + /* Open the right file and go to the correct position */ + FioSeekToFile(file_slot, file_pos); + + uint32 id = FioReadDword(); + + do { + int64 num = FioReadDword(); + size_t start_pos = FioGetPos(); + byte type = FioReadByte(); + + /* Type 0xFF indicates either a colourmap or some other non-sprite info; we do not handle them here. */ + if (type == 0xFF) return false; + + byte colour = type & SCC_MASK; + byte zoom = FioReadByte(); + + if (colour == SCC_PAL && zoom == 0) { + sprite->height = FioReadWord(); + sprite->width = FioReadWord(); + sprite->x_offs = FioReadWord(); + sprite->y_offs = FioReadWord(); + + /* Mask out colour information. */ + type = type & ~SCC_MASK; + + /* For chunked encoding we store the decompressed size in the file, + * otherwise we can calculate it from the image dimensions. */ + uint decomp_size = (type & 0x08) ? FioReadDword() : sprite->width * sprite->height; + + bool valid = DecodeSingleSprite(sprite, file_slot, file_pos, sprite_type, decomp_size, type); + if (FioGetPos() != start_pos + num) return WarnCorruptSprite(file_slot, file_pos, __LINE__); + return valid; + } else { + /* Not the wanted zoom level or colour depth, continue searching. */ + FioSkipBytes(num - 2); + } + + } while (FioReadDword() == id); + + return false; +} + +bool SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type) +{ + if (this->container_ver >= 2) { + return LoadSpriteV2(sprite, file_slot, file_pos, sprite_type); + } else { + return LoadSpriteV1(sprite, file_slot, file_pos, sprite_type); + } +}