/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ //============================================================================= // // SpriteFile class handles sprite file parsing and streaming sprites. // SpriteFileWriter manages writing sprites into the output stream one by one, // accumulating index information, and may therefore be suitable for a variety // of situations. // //============================================================================= #ifndef AGS_SHARED_AC_SPRITE_FILE_H #define AGS_SHARED_AC_SPRITE_FILE_H #include "ags/shared/core/types.h" #include "common/std/memory.h" #include "common/std/vector.h" #include "ags/shared/util/stream.h" #include "ags/globals.h" namespace AGS3 { namespace AGS { namespace Shared { class Bitmap; // TODO: research old version differences enum SpriteFileVersion { kSprfVersion_Undefined = 0, kSprfVersion_Uncompressed = 4, kSprfVersion_Compressed = 5, kSprfVersion_Last32bit = 6, kSprfVersion_64bit = 10, kSprfVersion_HighSpriteLimit = 11, kSprfVersion_StorageFormats = 12, kSprfVersion_Current = kSprfVersion_StorageFormats }; enum SpriteIndexFileVersion { kSpridxfVersion_Initial = 1, kSpridxfVersion_Last32bit = 2, kSpridxfVersion_64bit = 10, kSpridxfVersion_HighSpriteLimit = 11, kSpridxfVersion_Current = kSpridxfVersion_HighSpriteLimit }; // Instructions to how the sprites are allowed to be stored enum SpriteStorage { // When possible convert the sprite into another format for less disk space // e.g. save 16/32-bit images as 8-bit colormaps with palette kSprStore_OptimizeForSize = 0x01 }; // Format in which the sprite's pixel data is stored enum SpriteFormat { kSprFmt_Undefined = 0, // undefined, or keep as-is // Encoded as a 8-bit colormap with palette of 24-bit RGB values kSprFmt_PaletteRgb888 = 32, // Encoded as a 8-bit colormap with palette of 32-bit ARGB values kSprFmt_PaletteArgb8888 = 33, // Encoded as a 8-bit colormap with palette of 16-bit RGB565 values kSprFmt_PaletteRgb565 = 34 }; enum SpriteCompression { kSprCompress_None = 0, kSprCompress_RLE, kSprCompress_LZW, kSprCompress_Deflate }; typedef int32_t sprkey_t; // SpriteFileIndex contains sprite file's table of contents struct SpriteFileIndex { int SpriteFileIDCheck = 0; // tag matching sprite file and index file std::vector Widths; std::vector Heights; std::vector Offsets; inline size_t GetCount() const { return Offsets.size(); } inline sprkey_t GetLastSlot() const { return (sprkey_t)GetCount() - 1; } }; // Invidual sprite data header (as read from the file) struct SpriteDatHeader { int BPP = 0; // color depth (bytes per pixel); or input format SpriteFormat SFormat = kSprFmt_Undefined; // storage format uint32_t PalCount = 0; // palette length, if applicable to storage format SpriteCompression Compress = kSprCompress_None; // compression type int Width = 0; // sprite's width int Height = 0; // sprite's height SpriteDatHeader() = default; SpriteDatHeader(int bpp, SpriteFormat sformat = kSprFmt_Undefined, uint32_t pal_count = 0, SpriteCompression compress = kSprCompress_None, int w = 0, int h = 0) : BPP(bpp), SFormat(sformat), PalCount(pal_count), Compress(compress), Width(w), Height(h) { } }; // SpriteFile opens a sprite file for reading, reports general information, // and lets read sprites in any order. class SpriteFile { public: // Standart sprite file and sprite index names static const char *DefaultSpriteFileName; static const char *DefaultSpriteIndexName; SpriteFile(); // Loads sprite reference information and inits sprite stream HError OpenFile(const String &filename, const String &sprindex_filename, std::vector &metrics); // Closes stream; no reading will be possible unless opened again void Close(); int GetStoreFlags() const; // Tells if bitmaps in the file are compressed SpriteCompression GetSpriteCompression() const; // Tells the highest known sprite index sprkey_t GetTopmostSprite() const; // Loads sprite index file bool LoadSpriteIndexFile(const String &filename, int expectedFileID, soff_t spr_initial_offs, sprkey_t topmost, std::vector &metrics); // Rebuilds sprite index from the main sprite file HError RebuildSpriteIndex(Stream *in, sprkey_t topmost, std::vector &metrics); // Loads an image data and creates a ready bitmap HError LoadSprite(sprkey_t index, Bitmap *&sprite); // Loads a raw sprite element data into the buffer, stores header info separately HError LoadRawData(sprkey_t index, SpriteDatHeader &hdr, std::vector &data); private: // Seek stream to sprite void SeekToSprite(sprkey_t index); // Internal sprite reference struct SpriteRef { soff_t Offset = 0; // data offset size_t RawSize = 0; // file size of element, in bytes // TODO: RawSize is currently unused, due to incompleteness of spriteindex format }; // Array of sprite references std::vector _spriteData; std::unique_ptr _stream; // the sprite stream SpriteFileVersion _version = kSprfVersion_Current; int _storeFlags = 0; // storage flags, specify how sprites may be stored SpriteCompression _compress = kSprCompress_None; // sprite compression typ sprkey_t _curPos; // current stream position (sprite slot) }; // SpriteFileWriter class writes a sprite file in a requested format. // Start using it by calling Begin, write ready bitmaps or copy raw sprite data // over slot by slot, then call Finalize to let it close the format correctly. class SpriteFileWriter { public: SpriteFileWriter(std::unique_ptr &out); ~SpriteFileWriter() { } // Get the sprite index, accumulated after write const SpriteFileIndex &GetIndex() const { return _index; } // Initializes new sprite file format; // store_flags are SpriteStorage; // optionally hint how many sprites will be written. void Begin(int store_flags, SpriteCompression compress, sprkey_t last_slot = -1); // Writes a bitmap into file, compressing if necessary void WriteBitmap(Bitmap *image); // Writes an empty slot marker void WriteEmptySlot(); // Writes a raw sprite data without any additional processing void WriteRawData(const SpriteDatHeader &hdr, const uint8_t *data, size_t data_sz); // Finalizes current format; no further writing is possible after this void Finalize(); private: // Writes prepared image data in a proper file format, following explicit data_bpp rule void WriteSpriteData(const SpriteDatHeader &hdr, const uint8_t *im_data, size_t im_data_sz, int im_bpp, const uint32_t palette[256]); std::unique_ptr &_out; int _storeFlags = 0; SpriteCompression _compress = kSprCompress_None; soff_t _lastSlotPos = -1; // last slot save position in file // sprite index accumulated on write for reporting back to user SpriteFileIndex _index; // compression buffer std::vector _membuf; }; // Saves all sprites to file; fills in index data for external use. // TODO: refactor to be able to save main file and index file separately (separate function for gather data?) // Accepts available sprites as pairs of bool and Bitmap pointer, where boolean value // tells if sprite exists and Bitmap pointer may be null; // If a sprite's bitmap is missing, it will try reading one from the input file stream. int SaveSpriteFile(const String &save_to_file, const std::vector > &sprites, SpriteFile *read_from_file, // optional file to read missing sprites from int store_flags, SpriteCompression compress, SpriteFileIndex &index); // Saves sprite index table in a separate file extern int SaveSpriteIndex(const String &filename, const SpriteFileIndex &index); } // namespace Shared } // namespace AGS } // namespace AGS3 #endif