26 #include "table/strings.h"
32 uint _sprite_cache_size = 4;
35 static uint _spritecache_items = 0;
37 static std::vector<std::unique_ptr<SpriteFile>> _sprite_files;
39 static inline SpriteCache *GetSpriteCache(uint index)
41 return &_spritecache[index];
46 if (index >= _spritecache_items) {
48 uint items =
Align(index + 1, 1024);
50 Debug(sprite, 4,
"Increasing sprite cache to {} items ({} bytes)", items, items *
sizeof(*_spritecache));
52 _spritecache =
ReallocT(_spritecache, items);
55 memset(_spritecache + _spritecache_items, 0, (items - _spritecache_items) *
sizeof(*_spritecache));
56 _spritecache_items = items;
59 return GetSpriteCache(index);
69 for (
auto &f : _sprite_files) {
70 if (f->GetFilename() == filename) {
87 if (file ==
nullptr) {
88 file = _sprite_files.insert(std::end(_sprite_files), std::make_unique<SpriteFile>(filename, subdir, palette_remap))->get();
100 static uint _sprite_lru_counter;
102 static uint _allocated_sprite_cache_size = 0;
103 static int _compact_cache_counter;
121 int size = (i == 0) ? 0x80 : i;
122 if (size > num)
return false;
138 if (
id >= _spritecache_items)
return false;
141 if (
id == 0)
return true;
142 return !(GetSpriteCache(
id)->file_pos == 0 && GetSpriteCache(
id)->
file ==
nullptr);
153 return GetSpriteCache(sprite)->
type;
163 if (!SpriteExists(sprite))
return nullptr;
164 return GetSpriteCache(sprite)->
file;
174 if (!SpriteExists(sprite))
return 0;
175 return GetSpriteCache(sprite)->id;
188 if (file ==
nullptr)
return 0;
191 for (
SpriteID i = begin; i != end; i++) {
192 if (SpriteExists(i)) {
194 if (sc->
file == file) {
196 Debug(sprite, 4,
"Sprite: {}", i);
213 return _spritecache_items;
221 if (sprite[src].width * scaled_1 > UINT16_MAX || sprite[src].height * scaled_1 > UINT16_MAX)
return false;
223 sprite[tgt].width = sprite[src].width * scaled_1;
224 sprite[tgt].height = sprite[src].height * scaled_1;
225 sprite[tgt].x_offs = sprite[src].x_offs * scaled_1;
226 sprite[tgt].y_offs = sprite[src].y_offs * scaled_1;
227 sprite[tgt].colours = sprite[src].colours;
229 sprite[tgt].AllocateData(tgt,
static_cast<size_t>(sprite[tgt].width) * sprite[tgt].height);
232 for (
int y = 0; y < sprite[tgt].height; y++) {
234 for (
int x = 0; x < sprite[tgt].width; x++) {
235 *dst = src_ln[x / scaled_1];
252 sprite[zoom].AllocateData(zoom,
static_cast<size_t>(sprite[zoom].height) * sprite[zoom].width);
258 for (uint y = 0; y < sprite[zoom].height; y++) {
260 assert(src_ln <= src_end);
261 for (uint x = 0; x < sprite[zoom].width; x++) {
262 assert(src < src_ln);
263 if (src + 1 != src_ln && (src + 1)->a != 0) {
271 src = src_ln + sprite[zoom - 1].width;
277 uint width = sprite->
width + pad_left + pad_right;
278 uint height = sprite->
height + pad_top + pad_bottom;
280 if (width > UINT16_MAX || height > UINT16_MAX)
return false;
283 size_t sprite_size =
static_cast<size_t>(sprite->
width) * sprite->
height;
286 sprite->
AllocateData(zoom,
static_cast<size_t>(width) * height);
291 for (uint y = 0; y < height; y++) {
292 if (y < pad_top || pad_bottom + y >= height) {
305 src += sprite->
width;
306 data += sprite->
width;
318 sprite->
width = width;
320 sprite->
x_offs -= pad_left;
321 sprite->
y_offs -= pad_top;
329 int min_xoffs = INT32_MAX;
330 int min_yoffs = INT32_MAX;
332 if (
HasBit(sprite_avail, zoom)) {
333 min_xoffs = std::min(min_xoffs,
ScaleByZoom(sprite[zoom].x_offs, zoom));
334 min_yoffs = std::min(min_yoffs,
ScaleByZoom(sprite[zoom].y_offs, zoom));
339 int max_width = INT32_MIN;
340 int max_height = INT32_MIN;
342 if (
HasBit(sprite_avail, zoom)) {
343 max_width = std::max(max_width,
ScaleByZoom(sprite[zoom].width + sprite[zoom].x_offs -
UnScaleByZoom(min_xoffs, zoom), zoom));
344 max_height = std::max(max_height,
ScaleByZoom(sprite[zoom].height + sprite[zoom].y_offs -
UnScaleByZoom(min_yoffs, zoom), zoom));
351 max_width =
Align(max_width, align);
352 max_height =
Align(max_height, align);
357 if (
HasBit(sprite_avail, zoom)) {
360 int pad_left = std::max(0, sprite[zoom].x_offs -
UnScaleByZoom(min_xoffs, zoom));
361 int pad_top = std::max(0, sprite[zoom].y_offs -
UnScaleByZoom(min_yoffs, zoom));
362 int pad_right = std::max(0,
UnScaleByZoom(max_width, zoom) - sprite[zoom].width - pad_left);
363 int pad_bottom = std::max(0,
UnScaleByZoom(max_height, zoom) - sprite[zoom].height - pad_top);
365 if (pad_left > 0 || pad_right > 0 || pad_top > 0 || pad_bottom > 0) {
366 if (!PadSingleSprite(&sprite[zoom], zoom, pad_left, pad_top, pad_right, pad_bottom))
return false;
379 if (!ResizeSpriteIn(sprite, first_avail,
ZOOM_LVL_NORMAL))
return false;
384 if (!PadSprites(sprite, sprite_avail, encoder))
return false;
388 if (
HasBit(sprite_avail, zoom)) {
397 if (!
HasBit(sprite_avail, zoom)) ResizeSpriteOut(sprite, zoom);
421 static const uint RECOLOUR_SPRITE_SIZE = 257;
422 byte *dest = (
byte *)AllocSprite(std::max(RECOLOUR_SPRITE_SIZE, num));
425 byte *dest_tmp =
new byte[std::max(RECOLOUR_SPRITE_SIZE, num)];
428 if (num < RECOLOUR_SPRITE_SIZE) memset(dest_tmp, 0, RECOLOUR_SPRITE_SIZE);
432 for (uint i = 1; i < RECOLOUR_SPRITE_SIZE; i++) {
458 size_t file_pos = sc->file_pos;
462 assert(sc->
type == sprite_type);
464 Debug(sprite, 9,
"Load sprite {}",
id);
467 uint8_t sprite_avail = 0;
475 if (sprite_avail == 0) {
479 if (sprite_avail == 0) {
481 if (
id == SPR_IMG_QUERY) UserError(
"Okay... something went horribly wrong. I couldn't load the fallback sprite. What should I do?");
504 byte *dest = s->
data;
513 if (!ResizeSprites(sprite, sprite_avail, encoder)) {
514 if (
id == SPR_IMG_QUERY) UserError(
"Okay... something went horribly wrong. I couldn't resize the fallback sprite. What should I do?");
528 return encoder->
Encode(sprite, allocator);
560 size_t old_pos = file.
GetPos();
561 file.
SeekTo(data_offset, SEEK_CUR);
567 uint32_t id, prev_id = 0;
571 offset.file_pos = file.
GetPos() - 4;
572 offset.control_flags = 0;
582 if (colour != 0 && zoom == 0) {
586 if (colour != 0 && zoom == 2) {
596 file.
SeekTo(old_pos, SEEK_SET);
611 size_t file_pos = file.
GetPos();
615 if (num == 0)
return false;
619 void *data =
nullptr;
620 byte control_flags = 0;
621 if (grf_type == 0xFF) {
639 file_pos = iter->second.file_pos;
640 control_flags = iter->second.control_flags;
655 UserError(
"Tried to load too many sprites (#{}; max {})", load_index,
MAX_SPRITES);
658 bool is_mapgen = IsMapgenSpriteID(load_index);
661 if (type !=
SpriteType::Normal) UserError(
"Uhm, would you be so kind not to load a NewGRF that changes the type of the map generator sprites?");
667 sc->file_pos = file_pos;
670 sc->id = file_sprite_id;
685 scnew->file_pos = scold->file_pos;
686 scnew->ptr =
nullptr;
687 scnew->id = scold->id;
701 static_assert(
sizeof(
MemBlock) ==
sizeof(
size_t));
703 static_assert((
sizeof(
size_t) & (
sizeof(
size_t) - 1)) == 0);
710 static size_t GetSpriteCacheUsage()
715 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
723 void IncreaseSpriteLRU()
726 if (_sprite_lru_counter > 16384) {
729 Debug(sprite, 5,
"Fixing lru {}, inuse={}", _sprite_lru_counter, GetSpriteCacheUsage());
731 for (i = 0; i != _spritecache_items; i++) {
733 if (sc->ptr !=
nullptr) {
736 }
else if (sc->lru != -32768) {
741 _sprite_lru_counter = 0;
745 if (++_compact_cache_counter >= 740) {
747 _compact_cache_counter = 0;
759 Debug(sprite, 3,
"Compacting sprite cache, inuse={}", GetSpriteCacheUsage());
761 for (s = _spritecache_ptr; s->size != 0;) {
771 if (next->size == 0)
break;
774 for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
775 assert(i != _spritecache_items);
778 GetSpriteCache(i)->ptr = s->data;
781 memmove(s, next, next->size);
805 GetSpriteCache(item)->ptr =
nullptr;
808 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
819 uint best = UINT_MAX;
822 Debug(sprite, 3,
"DeleteEntryFromSpriteCache, inuse={}", GetSpriteCacheUsage());
825 for (
SpriteID i = 0; i != _spritecache_items; i++) {
835 if (best == UINT_MAX) FatalError(
"Out of sprite memory");
840 void *AllocSprite(
size_t mem_req)
851 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
857 if (cur_size == mem_req ||
858 cur_size >= mem_req +
sizeof(
MemBlock)) {
863 if (cur_size != mem_req) {
864 NextBlock(s)->size = (cur_size - mem_req) |
S_FREE_MASK;
882 return MallocT<byte>(size);
896 static const char *
const sprite_types[] = {
909 byte warning_level = sc->
warned ? 6 : 0;
911 Debug(sprite, warning_level,
"Tried to load {} sprite #{} as a {} sprite. Probable cause: NewGRF interference", sprite_types[
static_cast<byte>(available)], sprite, sprite_types[
static_cast<byte>(requested)]);
915 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?");
920 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?");
944 if (!SpriteExists(sprite)) {
945 Debug(sprite, 1,
"Tried to load non-existing sprite #{}. Probable cause: Wrong/missing NewGRFs", sprite);
948 sprite = SPR_IMG_QUERY;
955 if (allocator ==
nullptr && encoder ==
nullptr) {
959 sc->lru = ++_sprite_lru_counter;
962 if (sc->ptr ==
nullptr) sc->ptr =
ReadSprite(sc, sprite, type, AllocSprite,
nullptr);
967 return ReadSprite(sc, sprite, type, allocator, encoder);
972 static void GfxInitSpriteCache()
976 uint target_size = (bpp > 0 ? _sprite_cache_size * bpp / 8 : 1) * 1024 * 1024;
979 static uint last_alloc_attempt = 0;
981 if (_spritecache_ptr ==
nullptr || (_allocated_sprite_cache_size != target_size && target_size != last_alloc_attempt)) {
982 delete[]
reinterpret_cast<byte *
>(_spritecache_ptr);
984 last_alloc_attempt = target_size;
985 _allocated_sprite_cache_size = target_size;
989 _spritecache_ptr =
reinterpret_cast<MemBlock *
>(
new(std::nothrow)
byte[_allocated_sprite_cache_size + _allocated_sprite_cache_size / 2]);
991 if (_spritecache_ptr !=
nullptr) {
993 delete[]
reinterpret_cast<byte *
>(_spritecache_ptr);
994 _spritecache_ptr =
reinterpret_cast<MemBlock *
>(
new byte[_allocated_sprite_cache_size]);
995 }
else if (_allocated_sprite_cache_size < 2 * 1024 * 1024) {
996 UserError(
"Cannot allocate spritecache");
999 _allocated_sprite_cache_size >>= 1;
1001 }
while (_spritecache_ptr ==
nullptr);
1003 if (_allocated_sprite_cache_size != target_size) {
1004 Debug(misc, 0,
"Not enough memory to allocate {} MiB of spritecache. Spritecache was reduced to {} MiB.", target_size / 1024 / 1024, _allocated_sprite_cache_size / 1024 / 1024);
1006 ErrorMessageData msg(STR_CONFIG_ERROR_OUT_OF_MEMORY, STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG);
1007 msg.SetDParam(0, target_size);
1008 msg.SetDParam(1, _allocated_sprite_cache_size);
1016 NextBlock(_spritecache_ptr)->size = 0;
1019 void GfxInitSpriteMem()
1021 GfxInitSpriteCache();
1025 _spritecache_items = 0;
1026 _spritecache =
nullptr;
1028 _compact_cache_counter = 0;
1029 _sprite_files.clear();
1039 for (uint i = 0; i != _spritecache_items; i++) {
1054 for (uint i = 0; i != _spritecache_items; i++) {