(svn r7797) -Codechange: Replace static _sprite_ptr and associated arrays with dynamic array to allow variable number of sprites. This does not change the sprite limit.
This commit is contained in:
		@@ -12,9 +12,45 @@
 | 
				
			|||||||
#define SPRITE_CACHE_SIZE 1024*1024
 | 
					#define SPRITE_CACHE_SIZE 1024*1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void* _sprite_ptr[MAX_SPRITES];
 | 
					typedef struct SpriteCache {
 | 
				
			||||||
static uint32 _sprite_file_pos[MAX_SPRITES];
 | 
						void *ptr;
 | 
				
			||||||
static int16 _sprite_lru_new[MAX_SPRITES];
 | 
						uint32 file_pos;
 | 
				
			||||||
 | 
						int16 lru;
 | 
				
			||||||
 | 
					} SpriteCache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint _spritecache_items = 0;
 | 
				
			||||||
 | 
					static SpriteCache *_spritecache = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 {
 | 
					typedef struct MemBlock {
 | 
				
			||||||
	uint32 size;
 | 
						uint32 size;
 | 
				
			||||||
@@ -69,12 +105,14 @@ static bool ReadSpriteHeaderSkipData(void)
 | 
				
			|||||||
bool SpriteExists(SpriteID id)
 | 
					bool SpriteExists(SpriteID id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Special case for Sprite ID zero -- its position is also 0... */
 | 
						/* 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* AllocSprite(size_t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void* ReadSprite(SpriteID id)
 | 
					static void* ReadSprite(SpriteCache *sc, SpriteID id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint num;
 | 
						uint num;
 | 
				
			||||||
	byte type;
 | 
						byte type;
 | 
				
			||||||
@@ -89,14 +127,14 @@ static void* ReadSprite(SpriteID id)
 | 
				
			|||||||
		);
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FioSeekToFile(_sprite_file_pos[id]);
 | 
						FioSeekToFile(sc->file_pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	num  = FioReadWord();
 | 
						num  = FioReadWord();
 | 
				
			||||||
	type = FioReadByte();
 | 
						type = FioReadByte();
 | 
				
			||||||
	if (type == 0xFF) {
 | 
						if (type == 0xFF) {
 | 
				
			||||||
		byte* dest = AllocSprite(num);
 | 
							byte* dest = AllocSprite(num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_sprite_ptr[id] = dest;
 | 
							sc->ptr = dest;
 | 
				
			||||||
		FioReadBlock(dest, num);
 | 
							FioReadBlock(dest, num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return dest;
 | 
							return dest;
 | 
				
			||||||
@@ -108,7 +146,7 @@ static void* ReadSprite(SpriteID id)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		num = (type & 0x02) ? width * height : num - 8;
 | 
							num = (type & 0x02) ? width * height : num - 8;
 | 
				
			||||||
		sprite = AllocSprite(sizeof(*sprite) + num);
 | 
							sprite = AllocSprite(sizeof(*sprite) + num);
 | 
				
			||||||
		_sprite_ptr[id] = sprite;
 | 
							sc->ptr = sprite;
 | 
				
			||||||
		sprite->info   = type;
 | 
							sprite->info   = type;
 | 
				
			||||||
		sprite->height = (id != 142) ? height : 10; // Compensate for a TTD bug
 | 
							sprite->height = (id != 142) ? height : 10; // Compensate for a TTD bug
 | 
				
			||||||
		sprite->width  = width;
 | 
							sprite->width  = width;
 | 
				
			||||||
@@ -139,6 +177,7 @@ static void* ReadSprite(SpriteID id)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool LoadNextSprite(int load_index, byte file_index)
 | 
					bool LoadNextSprite(int load_index, byte file_index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						SpriteCache *sc;
 | 
				
			||||||
	uint32 file_pos = FioGetPos() | (file_index << 24);
 | 
						uint32 file_pos = FioGetPos() | (file_index << 24);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ReadSpriteHeaderSkipData()) return false;
 | 
						if (!ReadSpriteHeaderSkipData()) return false;
 | 
				
			||||||
@@ -147,11 +186,10 @@ bool LoadNextSprite(int load_index, byte file_index)
 | 
				
			|||||||
		error("Tried to load too many sprites (#%d; max %d)", load_index, MAX_SPRITES);
 | 
							error("Tried to load too many sprites (#%d; max %d)", load_index, MAX_SPRITES);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_sprite_file_pos[load_index] = file_pos;
 | 
						sc = AllocateSpriteCache(load_index);
 | 
				
			||||||
 | 
						sc->file_pos = file_pos;
 | 
				
			||||||
	_sprite_ptr[load_index] = NULL;
 | 
						sc->ptr = NULL;
 | 
				
			||||||
 | 
						sc->lru = 0;
 | 
				
			||||||
	_sprite_lru_new[load_index] = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -159,8 +197,11 @@ bool LoadNextSprite(int load_index, byte file_index)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void DupSprite(SpriteID old, SpriteID new)
 | 
					void DupSprite(SpriteID old, SpriteID new)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	_sprite_file_pos[new] = _sprite_file_pos[old];
 | 
						SpriteCache *scold = GetSpriteCache(old);
 | 
				
			||||||
	_sprite_ptr[new] = NULL;
 | 
						SpriteCache *scnew = AllocateSpriteCache(new);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						scnew->file_pos = scold->file_pos;
 | 
				
			||||||
 | 
						scnew->ptr = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -193,20 +234,22 @@ static uint32 GetSpriteCacheUsage(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void IncreaseSpriteLRU(void)
 | 
					void IncreaseSpriteLRU(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Increase all LRU values
 | 
						// Increase all LRU values
 | 
				
			||||||
	if (_sprite_lru_counter > 16384) {
 | 
						if (_sprite_lru_counter > 16384) {
 | 
				
			||||||
 | 
							SpriteID i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		DEBUG(sprite, 3, "Fixing lru %d, inuse=%d", _sprite_lru_counter, GetSpriteCacheUsage());
 | 
							DEBUG(sprite, 3, "Fixing lru %d, inuse=%d", _sprite_lru_counter, GetSpriteCacheUsage());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i != MAX_SPRITES; i++)
 | 
							for (i = 0; i != _spritecache_items; i++) {
 | 
				
			||||||
			if (_sprite_ptr[i] != NULL) {
 | 
								SpriteCache *sc = GetSpriteCache(i);
 | 
				
			||||||
				if (_sprite_lru_new[i] >= 0) {
 | 
								if (sc->ptr != NULL) {
 | 
				
			||||||
					_sprite_lru_new[i] = -1;
 | 
									if (sc->lru >= 0) {
 | 
				
			||||||
				} else if (_sprite_lru_new[i] != -32768) {
 | 
										sc->lru = -1;
 | 
				
			||||||
					_sprite_lru_new[i]--;
 | 
									} else if (sc->lru != -32768) {
 | 
				
			||||||
 | 
										sc->lru--;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		_sprite_lru_counter = 0;
 | 
							_sprite_lru_counter = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -229,7 +272,7 @@ static void CompactSpriteCache(void)
 | 
				
			|||||||
		if (s->size & S_FREE_MASK) {
 | 
							if (s->size & S_FREE_MASK) {
 | 
				
			||||||
			MemBlock* next = NextBlock(s);
 | 
								MemBlock* next = NextBlock(s);
 | 
				
			||||||
			MemBlock temp;
 | 
								MemBlock temp;
 | 
				
			||||||
			void** i;
 | 
								SpriteID i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Since free blocks are automatically coalesced, this should hold true.
 | 
								// Since free blocks are automatically coalesced, this should hold true.
 | 
				
			||||||
			assert(!(next->size & S_FREE_MASK));
 | 
								assert(!(next->size & S_FREE_MASK));
 | 
				
			||||||
@@ -239,11 +282,11 @@ static void CompactSpriteCache(void)
 | 
				
			|||||||
				break;
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Locate the sprite belonging to the next pointer.
 | 
								// Locate the sprite belonging to the next pointer.
 | 
				
			||||||
			for (i = _sprite_ptr; *i != next->data; ++i) {
 | 
								for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
 | 
				
			||||||
				assert(i != endof(_sprite_ptr));
 | 
									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
 | 
								// Swap this and the next block
 | 
				
			||||||
			temp = *s;
 | 
								temp = *s;
 | 
				
			||||||
			memmove(s, next, next->size);
 | 
								memmove(s, next, next->size);
 | 
				
			||||||
@@ -262,31 +305,32 @@ static void CompactSpriteCache(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void DeleteEntryFromSpriteCache(void)
 | 
					static void DeleteEntryFromSpriteCache(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						SpriteID i;
 | 
				
			||||||
	int best = -1;
 | 
						uint best = -1;
 | 
				
			||||||
	MemBlock* s;
 | 
						MemBlock* s;
 | 
				
			||||||
	int cur_lru;
 | 
						int cur_lru;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DEBUG(sprite, 3, "DeleteEntryFromSpriteCache, inuse=%d", GetSpriteCacheUsage());
 | 
						DEBUG(sprite, 3, "DeleteEntryFromSpriteCache, inuse=%d", GetSpriteCacheUsage());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cur_lru = 0xffff;
 | 
						cur_lru = 0xffff;
 | 
				
			||||||
	for (i = 0; i != MAX_SPRITES; i++) {
 | 
						for (i = 0; i != _spritecache_items; i++) {
 | 
				
			||||||
		if (_sprite_ptr[i] != NULL && _sprite_lru_new[i] < cur_lru) {
 | 
							SpriteCache *sc = GetSpriteCache(i);
 | 
				
			||||||
			cur_lru = _sprite_lru_new[i];
 | 
							if (sc->ptr != NULL && sc->lru < cur_lru) {
 | 
				
			||||||
 | 
								cur_lru = sc->lru;
 | 
				
			||||||
			best = i;
 | 
								best = i;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Display an error message and die, in case we found no sprite at all.
 | 
						// Display an error message and die, in case we found no sprite at all.
 | 
				
			||||||
	// This shouldn't really happen, unless all sprites are locked.
 | 
						// This shouldn't really happen, unless all sprites are locked.
 | 
				
			||||||
	if (best == -1)
 | 
						if (best == (uint)-1)
 | 
				
			||||||
		error("Out of sprite memory");
 | 
							error("Out of sprite memory");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Mark the block as free (the block must be in use)
 | 
						// 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));
 | 
						assert(!(s->size & S_FREE_MASK));
 | 
				
			||||||
	s->size |= S_FREE_MASK;
 | 
						s->size |= S_FREE_MASK;
 | 
				
			||||||
	_sprite_ptr[best] = NULL;
 | 
						GetSpriteCache(best)->ptr = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// And coalesce adjacent free blocks
 | 
						// And coalesce adjacent free blocks
 | 
				
			||||||
	for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
 | 
						for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
 | 
				
			||||||
@@ -338,16 +382,20 @@ static void* AllocSprite(size_t mem_req)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const void *GetRawSprite(SpriteID sprite)
 | 
					const void *GetRawSprite(SpriteID sprite)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						SpriteCache *sc;
 | 
				
			||||||
	void* p;
 | 
						void* p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert(sprite < MAX_SPRITES);
 | 
						assert(sprite < MAX_SPRITES);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Update LRU
 | 
						sc = GetSpriteCache(sprite);
 | 
				
			||||||
	_sprite_lru_new[sprite] = ++_sprite_lru_counter;
 | 
					
 | 
				
			||||||
 | 
						// Update LRU
 | 
				
			||||||
 | 
						sc->lru = ++_sprite_lru_counter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p = sc->ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = _sprite_ptr[sprite];
 | 
					 | 
				
			||||||
	// Load the sprite, if it is not loaded, yet
 | 
						// Load the sprite, if it is not loaded, yet
 | 
				
			||||||
	if (p == NULL) p = ReadSprite(sprite);
 | 
						if (p == NULL) p = ReadSprite(sc, sprite);
 | 
				
			||||||
	return p;
 | 
						return p;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -362,7 +410,10 @@ void GfxInitSpriteMem(void)
 | 
				
			|||||||
	// Sentinel block (identified by size == 0)
 | 
						// Sentinel block (identified by size == 0)
 | 
				
			||||||
	NextBlock(_spritecache_ptr)->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;
 | 
						_compact_cache_counter = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user