mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-10-31 15:20:10 +00:00
Only discard sprite zoom levels when a suitable higher zoom level is defined in the same colour mode This is to avoid placeholder or empty sprites being used, causing visual artefacts
This commit is contained in:
parent
20f7ff8ac0
commit
5e413c9dcd
@ -36,6 +36,7 @@ struct SpriteCache {
|
|||||||
int16 lru;
|
int16 lru;
|
||||||
SpriteType type; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour sprite. If the recolour sprite gets into the cache it might be drawn as real sprite which causes enormous trouble.
|
SpriteType type; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour sprite. If the recolour sprite gets into the cache it might be drawn as real sprite which causes enormous trouble.
|
||||||
bool warned; ///< True iff the user has been warned about incorrect use of this sprite
|
bool warned; ///< True iff the user has been warned about incorrect use of this sprite
|
||||||
|
byte control_flags; ///< Control flags, see SpriteCacheCtrlFlags
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -471,10 +472,10 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty
|
|||||||
SpriteLoaderGrf sprite_loader(file.GetContainerVersion());
|
SpriteLoaderGrf sprite_loader(file.GetContainerVersion());
|
||||||
if (sprite_type != ST_MAPGEN && encoder->Is32BppSupported()) {
|
if (sprite_type != ST_MAPGEN && encoder->Is32BppSupported()) {
|
||||||
/* Try for 32bpp sprites first. */
|
/* Try for 32bpp sprites first. */
|
||||||
sprite_avail = sprite_loader.LoadSprite(sprite, file, file_pos, sprite_type, true);
|
sprite_avail = sprite_loader.LoadSprite(sprite, file, file_pos, sprite_type, true, sc->control_flags);
|
||||||
}
|
}
|
||||||
if (sprite_avail == 0) {
|
if (sprite_avail == 0) {
|
||||||
sprite_avail = sprite_loader.LoadSprite(sprite, file, file_pos, sprite_type, false);
|
sprite_avail = sprite_loader.LoadSprite(sprite, file, file_pos, sprite_type, false, sc->control_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sprite_avail == 0) {
|
if (sprite_avail == 0) {
|
||||||
@ -529,9 +530,13 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty
|
|||||||
return encoder->Encode(sprite, allocator);
|
return encoder->Encode(sprite, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct GrfSpriteOffset {
|
||||||
|
size_t file_pos;
|
||||||
|
byte control_flags;
|
||||||
|
};
|
||||||
|
|
||||||
/** Map from sprite numbers to position in the GRF file. */
|
/** Map from sprite numbers to position in the GRF file. */
|
||||||
static std::map<uint32, size_t> _grf_sprite_offsets;
|
static std::map<uint32, GrfSpriteOffset> _grf_sprite_offsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the file offset for a specific sprite in the sprite section of a GRF.
|
* Get the file offset for a specific sprite in the sprite section of a GRF.
|
||||||
@ -540,7 +545,7 @@ static std::map<uint32, size_t> _grf_sprite_offsets;
|
|||||||
*/
|
*/
|
||||||
size_t GetGRFSpriteOffset(uint32 id)
|
size_t GetGRFSpriteOffset(uint32 id)
|
||||||
{
|
{
|
||||||
return _grf_sprite_offsets.find(id) != _grf_sprite_offsets.end() ? _grf_sprite_offsets[id] : SIZE_MAX;
|
return _grf_sprite_offsets.find(id) != _grf_sprite_offsets.end() ? _grf_sprite_offsets[id].file_pos : SIZE_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -557,13 +562,35 @@ void ReadGRFSpriteOffsets(SpriteFile &file)
|
|||||||
size_t old_pos = file.GetPos();
|
size_t old_pos = file.GetPos();
|
||||||
file.SeekTo(data_offset, SEEK_CUR);
|
file.SeekTo(data_offset, SEEK_CUR);
|
||||||
|
|
||||||
|
GrfSpriteOffset offset = { 0, 0 };
|
||||||
|
|
||||||
/* Loop over all sprite section entries and store the file
|
/* Loop over all sprite section entries and store the file
|
||||||
* offset for each newly encountered ID. */
|
* offset for each newly encountered ID. */
|
||||||
uint32 id, prev_id = 0;
|
uint32 id, prev_id = 0;
|
||||||
while ((id = file.ReadDword()) != 0) {
|
while ((id = file.ReadDword()) != 0) {
|
||||||
if (id != prev_id) _grf_sprite_offsets[id] = file.GetPos() - 4;
|
if (id != prev_id) {
|
||||||
|
_grf_sprite_offsets[prev_id] = offset;
|
||||||
|
offset.file_pos = file.GetPos() - 4;
|
||||||
|
offset.control_flags = 0;
|
||||||
|
}
|
||||||
prev_id = id;
|
prev_id = id;
|
||||||
file.SkipBytes(file.ReadDword());
|
uint length = file.ReadDword();
|
||||||
|
if (length > 0) {
|
||||||
|
byte colour = file.ReadByte() & SCC_MASK;
|
||||||
|
length--;
|
||||||
|
if (length > 0) {
|
||||||
|
byte zoom = file.ReadByte();
|
||||||
|
length--;
|
||||||
|
if (colour != 0 && zoom == 0) { // ZOOM_LVL_OUT_4X (normal zoom)
|
||||||
|
SetBit(offset.control_flags, (colour != SCC_PAL) ? SCCF_ALLOW_ZOOM_MIN_1X_32BPP : SCCF_ALLOW_ZOOM_MIN_1X_PAL);
|
||||||
|
SetBit(offset.control_flags, (colour != SCC_PAL) ? SCCF_ALLOW_ZOOM_MIN_2X_32BPP : SCCF_ALLOW_ZOOM_MIN_2X_PAL);
|
||||||
|
}
|
||||||
|
if (colour != 0 && zoom == 2) { // ZOOM_LVL_OUT_2X (2x zoomed in)
|
||||||
|
SetBit(offset.control_flags, (colour != SCC_PAL) ? SCCF_ALLOW_ZOOM_MIN_2X_32BPP : SCCF_ALLOW_ZOOM_MIN_2X_PAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.SkipBytes(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Continue processing the data section. */
|
/* Continue processing the data section. */
|
||||||
@ -591,6 +618,7 @@ bool LoadNextSprite(int load_index, SpriteFile &file, uint file_sprite_id)
|
|||||||
|
|
||||||
SpriteType type;
|
SpriteType type;
|
||||||
void *data = nullptr;
|
void *data = nullptr;
|
||||||
|
byte control_flags = 0;
|
||||||
if (grf_type == 0xFF) {
|
if (grf_type == 0xFF) {
|
||||||
/* Some NewGRF files have "empty" pseudo-sprites which are 1
|
/* Some NewGRF files have "empty" pseudo-sprites which are 1
|
||||||
* byte long. Catch these so the sprites won't be displayed. */
|
* byte long. Catch these so the sprites won't be displayed. */
|
||||||
@ -607,7 +635,13 @@ bool LoadNextSprite(int load_index, SpriteFile &file, uint file_sprite_id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* It is not an error if no sprite with the provided ID is found in the sprite section. */
|
/* It is not an error if no sprite with the provided ID is found in the sprite section. */
|
||||||
file_pos = GetGRFSpriteOffset(file.ReadDword());
|
auto iter = _grf_sprite_offsets.find(file.ReadDword());
|
||||||
|
if (iter != _grf_sprite_offsets.end()) {
|
||||||
|
file_pos = iter->second.file_pos;
|
||||||
|
control_flags = iter->second.control_flags;
|
||||||
|
} else {
|
||||||
|
file_pos = SIZE_MAX;
|
||||||
|
}
|
||||||
type = ST_NORMAL;
|
type = ST_NORMAL;
|
||||||
} else {
|
} else {
|
||||||
file.SkipBytes(7);
|
file.SkipBytes(7);
|
||||||
@ -637,6 +671,7 @@ bool LoadNextSprite(int load_index, SpriteFile &file, uint file_sprite_id)
|
|||||||
sc->id = file_sprite_id;
|
sc->id = file_sprite_id;
|
||||||
sc->type = type;
|
sc->type = type;
|
||||||
sc->warned = false;
|
sc->warned = false;
|
||||||
|
sc->control_flags = control_flags;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,13 @@ struct Sprite {
|
|||||||
byte data[]; ///< Sprite data.
|
byte data[]; ///< Sprite data.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SpriteCacheCtrlFlags {
|
||||||
|
SCCF_ALLOW_ZOOM_MIN_1X_PAL = 0, ///< Allow use of sprite min zoom setting at 1x in palette mode.
|
||||||
|
SCCF_ALLOW_ZOOM_MIN_1X_32BPP = 1, ///< Allow use of sprite min zoom setting at 1x in 32bpp mode.
|
||||||
|
SCCF_ALLOW_ZOOM_MIN_2X_PAL = 2, ///< Allow use of sprite min zoom setting at 2x in palette mode.
|
||||||
|
SCCF_ALLOW_ZOOM_MIN_2X_32BPP = 3, ///< Allow use of sprite min zoom setting at 2x in 32bpp mode.
|
||||||
|
};
|
||||||
|
|
||||||
extern uint _sprite_cache_size;
|
extern uint _sprite_cache_size;
|
||||||
|
|
||||||
typedef void *AllocatorProc(size_t size);
|
typedef void *AllocatorProc(size_t size);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "../core/math_func.hpp"
|
#include "../core/math_func.hpp"
|
||||||
#include "../core/alloc_type.hpp"
|
#include "../core/alloc_type.hpp"
|
||||||
#include "../core/bitmath_func.hpp"
|
#include "../core/bitmath_func.hpp"
|
||||||
|
#include "../spritecache.h"
|
||||||
#include "grf.hpp"
|
#include "grf.hpp"
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
@ -241,7 +242,7 @@ uint8 LoadSpriteV1(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_p
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 LoadSpriteV2(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp)
|
uint8 LoadSpriteV2(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, byte control_flags)
|
||||||
{
|
{
|
||||||
static const ZoomLevel zoom_lvl_map[6] = {ZOOM_LVL_OUT_4X, ZOOM_LVL_NORMAL, ZOOM_LVL_OUT_2X, ZOOM_LVL_OUT_8X, ZOOM_LVL_OUT_16X, ZOOM_LVL_OUT_32X};
|
static const ZoomLevel zoom_lvl_map[6] = {ZOOM_LVL_OUT_4X, ZOOM_LVL_NORMAL, ZOOM_LVL_OUT_2X, ZOOM_LVL_OUT_8X, ZOOM_LVL_OUT_16X, ZOOM_LVL_OUT_32X};
|
||||||
|
|
||||||
@ -269,7 +270,19 @@ uint8 LoadSpriteV2(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_p
|
|||||||
bool is_wanted_zoom_lvl;
|
bool is_wanted_zoom_lvl;
|
||||||
|
|
||||||
if (sprite_type != ST_MAPGEN) {
|
if (sprite_type != ST_MAPGEN) {
|
||||||
is_wanted_zoom_lvl = (zoom < lengthof(zoom_lvl_map) && zoom_lvl_map[zoom] >= _settings_client.gui.sprite_zoom_min);
|
if (zoom < lengthof(zoom_lvl_map)) {
|
||||||
|
is_wanted_zoom_lvl = true;
|
||||||
|
if (_settings_client.gui.sprite_zoom_min >= ZOOM_LVL_OUT_2X &&
|
||||||
|
HasBit(control_flags, load_32bpp ? SCCF_ALLOW_ZOOM_MIN_2X_32BPP : SCCF_ALLOW_ZOOM_MIN_2X_PAL) && zoom_lvl_map[zoom] < ZOOM_LVL_OUT_2X) {
|
||||||
|
is_wanted_zoom_lvl = false;
|
||||||
|
}
|
||||||
|
if (_settings_client.gui.sprite_zoom_min >= ZOOM_LVL_OUT_4X &&
|
||||||
|
HasBit(control_flags, load_32bpp ? SCCF_ALLOW_ZOOM_MIN_1X_32BPP : SCCF_ALLOW_ZOOM_MIN_1X_PAL) && zoom_lvl_map[zoom] < ZOOM_LVL_OUT_4X) {
|
||||||
|
is_wanted_zoom_lvl = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
is_wanted_zoom_lvl = false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
is_wanted_zoom_lvl = (zoom == 0);
|
is_wanted_zoom_lvl = (zoom == 0);
|
||||||
}
|
}
|
||||||
@ -326,10 +339,10 @@ uint8 LoadSpriteV2(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_p
|
|||||||
return loaded_sprites;
|
return loaded_sprites;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp)
|
uint8 SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, byte control_flags)
|
||||||
{
|
{
|
||||||
if (this->container_ver >= 2) {
|
if (this->container_ver >= 2) {
|
||||||
return LoadSpriteV2(sprite, file, file_pos, sprite_type, load_32bpp);
|
return LoadSpriteV2(sprite, file, file_pos, sprite_type, load_32bpp, control_flags);
|
||||||
} else {
|
} else {
|
||||||
return LoadSpriteV1(sprite, file, file_pos, sprite_type, load_32bpp);
|
return LoadSpriteV1(sprite, file, file_pos, sprite_type, load_32bpp);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class SpriteLoaderGrf : public SpriteLoader {
|
|||||||
byte container_ver;
|
byte container_ver;
|
||||||
public:
|
public:
|
||||||
SpriteLoaderGrf(byte container_ver) : container_ver(container_ver) {}
|
SpriteLoaderGrf(byte container_ver) : container_ver(container_ver) {}
|
||||||
uint8 LoadSprite(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp);
|
uint8 LoadSprite(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, byte control_flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SPRITELOADER_GRF_HPP */
|
#endif /* SPRITELOADER_GRF_HPP */
|
||||||
|
@ -72,9 +72,10 @@ public:
|
|||||||
* @param file_pos The position within the file the image begins.
|
* @param file_pos The position within the file the image begins.
|
||||||
* @param sprite_type The type of sprite we're trying to load.
|
* @param sprite_type The type of sprite we're trying to load.
|
||||||
* @param load_32bpp True if 32bpp sprites should be loaded, false for a 8bpp sprite.
|
* @param load_32bpp True if 32bpp sprites should be loaded, false for a 8bpp sprite.
|
||||||
|
* @param control_flags Control flags, see SpriteCacheCtrlFlags.
|
||||||
* @return Bit mask of the zoom levels successfully loaded or 0 if no sprite could be loaded.
|
* @return Bit mask of the zoom levels successfully loaded or 0 if no sprite could be loaded.
|
||||||
*/
|
*/
|
||||||
virtual uint8 LoadSprite(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp) = 0;
|
virtual uint8 LoadSprite(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, byte control_flags) = 0;
|
||||||
|
|
||||||
virtual ~SpriteLoader() { }
|
virtual ~SpriteLoader() { }
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user