27#include "table/strings.h"
33uint _sprite_cache_size = 4;
36static std::vector<SpriteCache> _spritecache;
37static std::vector<std::unique_ptr<SpriteFile>> _sprite_files;
39static inline SpriteCache *GetSpriteCache(uint index)
41 return &_spritecache[index];
46 if (index >= _spritecache.size()) {
48 uint items =
Align(index + 1, 1024);
50 Debug(sprite, 4,
"Increasing sprite cache to {} items ({} bytes)", items, items *
sizeof(
SpriteCache));
52 _spritecache.resize(items);
55 return GetSpriteCache(index);
65 for (
auto &f : _sprite_files) {
66 if (f->GetFilename() == filename) {
92 if (file ==
nullptr) {
93 file = _sprite_files.insert(std::end(_sprite_files), std::make_unique<SpriteFile>(filename, subdir, palette_remap))->get();
105static uint _sprite_lru_counter;
107static uint _allocated_sprite_cache_size = 0;
108static int _compact_cache_counter;
126 int size = (i == 0) ? 0x80 : i;
127 if (size > num)
return false;
143 if (
id >= _spritecache.size())
return false;
146 if (
id == 0)
return true;
147 return !(GetSpriteCache(
id)->file_pos == 0 && GetSpriteCache(
id)->
file ==
nullptr);
158 return GetSpriteCache(sprite)->
type;
168 if (!SpriteExists(sprite))
return nullptr;
169 return GetSpriteCache(sprite)->
file;
179 if (!SpriteExists(sprite))
return 0;
180 return GetSpriteCache(sprite)->id;
193 if (file ==
nullptr)
return 0;
196 for (
SpriteID i = begin; i != end; i++) {
197 if (SpriteExists(i)) {
199 if (sc->
file == file) {
201 Debug(sprite, 4,
"Sprite: {}", i);
218 return static_cast<SpriteID>(_spritecache.size());
224 const auto &src_sprite = sprite[src];
225 auto &dest_sprite = sprite[tgt];
228 if (src_sprite.width * scaled_1 > UINT16_MAX || src_sprite.height * scaled_1 > UINT16_MAX)
return false;
230 dest_sprite.width = src_sprite.width * scaled_1;
231 dest_sprite.height = src_sprite.height * scaled_1;
232 dest_sprite.x_offs = src_sprite.x_offs * scaled_1;
233 dest_sprite.y_offs = src_sprite.y_offs * scaled_1;
234 dest_sprite.colours = src_sprite.colours;
236 dest_sprite.AllocateData(tgt,
static_cast<size_t>(dest_sprite.width) * dest_sprite.height);
239 for (
int y = 0; y < dest_sprite.height; y++) {
241 for (
int x = 0; x < dest_sprite.width; x++) {
242 *dst = src_ln[x / scaled_1];
252 const auto &root_sprite = sprite.Root();
253 const auto &src_sprite = sprite[zoom - 1];
254 auto &dest_sprite = sprite[zoom];
258 dest_sprite.height =
UnScaleByZoom(root_sprite.height, zoom);
259 dest_sprite.x_offs =
UnScaleByZoom(root_sprite.x_offs, zoom);
260 dest_sprite.y_offs =
UnScaleByZoom(root_sprite.y_offs, zoom);
261 dest_sprite.colours = root_sprite.colours;
263 dest_sprite.AllocateData(zoom,
static_cast<size_t>(dest_sprite.height) * dest_sprite.width);
269 for (uint y = 0; y < dest_sprite.height; y++) {
271 assert(src_ln <= src_end);
272 for (uint x = 0; x < dest_sprite.width; x++) {
273 assert(src < src_ln);
274 if (src + 1 != src_ln && (src + 1)->a != 0) {
282 src = src_ln + src_sprite.width;
288 uint width = sprite->
width + pad_left + pad_right;
289 uint height = sprite->
height + pad_top + pad_bottom;
291 if (width > UINT16_MAX || height > UINT16_MAX)
return false;
294 size_t sprite_size =
static_cast<size_t>(sprite->
width) * sprite->
height;
295 std::vector<SpriteLoader::CommonPixel> src_data(sprite->
data, sprite->
data + sprite_size);
296 sprite->
AllocateData(zoom,
static_cast<size_t>(width) * height);
301 for (uint y = 0; y < height; y++) {
302 if (y < pad_top || pad_bottom + y >= height) {
314 std::copy_n(src, sprite->
width, data);
315 src += sprite->
width;
316 data += sprite->
width;
327 sprite->
width = width;
329 sprite->
x_offs -= pad_left;
330 sprite->
y_offs -= pad_top;
338 int min_xoffs = INT32_MAX;
339 int min_yoffs = INT32_MAX;
341 if (sprite_avail.
Test(zoom)) {
342 min_xoffs = std::min(min_xoffs,
ScaleByZoom(sprite[zoom].x_offs, zoom));
343 min_yoffs = std::min(min_yoffs,
ScaleByZoom(sprite[zoom].y_offs, zoom));
348 int max_width = INT32_MIN;
349 int max_height = INT32_MIN;
351 if (sprite_avail.
Test(zoom)) {
352 max_width = std::max(max_width,
ScaleByZoom(sprite[zoom].width + sprite[zoom].x_offs -
UnScaleByZoom(min_xoffs, zoom), zoom));
353 max_height = std::max(max_height,
ScaleByZoom(sprite[zoom].height + sprite[zoom].y_offs -
UnScaleByZoom(min_yoffs, zoom), zoom));
360 max_width =
Align(max_width, align);
361 max_height =
Align(max_height, align);
366 if (sprite_avail.
Test(zoom)) {
367 auto &cur_sprite = sprite[zoom];
370 int pad_left = std::max(0, cur_sprite.x_offs -
UnScaleByZoom(min_xoffs, zoom));
371 int pad_top = std::max(0, cur_sprite.y_offs -
UnScaleByZoom(min_yoffs, zoom));
372 int pad_right = std::max(0,
UnScaleByZoom(max_width, zoom) - cur_sprite.width - pad_left);
373 int pad_bottom = std::max(0,
UnScaleByZoom(max_height, zoom) - cur_sprite.height - pad_top);
375 if (pad_left > 0 || pad_right > 0 || pad_top > 0 || pad_bottom > 0) {
376 if (!PadSingleSprite(&cur_sprite, zoom, pad_left, pad_top, pad_right, pad_bottom))
return false;
389 if (!sprite_avail.
Test(zoom))
continue;
399 if (!PadSprites(sprite, sprite_avail, encoder))
return false;
405 if (sprite_avail.
Test(zoom)) {
407 [[maybe_unused]]
const auto &root_sprite = sprite[
ZoomLevel::Min];
408 [[maybe_unused]]
const auto &dest_sprite = sprite[zoom];
409 assert(dest_sprite.width ==
UnScaleByZoom(root_sprite.width, zoom));
410 assert(dest_sprite.height ==
UnScaleByZoom(root_sprite.height, zoom));
411 assert(dest_sprite.x_offs ==
UnScaleByZoom(root_sprite.x_offs, zoom));
412 assert(dest_sprite.y_offs ==
UnScaleByZoom(root_sprite.y_offs, zoom));
415 ResizeSpriteOut(sprite, zoom);
422 ResizeSpriteIn(sprite, zoom, zoom - 1);
443 static const uint RECOLOUR_SPRITE_SIZE = 257;
444 uint8_t *dest = allocator.
Allocate<uint8_t>(std::max(RECOLOUR_SPRITE_SIZE, num));
446 file.
SeekTo(file_pos, SEEK_SET);
448 uint8_t *dest_tmp =
new uint8_t[std::max(RECOLOUR_SPRITE_SIZE, num)];
451 if (num < RECOLOUR_SPRITE_SIZE) std::fill_n(dest_tmp, RECOLOUR_SPRITE_SIZE, 0);
455 for (uint i = 1; i < RECOLOUR_SPRITE_SIZE; i++) {
456 dest[i] = _palmap_w2d[dest_tmp[
_palmap_d2w[i - 1] + 1]];
481 size_t file_pos = sc->file_pos;
485 assert(sc->
type == sprite_type);
487 Debug(sprite, 9,
"Load sprite {}",
id);
497 sprite_avail = sprite_loader.
LoadSprite(sprite, file, file_pos, sprite_type,
true, sc->
control_flags, avail_8bpp, avail_32bpp);
499 if (sprite_avail.
None()) {
500 sprite_avail = sprite_loader.
LoadSprite(sprite, file, file_pos, sprite_type,
false, sc->
control_flags, avail_8bpp, avail_32bpp);
504 sprite_avail = make_indexed.
LoadSprite(sprite, file, file_pos, sprite_type,
true, sc->
control_flags, sprite_avail, avail_32bpp);
508 if (sprite_avail.
None()) {
510 if (
id == SPR_IMG_QUERY) UserError(
"Okay... something went horribly wrong. I couldn't load the fallback sprite. What should I do?");
524 const auto &root_sprite = sprite.Root();
525 uint num = root_sprite.width * root_sprite.height;
528 s->
width = root_sprite.width;
529 s->
height = root_sprite.height;
530 s->
x_offs = root_sprite.x_offs;
531 s->
y_offs = root_sprite.y_offs;
534 uint8_t *dest =
reinterpret_cast<uint8_t *
>(s->
data);
543 if (!ResizeSprites(sprite, sprite_avail, encoder)) {
544 if (
id == SPR_IMG_QUERY) UserError(
"Okay... something went horribly wrong. I couldn't resize the fallback sprite. What should I do?");
553 return encoder->
Encode(sprite_type, sprite, allocator);
558 uint8_t control_flags;
585 size_t old_pos = file.
GetPos();
586 file.
SeekTo(data_offset, SEEK_CUR);
596 offset.file_pos = file.
GetPos() - 4;
597 offset.control_flags = 0;
621 file.
SeekTo(old_pos, SEEK_SET);
636 size_t file_pos = file.
GetPos();
640 if (num == 0)
return false;
644 void *data =
nullptr;
645 uint8_t control_flags = 0;
646 if (grf_type == 0xFF) {
665 file_pos = iter->second.file_pos;
666 control_flags = iter->second.control_flags;
681 UserError(
"Tried to load too many sprites (#{}; max {})", load_index,
MAX_SPRITES);
684 bool is_mapgen = IsMapgenSpriteID(load_index);
687 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?");
693 sc->file_pos = file_pos;
697 sc->id = file_sprite_id;
712 scnew->file_pos = scold->file_pos;
713 scnew->ptr =
nullptr;
714 scnew->id = scold->id;
729static_assert(
sizeof(
MemBlock) ==
sizeof(
size_t));
731static_assert((
sizeof(size_t) & (
sizeof(
size_t) - 1)) == 0);
738static size_t GetSpriteCacheUsage()
743 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
751void IncreaseSpriteLRU()
754 if (_sprite_lru_counter > 16384) {
755 Debug(sprite, 5,
"Fixing lru {}, inuse={}", _sprite_lru_counter, GetSpriteCacheUsage());
758 if (sc.ptr !=
nullptr) {
761 }
else if (sc.lru != -32768) {
766 _sprite_lru_counter = 0;
770 if (++_compact_cache_counter >= 740) {
772 _compact_cache_counter = 0;
784 Debug(sprite, 3,
"Compacting sprite cache, inuse={}", GetSpriteCacheUsage());
786 for (s = _spritecache_ptr; s->size != 0;) {
796 if (next->size == 0)
break;
799 for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
800 assert(i != _spritecache.size());
803 GetSpriteCache(i)->ptr = s->data;
806 std::byte *p =
reinterpret_cast<std::byte *
>(next);
807 std::move(p, &p[next->size],
reinterpret_cast<std::byte *
>(s));
813 s->size += NextBlock(s)->size & ~S_FREE_MASK;
834 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
837 s->size += NextBlock(s)->size & ~S_FREE_MASK;
845 Debug(sprite, 3,
"DeleteEntryFromSpriteCache, inuse={}", GetSpriteCacheUsage());
848 int cur_lru = 0xffff;
850 if (sc.ptr !=
nullptr && sc.lru < cur_lru) {
858 if (best ==
nullptr) FatalError(
"Out of sprite memory");
874 for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
876 size_t cur_size = s->size & ~S_FREE_MASK;
880 if (cur_size == mem_req ||
881 cur_size >= mem_req +
sizeof(
MemBlock)) {
886 if (cur_size != mem_req) {
887 NextBlock(s)->size = (cur_size - mem_req) |
S_FREE_MASK;
902 this->data = std::make_unique<std::byte[]>(size);
903 return this->data.get();
917 static const std::string_view sprite_types[] = {
930 uint8_t warning_level = sc->
warned ? 6 : 0;
932 Debug(sprite, warning_level,
"Tried to load {} sprite #{} as a {} sprite. Probable cause: NewGRF interference", sprite_types[
static_cast<uint8_t
>(available)], sprite, sprite_types[
static_cast<uint8_t
>(requested)]);
936 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?");
941 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?");
965 if (!SpriteExists(sprite)) {
966 Debug(sprite, 1,
"Tried to load non-existing sprite #{}. Probable cause: Wrong/missing NewGRFs", sprite);
969 sprite = SPR_IMG_QUERY;
976 if (allocator ==
nullptr && encoder ==
nullptr) {
981 sc->lru = ++_sprite_lru_counter;
984 if (sc->ptr ==
nullptr) {
988 sc->ptr =
ReadSprite(sc, sprite, type, cache_allocator,
nullptr);
995 return ReadSprite(sc, sprite, type, *allocator, encoder);
1000static void GfxInitSpriteCache()
1004 uint target_size = (bpp > 0 ? _sprite_cache_size * bpp / 8 : 1) * 1024 * 1024;
1007 static uint last_alloc_attempt = 0;
1009 if (_spritecache_ptr ==
nullptr || (_allocated_sprite_cache_size != target_size && target_size != last_alloc_attempt)) {
1010 delete[]
reinterpret_cast<uint8_t *
>(_spritecache_ptr);
1012 last_alloc_attempt = target_size;
1013 _allocated_sprite_cache_size = target_size;
1017 _spritecache_ptr =
reinterpret_cast<MemBlock *
>(
new(std::nothrow) uint8_t[_allocated_sprite_cache_size + _allocated_sprite_cache_size / 2]);
1019 if (_spritecache_ptr !=
nullptr) {
1021 delete[]
reinterpret_cast<uint8_t *
>(_spritecache_ptr);
1022 _spritecache_ptr =
reinterpret_cast<MemBlock *
>(
new uint8_t[_allocated_sprite_cache_size]);
1023 }
else if (_allocated_sprite_cache_size < 2 * 1024 * 1024) {
1024 UserError(
"Cannot allocate spritecache");
1027 _allocated_sprite_cache_size >>= 1;
1029 }
while (_spritecache_ptr ==
nullptr);
1031 if (_allocated_sprite_cache_size != target_size) {
1032 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);
1042 NextBlock(_spritecache_ptr)->size = 0;
1045void GfxInitSpriteMem()
1047 GfxInitSpriteCache();
1050 _spritecache.clear();
1051 _spritecache.shrink_to_fit();
1053 _compact_cache_counter = 0;
1054 _sprite_files.clear();
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr bool None() const
Test if none of the values are set.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
virtual uint8_t GetScreenDepth()=0
Get the screen depth this blitter works for.
SpriteAllocator that allocates memory from the sprite cache.
void * AllocatePtr(size_t size) override
Allocate memory for a sprite.
The data of the error message.
void ReadBlock(void *ptr, size_t size)
Read a block.
size_t GetPos() const
Get position in the file.
void SeekTo(size_t pos, int mode)
Seek in the current file.
uint8_t ReadByte()
Read a byte from the file.
uint32_t ReadDword()
Read a double word (32 bits) from the file (in low endian format).
void SkipBytes(size_t n)
Skip n bytes ahead in the file.
uint16_t ReadWord()
Read a word (16 bits) from the file (in low endian format).
Interface for something that can allocate memory for a sprite.
T * Allocate(size_t size)
Allocate memory for a sprite.
Interface for something that can encode a sprite.
virtual bool Is32BppSupported()=0
Can the sprite encoder make use of RGBA sprites?
virtual uint GetSpriteAlignment()
Get the value which the height and width on a sprite have to be aligned by.
virtual Sprite * Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)=0
Convert a sprite from the loader to our own format.
RandomAccessFile with some extra information specific for sprite files.
bool NeedsPaletteRemap() const
Whether a palette remap is needed when loading sprites from this file.
uint8_t GetContainerVersion() const
Get the version number of container type used by the file.
void SeekToBegin()
Seek to the begin of the content, i.e.
Sprite loader for graphics coming from a (New)GRF.
ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, uint8_t control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) override
Load a sprite from the disk and return a sprite struct which is the same for all loaders.
Sprite loader for converting graphics coming from another source.
ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, uint8_t control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) override
Load a sprite from the disk and return a sprite struct which is the same for all loaders.
void * AllocatePtr(size_t size) override
Allocate memory for a sprite.
virtual void ClearSystemSprites()
Clear all cached sprites.
static VideoDriver * GetInstance()
Get the currently active instance of the video driver.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Functions related to errors.
void ScheduleErrorMessage(ErrorList &datas)
Schedule a list of errors.
Error reporting related functions.
Factory to 'query' all available blitters.
Subdirectory
The different kinds of subdirectories OpenTTD uses.
ZoomLevel _font_zoom
Sprite font Zoom level (not clamped)
Functions related to the gfx engine.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
SpriteType
Types of sprites that might be loaded.
@ Recolour
Recolour sprite.
@ Font
A sprite used for fonts.
@ MapGen
Special sprite for the map generator.
@ Invalid
Pseudosprite or other unusable sprite, used only internally.
@ Normal
The most basic (normal) sprite.
Base for reading sprites from (New)GRFs.
Base for converting sprites from another source from 32bpp RGBA to indexed 8bpp.
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
Translation tables from one GRF to another GRF.
static const uint8_t _palmap_d2w[]
Converting from the DOS palette to the Windows palette.
Class related to random access to files.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Types related to global configuration settings.
static std::map< uint32_t, GrfSpriteOffset > _grf_sprite_offsets
Map from sprite numbers to position in the GRF file.
SpriteType GetSpriteType(SpriteID sprite)
Get the sprite type of a given sprite.
void GfxClearSpriteCache()
Remove all encoded sprites from the sprite cache without discarding sprite location information.
static SpriteFile * GetCachedSpriteFileByName(const std::string &filename)
Get the cached SpriteFile given the name of the file.
uint GetSpriteCountForFile(const std::string &filename, SpriteID begin, SpriteID end)
Count the sprites which originate from a specific file in a range of SpriteIDs.
static void DeleteEntryFromSpriteCache(SpriteCache *item)
Delete a single entry from the sprite cache.
static void * ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_type, SpriteAllocator &allocator, SpriteEncoder *encoder)
Read a sprite from disk.
void GfxClearFontSpriteCache()
Remove all encoded font sprites from the sprite cache without discarding sprite location information.
SpriteID GetMaxSpriteID()
Get a reasonable (upper bound) estimate of the maximum SpriteID used in OpenTTD; there will be no spr...
SpriteFile & OpenCachedSpriteFile(const std::string &filename, Subdirectory subdir, bool palette_remap)
Open/get the SpriteFile that is cached for use in the sprite cache.
static void * HandleInvalidSpriteRequest(SpriteID sprite, SpriteType requested, SpriteCache *sc, SpriteAllocator *allocator)
Handles the case when a sprite of different type is requested than is present in the SpriteCache.
void * GetRawSprite(SpriteID sprite, SpriteType type, SpriteAllocator *allocator, SpriteEncoder *encoder)
Reads a sprite (from disk or sprite cache).
std::span< const std::unique_ptr< SpriteFile > > GetCachedSpriteFiles()
Get the list of cached SpriteFiles.
bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id)
Load a real or recolour sprite.
SpriteFile * GetOriginFile(SpriteID sprite)
Get the SpriteFile of a given sprite.
size_t GetGRFSpriteOffset(uint32_t id)
Get the file offset for a specific sprite in the sprite section of a GRF.
static void * ReadRecolourSprite(SpriteFile &file, size_t file_pos, uint num, SpriteAllocator &allocator)
Load a recolour sprite into memory.
bool SkipSpriteData(SpriteFile &file, uint8_t type, uint16_t num)
Skip the given amount of sprite graphics data.
uint32_t GetSpriteLocalID(SpriteID sprite)
Get the GRF-local sprite id of a given sprite.
static void CompactSpriteCache()
Called when holes in the sprite cache should be removed.
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,...
void ReadGRFSpriteOffsets(SpriteFile &file)
Parse the sprite section of GRFs.
Functions to cache sprites in memory.
@ SCCF_ALLOW_ZOOM_MIN_2X_32BPP
Allow use of sprite min zoom setting at 2x in 32bpp mode.
@ SCCF_ALLOW_ZOOM_MIN_1X_32BPP
Allow use of sprite min zoom setting at 1x in 32bpp mode.
@ SCCF_ALLOW_ZOOM_MIN_1X_PAL
Allow use of sprite min zoom setting at 1x in palette mode.
@ SCCF_ALLOW_ZOOM_MIN_2X_PAL
Allow use of sprite min zoom setting at 2x in palette mode.
Internal functions to cache sprites in memory.
@ Palette
Sprite has palette data.
This file contains all sprite-related enums and defines.
static constexpr uint32_t MAX_SPRITES
Masks needed for sprite operations.
Definition of base types and functions in a cross-platform compatible way.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Functions related to OTTD's strings.
GUISettings gui
settings related to the GUI
ZoomLevel sprite_zoom_min
maximum zoom level at which higher-resolution alternative sprites will be used (if available) instead...
uint8_t control_flags
Control flags, see SpriteCacheCtrlFlags.
uint32_t length
Length of sprite data.
bool warned
True iff the user has been warned about incorrect use of this sprite.
SpriteType type
In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour spr...
SpriteFile * file
The file the sprite in this entry can be found in.
Definition of a common pixel in OpenTTD's realm.
Structure for passing information from the sprite loader to the blitter.
static SpriteCollMap< ReusableBuffer< SpriteLoader::CommonPixel > > buffer
Allocated memory to pass sprite data around.
void AllocateData(ZoomLevel zoom, size_t size)
Allocate the sprite data of this sprite.
uint16_t width
Width of the sprite.
int16_t x_offs
The x-offset of where the sprite will be drawn.
SpriteLoader::CommonPixel * data
The sprite itself.
uint16_t height
Height of the sprite.
int16_t y_offs
The y-offset of where the sprite will be drawn.
Data structure describing a sprite.
uint16_t width
Width of the sprite.
uint16_t height
Height of the sprite.
int16_t y_offs
Number of pixels to shift the sprite downwards.
std::byte data[]
Sprite data.
int16_t x_offs
Number of pixels to shift the sprite to the right.
Base of all video drivers.
Functions related to zooming.
int ScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift left (when zoom > ZoomLevel::Min) When shifting right,...
int AdjustByZoom(int value, int zoom)
Adjust by zoom level; zoom < 0 shifts right, zoom >= 0 shifts left.
int UnScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZoomLevel::Min) When shifting right,...
ZoomLevel
All zoom levels we know.
@ Begin
Begin for iteration.
@ Normal
The normal zoom level.