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   return _spritecache_items;
 
  170   if (sprite[src].width * scaled_1 > UINT16_MAX || sprite[src].height * scaled_1 > UINT16_MAX) 
return false;
 
  172   sprite[tgt].
width  = sprite[src].
width  * scaled_1;
 
  177   sprite[tgt].
AllocateData(tgt, sprite[tgt].width * sprite[tgt].height);
 
  180   for (
int y = 0; y < sprite[tgt].
height; y++) {
 
  182     for (
int x = 0; x < sprite[tgt].width; x++) {
 
  183       *dst = src_ln[x / scaled_1];
 
  199   sprite[zoom].
AllocateData(zoom, sprite[zoom].height * sprite[zoom].width);
 
  205   for (uint y = 0; y < sprite[zoom].
height; y++) {
 
  207     assert(src_ln <= src_end);
 
  208     for (uint x = 0; x < sprite[zoom].
width; x++) {
 
  209       assert(src < src_ln);
 
  210       if (src + 1 != src_ln && (src + 1)->a != 0) {
 
  218     src = src_ln + sprite[zoom - 1].
width;
 
  224   uint width  = sprite->
width + pad_left + pad_right;
 
  225   uint height = sprite->
height + pad_top + pad_bottom;
 
  227   if (width > UINT16_MAX || height > UINT16_MAX) 
return false;
 
  237   for (uint y = 0; y < height; y++) {
 
  238     if (y < pad_top || pad_bottom + y >= height) {
 
  251       src += sprite->
width;
 
  252       data += sprite->
width;
 
  264   sprite->
width   = width;
 
  266   sprite->
x_offs -= pad_left;
 
  267   sprite->
y_offs -= pad_top;
 
  275   int min_xoffs = INT32_MAX;
 
  276   int min_yoffs = INT32_MAX;
 
  278     if (
HasBit(sprite_avail, zoom)) {
 
  279       min_xoffs = 
min(min_xoffs, 
ScaleByZoom(sprite[zoom].x_offs, zoom));
 
  280       min_yoffs = 
min(min_yoffs, 
ScaleByZoom(sprite[zoom].y_offs, zoom));
 
  285   int max_width  = INT32_MIN;
 
  286   int max_height = INT32_MIN;
 
  288     if (
HasBit(sprite_avail, zoom)) {
 
  296     if (
HasBit(sprite_avail, zoom)) {
 
  299       int pad_left   = 
max(0, sprite[zoom].x_offs - 
UnScaleByZoom(min_xoffs, zoom));
 
  301       int pad_right  = 
max(0, 
UnScaleByZoom(max_width, zoom) - sprite[zoom].width - pad_left);
 
  302       int pad_bottom = 
max(0, 
UnScaleByZoom(max_height, zoom) - sprite[zoom].height - pad_top);
 
  304       if (pad_left > 0 || pad_right > 0 || pad_top > 0 || pad_bottom > 0) {
 
  305         if (!PadSingleSprite(&sprite[zoom], zoom, pad_left, pad_top, pad_right, pad_bottom)) 
return false;
 
  313 static bool ResizeSprites(
SpriteLoader::Sprite *sprite, uint8 sprite_avail, uint32 file_slot, uint32 file_pos)
 
  318     if (!ResizeSpriteIn(sprite, first_avail, 
ZOOM_LVL_NORMAL)) 
return false;
 
  323   if (!PadSprites(sprite, sprite_avail)) 
return false;
 
  327     if (
HasBit(sprite_avail, zoom)) {
 
  336     if (!
HasBit(sprite_avail, zoom)) ResizeSpriteOut(sprite, zoom);
 
  354   static const uint RECOLOUR_SPRITE_SIZE = 257;
 
  355   byte *dest = (byte *)AllocSprite(
max(RECOLOUR_SPRITE_SIZE, num));
 
  358     byte *dest_tmp = 
AllocaM(byte, 
max(RECOLOUR_SPRITE_SIZE, num));
 
  361     if (num < RECOLOUR_SPRITE_SIZE) memset(dest_tmp, 0, RECOLOUR_SPRITE_SIZE);
 
  365     for (uint i = 1; i < RECOLOUR_SPRITE_SIZE; i++) {
 
  366       dest[i] = _palmap_w2d[dest_tmp[
_palmap_d2w[i - 1] + 1]];
 
  385   uint8 file_slot = sc->file_slot;
 
  386   size_t file_pos = sc->file_pos;
 
  389   assert(IsMapgenSpriteID(
id) == (sprite_type == 
ST_MAPGEN));
 
  390   assert(sc->
type == sprite_type);
 
  392   DEBUG(sprite, 9, 
"Load sprite %d", 
id);
 
  395   uint8 sprite_avail = 0;
 
  401     sprite_avail = sprite_loader.
LoadSprite(sprite, file_slot, file_pos, sprite_type, 
true);
 
  403   if (sprite_avail == 0) {
 
  404     sprite_avail = sprite_loader.
LoadSprite(sprite, file_slot, file_pos, sprite_type, 
false);
 
  407   if (sprite_avail == 0) {
 
  408     if (sprite_type == 
ST_MAPGEN) 
return NULL;
 
  409     if (
id == SPR_IMG_QUERY) 
usererror(
"Okay... something went horribly wrong. I couldn't load the fallback sprite. What should I do?");
 
  432     byte *dest = s->
data;
 
  441   if (!ResizeSprites(sprite, sprite_avail, file_slot, sc->id)) {
 
  442     if (
id == SPR_IMG_QUERY) 
usererror(
"Okay... something went horribly wrong. I couldn't resize the fallback sprite. What should I do?");
 
  469   return _grf_sprite_offsets.find(
id) != _grf_sprite_offsets.end() ? _grf_sprite_offsets[id] : SIZE_MAX;
 
  478   _grf_sprite_offsets.clear();
 
  480   if (container_version >= 2) {
 
  488     uint32 id, prev_id = 0;
 
  490       if (
id != prev_id) _grf_sprite_offsets[id] = 
FioGetPos() - 4;
 
  509 bool LoadNextSprite(
int load_index, byte file_slot, uint file_sprite_id, byte container_version)
 
  515   if (num == 0) 
return false;
 
  520   if (grf_type == 0xFF) {
 
  529   } 
else if (container_version >= 2 && grf_type == 0xFD) {
 
  542     if (container_version >= 2) 
return false;
 
  551   bool is_mapgen = IsMapgenSpriteID(load_index);
 
  554     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?");
 
  559   sc->file_slot = file_slot;
 
  560   sc->file_pos = file_pos;
 
  563   sc->id = file_sprite_id;
 
  577   scnew->file_slot = scold->file_slot;
 
  578   scnew->file_pos = scold->file_pos;
 
  580   scnew->id = scold->id;
 
  595 assert_compile(
sizeof(
MemBlock) == 
sizeof(
size_t));
 
  597 assert_compile((
sizeof(
size_t) & (
sizeof(
size_t) - 1)) == 0);
 
  601   return (
MemBlock*)((byte*)block + (block->size & ~S_FREE_MASK));
 
  604 static size_t GetSpriteCacheUsage()
 
  609   for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
 
  610     if (!(s->size & S_FREE_MASK)) tot_size += s->size;
 
  617 void IncreaseSpriteLRU()
 
  620   if (_sprite_lru_counter > 16384) {
 
  623     DEBUG(sprite, 3, 
"Fixing lru %u, inuse=" PRINTF_SIZE, _sprite_lru_counter, GetSpriteCacheUsage());
 
  625     for (i = 0; i != _spritecache_items; i++) {
 
  627       if (sc->ptr != NULL) {
 
  630         } 
else if (sc->lru != -32768) {
 
  635     _sprite_lru_counter = 0;
 
  639   if (++_compact_cache_counter >= 740) {
 
  641     _compact_cache_counter = 0;
 
  653   DEBUG(sprite, 3, 
"Compacting sprite cache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
 
  655   for (s = _spritecache_ptr; s->size != 0;) {
 
  656     if (s->size & S_FREE_MASK) {
 
  662       assert(!(next->size & S_FREE_MASK));
 
  665       if (next->size == 0) 
break;
 
  668       for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
 
  669         assert(i != _spritecache_items);
 
  672       GetSpriteCache(i)->ptr = s->data; 
 
  675       memmove(s, next, next->size);
 
  680       while (NextBlock(s)->size & S_FREE_MASK) {
 
  681         s->size += NextBlock(s)->size & ~S_FREE_MASK;
 
  697   assert(!(s->size & S_FREE_MASK));
 
  699   GetSpriteCache(item)->ptr = NULL;
 
  702   for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
 
  703     if (s->size & S_FREE_MASK) {
 
  705         s->size += NextBlock(s)->size & ~S_FREE_MASK;
 
  713   uint best = UINT_MAX;
 
  716   DEBUG(sprite, 3, 
"DeleteEntryFromSpriteCache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
 
  719   for (
SpriteID i = 0; i != _spritecache_items; i++) {
 
  729   if (best == UINT_MAX) 
error(
"Out of sprite memory");
 
  734 static void *AllocSprite(
size_t mem_req)
 
  740   mem_req = 
Align(mem_req, S_FREE_MASK + 1);
 
  745     for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
 
  746       if (s->size & S_FREE_MASK) {
 
  747         size_t cur_size = s->size & ~S_FREE_MASK;
 
  751         if (cur_size == mem_req ||
 
  752             cur_size >= mem_req + 
sizeof(
MemBlock)) {
 
  757           if (cur_size != mem_req) {
 
  758             NextBlock(s)->size = (cur_size - mem_req) | S_FREE_MASK;
 
  782   static const char * 
const sprite_types[] = {
 
  795   byte warning_level = sc->
warned ? 6 : 0;
 
  797   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]);
 
  801       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?");
 
  806       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?");
 
  826   assert(type != 
ST_MAPGEN || IsMapgenSpriteID(sprite));
 
  829   if (!SpriteExists(sprite)) {
 
  830     DEBUG(sprite, 1, 
"Tried to load non-existing sprite #%d. Probable cause: Wrong/missing NewGRFs", sprite);
 
  833     sprite = SPR_IMG_QUERY;
 
  840   if (allocator == NULL) {
 
  844     sc->lru = ++_sprite_lru_counter;
 
  847     if (sc->ptr == NULL) sc->ptr = 
ReadSprite(sc, sprite, type, AllocSprite);
 
  852     return ReadSprite(sc, sprite, type, allocator);
 
  857 static void GfxInitSpriteCache()
 
  861   uint target_size = (bpp > 0 ? _sprite_cache_size * bpp / 8 : 1) * 1024 * 1024;
 
  864   static uint last_alloc_attempt = 0;
 
  866   if (_spritecache_ptr == NULL || (_allocated_sprite_cache_size != target_size && target_size != last_alloc_attempt)) {
 
  867     delete[] 
reinterpret_cast<byte *
>(_spritecache_ptr);
 
  869     last_alloc_attempt = target_size;
 
  870     _allocated_sprite_cache_size = target_size;
 
  875         _spritecache_ptr = 
reinterpret_cast<MemBlock *
>(
new byte[_allocated_sprite_cache_size + _allocated_sprite_cache_size / 2]);
 
  876       } 
catch (std::bad_alloc &) {
 
  877         _spritecache_ptr = NULL;
 
  880       if (_spritecache_ptr != NULL) {
 
  882         delete[] 
reinterpret_cast<byte *
>(_spritecache_ptr);
 
  883         _spritecache_ptr = 
reinterpret_cast<MemBlock *
>(
new byte[_allocated_sprite_cache_size]);
 
  884       } 
else if (_allocated_sprite_cache_size < 2 * 1024 * 1024) {
 
  885         usererror(
"Cannot allocate spritecache");
 
  888         _allocated_sprite_cache_size >>= 1;
 
  890     } 
while (_spritecache_ptr == NULL);
 
  892     if (_allocated_sprite_cache_size != target_size) {
 
  893       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);
 
  895       ErrorMessageData msg(STR_CONFIG_ERROR_OUT_OF_MEMORY, STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG);
 
  896       msg.SetDParam(0, target_size);
 
  897       msg.SetDParam(1, _allocated_sprite_cache_size);
 
  905   NextBlock(_spritecache_ptr)->size = 0;
 
  908 void GfxInitSpriteMem()
 
  910   GfxInitSpriteCache();
 
  914   _spritecache_items = 0;
 
  917   _compact_cache_counter = 0;
 
  927   for (uint i = 0; i != _spritecache_items; i++) {