24 #include "table/strings.h"
30 uint _sprite_cache_size = 4;
46 static uint _spritecache_items = 0;
50 static inline SpriteCache *GetSpriteCache(uint index)
52 return &_spritecache[index];
55 static inline bool IsMapgenSpriteID(
SpriteID sprite)
62 if (index >= _spritecache_items) {
64 uint items =
Align(index + 1, 1024);
66 DEBUG(sprite, 4,
"Increasing sprite cache to %u items (" PRINTF_SIZE
" bytes)", items, items *
sizeof(*_spritecache));
68 _spritecache =
ReallocT(_spritecache, items);
71 memset(_spritecache + _spritecache_items, 0, (items - _spritecache_items) *
sizeof(*_spritecache));
72 _spritecache_items = items;
75 return GetSpriteCache(index);
84 static uint _sprite_lru_counter;
86 static uint _allocated_sprite_cache_size = 0;
87 static int _compact_cache_counter;
90 static void *AllocSprite(
size_t mem_req);
106 int size = (i == 0) ? 0x80 : i;
107 if (size > num)
return false;
123 if (
id >= _spritecache_items)
return false;
126 if (
id == 0)
return true;
127 return !(GetSpriteCache(
id)->file_pos == 0 && GetSpriteCache(
id)->file_slot == 0);
138 return GetSpriteCache(sprite)->
type;
148 if (!SpriteExists(sprite))
return 0;
149 return GetSpriteCache(sprite)->file_slot;
162 for (
SpriteID i = begin; i != end; i++) {
163 if (SpriteExists(i)) {
165 if (sc->file_slot == file_slot) count++;
181 return _spritecache_items;
189 if (sprite[src].width * scaled_1 > UINT16_MAX || sprite[src].height * scaled_1 > UINT16_MAX)
return false;
191 sprite[tgt].
width = sprite[src].
width * scaled_1;
196 sprite[tgt].
AllocateData(tgt, sprite[tgt].width * sprite[tgt].height);
199 for (
int y = 0; y < sprite[tgt].
height; y++) {
201 for (
int x = 0; x < sprite[tgt].width; x++) {
202 *dst = src_ln[x / scaled_1];
218 sprite[zoom].
AllocateData(zoom, sprite[zoom].height * sprite[zoom].width);
224 for (uint y = 0; y < sprite[zoom].
height; y++) {
226 assert(src_ln <= src_end);
227 for (uint x = 0; x < sprite[zoom].
width; x++) {
228 assert(src < src_ln);
229 if (src + 1 != src_ln && (src + 1)->a != 0) {
237 src = src_ln + sprite[zoom - 1].
width;
243 uint width = sprite->
width + pad_left + pad_right;
244 uint height = sprite->
height + pad_top + pad_bottom;
246 if (width > UINT16_MAX || height > UINT16_MAX)
return false;
256 for (uint y = 0; y < height; y++) {
257 if (y < pad_top || pad_bottom + y >= height) {
270 src += sprite->
width;
271 data += sprite->
width;
283 sprite->
width = width;
285 sprite->
x_offs -= pad_left;
286 sprite->
y_offs -= pad_top;
294 int min_xoffs = INT32_MAX;
295 int min_yoffs = INT32_MAX;
297 if (
HasBit(sprite_avail, zoom)) {
298 min_xoffs =
min(min_xoffs,
ScaleByZoom(sprite[zoom].x_offs, zoom));
299 min_yoffs =
min(min_yoffs,
ScaleByZoom(sprite[zoom].y_offs, zoom));
304 int max_width = INT32_MIN;
305 int max_height = INT32_MIN;
307 if (
HasBit(sprite_avail, zoom)) {
315 if (
HasBit(sprite_avail, zoom)) {
318 int pad_left =
max(0, sprite[zoom].x_offs -
UnScaleByZoom(min_xoffs, zoom));
320 int pad_right =
max(0,
UnScaleByZoom(max_width, zoom) - sprite[zoom].width - pad_left);
321 int pad_bottom =
max(0,
UnScaleByZoom(max_height, zoom) - sprite[zoom].height - pad_top);
323 if (pad_left > 0 || pad_right > 0 || pad_top > 0 || pad_bottom > 0) {
324 if (!PadSingleSprite(&sprite[zoom], zoom, pad_left, pad_top, pad_right, pad_bottom))
return false;
332 static bool ResizeSprites(
SpriteLoader::Sprite *sprite, uint8 sprite_avail, uint32 file_slot, uint32 file_pos)
337 if (!ResizeSpriteIn(sprite, first_avail,
ZOOM_LVL_NORMAL))
return false;
342 if (!PadSprites(sprite, sprite_avail))
return false;
346 if (
HasBit(sprite_avail, zoom)) {
355 if (!
HasBit(sprite_avail, zoom)) ResizeSpriteOut(sprite, zoom);
373 static const uint RECOLOUR_SPRITE_SIZE = 257;
374 byte *dest = (byte *)AllocSprite(
max(RECOLOUR_SPRITE_SIZE, num));
377 byte *dest_tmp =
AllocaM(byte,
max(RECOLOUR_SPRITE_SIZE, num));
380 if (num < RECOLOUR_SPRITE_SIZE) memset(dest_tmp, 0, RECOLOUR_SPRITE_SIZE);
384 for (uint i = 1; i < RECOLOUR_SPRITE_SIZE; i++) {
385 dest[i] = _palmap_w2d[dest_tmp[
_palmap_d2w[i - 1] + 1]];
404 uint8 file_slot = sc->file_slot;
405 size_t file_pos = sc->file_pos;
408 assert(IsMapgenSpriteID(
id) == (sprite_type ==
ST_MAPGEN));
409 assert(sc->
type == sprite_type);
411 DEBUG(sprite, 9,
"Load sprite %d",
id);
414 uint8 sprite_avail = 0;
420 sprite_avail = sprite_loader.
LoadSprite(sprite, file_slot, file_pos, sprite_type,
true);
422 if (sprite_avail == 0) {
423 sprite_avail = sprite_loader.
LoadSprite(sprite, file_slot, file_pos, sprite_type,
false);
426 if (sprite_avail == 0) {
427 if (sprite_type ==
ST_MAPGEN)
return NULL;
428 if (
id == SPR_IMG_QUERY)
usererror(
"Okay... something went horribly wrong. I couldn't load the fallback sprite. What should I do?");
451 byte *dest = s->
data;
460 if (!ResizeSprites(sprite, sprite_avail, file_slot, sc->id)) {
461 if (
id == SPR_IMG_QUERY)
usererror(
"Okay... something went horribly wrong. I couldn't resize the fallback sprite. What should I do?");
488 return _grf_sprite_offsets.find(
id) != _grf_sprite_offsets.end() ? _grf_sprite_offsets[id] : SIZE_MAX;
497 _grf_sprite_offsets.clear();
499 if (container_version >= 2) {
507 uint32 id, prev_id = 0;
509 if (
id != prev_id) _grf_sprite_offsets[id] =
FioGetPos() - 4;
528 bool LoadNextSprite(
int load_index, byte file_slot, uint file_sprite_id, byte container_version)
534 if (num == 0)
return false;
539 if (grf_type == 0xFF) {
548 }
else if (container_version >= 2 && grf_type == 0xFD) {
561 if (container_version >= 2)
return false;
570 bool is_mapgen = IsMapgenSpriteID(load_index);
573 if (type !=
ST_NORMAL)
usererror(
"Uhm, would you be so kind not to load a NewGRF that changes the type of the map generator sprites?");
578 sc->file_slot = file_slot;
579 sc->file_pos = file_pos;
582 sc->id = file_sprite_id;
596 scnew->file_slot = scold->file_slot;
597 scnew->file_pos = scold->file_pos;
599 scnew->id = scold->id;
614 assert_compile(
sizeof(
MemBlock) ==
sizeof(
size_t));
616 assert_compile((
sizeof(
size_t) & (
sizeof(
size_t) - 1)) == 0);
620 return (
MemBlock*)((byte*)block + (block->size & ~S_FREE_MASK));
623 static size_t GetSpriteCacheUsage()
628 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
629 if (!(s->size & S_FREE_MASK)) tot_size += s->size;
636 void IncreaseSpriteLRU()
639 if (_sprite_lru_counter > 16384) {
642 DEBUG(sprite, 3,
"Fixing lru %u, inuse=" PRINTF_SIZE, _sprite_lru_counter, GetSpriteCacheUsage());
644 for (i = 0; i != _spritecache_items; i++) {
646 if (sc->ptr != NULL) {
649 }
else if (sc->lru != -32768) {
654 _sprite_lru_counter = 0;
658 if (++_compact_cache_counter >= 740) {
660 _compact_cache_counter = 0;
672 DEBUG(sprite, 3,
"Compacting sprite cache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
674 for (s = _spritecache_ptr; s->size != 0;) {
675 if (s->size & S_FREE_MASK) {
681 assert(!(next->size & S_FREE_MASK));
684 if (next->size == 0)
break;
687 for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
688 assert(i != _spritecache_items);
691 GetSpriteCache(i)->ptr = s->data;
694 memmove(s, next, next->size);
699 while (NextBlock(s)->size & S_FREE_MASK) {
700 s->size += NextBlock(s)->size & ~S_FREE_MASK;
716 assert(!(s->size & S_FREE_MASK));
718 GetSpriteCache(item)->ptr = NULL;
721 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
722 if (s->size & S_FREE_MASK) {
724 s->size += NextBlock(s)->size & ~S_FREE_MASK;
732 uint best = UINT_MAX;
735 DEBUG(sprite, 3,
"DeleteEntryFromSpriteCache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
738 for (
SpriteID i = 0; i != _spritecache_items; i++) {
748 if (best == UINT_MAX)
error(
"Out of sprite memory");
753 static void *AllocSprite(
size_t mem_req)
759 mem_req =
Align(mem_req, S_FREE_MASK + 1);
764 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
765 if (s->size & S_FREE_MASK) {
766 size_t cur_size = s->size & ~S_FREE_MASK;
770 if (cur_size == mem_req ||
771 cur_size >= mem_req +
sizeof(
MemBlock)) {
776 if (cur_size != mem_req) {
777 NextBlock(s)->size = (cur_size - mem_req) | S_FREE_MASK;
801 static const char *
const sprite_types[] = {
814 byte warning_level = sc->
warned ? 6 : 0;
816 DEBUG(sprite, warning_level,
"Tried to load %s sprite #%d as a %s sprite. Probable cause: NewGRF interference", sprite_types[available], sprite, sprite_types[requested]);
820 if (sprite == SPR_IMG_QUERY)
usererror(
"Uhm, would you be so kind not to load a NewGRF that makes the 'query' sprite a non-normal sprite?");
825 if (sprite == PALETTE_TO_DARK_BLUE)
usererror(
"Uhm, would you be so kind not to load a NewGRF that makes the 'PALETTE_TO_DARK_BLUE' sprite a non-remap sprite?");
845 assert(type !=
ST_MAPGEN || IsMapgenSpriteID(sprite));
848 if (!SpriteExists(sprite)) {
849 DEBUG(sprite, 1,
"Tried to load non-existing sprite #%d. Probable cause: Wrong/missing NewGRFs", sprite);
852 sprite = SPR_IMG_QUERY;
859 if (allocator == NULL) {
863 sc->lru = ++_sprite_lru_counter;
866 if (sc->ptr == NULL) sc->ptr =
ReadSprite(sc, sprite, type, AllocSprite);
871 return ReadSprite(sc, sprite, type, allocator);
876 static void GfxInitSpriteCache()
880 uint target_size = (bpp > 0 ? _sprite_cache_size * bpp / 8 : 1) * 1024 * 1024;
883 static uint last_alloc_attempt = 0;
885 if (_spritecache_ptr == NULL || (_allocated_sprite_cache_size != target_size && target_size != last_alloc_attempt)) {
886 delete[]
reinterpret_cast<byte *
>(_spritecache_ptr);
888 last_alloc_attempt = target_size;
889 _allocated_sprite_cache_size = target_size;
894 _spritecache_ptr =
reinterpret_cast<MemBlock *
>(
new byte[_allocated_sprite_cache_size + _allocated_sprite_cache_size / 2]);
895 }
catch (std::bad_alloc &) {
896 _spritecache_ptr = NULL;
899 if (_spritecache_ptr != NULL) {
901 delete[]
reinterpret_cast<byte *
>(_spritecache_ptr);
902 _spritecache_ptr =
reinterpret_cast<MemBlock *
>(
new byte[_allocated_sprite_cache_size]);
903 }
else if (_allocated_sprite_cache_size < 2 * 1024 * 1024) {
904 usererror(
"Cannot allocate spritecache");
907 _allocated_sprite_cache_size >>= 1;
909 }
while (_spritecache_ptr == NULL);
911 if (_allocated_sprite_cache_size != target_size) {
912 DEBUG(misc, 0,
"Not enough memory to allocate %d MiB of spritecache. Spritecache was reduced to %d MiB.", target_size / 1024 / 1024, _allocated_sprite_cache_size / 1024 / 1024);
914 ErrorMessageData msg(STR_CONFIG_ERROR_OUT_OF_MEMORY, STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG);
915 msg.SetDParam(0, target_size);
916 msg.SetDParam(1, _allocated_sprite_cache_size);
924 NextBlock(_spritecache_ptr)->size = 0;
927 void GfxInitSpriteMem()
929 GfxInitSpriteCache();
933 _spritecache_items = 0;
936 _compact_cache_counter = 0;
946 for (uint i = 0; i != _spritecache_items; i++) {