src/spritecache.c
branchcustombridgeheads
changeset 5648 1608018c5ff2
parent 5643 3778051e8095
--- a/src/spritecache.c	Wed Jan 03 20:00:29 2007 +0000
+++ b/src/spritecache.c	Thu Jan 11 13:16:26 2007 +0000
@@ -11,18 +11,46 @@
 
 #define SPRITE_CACHE_SIZE 1024*1024
 
-#define WANT_NEW_LRU
+
+typedef struct SpriteCache {
+	void *ptr;
+	uint32 file_pos;
+	int16 lru;
+} SpriteCache;
 
 
-static void* _sprite_ptr[MAX_SPRITES];
-static uint32 _sprite_file_pos[MAX_SPRITES];
+static uint _spritecache_items = 0;
+static SpriteCache *_spritecache = NULL;
 
-#if defined(WANT_NEW_LRU)
-static int16 _sprite_lru_new[MAX_SPRITES];
-#else
-static uint16 _sprite_lru[MAX_SPRITES];
-static uint16 _sprite_lru_cur[MAX_SPRITES];
-#endif
+
+static inline SpriteCache *GetSpriteCache(uint index)
+{
+	return &_spritecache[index];
+}
+
+
+static SpriteCache *AllocateSpriteCache(uint index)
+{
+	if (index >= _spritecache_items) {
+		/* Add another 1024 items to the 'pool' */
+		uint items = ALIGN(index + 1, 1024);
+
+		DEBUG(sprite, 4, "Increasing sprite cache to %d items (%d bytes)", items, items * sizeof(*_spritecache));
+
+		_spritecache = realloc(_spritecache, items * sizeof(*_spritecache));
+
+		if (_spritecache == NULL) {
+			error("Unable to allocate sprite cache of %d items (%d bytes)", items, items * sizeof(*_spritecache));
+		}
+
+		/* Reset the new items and update the count */
+		memset(_spritecache + _spritecache_items, 0, (items - _spritecache_items) * sizeof(*_spritecache));
+		_spritecache_items = items;
+	}
+
+	return GetSpriteCache(index);
+}
+
 
 typedef struct MemBlock {
 	uint32 size;
@@ -77,12 +105,14 @@
 bool SpriteExists(SpriteID id)
 {
 	/* Special case for Sprite ID zero -- its position is also 0... */
-	return _sprite_file_pos[id] != 0 || id == 0;
+	if (id == 0) return true;
+
+	return GetSpriteCache(id)->file_pos != 0;
 }
 
 static void* AllocSprite(size_t);
 
-static void* ReadSprite(SpriteID id)
+static void* ReadSprite(SpriteCache *sc, SpriteID id)
 {
 	uint num;
 	byte type;
@@ -97,14 +127,14 @@
 		);
 	}
 
-	FioSeekToFile(_sprite_file_pos[id]);
+	FioSeekToFile(sc->file_pos);
 
 	num  = FioReadWord();
 	type = FioReadByte();
 	if (type == 0xFF) {
 		byte* dest = AllocSprite(num);
 
-		_sprite_ptr[id] = dest;
+		sc->ptr = dest;
 		FioReadBlock(dest, num);
 
 		return dest;
@@ -116,7 +146,7 @@
 
 		num = (type & 0x02) ? width * height : num - 8;
 		sprite = AllocSprite(sizeof(*sprite) + num);
-		_sprite_ptr[id] = sprite;
+		sc->ptr = sprite;
 		sprite->info   = type;
 		sprite->height = (id != 142) ? height : 10; // Compensate for a TTD bug
 		sprite->width  = width;
@@ -147,6 +177,7 @@
 
 bool LoadNextSprite(int load_index, byte file_index)
 {
+	SpriteCache *sc;
 	uint32 file_pos = FioGetPos() | (file_index << 24);
 
 	if (!ReadSpriteHeaderSkipData()) return false;
@@ -155,16 +186,10 @@
 		error("Tried to load too many sprites (#%d; max %d)", load_index, MAX_SPRITES);
 	}
 
-	_sprite_file_pos[load_index] = file_pos;
-
-	_sprite_ptr[load_index] = NULL;
-
-#if defined(WANT_NEW_LRU)
-	_sprite_lru_new[load_index] = 0;
-#else
-	_sprite_lru[load_index] = 0xFFFF;
-	_sprite_lru_cur[load_index] = 0;
-#endif
+	sc = AllocateSpriteCache(load_index);
+	sc->file_pos = file_pos;
+	sc->ptr = NULL;
+	sc->lru = 0;
 
 	return true;
 }
@@ -172,8 +197,11 @@
 
 void DupSprite(SpriteID old, SpriteID new)
 {
-	_sprite_file_pos[new] = _sprite_file_pos[old];
-	_sprite_ptr[new] = NULL;
+	SpriteCache *scold = GetSpriteCache(old);
+	SpriteCache *scnew = AllocateSpriteCache(new);
+
+	scnew->file_pos = scold->file_pos;
+	scnew->ptr = NULL;
 }
 
 
@@ -206,30 +234,24 @@
 
 void IncreaseSpriteLRU(void)
 {
-	int i;
+	// Increase all LRU values
+	if (_sprite_lru_counter > 16384) {
+		SpriteID i;
 
-	// Increase all LRU values
-#if defined(WANT_NEW_LRU)
-	if (_sprite_lru_counter > 16384) {
 		DEBUG(sprite, 3, "Fixing lru %d, inuse=%d", _sprite_lru_counter, GetSpriteCacheUsage());
 
-		for (i = 0; i != MAX_SPRITES; i++)
-			if (_sprite_ptr[i] != NULL) {
-				if (_sprite_lru_new[i] >= 0) {
-					_sprite_lru_new[i] = -1;
-				} else if (_sprite_lru_new[i] != -32768) {
-					_sprite_lru_new[i]--;
+		for (i = 0; i != _spritecache_items; i++) {
+			SpriteCache *sc = GetSpriteCache(i);
+			if (sc->ptr != NULL) {
+				if (sc->lru >= 0) {
+					sc->lru = -1;
+				} else if (sc->lru != -32768) {
+					sc->lru--;
 				}
 			}
+		}
 		_sprite_lru_counter = 0;
 	}
-#else
-	for (i = 0; i != MAX_SPRITES; i++)
-		if (_sprite_ptr[i] != NULL && _sprite_lru[i] != 65535)
-			_sprite_lru[i]++;
-	// Reset the lru counter.
-	_sprite_lru_counter = 0;
-#endif
 
 	// Compact sprite cache every now and then.
 	if (++_compact_cache_counter >= 740) {
@@ -250,7 +272,7 @@
 		if (s->size & S_FREE_MASK) {
 			MemBlock* next = NextBlock(s);
 			MemBlock temp;
-			void** i;
+			SpriteID i;
 
 			// Since free blocks are automatically coalesced, this should hold true.
 			assert(!(next->size & S_FREE_MASK));
@@ -260,11 +282,11 @@
 				break;
 
 			// Locate the sprite belonging to the next pointer.
-			for (i = _sprite_ptr; *i != next->data; ++i) {
-				assert(i != endof(_sprite_ptr));
+			for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
+				assert(i != _spritecache_items);
 			}
 
-			*i = s->data; // Adjust sprite array entry
+			GetSpriteCache(i)->ptr = s->data; // Adjust sprite array entry
 			// Swap this and the next block
 			temp = *s;
 			memmove(s, next, next->size);
@@ -283,52 +305,32 @@
 
 static void DeleteEntryFromSpriteCache(void)
 {
-	int i;
-	int best = -1;
+	SpriteID i;
+	uint best = -1;
 	MemBlock* s;
 	int cur_lru;
 
 	DEBUG(sprite, 3, "DeleteEntryFromSpriteCache, inuse=%d", GetSpriteCacheUsage());
 
-#if defined(WANT_NEW_LRU)
 	cur_lru = 0xffff;
-	for (i = 0; i != MAX_SPRITES; i++) {
-		if (_sprite_ptr[i] != NULL && _sprite_lru_new[i] < cur_lru) {
-			cur_lru = _sprite_lru_new[i];
+	for (i = 0; i != _spritecache_items; i++) {
+		SpriteCache *sc = GetSpriteCache(i);
+		if (sc->ptr != NULL && sc->lru < cur_lru) {
+			cur_lru = sc->lru;
 			best = i;
 		}
 	}
-#else
-	{
-	uint16 cur_lru = 0, cur_lru_cur = 0xffff;
-	for (i = 0; i != MAX_SPRITES; i++) {
-		if (_sprite_ptr[i] == NULL || _sprite_lru[i] < cur_lru) continue;
-
-		// Found a sprite with a higher LRU value, then remember it.
-		if (_sprite_lru[i] != cur_lru) {
-			cur_lru = _sprite_lru[i];
-			best = i;
-
-		// Else if both sprites were very recently referenced, compare by the cur value instead.
-		} else if (cur_lru == 0 && _sprite_lru_cur[i] <= cur_lru_cur) {
-			cur_lru_cur = _sprite_lru_cur[i];
-			cur_lru = _sprite_lru[i];
-			best = i;
-		}
-	}
-	}
-#endif
 
 	// Display an error message and die, in case we found no sprite at all.
 	// This shouldn't really happen, unless all sprites are locked.
-	if (best == -1)
+	if (best == (uint)-1)
 		error("Out of sprite memory");
 
 	// Mark the block as free (the block must be in use)
-	s = (MemBlock*)_sprite_ptr[best] - 1;
+	s = (MemBlock*)GetSpriteCache(best)->ptr - 1;
 	assert(!(s->size & S_FREE_MASK));
 	s->size |= S_FREE_MASK;
-	_sprite_ptr[best] = NULL;
+	GetSpriteCache(best)->ptr = NULL;
 
 	// And coalesce adjacent free blocks
 	for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
@@ -377,70 +379,23 @@
 	}
 }
 
-#if defined(NEW_ROTATION)
-#define X15(x) else if (s >= x && s < (x+15)) { s = _rotate_tile_sprite[s - x] + x; }
-#define X19(x) else if (s >= x && s < (x+19)) { s = _rotate_tile_sprite[s - x] + x; }
-#define MAP(from,to,map) else if (s >= from && s <= to) { s = map[s - from] + from; }
-
-
-static uint RotateSprite(uint s)
-{
-	static const byte _rotate_tile_sprite[19] = { 0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 17, 18, 16, 15 };
-	static const byte _coast_map[9] = {0, 4, 3, 1, 2, 6, 8, 5, 7};
-	static const byte _fence_map[6] = {1, 0, 5, 4, 3, 2};
-
-	if (0);
-	X19(752)
-	X15(990-1)
-	X19(3924)
-	X19(3943)
-	X19(3962)
-	X19(3981)
-	X19(4000)
-	X19(4023)
-	X19(4042)
-	MAP(4061, 4069, _coast_map)
-	X19(4126)
-	X19(4145)
-	X19(4164)
-	X19(4183)
-	X19(4202)
-	X19(4221)
-	X19(4240)
-	X19(4259)
-	X19(4259)
-	X19(4278)
-	MAP(4090, 4095, _fence_map)
-	MAP(4096, 4101, _fence_map)
-	MAP(4102, 4107, _fence_map)
-	MAP(4108, 4113, _fence_map)
-	MAP(4114, 4119, _fence_map)
-	MAP(4120, 4125, _fence_map)
-	return s;
-}
-#endif
 
 const void *GetRawSprite(SpriteID sprite)
 {
+	SpriteCache *sc;
 	void* p;
 
 	assert(sprite < MAX_SPRITES);
 
-#if defined(NEW_ROTATION)
-	sprite = RotateSprite(sprite);
-#endif
+	sc = GetSpriteCache(sprite);
 
 	// Update LRU
-#if defined(WANT_NEW_LRU)
-	_sprite_lru_new[sprite] = ++_sprite_lru_counter;
-#else
-	_sprite_lru_cur[sprite] = ++_sprite_lru_counter;
-	_sprite_lru[sprite] = 0;
-#endif
+	sc->lru = ++_sprite_lru_counter;
 
-	p = _sprite_ptr[sprite];
+	p = sc->ptr;
+
 	// Load the sprite, if it is not loaded, yet
-	if (p == NULL) p = ReadSprite(sprite);
+	if (p == NULL) p = ReadSprite(sc, sprite);
 	return p;
 }
 
@@ -455,7 +410,10 @@
 	// Sentinel block (identified by size == 0)
 	NextBlock(_spritecache_ptr)->size = 0;
 
-	memset(_sprite_ptr, 0, sizeof(_sprite_ptr));
+	/* Reset the spritecache 'pool' */
+	free(_spritecache);
+	_spritecache_items = 0;
+	_spritecache = NULL;
 
 	_compact_cache_counter = 0;
 }