summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/spritecache.cpp157
1 files changed, 85 insertions, 72 deletions
diff --git a/src/spritecache.cpp b/src/spritecache.cpp
index dc5a2acd1..7e70f2fa7 100644
--- a/src/spritecache.cpp
+++ b/src/spritecache.cpp
@@ -81,6 +81,7 @@ static MemBlock *_spritecache_ptr;
static int _compact_cache_counter;
static void CompactSpriteCache();
+static void *AllocSprite(size_t mem_req);
/**
* Skip the given amount of sprite graphics data.
@@ -110,28 +111,6 @@ bool SkipSpriteData(byte type, uint16 num)
return true;
}
-/**
- * Read the sprite header data and then skip the real payload.
- * @return type of sprite; ST_INVALID if the sprite is a pseudo- or unusable sprite
- */
-static SpriteType ReadSpriteHeaderSkipData()
-{
- uint16 num = FioReadWord();
-
- if (num == 0) return ST_INVALID;
-
- byte type = FioReadByte();
- if (type == 0xFF) {
- FioSkipBytes(num);
- /* Some NewGRF files have "empty" pseudo-sprites which are 1
- * byte long. Catch these so the sprites won't be displayed. */
- return (num == 1) ? ST_INVALID : ST_RECOLOUR;
- }
-
- FioSkipBytes(7);
- return SkipSpriteData(type, num - 8) ? ST_NORMAL : ST_INVALID;
-}
-
/* Check if the given Sprite ID exists */
bool SpriteExists(SpriteID id)
{
@@ -177,6 +156,39 @@ uint GetMaxSpriteID()
}
/**
+ * Load a recolour sprite into memory.
+ * @param file_slot 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)
+{
+ /* "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
+ * GRFs which are the same as 257 byte recolour sprites, but with the last
+ * 240 bytes zeroed. */
+ static const uint RECOLOUR_SPRITE_SIZE = 257;
+ byte *dest = (byte *)AllocSprite(max(RECOLOUR_SPRITE_SIZE, num));
+
+ if (_palette_remap_grf[file_slot]) {
+ byte *dest_tmp = AllocaM(byte, 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);
+
+ /* 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);
+ }
+
+ return dest;
+}
+
+/**
* Read a sprite from disk.
* @param sc Location of sprite.
* @param id Sprite number.
@@ -189,6 +201,7 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty
uint8 file_slot = sc->file_slot;
size_t file_pos = sc->file_pos;
+ assert(sprite_type != ST_RECOLOUR);
assert(IsMapgenSpriteID(id) == (sprite_type == ST_MAPGEN));
assert(sc->type == sprite_type);
@@ -220,33 +233,9 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty
int num = FioReadWord();
byte type = FioReadByte();
- /* Type 0xFF indicates either a colourmap or some other non-sprite info */
- assert((type == 0xFF) == (sprite_type == ST_RECOLOUR));
- if (type == 0xFF) {
- /* "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
- * GRFs which are the same as 257 byte recolour sprites, but with the last
- * 240 bytes zeroed. */
- static const int RECOLOUR_SPRITE_SIZE = 257;
- byte *dest = (byte *)allocator(max(RECOLOUR_SPRITE_SIZE, num));
-
- if (_palette_remap_grf[sc->file_slot]) {
- byte *dest_tmp = AllocaM(byte, 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);
-
- /* The data of index 0 is never used; "literal 00" according to the (New)GRF specs. */
- for (int i = 1; i < RECOLOUR_SPRITE_SIZE; i++) {
- dest[i] = _palmap_w2d[dest_tmp[_palmap_d2w[i - 1] + 1]];
- }
- } else {
- FioReadBlock(dest, num);
- }
-
- return dest;
- }
+ /* Type 0xFF indicates either a colourmap or some other non-sprite info
+ * which we should have already handled during GRF loading. */
+ assert(type != 0xFF);
/* Ugly hack to work around the problem that the old landscape
* generator assumes that those sprites are stored uncompressed in
@@ -305,7 +294,26 @@ bool LoadNextSprite(int load_index, byte file_slot, uint file_sprite_id)
{
size_t file_pos = FioGetPos();
- SpriteType type = ReadSpriteHeaderSkipData();
+ /* Read sprite header. */
+ uint16 num = FioReadWord();
+ if (num == 0) return false;
+ byte grf_type = FioReadByte();
+
+ SpriteType type;
+ void *data = NULL;
+ if (grf_type == 0xFF) {
+ /* 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();
+ return false;
+ }
+ type = ST_RECOLOUR;
+ data = ReadRecolourSprite(file_slot, num);
+ } else {
+ FioSkipBytes(7);
+ type = SkipSpriteData(grf_type, num - 8) ? ST_NORMAL : ST_INVALID;
+ }
if (type == ST_INVALID) return false;
@@ -323,7 +331,7 @@ bool LoadNextSprite(int load_index, byte file_slot, uint file_sprite_id)
SpriteCache *sc = AllocateSpriteCache(load_index);
sc->file_slot = file_slot;
sc->file_pos = file_pos;
- sc->ptr = NULL;
+ sc->ptr = data;
sc->lru = 0;
sc->id = file_sprite_id;
sc->type = type;
@@ -449,19 +457,39 @@ static void CompactSpriteCache()
}
}
+/**
+ * Delete a single entry from the sprite cache.
+ * @param item Entry to delete.
+ */
+static void DeleteEntryFromSpriteCache(uint item)
+{
+ /* Mark the block as free (the block must be in use) */
+ MemBlock *s = (MemBlock*)GetSpriteCache(item)->ptr - 1;
+ assert(!(s->size & S_FREE_MASK));
+ s->size |= S_FREE_MASK;
+ GetSpriteCache(item)->ptr = NULL;
+
+ /* And coalesce adjacent free blocks */
+ for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
+ if (s->size & S_FREE_MASK) {
+ while (NextBlock(s)->size & S_FREE_MASK) {
+ s->size += NextBlock(s)->size & ~S_FREE_MASK;
+ }
+ }
+ }
+}
+
static void DeleteEntryFromSpriteCache()
{
- SpriteID i;
uint best = UINT_MAX;
- MemBlock *s;
int cur_lru;
DEBUG(sprite, 3, "DeleteEntryFromSpriteCache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
cur_lru = 0xffff;
- for (i = 0; i != _spritecache_items; i++) {
+ for (SpriteID i = 0; i != _spritecache_items; i++) {
SpriteCache *sc = GetSpriteCache(i);
- if (sc->ptr != NULL && sc->lru < cur_lru) {
+ if (sc->type != ST_RECOLOUR && sc->ptr != NULL && sc->lru < cur_lru) {
cur_lru = sc->lru;
best = i;
}
@@ -471,20 +499,7 @@ static void DeleteEntryFromSpriteCache()
* This shouldn't really happen, unless all sprites are locked. */
if (best == UINT_MAX) error("Out of sprite memory");
- /* Mark the block as free (the block must be in use) */
- s = (MemBlock*)GetSpriteCache(best)->ptr - 1;
- assert(!(s->size & S_FREE_MASK));
- s->size |= S_FREE_MASK;
- GetSpriteCache(best)->ptr = NULL;
-
- /* And coalesce adjacent free blocks */
- for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
- if (s->size & S_FREE_MASK) {
- while (NextBlock(s)->size & S_FREE_MASK) {
- s->size += NextBlock(s)->size & ~S_FREE_MASK;
- }
- }
- }
+ DeleteEntryFromSpriteCache(best);
}
static void *AllocSprite(size_t mem_req)
@@ -642,10 +657,8 @@ void GfxClearSpriteCache()
/* Clear sprite ptr for all cached items */
for (uint i = 0; i != _spritecache_items; i++) {
SpriteCache *sc = GetSpriteCache(i);
- sc->ptr = NULL;
+ if (sc->type != ST_RECOLOUR) DeleteEntryFromSpriteCache(i);
}
-
- GfxInitSpriteCache();
}
/* static */ ReusableBuffer<SpriteLoader::CommonPixel> SpriteLoader::Sprite::buffer;