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++) {
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?");
499 if (container_version >= 2) {
507 uint32 id, prev_id = 0;
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);
623 static size_t GetSpriteCacheUsage()
628 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
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;) {
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);
700 s->size += NextBlock(s)->size & ~S_FREE_MASK;
718 GetSpriteCache(item)->ptr = NULL;
721 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
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)
764 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
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);
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++) {
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.
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 bool IsInsideMM(const T x, const uint min, const uint max)
Checks if a value is in an interval.
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.
The most basic (normal) sprite.
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.
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.
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).
SpriteType
Types of sprites that might be loaded.
Functions related to the gfx engine.
Special sprite for the map generator.
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.
Pseudosprite or other unusable sprite, used only internally.
bool SkipSpriteData(byte type, uint16 num)
Skip the given amount of sprite graphics data.
uint16 height
Height of the 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.
SpriteTypeByte type
In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour spr...
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.
ZoomLevel
All zoom levels we know.
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.
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().