24 #include "table/strings.h" 30 uint _sprite_cache_size = 4;
44 static uint _spritecache_items = 0;
48 static inline SpriteCache *GetSpriteCache(uint index)
50 return &_spritecache[index];
53 static inline bool IsMapgenSpriteID(
SpriteID sprite)
60 if (index >= _spritecache_items) {
62 uint items =
Align(index + 1, 1024);
64 DEBUG(sprite, 4,
"Increasing sprite cache to %u items (" PRINTF_SIZE
" bytes)", items, items *
sizeof(*_spritecache));
66 _spritecache =
ReallocT(_spritecache, items);
69 memset(_spritecache + _spritecache_items, 0, (items - _spritecache_items) *
sizeof(*_spritecache));
70 _spritecache_items = items;
73 return GetSpriteCache(index);
82 static uint _sprite_lru_counter;
84 static uint _allocated_sprite_cache_size = 0;
85 static int _compact_cache_counter;
88 static void *AllocSprite(
size_t mem_req);
104 int size = (i == 0) ? 0x80 : i;
105 if (size > num)
return false;
121 if (
id >= _spritecache_items)
return false;
124 if (
id == 0)
return true;
125 return !(GetSpriteCache(
id)->file_pos == 0 && GetSpriteCache(
id)->file_slot == 0);
136 return GetSpriteCache(sprite)->
type;
146 if (!SpriteExists(sprite))
return 0;
147 return GetSpriteCache(sprite)->file_slot;
160 for (
SpriteID i = begin; i != end; i++) {
161 if (SpriteExists(i)) {
163 if (sc->file_slot == file_slot) count++;
179 return _spritecache_items;
187 if (sprite[src].width * scaled_1 > UINT16_MAX || sprite[src].height * scaled_1 > UINT16_MAX)
return false;
189 sprite[tgt].
width = sprite[src].
width * scaled_1;
194 sprite[tgt].
AllocateData(tgt, sprite[tgt].width * sprite[tgt].height);
197 for (
int y = 0; y < sprite[tgt].
height; y++) {
199 for (
int x = 0; x < sprite[tgt].width; x++) {
200 *dst = src_ln[x / scaled_1];
216 sprite[zoom].
AllocateData(zoom, sprite[zoom].height * sprite[zoom].width);
222 for (uint y = 0; y < sprite[zoom].
height; y++) {
224 assert(src_ln <= src_end);
225 for (uint x = 0; x < sprite[zoom].
width; x++) {
226 assert(src < src_ln);
227 if (src + 1 != src_ln && (src + 1)->a != 0) {
235 src = src_ln + sprite[zoom - 1].
width;
241 uint width = sprite->
width + pad_left + pad_right;
242 uint height = sprite->
height + pad_top + pad_bottom;
244 if (width > UINT16_MAX || height > UINT16_MAX)
return false;
254 for (uint y = 0; y < height; y++) {
255 if (y < pad_top || pad_bottom + y >= height) {
268 src += sprite->
width;
269 data += sprite->
width;
281 sprite->
width = width;
283 sprite->
x_offs -= pad_left;
284 sprite->
y_offs -= pad_top;
292 int min_xoffs = INT32_MAX;
293 int min_yoffs = INT32_MAX;
295 if (
HasBit(sprite_avail, zoom)) {
296 min_xoffs =
min(min_xoffs,
ScaleByZoom(sprite[zoom].x_offs, zoom));
297 min_yoffs =
min(min_yoffs,
ScaleByZoom(sprite[zoom].y_offs, zoom));
302 int max_width = INT32_MIN;
303 int max_height = INT32_MIN;
305 if (
HasBit(sprite_avail, zoom)) {
313 if (
HasBit(sprite_avail, zoom)) {
316 int pad_left =
max(0, sprite[zoom].x_offs -
UnScaleByZoom(min_xoffs, zoom));
318 int pad_right =
max(0,
UnScaleByZoom(max_width, zoom) - sprite[zoom].width - pad_left);
319 int pad_bottom =
max(0,
UnScaleByZoom(max_height, zoom) - sprite[zoom].height - pad_top);
321 if (pad_left > 0 || pad_right > 0 || pad_top > 0 || pad_bottom > 0) {
322 if (!PadSingleSprite(&sprite[zoom], zoom, pad_left, pad_top, pad_right, pad_bottom))
return false;
330 static bool ResizeSprites(
SpriteLoader::Sprite *sprite, uint8 sprite_avail, uint32 file_slot, uint32 file_pos)
335 if (!ResizeSpriteIn(sprite, first_avail,
ZOOM_LVL_NORMAL))
return false;
340 if (!PadSprites(sprite, sprite_avail))
return false;
344 if (
HasBit(sprite_avail, zoom)) {
353 if (!
HasBit(sprite_avail, zoom)) ResizeSpriteOut(sprite, zoom);
371 static const uint RECOLOUR_SPRITE_SIZE = 257;
372 byte *dest = (byte *)AllocSprite(
max(RECOLOUR_SPRITE_SIZE, num));
375 byte *dest_tmp =
AllocaM(byte,
max(RECOLOUR_SPRITE_SIZE, num));
378 if (num < RECOLOUR_SPRITE_SIZE) memset(dest_tmp, 0, RECOLOUR_SPRITE_SIZE);
382 for (uint i = 1; i < RECOLOUR_SPRITE_SIZE; i++) {
402 uint8 file_slot = sc->file_slot;
403 size_t file_pos = sc->file_pos;
406 assert(IsMapgenSpriteID(
id) == (sprite_type ==
ST_MAPGEN));
407 assert(sc->
type == sprite_type);
409 DEBUG(sprite, 9,
"Load sprite %d",
id);
412 uint8 sprite_avail = 0;
418 sprite_avail = sprite_loader.
LoadSprite(sprite, file_slot, file_pos, sprite_type,
true);
420 if (sprite_avail == 0) {
421 sprite_avail = sprite_loader.
LoadSprite(sprite, file_slot, file_pos, sprite_type,
false);
424 if (sprite_avail == 0) {
425 if (sprite_type ==
ST_MAPGEN)
return nullptr;
426 if (
id == SPR_IMG_QUERY)
usererror(
"Okay... something went horribly wrong. I couldn't load the fallback sprite. What should I do?");
449 byte *dest = s->
data;
458 if (!ResizeSprites(sprite, sprite_avail, file_slot, sc->id)) {
459 if (
id == SPR_IMG_QUERY)
usererror(
"Okay... something went horribly wrong. I couldn't resize the fallback sprite. What should I do?");
497 if (container_version >= 2) {
505 uint32 id, prev_id = 0;
526 bool LoadNextSprite(
int load_index, byte file_slot, uint file_sprite_id, byte container_version)
532 if (num == 0)
return false;
536 void *data =
nullptr;
537 if (grf_type == 0xFF) {
546 }
else if (container_version >= 2 && grf_type == 0xFD) {
559 if (container_version >= 2)
return false;
568 bool is_mapgen = IsMapgenSpriteID(load_index);
571 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?");
576 sc->file_slot = file_slot;
577 sc->file_pos = file_pos;
580 sc->id = file_sprite_id;
594 scnew->file_slot = scold->file_slot;
595 scnew->file_pos = scold->file_pos;
596 scnew->ptr =
nullptr;
597 scnew->id = scold->id;
612 assert_compile(
sizeof(
MemBlock) ==
sizeof(
size_t));
614 assert_compile((
sizeof(
size_t) & (
sizeof(
size_t) - 1)) == 0);
621 static size_t GetSpriteCacheUsage()
626 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
634 void IncreaseSpriteLRU()
637 if (_sprite_lru_counter > 16384) {
640 DEBUG(sprite, 3,
"Fixing lru %u, inuse=" PRINTF_SIZE, _sprite_lru_counter, GetSpriteCacheUsage());
642 for (i = 0; i != _spritecache_items; i++) {
644 if (sc->ptr !=
nullptr) {
647 }
else if (sc->lru != -32768) {
652 _sprite_lru_counter = 0;
656 if (++_compact_cache_counter >= 740) {
658 _compact_cache_counter = 0;
670 DEBUG(sprite, 3,
"Compacting sprite cache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
672 for (s = _spritecache_ptr; s->size != 0;) {
682 if (next->size == 0)
break;
685 for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
686 assert(i != _spritecache_items);
689 GetSpriteCache(i)->ptr = s->data;
692 memmove(s, next, next->size);
698 s->size += NextBlock(s)->size & ~S_FREE_MASK;
716 GetSpriteCache(item)->ptr =
nullptr;
719 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
730 uint best = UINT_MAX;
733 DEBUG(sprite, 3,
"DeleteEntryFromSpriteCache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
736 for (
SpriteID i = 0; i != _spritecache_items; i++) {
738 if (sc->
type !=
ST_RECOLOUR && sc->ptr !=
nullptr && sc->lru < cur_lru) {
746 if (best == UINT_MAX)
error(
"Out of sprite memory");
751 static void *AllocSprite(
size_t mem_req)
762 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
768 if (cur_size == mem_req ||
769 cur_size >= mem_req +
sizeof(
MemBlock)) {
774 if (cur_size != mem_req) {
775 NextBlock(s)->size = (cur_size - mem_req) |
S_FREE_MASK;
799 static const char *
const sprite_types[] = {
812 byte warning_level = sc->
warned ? 6 : 0;
814 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]);
818 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?");
823 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?");
843 assert(type !=
ST_MAPGEN || IsMapgenSpriteID(sprite));
846 if (!SpriteExists(sprite)) {
847 DEBUG(sprite, 1,
"Tried to load non-existing sprite #%d. Probable cause: Wrong/missing NewGRFs", sprite);
850 sprite = SPR_IMG_QUERY;
857 if (allocator ==
nullptr) {
861 sc->lru = ++_sprite_lru_counter;
864 if (sc->ptr ==
nullptr) sc->ptr =
ReadSprite(sc, sprite, type, AllocSprite);
869 return ReadSprite(sc, sprite, type, allocator);
874 static void GfxInitSpriteCache()
878 uint target_size = (bpp > 0 ? _sprite_cache_size * bpp / 8 : 1) * 1024 * 1024;
881 static uint last_alloc_attempt = 0;
883 if (_spritecache_ptr ==
nullptr || (_allocated_sprite_cache_size != target_size && target_size != last_alloc_attempt)) {
884 delete[]
reinterpret_cast<byte *
>(_spritecache_ptr);
886 last_alloc_attempt = target_size;
887 _allocated_sprite_cache_size = target_size;
892 _spritecache_ptr =
reinterpret_cast<MemBlock *
>(
new byte[_allocated_sprite_cache_size + _allocated_sprite_cache_size / 2]);
893 }
catch (std::bad_alloc &) {
894 _spritecache_ptr =
nullptr;
897 if (_spritecache_ptr !=
nullptr) {
899 delete[]
reinterpret_cast<byte *
>(_spritecache_ptr);
900 _spritecache_ptr =
reinterpret_cast<MemBlock *
>(
new byte[_allocated_sprite_cache_size]);
901 }
else if (_allocated_sprite_cache_size < 2 * 1024 * 1024) {
902 usererror(
"Cannot allocate spritecache");
905 _allocated_sprite_cache_size >>= 1;
907 }
while (_spritecache_ptr ==
nullptr);
909 if (_allocated_sprite_cache_size != target_size) {
910 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);
912 ErrorMessageData msg(STR_CONFIG_ERROR_OUT_OF_MEMORY, STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG);
914 msg.
SetDParam(1, _allocated_sprite_cache_size);
922 NextBlock(_spritecache_ptr)->size = 0;
925 void GfxInitSpriteMem()
927 GfxInitSpriteCache();
931 _spritecache_items = 0;
932 _spritecache =
nullptr;
934 _compact_cache_counter = 0;
944 for (uint i = 0; i != _spritecache_items; i++) {
static const size_t S_FREE_MASK
S_FREE_MASK is used to mask-out lower bits of MemBlock::size If they are non-zero, the block is free.
Pseudosprite or other unusable sprite, used only internally.
uint GetOriginFileSlot(SpriteID sprite)
Get the (FIOS) file slot of a given sprite.
static ReusableBuffer< SpriteLoader::CommonPixel > buffer[ZOOM_LVL_COUNT]
Allocated memory to pass sprite data around.
static void * HandleInvalidSpriteRequest(SpriteID sprite, SpriteType requested, SpriteCache *sc, AllocatorProc *allocator)
Handles the case when a sprite of different type is requested than is present in the SpriteCache...
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
static int UnScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZOOM_LVL_NORMAL) When shifting right...
Data structure describing a sprite.
uint16 FioReadWord()
Read a word (16 bits) from the file (in low endian format).
uint8 LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp)
Load a sprite from the disk and return a sprite struct which is the same for all loaders.
void SetDParam(uint n, uint64 v)
Set a error string parameter.
static void DeleteEntryFromSpriteCache(uint item)
Delete a single entry from the sprite cache.
static int ScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift left (when zoom > ZOOM_LVL_NORMAL) When shifting right...
void AllocateData(ZoomLevel zoom, size_t size)
Allocate the sprite data of this sprite.
Functions for Standard In/Out file operations.
Maximum number of sprites that can be loaded at a given time.
const byte _palmap_w2d[]
Converting from the Windows palette to the DOS palette.
virtual Sprite * Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator)=0
Convert a sprite from the loader to our own format.
#define AllocaM(T, num_elements)
alloca() has to be called in the parent function, so define AllocaM() as a macro
static void * ReadRecolourSprite(uint16 file_slot, uint num)
Load a recolour sprite into memory.
static T max(const T a, const T b)
Returns the maximum of two values.
byte FioReadByte()
Read a byte from the file.
bool warned
True iff the user has been warned about incorrect use of this sprite.
SpriteType GetSpriteType(SpriteID sprite)
Get the sprite type of a given sprite.
size_t GetGRFSpriteOffset(uint32 id)
Get the file offset for a specific sprite in the sprite section of a GRF.
Definition of a common pixel in OpenTTD's realm.
SpriteType type
The sprite type.
Base for reading sprites from (New)GRFs.
static bool IsInsideMM(const T x, const size_t min, const size_t max)
Checks if a value is in an interval.
void ReadGRFSpriteOffsets(byte container_version)
Parse the sprite section of GRFs.
static void * ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_type, AllocatorProc *allocator)
Read a sprite from disk.
Special sprite for the map generator.
int16 y_offs
Number of pixels to shift the sprite downwards.
Functions related to errors.
static T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
#define FIND_FIRST_BIT(x)
Returns the first non-zero bit in a 6-bit value (from right).
Functions related to the gfx engine.
Types related to global configuration settings.
Definition of base types and functions in a cross-platform compatible way.
void CDECL usererror(const char *s,...)
Error handling for fatal user errors.
A number of safeguards to prevent using unsafe methods.
void FioSeekTo(size_t pos, int mode)
Seek in the current file.
int16 x_offs
The x-offset of where the sprite will be drawn.
static T * ReallocT(T *t_ptr, size_t num_elements)
Simplified reallocation function that allocates the specified number of elements of the given type...
void ScheduleErrorMessage(const ErrorMessageData &data)
Schedule an error.
SpriteLoader::CommonPixel * data
The sprite itself.
Structure for passing information from the sprite loader to the blitter.
void FioReadBlock(void *ptr, size_t size)
Read a block.
bool _palette_remap_grf[]
Whether the given NewGRFs must get a palette remap from windows to DOS or not.
void GfxClearSpriteCache()
Remove all encoded sprites from the sprite cache without discarding sprite location information...
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
static T min(const T a, const T b)
Returns the minimum of two values.
bool SkipSpriteData(byte type, uint16 num)
Skip the given amount of sprite graphics data.
SpriteType
Types of sprites that might be loaded.
uint16 height
Height of the sprite.
The most basic (normal) sprite.
static void MemCpyT(T *destination, const T *source, size_t num=1)
Type-safe version of memcpy().
#define DEBUG(name, level,...)
Output a line of debugging information.
byte container_ver
Container version of the GRF the sprite is from.
uint GetMaxSpriteID()
Get a reasonable (upper bound) estimate of the maximum SpriteID used in OpenTTD; there will be no spr...
static std::map< uint32, size_t > _grf_sprite_offsets
Map from sprite numbers to position in the GRF file.
uint32 FioReadDword()
Read a double word (32 bits) from the file (in low endian format).
uint16 width
Width of the sprite.
uint16 width
Width of the sprite.
static void CompactSpriteCache()
Called when holes in the sprite cache should be removed.
The data of the error message.
uint32 SpriteID
The number of a sprite, without mapping bits and colourtables.
void * GetRawSprite(SpriteID sprite, SpriteType type, AllocatorProc *allocator)
Reads a sprite (from disk or sprite cache).
Sprite loader for graphics coming from a (New)GRF.
void FioSkipBytes(int n)
Skip n bytes ahead in the file.
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
Functions related to zooming.
uint16 height
Height of the sprite.
bool LoadNextSprite(int load_index, byte file_slot, uint file_sprite_id, byte container_version)
Load a real or recolour sprite.
int16 x_offs
Number of pixels to shift the sprite to the right.
uint GetSpriteCountForSlot(uint file_slot, SpriteID begin, SpriteID end)
Count the sprites which originate from a specific file slot in a range of SpriteIDs.
static const byte _palmap_d2w[]
Converting from the DOS palette to the Windows palette.
int16 y_offs
The y-offset of where the sprite will be drawn.
virtual uint8 GetScreenDepth()=0
Get the screen depth this blitter works for.
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
SpriteType type
In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour spr...
ZoomLevel
All zoom levels we know.
size_t FioGetPos()
Get position in the current file.
Functions related to memory operations.
This file contains all sprite-related enums and defines.
Factory to 'query' all available blitters.
Translation tables from one GRF to another GRF.
static void MemSetT(T *ptr, byte value, size_t num=1)
Type-safe version of memset().