summaryrefslogtreecommitdiff
path: root/src/spritecache.cpp
diff options
context:
space:
mode:
authorRubidium <rubidium@openttd.org>2021-04-14 17:20:39 +0200
committerrubidium42 <rubidium42@users.noreply.github.com>2021-05-08 12:39:34 +0200
commitfdc11a9f943bcbd674b8b69a2bb0895414928028 (patch)
treeccd04bb045ed1aeebbff2b88224f9c52988ddc92 /src/spritecache.cpp
parent0dd339ecd8fab0ae3a4901e0ad185798e04cccf3 (diff)
downloadopenttd-fdc11a9f943bcbd674b8b69a2bb0895414928028.tar.xz
Codechange: introduce SpriteFile to be used by the sprite loader instead of the global FIO slot functionality
Diffstat (limited to 'src/spritecache.cpp')
-rw-r--r--src/spritecache.cpp144
1 files changed, 88 insertions, 56 deletions
diff --git a/src/spritecache.cpp b/src/spritecache.cpp
index 288f74af4..f2840c1b0 100644
--- a/src/spritecache.cpp
+++ b/src/spritecache.cpp
@@ -8,7 +8,7 @@
/** @file spritecache.cpp Caching of sprites. */
#include "stdafx.h"
-#include "fileio_func.h"
+#include "random_access_file_type.h"
#include "spriteloader/grf.hpp"
#include "gfx_func.h"
#include "error.h"
@@ -31,18 +31,17 @@ uint _sprite_cache_size = 4;
struct SpriteCache {
void *ptr;
size_t file_pos;
+ SpriteFile *file; ///< The file the sprite in this entry can be found in.
uint32 id;
- uint16 file_slot;
int16 lru;
SpriteType type; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour sprite. If the recolour sprite gets into the cache it might be drawn as real sprite which causes enormous trouble.
bool warned; ///< True iff the user has been warned about incorrect use of this sprite
- byte container_ver; ///< Container version of the GRF the sprite is from.
};
static uint _spritecache_items = 0;
static SpriteCache *_spritecache = nullptr;
-
+static std::vector<std::unique_ptr<SpriteFile>> _sprite_files;
static inline SpriteCache *GetSpriteCache(uint index)
{
@@ -72,6 +71,37 @@ static SpriteCache *AllocateSpriteCache(uint index)
return GetSpriteCache(index);
}
+/**
+ * Get the cached SpriteFile given the name of the file.
+ * @param filename The name of the file at the disk.
+ * @return The SpriteFile or \c null.
+ */
+static SpriteFile *GetCachedSpriteFileByName(const std::string &filename) {
+ for (auto &f : _sprite_files) {
+ if (f->GetFilename() == filename) {
+ return f.get();
+ }
+ }
+ return nullptr;
+}
+
+/**
+ * Open/get the SpriteFile that is cached for use in the sprite cache.
+ * @param filename Name of the file at the disk.
+ * @param subdir The sub directory to search this file in.
+ * @param palette_remap Whether a palette remap needs to be performed for this file.
+ * @return The reference to the SpriteCache.
+ */
+SpriteFile &OpenCachedSpriteFile(const std::string &filename, Subdirectory subdir, bool palette_remap)
+{
+ SpriteFile *file = GetCachedSpriteFileByName(filename);
+ if (file == nullptr) {
+ file = _sprite_files.emplace_back(new SpriteFile(filename, subdir, palette_remap)).get();
+ } else {
+ file->SeekToBegin();
+ }
+ return *file;
+}
struct MemBlock {
size_t size;
@@ -92,22 +122,22 @@ static void *AllocSprite(size_t mem_req);
* @param num the amount of sprites to skip
* @return true if the data could be correctly skipped.
*/
-bool SkipSpriteData(byte type, uint16 num)
+bool SkipSpriteData(SpriteFile &file, byte type, uint16 num)
{
if (type & 2) {
- FioSkipBytes(num);
+ file.SkipBytes(num);
} else {
while (num > 0) {
- int8 i = FioReadByte();
+ int8 i = file.ReadByte();
if (i >= 0) {
int size = (i == 0) ? 0x80 : i;
if (size > num) return false;
num -= size;
- FioSkipBytes(size);
+ file.SkipBytes(size);
} else {
i = -(i >> 3);
num -= i;
- FioReadByte();
+ file.ReadByte();
}
}
}
@@ -121,7 +151,7 @@ bool SpriteExists(SpriteID id)
/* Special case for Sprite ID zero -- its position is also 0... */
if (id == 0) return true;
- return !(GetSpriteCache(id)->file_pos == 0 && GetSpriteCache(id)->file_slot == 0);
+ return !(GetSpriteCache(id)->file_pos == 0 && GetSpriteCache(id)->file == nullptr);
}
/**
@@ -136,14 +166,14 @@ SpriteType GetSpriteType(SpriteID sprite)
}
/**
- * Get the (FIOS) file slot of a given sprite.
+ * Get the SpriteFile of a given sprite.
* @param sprite The sprite to look at.
- * @return the FIOS file slot
+ * @return The SpriteFile.
*/
-uint GetOriginFileSlot(SpriteID sprite)
+SpriteFile *GetOriginFile(SpriteID sprite)
{
- if (!SpriteExists(sprite)) return 0;
- return GetSpriteCache(sprite)->file_slot;
+ if (!SpriteExists(sprite)) return nullptr;
+ return GetSpriteCache(sprite)->file;
}
/**
@@ -158,19 +188,22 @@ uint32 GetSpriteLocalID(SpriteID sprite)
}
/**
- * Count the sprites which originate from a specific file slot in a range of SpriteIDs.
- * @param file_slot FIOS file slot.
+ * Count the sprites which originate from a specific file in a range of SpriteIDs.
+ * @param file The loaded SpriteFile.
* @param begin First sprite in range.
* @param end First sprite not in range.
* @return Number of sprites.
*/
-uint GetSpriteCountForSlot(uint file_slot, SpriteID begin, SpriteID end)
+uint GetSpriteCountForFile(const std::string &filename, SpriteID begin, SpriteID end)
{
+ SpriteFile *file = GetCachedSpriteFileByName(filename);
+ if (file == nullptr) return 0;
+
uint count = 0;
for (SpriteID i = begin; i != end; i++) {
if (SpriteExists(i)) {
SpriteCache *sc = GetSpriteCache(i);
- if (sc->file_slot == file_slot) count++;
+ if (sc->file == file) count++;
}
}
return count;
@@ -348,7 +381,7 @@ static bool PadSprites(SpriteLoader::Sprite *sprite, uint8 sprite_avail, SpriteE
return true;
}
-static bool ResizeSprites(SpriteLoader::Sprite *sprite, uint8 sprite_avail, uint32 file_slot, uint32 file_pos, SpriteEncoder *encoder)
+static bool ResizeSprites(SpriteLoader::Sprite *sprite, uint8 sprite_avail, SpriteEncoder *encoder)
{
/* Create a fully zoomed image if it does not exist */
ZoomLevel first_avail = static_cast<ZoomLevel>(FIND_FIRST_BIT(sprite_avail));
@@ -379,11 +412,11 @@ static bool ResizeSprites(SpriteLoader::Sprite *sprite, uint8 sprite_avail, uint
/**
* Load a recolour sprite into memory.
- * @param file_slot GRF we're reading from.
+ * @param file GRF we're reading from.
* @param num Size of the sprite in the GRF.
* @return Sprite data.
*/
-static void *ReadRecolourSprite(uint16 file_slot, uint num)
+static void *ReadRecolourSprite(SpriteFile &file, uint num)
{
/* "Normal" recolour sprites are ALWAYS 257 bytes. Then there is a small
* number of recolour sprites that are 17 bytes that only exist in DOS
@@ -392,19 +425,19 @@ static void *ReadRecolourSprite(uint16 file_slot, uint num)
static const uint RECOLOUR_SPRITE_SIZE = 257;
byte *dest = (byte *)AllocSprite(std::max(RECOLOUR_SPRITE_SIZE, num));
- if (_palette_remap_grf[file_slot]) {
+ if (file.NeedsPaletteRemap()) {
byte *dest_tmp = AllocaM(byte, std::max(RECOLOUR_SPRITE_SIZE, num));
/* Only a few recolour sprites are less than 257 bytes */
if (num < RECOLOUR_SPRITE_SIZE) memset(dest_tmp, 0, RECOLOUR_SPRITE_SIZE);
- FioReadBlock(dest_tmp, num);
+ file.ReadBlock(dest_tmp, num);
/* The data of index 0 is never used; "literal 00" according to the (New)GRF specs. */
for (uint i = 1; i < RECOLOUR_SPRITE_SIZE; i++) {
dest[i] = _palmap_w2d[dest_tmp[_palmap_d2w[i - 1] + 1]];
}
} else {
- FioReadBlock(dest, num);
+ file.ReadBlock(dest, num);
}
return dest;
@@ -424,7 +457,7 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty
/* Use current blitter if no other sprite encoder is given. */
if (encoder == nullptr) encoder = BlitterFactory::GetCurrentBlitter();
- uint8 file_slot = sc->file_slot;
+ SpriteFile &file = *sc->file;
size_t file_pos = sc->file_pos;
assert(sprite_type != ST_RECOLOUR);
@@ -437,13 +470,13 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty
uint8 sprite_avail = 0;
sprite[ZOOM_LVL_NORMAL].type = sprite_type;
- SpriteLoaderGrf sprite_loader(sc->container_ver);
+ SpriteLoaderGrf sprite_loader(file.GetContainerVersion());
if (sprite_type != ST_MAPGEN && encoder->Is32BppSupported()) {
/* Try for 32bpp sprites first. */
- sprite_avail = sprite_loader.LoadSprite(sprite, file_slot, file_pos, sprite_type, true);
+ sprite_avail = sprite_loader.LoadSprite(sprite, file, file_pos, sprite_type, true);
}
if (sprite_avail == 0) {
- sprite_avail = sprite_loader.LoadSprite(sprite, file_slot, file_pos, sprite_type, false);
+ sprite_avail = sprite_loader.LoadSprite(sprite, file, file_pos, sprite_type, false);
}
if (sprite_avail == 0) {
@@ -480,7 +513,7 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty
return s;
}
- if (!ResizeSprites(sprite, sprite_avail, file_slot, sc->id, encoder)) {
+ if (!ResizeSprites(sprite, sprite_avail, encoder)) {
if (id == SPR_IMG_QUERY) usererror("Okay... something went horribly wrong. I couldn't resize the fallback sprite. What should I do?");
return (void*)GetRawSprite(SPR_IMG_QUERY, ST_NORMAL, allocator, encoder);
}
@@ -516,27 +549,27 @@ size_t GetGRFSpriteOffset(uint32 id)
* Parse the sprite section of GRFs.
* @param container_version Container version of the GRF we're currently processing.
*/
-void ReadGRFSpriteOffsets(byte container_version)
+void ReadGRFSpriteOffsets(SpriteFile &file)
{
_grf_sprite_offsets.clear();
- if (container_version >= 2) {
+ if (file.GetContainerVersion() >= 2) {
/* Seek to sprite section of the GRF. */
- size_t data_offset = FioReadDword();
- size_t old_pos = FioGetPos();
- FioSeekTo(data_offset, SEEK_CUR);
+ size_t data_offset = file.ReadDword();
+ size_t old_pos = file.GetPos();
+ file.SeekTo(data_offset, SEEK_CUR);
/* Loop over all sprite section entries and store the file
* offset for each newly encountered ID. */
uint32 id, prev_id = 0;
- while ((id = FioReadDword()) != 0) {
- if (id != prev_id) _grf_sprite_offsets[id] = FioGetPos() - 4;
+ while ((id = file.ReadDword()) != 0) {
+ if (id != prev_id) _grf_sprite_offsets[id] = file.GetPos() - 4;
prev_id = id;
- FioSkipBytes(FioReadDword());
+ file.SkipBytes(file.ReadDword());
}
/* Continue processing the data section. */
- FioSeekTo(old_pos, SEEK_SET);
+ file.SeekTo(old_pos, SEEK_SET);
}
}
@@ -544,19 +577,19 @@ void ReadGRFSpriteOffsets(byte container_version)
/**
* Load a real or recolour sprite.
* @param load_index Global sprite index.
- * @param file_slot GRF to load from.
+ * @param file GRF to load from.
* @param file_sprite_id Sprite number in the GRF.
* @param container_version Container version of the GRF.
* @return True if a valid sprite was loaded, false on any error.
*/
-bool LoadNextSprite(int load_index, byte file_slot, uint file_sprite_id, byte container_version)
+bool LoadNextSprite(int load_index, SpriteFile &file, uint file_sprite_id)
{
- size_t file_pos = FioGetPos();
+ size_t file_pos = file.GetPos();
/* Read sprite header. */
- uint32 num = container_version >= 2 ? FioReadDword() : FioReadWord();
+ uint32 num = file.GetContainerVersion() >= 2 ? file.ReadDword() : file.ReadWord();
if (num == 0) return false;
- byte grf_type = FioReadByte();
+ byte grf_type = file.ReadByte();
SpriteType type;
void *data = nullptr;
@@ -564,25 +597,25 @@ bool LoadNextSprite(int load_index, byte file_slot, uint file_sprite_id, byte co
/* Some NewGRF files have "empty" pseudo-sprites which are 1
* byte long. Catch these so the sprites won't be displayed. */
if (num == 1) {
- FioReadByte();
+ file.ReadByte();
return false;
}
type = ST_RECOLOUR;
- data = ReadRecolourSprite(file_slot, num);
- } else if (container_version >= 2 && grf_type == 0xFD) {
+ data = ReadRecolourSprite(file, num);
+ } else if (file.GetContainerVersion() >= 2 && grf_type == 0xFD) {
if (num != 4) {
/* Invalid sprite section include, ignore. */
- FioSkipBytes(num);
+ file.SkipBytes(num);
return false;
}
/* It is not an error if no sprite with the provided ID is found in the sprite section. */
- file_pos = GetGRFSpriteOffset(FioReadDword());
+ file_pos = GetGRFSpriteOffset(file.ReadDword());
type = ST_NORMAL;
} else {
- FioSkipBytes(7);
- type = SkipSpriteData(grf_type, num - 8) ? ST_NORMAL : ST_INVALID;
+ file.SkipBytes(7);
+ type = SkipSpriteData(file, grf_type, num - 8) ? ST_NORMAL : ST_INVALID;
/* Inline sprites are not supported for container version >= 2. */
- if (container_version >= 2) return false;
+ if (file.GetContainerVersion() >= 2) return false;
}
if (type == ST_INVALID) return false;
@@ -599,14 +632,13 @@ bool LoadNextSprite(int load_index, byte file_slot, uint file_sprite_id, byte co
}
SpriteCache *sc = AllocateSpriteCache(load_index);
- sc->file_slot = file_slot;
+ sc->file = &file;
sc->file_pos = file_pos;
sc->ptr = data;
sc->lru = 0;
sc->id = file_sprite_id;
sc->type = type;
sc->warned = false;
- sc->container_ver = container_version;
return true;
}
@@ -617,13 +649,12 @@ void DupSprite(SpriteID old_spr, SpriteID new_spr)
SpriteCache *scnew = AllocateSpriteCache(new_spr); // may reallocate: so put it first
SpriteCache *scold = GetSpriteCache(old_spr);
- scnew->file_slot = scold->file_slot;
+ scnew->file = scold->file;
scnew->file_pos = scold->file_pos;
scnew->ptr = nullptr;
scnew->id = scold->id;
scnew->type = scold->type;
scnew->warned = false;
- scnew->container_ver = scold->container_ver;
}
/**
@@ -967,6 +998,7 @@ void GfxInitSpriteMem()
_spritecache = nullptr;
_compact_cache_counter = 0;
+ _sprite_files.clear();
}
/**