22 #include "table/strings.h" 28 uint _sprite_cache_size = 4;
42 static uint _spritecache_items = 0;
46 static inline SpriteCache *GetSpriteCache(uint index)
48 return &_spritecache[index];
51 static inline bool IsMapgenSpriteID(
SpriteID sprite)
58 if (index >= _spritecache_items) {
60 uint items =
Align(index + 1, 1024);
62 DEBUG(sprite, 4,
"Increasing sprite cache to %u items (" PRINTF_SIZE
" bytes)", items, items *
sizeof(*_spritecache));
64 _spritecache =
ReallocT(_spritecache, items);
67 memset(_spritecache + _spritecache_items, 0, (items - _spritecache_items) *
sizeof(*_spritecache));
68 _spritecache_items = items;
71 return GetSpriteCache(index);
80 static uint _sprite_lru_counter;
82 static uint _allocated_sprite_cache_size = 0;
83 static int _compact_cache_counter;
86 static void *AllocSprite(
size_t mem_req);
102 int size = (i == 0) ? 0x80 : i;
103 if (size > num)
return false;
119 if (
id >= _spritecache_items)
return false;
122 if (
id == 0)
return true;
123 return !(GetSpriteCache(
id)->file_pos == 0 && GetSpriteCache(
id)->file_slot == 0);
134 return GetSpriteCache(sprite)->
type;
144 if (!SpriteExists(sprite))
return 0;
145 return GetSpriteCache(sprite)->file_slot;
158 for (
SpriteID i = begin; i != end; i++) {
159 if (SpriteExists(i)) {
161 if (sc->file_slot == file_slot) count++;
177 return _spritecache_items;
185 if (sprite[src].width * scaled_1 > UINT16_MAX || sprite[src].height * scaled_1 > UINT16_MAX)
return false;
187 sprite[tgt].
width = sprite[src].
width * scaled_1;
192 sprite[tgt].
AllocateData(tgt, sprite[tgt].width * sprite[tgt].height);
195 for (
int y = 0; y < sprite[tgt].
height; y++) {
197 for (
int x = 0; x < sprite[tgt].width; x++) {
198 *dst = src_ln[x / scaled_1];
214 sprite[zoom].
AllocateData(zoom, sprite[zoom].height * sprite[zoom].width);
220 for (uint y = 0; y < sprite[zoom].
height; y++) {
222 assert(src_ln <= src_end);
223 for (uint x = 0; x < sprite[zoom].
width; x++) {
224 assert(src < src_ln);
225 if (src + 1 != src_ln && (src + 1)->a != 0) {
233 src = src_ln + sprite[zoom - 1].
width;
239 uint width = sprite->
width + pad_left + pad_right;
240 uint height = sprite->
height + pad_top + pad_bottom;
242 if (width > UINT16_MAX || height > UINT16_MAX)
return false;
252 for (uint y = 0; y < height; y++) {
253 if (y < pad_top || pad_bottom + y >= height) {
266 src += sprite->
width;
267 data += sprite->
width;
279 sprite->
width = width;
281 sprite->
x_offs -= pad_left;
282 sprite->
y_offs -= pad_top;
290 int min_xoffs = INT32_MAX;
291 int min_yoffs = INT32_MAX;
293 if (
HasBit(sprite_avail, zoom)) {
294 min_xoffs =
min(min_xoffs,
ScaleByZoom(sprite[zoom].x_offs, zoom));
295 min_yoffs =
min(min_yoffs,
ScaleByZoom(sprite[zoom].y_offs, zoom));
300 int max_width = INT32_MIN;
301 int max_height = INT32_MIN;
303 if (
HasBit(sprite_avail, zoom)) {
311 if (
HasBit(sprite_avail, zoom)) {
314 int pad_left =
max(0, sprite[zoom].x_offs -
UnScaleByZoom(min_xoffs, zoom));
316 int pad_right =
max(0,
UnScaleByZoom(max_width, zoom) - sprite[zoom].width - pad_left);
317 int pad_bottom =
max(0,
UnScaleByZoom(max_height, zoom) - sprite[zoom].height - pad_top);
319 if (pad_left > 0 || pad_right > 0 || pad_top > 0 || pad_bottom > 0) {
320 if (!PadSingleSprite(&sprite[zoom], zoom, pad_left, pad_top, pad_right, pad_bottom))
return false;
328 static bool ResizeSprites(
SpriteLoader::Sprite *sprite, uint8 sprite_avail, uint32 file_slot, uint32 file_pos)
333 if (!ResizeSpriteIn(sprite, first_avail,
ZOOM_LVL_NORMAL))
return false;
338 if (!PadSprites(sprite, sprite_avail))
return false;
342 if (
HasBit(sprite_avail, zoom)) {
351 if (!
HasBit(sprite_avail, zoom)) ResizeSpriteOut(sprite, zoom);
369 static const uint RECOLOUR_SPRITE_SIZE = 257;
370 byte *dest = (byte *)AllocSprite(
max(RECOLOUR_SPRITE_SIZE, num));
373 byte *dest_tmp =
AllocaM(byte,
max(RECOLOUR_SPRITE_SIZE, num));
376 if (num < RECOLOUR_SPRITE_SIZE) memset(dest_tmp, 0, RECOLOUR_SPRITE_SIZE);
380 for (uint i = 1; i < RECOLOUR_SPRITE_SIZE; i++) {
400 uint8 file_slot = sc->file_slot;
401 size_t file_pos = sc->file_pos;
404 assert(IsMapgenSpriteID(
id) == (sprite_type ==
ST_MAPGEN));
405 assert(sc->
type == sprite_type);
407 DEBUG(sprite, 9,
"Load sprite %d",
id);
410 uint8 sprite_avail = 0;
416 sprite_avail = sprite_loader.
LoadSprite(sprite, file_slot, file_pos, sprite_type,
true);
418 if (sprite_avail == 0) {
419 sprite_avail = sprite_loader.
LoadSprite(sprite, file_slot, file_pos, sprite_type,
false);
422 if (sprite_avail == 0) {
423 if (sprite_type ==
ST_MAPGEN)
return nullptr;
424 if (
id == SPR_IMG_QUERY)
usererror(
"Okay... something went horribly wrong. I couldn't load the fallback sprite. What should I do?");
447 byte *dest = s->
data;
456 if (!ResizeSprites(sprite, sprite_avail, file_slot, sc->id)) {
457 if (
id == SPR_IMG_QUERY)
usererror(
"Okay... something went horribly wrong. I couldn't resize the fallback sprite. What should I do?");
495 if (container_version >= 2) {
503 uint32 id, prev_id = 0;
524 bool LoadNextSprite(
int load_index, byte file_slot, uint file_sprite_id, byte container_version)
530 if (num == 0)
return false;
534 void *data =
nullptr;
535 if (grf_type == 0xFF) {
544 }
else if (container_version >= 2 && grf_type == 0xFD) {
557 if (container_version >= 2)
return false;
566 bool is_mapgen = IsMapgenSpriteID(load_index);
569 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?");
574 sc->file_slot = file_slot;
575 sc->file_pos = file_pos;
578 sc->id = file_sprite_id;
592 scnew->file_slot = scold->file_slot;
593 scnew->file_pos = scold->file_pos;
594 scnew->ptr =
nullptr;
595 scnew->id = scold->id;
610 assert_compile(
sizeof(
MemBlock) ==
sizeof(
size_t));
612 assert_compile((
sizeof(
size_t) & (
sizeof(
size_t) - 1)) == 0);
619 static size_t GetSpriteCacheUsage()
624 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
632 void IncreaseSpriteLRU()
635 if (_sprite_lru_counter > 16384) {
638 DEBUG(sprite, 3,
"Fixing lru %u, inuse=" PRINTF_SIZE, _sprite_lru_counter, GetSpriteCacheUsage());
640 for (i = 0; i != _spritecache_items; i++) {
642 if (sc->ptr !=
nullptr) {
645 }
else if (sc->lru != -32768) {
650 _sprite_lru_counter = 0;
654 if (++_compact_cache_counter >= 740) {
656 _compact_cache_counter = 0;
668 DEBUG(sprite, 3,
"Compacting sprite cache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
670 for (s = _spritecache_ptr; s->size != 0;) {
680 if (next->size == 0)
break;
683 for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
684 assert(i != _spritecache_items);
687 GetSpriteCache(i)->ptr = s->data;
690 memmove(s, next, next->size);
696 s->size += NextBlock(s)->size & ~S_FREE_MASK;
714 GetSpriteCache(item)->ptr =
nullptr;
717 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
728 uint best = UINT_MAX;
731 DEBUG(sprite, 3,
"DeleteEntryFromSpriteCache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
734 for (
SpriteID i = 0; i != _spritecache_items; i++) {
736 if (sc->
type !=
ST_RECOLOUR && sc->ptr !=
nullptr && sc->lru < cur_lru) {
744 if (best == UINT_MAX)
error(
"Out of sprite memory");
749 static void *AllocSprite(
size_t mem_req)
760 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
766 if (cur_size == mem_req ||
767 cur_size >= mem_req +
sizeof(
MemBlock)) {
772 if (cur_size != mem_req) {
773 NextBlock(s)->size = (cur_size - mem_req) |
S_FREE_MASK;
797 static const char *
const sprite_types[] = {
810 byte warning_level = sc->
warned ? 6 : 0;
812 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]);
816 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?");
821 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?");
841 assert(type !=
ST_MAPGEN || IsMapgenSpriteID(sprite));
844 if (!SpriteExists(sprite)) {
845 DEBUG(sprite, 1,
"Tried to load non-existing sprite #%d. Probable cause: Wrong/missing NewGRFs", sprite);
848 sprite = SPR_IMG_QUERY;
855 if (allocator ==
nullptr) {
859 sc->lru = ++_sprite_lru_counter;
862 if (sc->ptr ==
nullptr) sc->ptr =
ReadSprite(sc, sprite, type, AllocSprite);
867 return ReadSprite(sc, sprite, type, allocator);
872 static void GfxInitSpriteCache()
876 uint target_size = (bpp > 0 ? _sprite_cache_size * bpp / 8 : 1) * 1024 * 1024;
879 static uint last_alloc_attempt = 0;
881 if (_spritecache_ptr ==
nullptr || (_allocated_sprite_cache_size != target_size && target_size != last_alloc_attempt)) {
882 delete[]
reinterpret_cast<byte *
>(_spritecache_ptr);
884 last_alloc_attempt = target_size;
885 _allocated_sprite_cache_size = target_size;
890 _spritecache_ptr =
reinterpret_cast<MemBlock *
>(
new byte[_allocated_sprite_cache_size + _allocated_sprite_cache_size / 2]);
891 }
catch (std::bad_alloc &) {
892 _spritecache_ptr =
nullptr;
895 if (_spritecache_ptr !=
nullptr) {
897 delete[]
reinterpret_cast<byte *
>(_spritecache_ptr);
898 _spritecache_ptr =
reinterpret_cast<MemBlock *
>(
new byte[_allocated_sprite_cache_size]);
899 }
else if (_allocated_sprite_cache_size < 2 * 1024 * 1024) {
900 usererror(
"Cannot allocate spritecache");
903 _allocated_sprite_cache_size >>= 1;
905 }
while (_spritecache_ptr ==
nullptr);
907 if (_allocated_sprite_cache_size != target_size) {
908 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);
910 ErrorMessageData msg(STR_CONFIG_ERROR_OUT_OF_MEMORY, STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG);
912 msg.
SetDParam(1, _allocated_sprite_cache_size);
920 NextBlock(_spritecache_ptr)->size = 0;
923 void GfxInitSpriteMem()
925 GfxInitSpriteCache();
929 _spritecache_items = 0;
930 _spritecache =
nullptr;
932 _compact_cache_counter = 0;
942 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().