mirror of https://github.com/OpenTTD/OpenTTD
Compare commits
16 Commits
497d18d987
...
9429a1d7e8
Author | SHA1 | Date |
---|---|---|
|
9429a1d7e8 | |
|
1199ddb417 | |
|
bb536d37e6 | |
|
a8650c6b06 | |
|
7bb4940ebd | |
|
b8e56cd05d | |
|
df5237e721 | |
|
03f5f7145f | |
|
0dc40877fd | |
|
03672ed8eb | |
|
1b01a0636c | |
|
bccbd64037 | |
|
434163aa31 | |
|
55605ae8f2 | |
|
7f792e9c5f | |
|
6b6caa6fa8 |
|
@ -36,3 +36,11 @@ AITown.FoundTown <- function(tile, size, city, layout, name) { return AITown.Fou
|
|||
|
||||
AIVehicle.SetNameCompat14 <- AIVehicle.SetName;
|
||||
AIVehicle.SetName <- function(id, name) { return AIVehicle.SetNameCompat14(id, AICompat14.Text(name)); }
|
||||
|
||||
AIObject.constructorCompat14 <- AIObject.constructor;
|
||||
foreach(name, object in CompatScriptRootTable) {
|
||||
if (type(object) != "class") continue;
|
||||
if (!object.rawin("constructor")) continue;
|
||||
if (object.constructor != AIObject.constructorCompat14) continue;
|
||||
object.constructor <- function() : (name) { AILog.Error("'" + name + "' is not instantiable"); }
|
||||
}
|
||||
|
|
|
@ -81,3 +81,11 @@ GSTown.FoundTown <- function(tile, size, city, layout, name) { return GSTown.Fou
|
|||
|
||||
GSVehicle.SetNameCompat14 <- GSVehicle.SetName;
|
||||
GSVehicle.SetName <- function(id, name) { return GSVehicle.SetNameCompat14(id, GSCompat14.Text(name)); }
|
||||
|
||||
GSObject.constructorCompat14 <- GSObject.constructor;
|
||||
foreach(name, object in CompatScriptRootTable) {
|
||||
if (type(object) != "class") continue;
|
||||
if (!object.rawin("constructor")) continue;
|
||||
if (object.constructor != GSObject.constructorCompat14) continue;
|
||||
object.constructor <- function() : (name) { GSLog.Error("'" + name + "' is not instantiable"); }
|
||||
}
|
||||
|
|
|
@ -187,7 +187,6 @@ add_files(
|
|||
fios_gui.cpp
|
||||
fontcache.cpp
|
||||
fontcache.h
|
||||
fontdetection.h
|
||||
framerate_gui.cpp
|
||||
framerate_type.h
|
||||
gamelog.cpp
|
||||
|
@ -454,6 +453,7 @@ add_files(
|
|||
spritecache.cpp
|
||||
spritecache.h
|
||||
spritecache_internal.h
|
||||
spritecache_type.h
|
||||
station.cpp
|
||||
station_base.h
|
||||
station_cmd.cpp
|
||||
|
|
|
@ -83,7 +83,7 @@ void AIInstance::Died()
|
|||
|
||||
void AIInstance::LoadDummyScript()
|
||||
{
|
||||
ScriptAllocatorScope alloc_scope(this->engine);
|
||||
ScriptAllocatorScope alloc_scope(this->engine.get());
|
||||
Script_CreateDummy(this->engine->GetVM(), STR_ERROR_AI_NO_AI_FOUND, "AI");
|
||||
}
|
||||
|
||||
|
|
|
@ -1125,6 +1125,15 @@ static bool AircraftController(Aircraft *v)
|
|||
}
|
||||
|
||||
if (amd.flags.Test(AirportMovingDataFlag::Land)) {
|
||||
if (st->airport.blocks.Test(AirportBlock::Zeppeliner)) {
|
||||
/* Zeppeliner blocked the runway, abort landing */
|
||||
v->state = FLYING;
|
||||
UpdateAircraftCache(v);
|
||||
SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlightLevel(v));
|
||||
v->pos = v->previous_pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (st->airport.tile == INVALID_TILE) {
|
||||
/* Airport has been removed, abort the landing procedure */
|
||||
v->state = FLYING;
|
||||
|
@ -1782,6 +1791,11 @@ static void AirportClearBlock(const Aircraft *v, const AirportFTAClass *apc)
|
|||
if (apc->layout[v->previous_pos].blocks != apc->layout[v->pos].blocks) {
|
||||
Station *st = Station::Get(v->targetairport);
|
||||
|
||||
if (st->airport.blocks.Test(AirportBlock::Zeppeliner) &&
|
||||
apc->layout[v->previous_pos].blocks == AirportBlock::RunwayIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
st->airport.blocks.Reset(apc->layout[v->previous_pos].blocks);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ enum class AirportBlock : uint8_t {
|
|||
/* end of new blocks */
|
||||
|
||||
Nothing = 30,
|
||||
Zeppeliner = 62, ///< Block for the zeppeliner disaster vehicle.
|
||||
AirportClosed = 63, ///< Dummy block for indicating a closed airport.
|
||||
};
|
||||
using AirportBlocks = EnumBitSet<AirportBlock, uint64_t>;
|
||||
|
|
|
@ -141,6 +141,8 @@ void SetLocalCompany(CompanyID new_company)
|
|||
MarkWholeScreenDirty();
|
||||
InvalidateWindowClassesData(WC_SIGN_LIST, -1);
|
||||
InvalidateWindowClassesData(WC_GOALS_LIST);
|
||||
InvalidateWindowClassesData(WC_COMPANY_COLOUR, -1);
|
||||
ResetVehicleColourMap();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2369,7 +2369,7 @@ static bool ConFont(std::span<std::string_view> argv)
|
|||
FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
|
||||
/* Make sure all non sprite fonts are loaded. */
|
||||
if (!setting->font.empty() && !fc->HasParent()) {
|
||||
InitFontCache(fs == FS_MONO);
|
||||
FontCache::LoadFontCaches(fs);
|
||||
fc = FontCache::Get(fs);
|
||||
}
|
||||
IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs));
|
||||
|
|
|
@ -215,7 +215,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z)
|
|||
|
||||
/**
|
||||
* Zeppeliner handling, v->state states:
|
||||
* 0: Zeppeliner initialization has found a small airport, go there and crash
|
||||
* 0: Zeppeliner initialization has found an airport, go there and crash
|
||||
* 1: Create crash and animate falling down for extra dramatic effect
|
||||
* 2: Create more smoke and leave debris on ground
|
||||
* 2: Clear the runway after some time and remove crashed zeppeliner
|
||||
|
@ -263,7 +263,7 @@ static bool DisasterTick_Zeppeliner(DisasterVehicle *v)
|
|||
|
||||
if (IsValidTile(v->tile) && IsAirportTile(v->tile)) {
|
||||
Station *st = Station::GetByTile(v->tile);
|
||||
st->airport.blocks.Reset(AirportBlock::RunwayIn);
|
||||
st->airport.blocks.Reset({AirportBlock::Zeppeliner, AirportBlock::RunwayIn});
|
||||
AI::NewEvent(GetTileOwner(v->tile), new ScriptEventDisasterZeppelinerCleared(st->index));
|
||||
}
|
||||
|
||||
|
@ -300,7 +300,7 @@ static bool DisasterTick_Zeppeliner(DisasterVehicle *v)
|
|||
}
|
||||
|
||||
if (IsValidTile(v->tile) && IsAirportTile(v->tile)) {
|
||||
Station::GetByTile(v->tile)->airport.blocks.Set(AirportBlock::RunwayIn);
|
||||
Station::GetByTile(v->tile)->airport.blocks.Reset({AirportBlock::Zeppeliner, AirportBlock::RunwayIn});
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -722,14 +722,14 @@ typedef void DisasterInitProc();
|
|||
|
||||
|
||||
/**
|
||||
* Zeppeliner which crashes on a small airport if one found,
|
||||
* Zeppeliner which crashes on an airport if one found,
|
||||
* otherwise crashes on a random tile
|
||||
*/
|
||||
static void Disaster_Zeppeliner_Init()
|
||||
{
|
||||
if (!Vehicle::CanAllocateItem(2)) return;
|
||||
|
||||
/* Pick a random place, unless we find a small airport */
|
||||
/* Pick a random place, unless we find an airport */
|
||||
int x = TileX(RandomTile()) * TILE_SIZE + TILE_SIZE / 2;
|
||||
|
||||
for (const Station *st : Station::Iterate()) {
|
||||
|
|
|
@ -84,7 +84,7 @@ struct EnginePreviewWindow : Window {
|
|||
|
||||
/* Get size of engine sprite, on loan from depot_gui.cpp */
|
||||
EngineID engine = static_cast<EngineID>(this->window_number);
|
||||
EngineImageType image_type = EIT_PURCHASE;
|
||||
EngineImageType image_type = EIT_PREVIEW;
|
||||
uint x, y;
|
||||
int x_offs, y_offs;
|
||||
|
||||
|
|
|
@ -9,10 +9,8 @@
|
|||
|
||||
#include "stdafx.h"
|
||||
#include "fontcache.h"
|
||||
#include "fontdetection.h"
|
||||
#include "blitter/factory.hpp"
|
||||
#include "gfx_layout.h"
|
||||
#include "fontcache/spritefontcache.h"
|
||||
#include "openttd.h"
|
||||
#include "settings_func.h"
|
||||
#include "strings_func.h"
|
||||
|
@ -30,22 +28,38 @@
|
|||
FontCacheSettings _fcsettings;
|
||||
|
||||
/**
|
||||
* Create a new font cache.
|
||||
* @param fs The size of the font.
|
||||
* Try loading a font with any fontcache factory.
|
||||
* @param fs Font size to load.
|
||||
* @param fonttype Font type requested.
|
||||
* @return FontCache of the font if loaded, or nullptr.
|
||||
*/
|
||||
FontCache::FontCache(FontSize fs) : parent(FontCache::Get(fs)), fs(fs)
|
||||
/* static */ std::unique_ptr<FontCache> FontProviderManager::LoadFont(FontSize fs, FontType fonttype)
|
||||
{
|
||||
assert(this->parent == nullptr || this->fs == this->parent->fs);
|
||||
FontCache::caches[this->fs] = this;
|
||||
Layouter::ResetFontCache(this->fs);
|
||||
for (auto &provider : FontProviderManager::GetProviders()) {
|
||||
auto fc = provider->LoadFont(fs, fonttype);
|
||||
if (fc != nullptr) return fc;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** Clean everything up. */
|
||||
FontCache::~FontCache()
|
||||
/**
|
||||
* We would like to have a fallback font as the current one
|
||||
* doesn't contain all characters we need.
|
||||
* This function must set all fonts of settings.
|
||||
* @param settings the settings to overwrite the fontname of.
|
||||
* @param language_isocode the language, e.g. en_GB.
|
||||
* @param callback The function to call to check for missing glyphs.
|
||||
* @return true if a font has been set, false otherwise.
|
||||
*/
|
||||
/* static */ bool FontProviderManager::FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
||||
{
|
||||
assert(this->parent == nullptr || this->fs == this->parent->fs);
|
||||
FontCache::caches[this->fs] = this->parent;
|
||||
Layouter::ResetFontCache(this->fs);
|
||||
for (auto &provider : FontProviderManager::GetProviders()) {
|
||||
if (provider->FindFallbackFont(settings, language_isocode, callback)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int FontCache::GetDefaultFontHeight(FontSize fs)
|
||||
|
@ -80,12 +94,16 @@ int GetCharacterHeight(FontSize size)
|
|||
}
|
||||
|
||||
|
||||
/* static */ FontCache *FontCache::caches[FS_END];
|
||||
/* static */ std::array<std::unique_ptr<FontCache>, FS_END> FontCache::caches{};
|
||||
|
||||
/**
|
||||
* Initialise font caches with the base sprite font cache for all sizes.
|
||||
*/
|
||||
/* static */ void FontCache::InitializeFontCaches()
|
||||
{
|
||||
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
|
||||
if (FontCache::caches[fs] == nullptr) new SpriteFontCache(fs); /* FontCache inserts itself into to the cache. */
|
||||
if (FontCache::Get(fs) != nullptr) continue;
|
||||
FontCache::Register(FontProviderManager::LoadFont(fs, FontType::Sprite));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,25 +144,16 @@ void SetFont(FontSize fontsize, const std::string &font, uint size)
|
|||
CheckForMissingGlyphs();
|
||||
_fcsettings = std::move(backup);
|
||||
} else {
|
||||
InitFontCache(true);
|
||||
FontCache::LoadFontCaches(fontsize);
|
||||
}
|
||||
|
||||
LoadStringWidthTable(fontsize == FS_MONO);
|
||||
LoadStringWidthTable(fontsize);
|
||||
UpdateAllVirtCoords();
|
||||
ReInitAllWindows(true);
|
||||
|
||||
if (_save_config) SaveToConfig();
|
||||
}
|
||||
|
||||
#ifdef WITH_FREETYPE
|
||||
extern void LoadFreeTypeFont(FontSize fs);
|
||||
extern void UninitFreeType();
|
||||
#elif defined(_WIN32)
|
||||
extern void LoadWin32Font(FontSize fs);
|
||||
#elif defined(WITH_COCOA)
|
||||
extern void LoadCoreTextFont(FontSize fs);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Test if a font setting uses the default font.
|
||||
* @return true iff the font is not configured and no fallback font data is present.
|
||||
|
@ -212,44 +221,54 @@ std::string GetFontCacheFontName(FontSize fs)
|
|||
}
|
||||
|
||||
/**
|
||||
* (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
|
||||
* @param monospace Whether to initialise the monospace or regular fonts.
|
||||
* Register a FontCache for its font size.
|
||||
* @param fc FontCache to register.
|
||||
*/
|
||||
void InitFontCache(bool monospace)
|
||||
/* static */ void FontCache::Register(std::unique_ptr<FontCache> &&fc)
|
||||
{
|
||||
if (fc == nullptr) return;
|
||||
|
||||
FontSize fs = fc->fs;
|
||||
|
||||
fc->parent = std::move(FontCache::caches[fs]);
|
||||
FontCache::caches[fs] = std::move(fc);
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
|
||||
* @param fontsizes Font sizes to be initialised.
|
||||
*/
|
||||
/* static */ void FontCache::LoadFontCaches(FontSizes fontsizes)
|
||||
{
|
||||
FontCache::InitializeFontCaches();
|
||||
|
||||
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
|
||||
if (monospace != (fs == FS_MONO)) continue;
|
||||
for (FontSize fs : fontsizes) {
|
||||
Layouter::ResetFontCache(fs);
|
||||
|
||||
FontCache *fc = FontCache::Get(fs);
|
||||
if (fc->HasParent()) delete fc;
|
||||
/* Unload everything except the sprite font cache. */
|
||||
while (FontCache::Get(fs)->HasParent()) {
|
||||
FontCache::caches[fs] = std::move(FontCache::caches[fs]->parent);
|
||||
}
|
||||
|
||||
#ifdef WITH_FREETYPE
|
||||
LoadFreeTypeFont(fs);
|
||||
#elif defined(_WIN32)
|
||||
LoadWin32Font(fs);
|
||||
#elif defined(WITH_COCOA)
|
||||
LoadCoreTextFont(fs);
|
||||
#endif
|
||||
FontCache::Register(FontProviderManager::LoadFont(fs, FontType::TrueType));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cached information for the specified font caches.
|
||||
* @param fontsizes Font sizes to clear.
|
||||
*/
|
||||
/* static */ void FontCache::ClearFontCaches(FontSizes fontsizes)
|
||||
{
|
||||
for (FontSize fs : fontsizes) {
|
||||
FontCache::Get(fs)->ClearFontCache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free everything allocated w.r.t. fonts.
|
||||
*/
|
||||
void UninitFontCache()
|
||||
/* static */ void FontCache::UninitializeFontCaches()
|
||||
{
|
||||
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
|
||||
while (FontCache::Get(fs) != nullptr) delete FontCache::Get(fs);
|
||||
}
|
||||
|
||||
#ifdef WITH_FREETYPE
|
||||
UninitFreeType();
|
||||
#endif /* WITH_FREETYPE */
|
||||
std::ranges::generate(FontCache::caches, []() { return nullptr; });
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)
|
||||
|
||||
bool SetFallbackFont(FontCacheSettings *, const std::string &, MissingGlyphSearcher *) { return false; }
|
||||
#endif /* !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) */
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef FONTCACHE_H
|
||||
#define FONTCACHE_H
|
||||
|
||||
#include "provider_manager.h"
|
||||
#include "string_type.h"
|
||||
#include "spritecache.h"
|
||||
|
||||
|
@ -20,18 +21,23 @@ static const GlyphID SPRITE_GLYPH = 1U << 30;
|
|||
/** Font cache for basic fonts. */
|
||||
class FontCache {
|
||||
protected:
|
||||
static FontCache *caches[FS_END]; ///< All the font caches.
|
||||
FontCache *parent; ///< The parent of this font cache.
|
||||
const FontSize fs; ///< The size of the font.
|
||||
static std::array<std::unique_ptr<FontCache>, FS_END> caches; ///< All the font caches.
|
||||
std::unique_ptr<FontCache>parent; ///< The parent of this font cache.
|
||||
const FontSize fs; ///< The size of the font.
|
||||
int height = 0; ///< The height of the font.
|
||||
int ascender = 0; ///< The ascender value of the font.
|
||||
int descender = 0; ///< The descender value of the font.
|
||||
|
||||
FontCache(FontSize fs) : fs(fs) {}
|
||||
static void Register(std::unique_ptr<FontCache> &&fc);
|
||||
|
||||
public:
|
||||
FontCache(FontSize fs);
|
||||
virtual ~FontCache();
|
||||
virtual ~FontCache() {}
|
||||
|
||||
static void InitializeFontCaches();
|
||||
static void UninitializeFontCaches();
|
||||
static void LoadFontCaches(FontSizes fontsizes);
|
||||
static void ClearFontCaches(FontSizes fontsizes);
|
||||
|
||||
/** Default unscaled font heights. */
|
||||
static const int DEFAULT_FONT_HEIGHT[FS_END];
|
||||
|
@ -70,16 +76,6 @@ public:
|
|||
*/
|
||||
virtual int GetFontSize() const { return this->height; }
|
||||
|
||||
/**
|
||||
* Map a SpriteID to the key
|
||||
* @param key The key to map to.
|
||||
* @param sprite The sprite that is being mapped.
|
||||
*/
|
||||
virtual void SetUnicodeGlyph(char32_t key, SpriteID sprite) = 0;
|
||||
|
||||
/** Initialize the glyph map */
|
||||
virtual void InitializeUnicodeGlyphMap() = 0;
|
||||
|
||||
/** Clear the font cache. */
|
||||
virtual void ClearFontCache() = 0;
|
||||
|
||||
|
@ -134,7 +130,7 @@ public:
|
|||
static inline FontCache *Get(FontSize fs)
|
||||
{
|
||||
assert(fs < FS_END);
|
||||
return FontCache::caches[fs];
|
||||
return FontCache::caches[fs].get();
|
||||
}
|
||||
|
||||
static std::string GetName(FontSize fs);
|
||||
|
@ -153,27 +149,6 @@ public:
|
|||
virtual bool IsBuiltInFont() = 0;
|
||||
};
|
||||
|
||||
/** Map a SpriteID to the font size and key */
|
||||
inline void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite)
|
||||
{
|
||||
FontCache::Get(size)->SetUnicodeGlyph(key, sprite);
|
||||
}
|
||||
|
||||
/** Initialize the glyph map */
|
||||
inline void InitializeUnicodeGlyphMap()
|
||||
{
|
||||
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
|
||||
FontCache::Get(fs)->InitializeUnicodeGlyphMap();
|
||||
}
|
||||
}
|
||||
|
||||
inline void ClearFontCache()
|
||||
{
|
||||
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
|
||||
FontCache::Get(fs)->ClearFontCache();
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the Sprite for a glyph */
|
||||
inline const Sprite *GetGlyph(FontSize size, char32_t key)
|
||||
{
|
||||
|
@ -231,10 +206,41 @@ inline FontCacheSubSetting *GetFontCacheSubSetting(FontSize fs)
|
|||
|
||||
uint GetFontCacheFontSize(FontSize fs);
|
||||
std::string GetFontCacheFontName(FontSize fs);
|
||||
void InitFontCache(bool monospace);
|
||||
void UninitFontCache();
|
||||
|
||||
bool GetFontAAState();
|
||||
void SetFont(FontSize fontsize, const std::string &font, uint size);
|
||||
|
||||
/** Different types of font that can be loaded. */
|
||||
enum class FontType : uint8_t {
|
||||
Sprite, ///< Bitmap sprites from GRF files.
|
||||
TrueType, ///< Scalable TrueType fonts.
|
||||
};
|
||||
|
||||
/** Factory for FontCaches. */
|
||||
class FontCacheFactory : public BaseProvider<FontCacheFactory> {
|
||||
public:
|
||||
FontCacheFactory(std::string_view name, std::string_view description) : BaseProvider<FontCacheFactory>(name, description)
|
||||
{
|
||||
ProviderManager<FontCacheFactory>::Register(*this);
|
||||
}
|
||||
|
||||
virtual ~FontCacheFactory()
|
||||
{
|
||||
ProviderManager<FontCacheFactory>::Unregister(*this);
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) = 0;
|
||||
virtual bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) = 0;
|
||||
};
|
||||
|
||||
class FontProviderManager : ProviderManager<FontCacheFactory> {
|
||||
public:
|
||||
static std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype);
|
||||
static bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback);
|
||||
};
|
||||
|
||||
/* Implemented in spritefontcache.cpp */
|
||||
void InitializeUnicodeGlyphMap();
|
||||
void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite);
|
||||
|
||||
#endif /* FONTCACHE_H */
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
/** @file freetypefontcache.cpp FreeType font cache implementation. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
|
||||
#include "../debug.h"
|
||||
#include "../fontcache.h"
|
||||
#include "../fontdetection.h"
|
||||
#include "../blitter/factory.hpp"
|
||||
#include "../core/math_func.hpp"
|
||||
#include "../zoom_func.h"
|
||||
#include "../fileio_func.h"
|
||||
#include "../error_func.h"
|
||||
#include "../../os/unix/font_unix.h"
|
||||
#include "truetypefontcache.h"
|
||||
|
||||
#include "../table/control_codes.h"
|
||||
|
@ -46,9 +46,6 @@ public:
|
|||
const void *GetOSHandle() override { return &face; }
|
||||
};
|
||||
|
||||
FT_Library _ft_library = nullptr;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new FreeTypeFontCache.
|
||||
* @param fs The font size that is going to be cached.
|
||||
|
@ -113,93 +110,6 @@ void FreeTypeFontCache::SetFontSize(int pixels)
|
|||
}
|
||||
}
|
||||
|
||||
static FT_Error LoadFont(FontSize fs, FT_Face face, std::string_view font_name, uint size)
|
||||
{
|
||||
Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
|
||||
|
||||
/* Attempt to select the unicode character map */
|
||||
FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
|
||||
if (error == FT_Err_Ok) goto found_face; // Success
|
||||
|
||||
if (error == FT_Err_Invalid_CharMap_Handle) {
|
||||
/* Try to pick a different character map instead. We default to
|
||||
* the first map, but platform_id 0 encoding_id 0 should also
|
||||
* be unicode (strange system...) */
|
||||
FT_CharMap found = face->charmaps[0];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < face->num_charmaps; i++) {
|
||||
FT_CharMap charmap = face->charmaps[i];
|
||||
if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
|
||||
found = charmap;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != nullptr) {
|
||||
error = FT_Set_Charmap(face, found);
|
||||
if (error == FT_Err_Ok) goto found_face;
|
||||
}
|
||||
}
|
||||
|
||||
FT_Done_Face(face);
|
||||
return error;
|
||||
|
||||
found_face:
|
||||
new FreeTypeFontCache(fs, face, size);
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the freetype font.
|
||||
* First type to load the fontname as if it were a path. If that fails,
|
||||
* try to resolve the filename of the font using fontconfig, where the
|
||||
* format is 'font family name' or 'font family name, font style'.
|
||||
* @param fs The font size to load.
|
||||
*/
|
||||
void LoadFreeTypeFont(FontSize fs)
|
||||
{
|
||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||
|
||||
std::string font = GetFontCacheFontName(fs);
|
||||
if (font.empty()) return;
|
||||
|
||||
if (_ft_library == nullptr) {
|
||||
if (FT_Init_FreeType(&_ft_library) != FT_Err_Ok) {
|
||||
ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug(fontcache, 2, "Initialized");
|
||||
}
|
||||
|
||||
FT_Face face = nullptr;
|
||||
|
||||
/* If font is an absolute path to a ttf, try loading that first. */
|
||||
int32_t index = 0;
|
||||
if (settings->os_handle != nullptr) index = *static_cast<const int32_t *>(settings->os_handle);
|
||||
FT_Error error = FT_New_Face(_ft_library, font.c_str(), index, &face);
|
||||
|
||||
if (error != FT_Err_Ok) {
|
||||
/* Check if font is a relative filename in one of our search-paths. */
|
||||
std::string full_font = FioFindFullPath(BASE_DIR, font);
|
||||
if (!full_font.empty()) {
|
||||
error = FT_New_Face(_ft_library, full_font.c_str(), 0, &face);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try loading based on font face name (OS-wide fonts). */
|
||||
if (error != FT_Err_Ok) error = GetFontByFaceName(font, &face);
|
||||
|
||||
if (error == FT_Err_Ok) {
|
||||
error = LoadFont(fs, face, font, GetFontCacheFontSize(fs));
|
||||
if (error != FT_Err_Ok) {
|
||||
ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font, FontSizeToName(fs), error);
|
||||
}
|
||||
} else {
|
||||
FT_Done_Face(face);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free everything that was allocated for this font cache.
|
||||
*/
|
||||
|
@ -296,19 +206,116 @@ GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key, bool allow_fallback)
|
|||
return glyph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free everything allocated w.r.t. freetype.
|
||||
*/
|
||||
void UninitFreeType()
|
||||
{
|
||||
FT_Done_FreeType(_ft_library);
|
||||
_ft_library = nullptr;
|
||||
}
|
||||
FT_Library _ft_library = nullptr;
|
||||
|
||||
#if !defined(WITH_FONTCONFIG)
|
||||
class FreeTypeFontCacheFactory : public FontCacheFactory {
|
||||
public:
|
||||
FreeTypeFontCacheFactory() : FontCacheFactory("freetype", "FreeType font provider") {}
|
||||
|
||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face) { return FT_Err_Cannot_Open_Resource; }
|
||||
virtual ~FreeTypeFontCacheFactory()
|
||||
{
|
||||
FT_Done_FreeType(_ft_library);
|
||||
_ft_library = nullptr;
|
||||
}
|
||||
|
||||
#endif /* !defined(WITH_FONTCONFIG) */
|
||||
/**
|
||||
* Loads the freetype font.
|
||||
* First type to load the fontname as if it were a path. If that fails,
|
||||
* try to resolve the filename of the font using fontconfig, where the
|
||||
* format is 'font family name' or 'font family name, font style'.
|
||||
* @param fs The font size to load.
|
||||
*/
|
||||
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||
{
|
||||
if (fonttype != FontType::TrueType) return nullptr;
|
||||
|
||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||
|
||||
std::string font = GetFontCacheFontName(fs);
|
||||
if (font.empty()) return nullptr;
|
||||
|
||||
if (_ft_library == nullptr) {
|
||||
if (FT_Init_FreeType(&_ft_library) != FT_Err_Ok) {
|
||||
ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Debug(fontcache, 2, "Initialized");
|
||||
}
|
||||
|
||||
FT_Face face = nullptr;
|
||||
|
||||
/* If font is an absolute path to a ttf, try loading that first. */
|
||||
int32_t index = 0;
|
||||
if (settings->os_handle != nullptr) index = *static_cast<const int32_t *>(settings->os_handle);
|
||||
FT_Error error = FT_New_Face(_ft_library, font.c_str(), index, &face);
|
||||
|
||||
if (error != FT_Err_Ok) {
|
||||
/* Check if font is a relative filename in one of our search-paths. */
|
||||
std::string full_font = FioFindFullPath(BASE_DIR, font);
|
||||
if (!full_font.empty()) {
|
||||
error = FT_New_Face(_ft_library, full_font.c_str(), 0, &face);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_FONTCONFIG
|
||||
/* Try loading based on font face name (OS-wide fonts). */
|
||||
if (error != FT_Err_Ok) error = GetFontByFaceName(font, &face);
|
||||
#endif /* WITH_FONTCONFIG */
|
||||
|
||||
if (error != FT_Err_Ok) {
|
||||
FT_Done_Face(face);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return LoadFont(fs, face, font, GetFontCacheFontSize(fs));
|
||||
}
|
||||
|
||||
bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) override
|
||||
{
|
||||
#ifdef WITH_FONTCONFIG
|
||||
if (FontConfigFindFallbackFont(settings, language_isocode, callback)) return true;
|
||||
#endif /* WITH_FONTCONFIG */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::unique_ptr<FontCache> LoadFont(FontSize fs, FT_Face face, std::string_view font_name, uint size)
|
||||
{
|
||||
Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
|
||||
|
||||
/* Attempt to select the unicode character map */
|
||||
FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
|
||||
if (error == FT_Err_Invalid_CharMap_Handle) {
|
||||
/* Try to pick a different character map instead. We default to
|
||||
* the first map, but platform_id 0 encoding_id 0 should also
|
||||
* be unicode (strange system...) */
|
||||
FT_CharMap found = face->charmaps[0];
|
||||
|
||||
for (int i = 0; i < face->num_charmaps; ++i) {
|
||||
FT_CharMap charmap = face->charmaps[i];
|
||||
if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
|
||||
found = charmap;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != nullptr) {
|
||||
error = FT_Set_Charmap(face, found);
|
||||
}
|
||||
}
|
||||
|
||||
if (error != FT_Err_Ok) {
|
||||
FT_Done_Face(face);
|
||||
|
||||
ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<FreeTypeFontCache>(fs, face, size);
|
||||
}
|
||||
};
|
||||
|
||||
static FreeTypeFontCacheFactory s_freetype_fontcache_factory;
|
||||
|
||||
#endif /* WITH_FREETYPE */
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "../stdafx.h"
|
||||
#include "../fontcache.h"
|
||||
#include "../gfx_layout.h"
|
||||
#include "../string_func.h"
|
||||
#include "../zoom_func.h"
|
||||
#include "spritefontcache.h"
|
||||
|
||||
|
@ -31,41 +32,43 @@ static int ScaleFontTrad(int value)
|
|||
return UnScaleByZoom(value * ZOOM_BASE, _font_zoom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new sprite font cache.
|
||||
* @param fs The font size to create the cache for.
|
||||
*/
|
||||
SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs)
|
||||
{
|
||||
this->InitializeUnicodeGlyphMap();
|
||||
this->height = ScaleGUITrad(FontCache::GetDefaultFontHeight(this->fs));
|
||||
this->ascender = (this->height - ScaleFontTrad(FontCache::GetDefaultFontHeight(this->fs))) / 2;
|
||||
}
|
||||
static std::array<std::unordered_map<char32_t, SpriteID>, FS_END> _char_maps{}; ///< Glyph map for each font size.
|
||||
|
||||
/**
|
||||
* Get SpriteID associated with a character.
|
||||
* @param key Character to find.
|
||||
* @return SpriteID for character, or 0 if not present.
|
||||
*/
|
||||
SpriteID SpriteFontCache::GetUnicodeGlyph(char32_t key)
|
||||
static SpriteID GetUnicodeGlyph(FontSize fs, char32_t key)
|
||||
{
|
||||
const auto found = this->char_map.find(key);
|
||||
if (found == std::end(this->char_map)) return 0;
|
||||
return found->second;
|
||||
auto found = _char_maps[fs].find(key);
|
||||
if (found != std::end(_char_maps[fs])) return found->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SpriteFontCache::SetUnicodeGlyph(char32_t key, SpriteID sprite)
|
||||
/**
|
||||
* Set the SpriteID for a unicode character.
|
||||
* @param fs Font size to set.
|
||||
* @param key Unicode character to set.
|
||||
* @param sprite SpriteID of character.
|
||||
*/
|
||||
void SetUnicodeGlyph(FontSize fs, char32_t key, SpriteID sprite)
|
||||
{
|
||||
this->char_map[key] = sprite;
|
||||
_char_maps[fs][key] = sprite;
|
||||
}
|
||||
|
||||
void SpriteFontCache::InitializeUnicodeGlyphMap()
|
||||
/**
|
||||
* Initialize the glyph map for a font size.
|
||||
* This populates the glyph map with the baseset font sprites.
|
||||
* @param fs Font size to initialize.
|
||||
*/
|
||||
void InitializeUnicodeGlyphMap(FontSize fs)
|
||||
{
|
||||
/* Clear out existing glyph map if it exists */
|
||||
this->char_map.clear();
|
||||
_char_maps[fs].clear();
|
||||
|
||||
SpriteID base;
|
||||
switch (this->fs) {
|
||||
switch (fs) {
|
||||
default: NOT_REACHED();
|
||||
case FS_MONO: // Use normal as default for mono spaced font
|
||||
case FS_NORMAL: base = SPR_ASCII_SPACE; break;
|
||||
|
@ -76,24 +79,45 @@ void SpriteFontCache::InitializeUnicodeGlyphMap()
|
|||
for (uint i = ASCII_LETTERSTART; i < 256; i++) {
|
||||
SpriteID sprite = base + i - ASCII_LETTERSTART;
|
||||
if (!SpriteExists(sprite)) continue;
|
||||
this->SetUnicodeGlyph(i, sprite);
|
||||
this->SetUnicodeGlyph(i + SCC_SPRITE_START, sprite);
|
||||
SetUnicodeGlyph(fs, i, sprite);
|
||||
SetUnicodeGlyph(fs, i + SCC_SPRITE_START, sprite);
|
||||
}
|
||||
|
||||
/* Modify map to move non-standard glyphs to a better unicode codepoint. */
|
||||
for (const auto &unicode_map : _default_unicode_map) {
|
||||
uint8_t key = unicode_map.key;
|
||||
if (key == CLRA) {
|
||||
/* Clear the glyph. This happens if the glyph at this code point
|
||||
* is non-standard and should be accessed by an SCC_xxx enum
|
||||
* entry only. */
|
||||
this->SetUnicodeGlyph(unicode_map.code, 0);
|
||||
SetUnicodeGlyph(fs, unicode_map.code, 0);
|
||||
} else {
|
||||
SpriteID sprite = base + key - ASCII_LETTERSTART;
|
||||
this->SetUnicodeGlyph(unicode_map.code, sprite);
|
||||
SetUnicodeGlyph(fs, unicode_map.code, sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the glyph map.
|
||||
*/
|
||||
void InitializeUnicodeGlyphMap()
|
||||
{
|
||||
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
|
||||
InitializeUnicodeGlyphMap(fs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new sprite font cache.
|
||||
* @param fs The font size to create the cache for.
|
||||
*/
|
||||
SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs)
|
||||
{
|
||||
this->height = ScaleGUITrad(FontCache::GetDefaultFontHeight(this->fs));
|
||||
this->ascender = (this->height - ScaleFontTrad(FontCache::GetDefaultFontHeight(this->fs))) / 2;
|
||||
}
|
||||
|
||||
void SpriteFontCache::ClearFontCache()
|
||||
{
|
||||
Layouter::ResetFontCache(this->fs);
|
||||
|
@ -104,21 +128,21 @@ void SpriteFontCache::ClearFontCache()
|
|||
const Sprite *SpriteFontCache::GetGlyph(GlyphID key)
|
||||
{
|
||||
SpriteID sprite = static_cast<SpriteID>(key & ~SPRITE_GLYPH);
|
||||
if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
|
||||
if (sprite == 0) sprite = GetUnicodeGlyph(this->fs, '?');
|
||||
return GetSprite(sprite, SpriteType::Font);
|
||||
}
|
||||
|
||||
uint SpriteFontCache::GetGlyphWidth(GlyphID key)
|
||||
{
|
||||
SpriteID sprite = static_cast<SpriteID>(key & ~SPRITE_GLYPH);
|
||||
if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
|
||||
if (sprite == 0) sprite = GetUnicodeGlyph(this->fs, '?');
|
||||
return SpriteExists(sprite) ? GetSprite(sprite, SpriteType::Font)->width + ScaleFontTrad(this->fs != FS_NORMAL ? 1 : 0) : 0;
|
||||
}
|
||||
|
||||
GlyphID SpriteFontCache::MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback)
|
||||
{
|
||||
assert(IsPrintable(key));
|
||||
SpriteID sprite = this->GetUnicodeGlyph(key);
|
||||
SpriteID sprite = GetUnicodeGlyph(this->fs, key);
|
||||
if (sprite == 0) return 0;
|
||||
return SPRITE_GLYPH | sprite;
|
||||
}
|
||||
|
@ -127,3 +151,22 @@ bool SpriteFontCache::GetDrawGlyphShadow()
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
class SpriteFontCacheFactory : public FontCacheFactory {
|
||||
public:
|
||||
SpriteFontCacheFactory() : FontCacheFactory("sprite", "Sprite font provider") {}
|
||||
|
||||
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||
{
|
||||
if (fonttype != FontType::Sprite) return nullptr;
|
||||
|
||||
return std::make_unique<SpriteFontCache>(fs);
|
||||
}
|
||||
|
||||
bool FindFallbackFont(struct FontCacheSettings *, const std::string &, class MissingGlyphSearcher *) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static SpriteFontCacheFactory s_sprite_fontcache_factory;
|
||||
|
|
|
@ -10,15 +10,12 @@
|
|||
#ifndef SPRITEFONTCACHE_H
|
||||
#define SPRITEFONTCACHE_H
|
||||
|
||||
#include "../string_func.h"
|
||||
#include "../fontcache.h"
|
||||
|
||||
/** Font cache for fonts that are based on a freetype font. */
|
||||
class SpriteFontCache : public FontCache {
|
||||
public:
|
||||
SpriteFontCache(FontSize fs);
|
||||
void SetUnicodeGlyph(char32_t key, SpriteID sprite) override;
|
||||
void InitializeUnicodeGlyphMap() override;
|
||||
void ClearFontCache() override;
|
||||
const Sprite *GetGlyph(GlyphID key) override;
|
||||
uint GetGlyphWidth(GlyphID key) override;
|
||||
|
@ -26,10 +23,6 @@ public:
|
|||
GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override;
|
||||
std::string GetFontName() override { return "sprite"; }
|
||||
bool IsBuiltInFont() override { return true; }
|
||||
|
||||
private:
|
||||
std::unordered_map<char32_t, SpriteID> char_map{}; ///< Mapping of characters to sprite IDs.
|
||||
SpriteID GetUnicodeGlyph(char32_t key);
|
||||
};
|
||||
|
||||
#endif /* SPRITEFONTCACHE_H */
|
||||
|
|
|
@ -46,8 +46,6 @@ public:
|
|||
TrueTypeFontCache(FontSize fs, int pixels);
|
||||
virtual ~TrueTypeFontCache();
|
||||
int GetFontSize() const override { return this->used_size; }
|
||||
void SetUnicodeGlyph(char32_t key, SpriteID sprite) override { this->parent->SetUnicodeGlyph(key, sprite); }
|
||||
void InitializeUnicodeGlyphMap() override { this->parent->InitializeUnicodeGlyphMap(); }
|
||||
const Sprite *GetGlyph(GlyphID key) override;
|
||||
void ClearFontCache() override;
|
||||
uint GetGlyphWidth(GlyphID key) override;
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file fontdetection.h Functions related to detecting/finding the right font. */
|
||||
|
||||
#ifndef FONTDETECTION_H
|
||||
#define FONTDETECTION_H
|
||||
|
||||
#include "fontcache.h"
|
||||
|
||||
#ifdef WITH_FREETYPE
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
/**
|
||||
* Load a freetype font face with the given font name.
|
||||
* @param font_name The name of the font to load.
|
||||
* @param face The face that has been found.
|
||||
* @return The error we encountered.
|
||||
*/
|
||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face);
|
||||
|
||||
#endif /* WITH_FREETYPE */
|
||||
|
||||
/**
|
||||
* We would like to have a fallback font as the current one
|
||||
* doesn't contain all characters we need.
|
||||
* This function must set all fonts of settings.
|
||||
* @param settings the settings to overwrite the fontname of.
|
||||
* @param language_isocode the language, e.g. en_GB.
|
||||
* @param callback The function to call to check for missing glyphs.
|
||||
* @return true if a font has been set, false otherwise.
|
||||
*/
|
||||
bool SetFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback);
|
||||
|
||||
#endif
|
29
src/gfx.cpp
29
src/gfx.cpp
|
@ -8,6 +8,7 @@
|
|||
/** @file gfx.cpp Handling of drawing text and other gfx related stuff. */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "gfx_func.h"
|
||||
#include "gfx_layout.h"
|
||||
#include "progress.h"
|
||||
#include "zoom_func.h"
|
||||
|
@ -579,7 +580,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
|
|||
|
||||
const uint shadow_offset = ScaleGUITrad(1);
|
||||
|
||||
auto draw_line = [&](const ParagraphLayouter::Line &line, bool do_shadow, int left, int min_x, int max_x, bool truncation) {
|
||||
auto draw_line = [&](const ParagraphLayouter::Line &line, bool do_shadow, int left, int min_x, int max_x, bool truncation, TextColour &last_colour) {
|
||||
const DrawPixelInfo *dpi = _cur_dpi;
|
||||
int dpi_left = dpi->left;
|
||||
int dpi_right = dpi->left + dpi->width - 1;
|
||||
|
@ -592,10 +593,15 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
|
|||
|
||||
FontCache *fc = f->fc;
|
||||
TextColour colour = f->colour;
|
||||
if (colour == TC_INVALID || HasFlag(default_colour, TC_FORCED)) colour = default_colour;
|
||||
if (colour == TC_INVALID || HasFlag(last_colour, TC_FORCED)) {
|
||||
colour = last_colour;
|
||||
} else {
|
||||
/* Update the last colour for the truncation ellipsis. */
|
||||
last_colour = colour;
|
||||
}
|
||||
bool colour_has_shadow = (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
|
||||
SetColourRemap(do_shadow ? TC_BLACK : colour); // the last run also sets the colour for the truncation dots
|
||||
if (do_shadow && (!fc->GetDrawGlyphShadow() || !colour_has_shadow)) continue;
|
||||
SetColourRemap(do_shadow ? TC_BLACK : colour);
|
||||
|
||||
for (int i = 0; i < run.GetGlyphCount(); i++) {
|
||||
GlyphID glyph = glyphs[i];
|
||||
|
@ -623,11 +629,12 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
|
|||
|
||||
/* Draw shadow, then foreground */
|
||||
for (bool do_shadow : {true, false}) {
|
||||
draw_line(line, do_shadow, left - offset_x, min_x, max_x, truncation);
|
||||
TextColour last_colour = default_colour;
|
||||
draw_line(line, do_shadow, left - offset_x, min_x, max_x, truncation, last_colour);
|
||||
|
||||
if (truncation) {
|
||||
int x = (_current_text_dir == TD_RTL) ? left : (right - truncation_width);
|
||||
draw_line(*truncation_layout->front(), do_shadow, x, INT32_MIN, INT32_MAX, false);
|
||||
draw_line(*truncation_layout->front(), do_shadow, x, INT32_MIN, INT32_MAX, false, last_colour);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1240,14 +1247,14 @@ static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode,
|
|||
}
|
||||
|
||||
/**
|
||||
* Initialize _stringwidth_table cache
|
||||
* @param monospace Whether to load the monospace cache or the normal fonts.
|
||||
* Initialize _stringwidth_table cache for the specified font sizes.
|
||||
* @param fontsizes Font sizes to initialise.
|
||||
*/
|
||||
void LoadStringWidthTable(bool monospace)
|
||||
void LoadStringWidthTable(FontSizes fontsizes)
|
||||
{
|
||||
ClearFontCache();
|
||||
FontCache::ClearFontCaches(fontsizes);
|
||||
|
||||
for (FontSize fs = monospace ? FS_MONO : FS_BEGIN; fs < (monospace ? FS_END : FS_MONO); fs++) {
|
||||
for (FontSize fs : fontsizes) {
|
||||
for (uint i = 0; i != 224; i++) {
|
||||
_stringwidth_table[fs][i] = GetGlyphWidth(fs, i + 32);
|
||||
}
|
||||
|
@ -1812,7 +1819,7 @@ bool AdjustGUIZoom(bool automatic)
|
|||
if (old_font_zoom != _font_zoom) {
|
||||
GfxClearFontSpriteCache();
|
||||
}
|
||||
ClearFontCache();
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
LoadStringWidthTable();
|
||||
|
||||
SetupWidgetDimensions();
|
||||
|
|
|
@ -149,7 +149,7 @@ int GetStringHeight(StringID str, int maxw);
|
|||
int GetStringLineCount(std::string_view str, int maxw);
|
||||
Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion);
|
||||
Dimension GetStringMultiLineBoundingBox(std::string_view str, const Dimension &suggestion, FontSize fontsize = FS_NORMAL);
|
||||
void LoadStringWidthTable(bool monospace = false);
|
||||
void LoadStringWidthTable(FontSizes fontsizes = FONTSIZES_REQUIRED);
|
||||
|
||||
void DrawDirtyBlocks();
|
||||
void AddDirtyBlock(int left, int top, int right, int bottom);
|
||||
|
|
|
@ -258,6 +258,13 @@ enum FontSize : uint8_t {
|
|||
};
|
||||
DECLARE_INCREMENT_DECREMENT_OPERATORS(FontSize)
|
||||
|
||||
using FontSizes = EnumBitSet<FontSize, uint8_t>;
|
||||
|
||||
/** Mask of all possible font sizes. */
|
||||
constexpr FontSizes FONTSIZES_ALL{FS_NORMAL, FS_SMALL, FS_LARGE, FS_MONO};
|
||||
/** Mask of font sizes required to be present. */
|
||||
constexpr FontSizes FONTSIZES_REQUIRED{FS_NORMAL, FS_SMALL, FS_LARGE};
|
||||
|
||||
inline std::string_view FontSizeToName(FontSize fs)
|
||||
{
|
||||
static const std::string_view SIZE_TO_NAME[] = { "medium", "small", "large", "mono" };
|
||||
|
|
|
@ -245,7 +245,7 @@ static void RealChangeBlitter(std::string_view repl_blitter)
|
|||
|
||||
/* Clear caches that might have sprites for another blitter. */
|
||||
VideoDriver::GetInstance()->ClearSystemSprites();
|
||||
ClearFontCache();
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
GfxClearSpriteCache();
|
||||
ReInitAllWindows(false);
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ void CheckBlitter()
|
|||
{
|
||||
if (!SwitchNewGRFBlitter()) return;
|
||||
|
||||
ClearFontCache();
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
GfxClearSpriteCache();
|
||||
ReInitAllWindows(false);
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ void GfxLoadSprites()
|
|||
|
||||
SwitchNewGRFBlitter();
|
||||
VideoDriver::GetInstance()->ClearSystemSprites();
|
||||
ClearFontCache();
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
GfxInitSpriteMem();
|
||||
LoadSpriteTables();
|
||||
GfxInitPalettes();
|
||||
|
|
|
@ -5002,6 +5002,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}O terren
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Terreno inclinado na direção errada
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}Não é possível fazer isto...
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}A construção precisa ser demolida primeiro
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... construção é protegida
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Não é possível limpar esta área...
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... local não adequado
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}... já construído
|
||||
|
|
|
@ -268,6 +268,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}any{
|
|||
STR_UNITS_PERIODS :{NUM}{NBSP}període{P "" s}
|
||||
|
||||
STR_LIST_SEPARATOR :,{SPACE}
|
||||
STR_TRUNCATION_ELLIPSIS :...
|
||||
|
||||
# Common window strings
|
||||
STR_LIST_FILTER_TITLE :{BLACK}Filtre:
|
||||
|
@ -286,7 +287,7 @@ STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Tanca la
|
|||
STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Títol de la finestra: arrossegueu el títol per desplaçar la finestra.
|
||||
STR_TOOLTIP_SHADE :{BLACK}Ombra de la finestra: mostra només la barra de títol.
|
||||
STR_TOOLTIP_DEBUG :{BLACK}Mostra la informació de depuració NewGRF
|
||||
STR_TOOLTIP_DEFSIZE :{BLACK}Redimensiona la finestra a la mida predeterminada. Ctrl+Clic desa la mida actual com a predeterminada.
|
||||
STR_TOOLTIP_DEFSIZE :{BLACK}Redimensiona la finestra a la mida predeterminada. Amb Ctrl+Clic, es desa la mida actual com a predeterminada. Amb Ctrl+doble clic, es restableix als valors per defecte.
|
||||
STR_TOOLTIP_STICKY :{BLACK}Marca aquesta finestra com a no eliminable per la tecla «Tanca totes les finestres». Ctrl+Clic per desar també l'estat predeterminat.
|
||||
STR_TOOLTIP_RESIZE :{BLACK}Clica i arrossega per redimensionar aquesta finestra
|
||||
STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Commuta entre la mida gran i petita de la finestra
|
||||
|
@ -1108,7 +1109,7 @@ STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :Informació add
|
|||
STR_GAME_OPTIONS_ONLINE_CONTENT :Descarrega contingut
|
||||
STR_GAME_OPTIONS_ONLINE_CONTENT_TOOLTIP :Comprova si hi ha continguts nous o actualitzats per a descarregar.
|
||||
|
||||
STR_GAME_OPTIONS_SOCIAL_PLUGINS_NONE :{LTBLUE}(no s'han instal·lat complements per a interactuar amb plataformes socials)
|
||||
STR_GAME_OPTIONS_SOCIAL_PLUGINS_NONE :(no s'han instal·lat complements per a interactuar amb plataformes socials)
|
||||
|
||||
STR_GAME_OPTIONS_SOCIAL_PLUGIN_TITLE :{STRING} ({STRING})
|
||||
STR_GAME_OPTIONS_SOCIAL_PLUGIN_PLATFORM :Plataforma:
|
||||
|
@ -1226,7 +1227,7 @@ STR_CITY_APPROVAL_PERMISSIVE :Permissiva (les
|
|||
STR_WARNING_NO_SUITABLE_AI :{WHITE}No hi ha cap IA disponible...{}Podeu descarregar-ne a través del «Contingut en línia».
|
||||
|
||||
# Settings tree in the Game Options window
|
||||
STR_CONFIG_SETTING_FILTER_TITLE :{G=Masculin}{BLACK}Filtre:
|
||||
STR_CONFIG_SETTING_FILTER_TITLE :{G=Masculin}Filtre:
|
||||
STR_CONFIG_SETTING_EXPAND_ALL :Desplega-ho tot
|
||||
STR_CONFIG_SETTING_COLLAPSE_ALL :Plega-ho tot
|
||||
STR_CONFIG_SETTING_RESET_ALL :Restableix tots els valors
|
||||
|
@ -1302,6 +1303,9 @@ STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Tipus d'interè
|
|||
STR_CONFIG_SETTING_RUNNING_COSTS :Costos d'utilització: {STRING}
|
||||
STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Fixa el nivell de manteniment i els costos d'utilització dels vehicles i infraestructures
|
||||
###length 3
|
||||
STR_CONFIG_SETTING_RUNNING_COSTS_LOW :Baix
|
||||
STR_CONFIG_SETTING_RUNNING_COSTS_MEDIUM :Mitjà
|
||||
STR_CONFIG_SETTING_RUNNING_COSTS_HIGH :Alt
|
||||
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Ritme de construcció: {STRING}
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Limita la quantitat d'accions de construcció per part de les IA
|
||||
|
@ -1324,6 +1328,9 @@ STR_CONFIG_SETTING_SUBSIDY_DURATION_DISABLED :Sense subsidis
|
|||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Costos de construcció: {STRING}
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Fixa el nivell de construcció i els preus de compra
|
||||
###length 3
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_LOW :Baix
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_MEDIUM :Mitjà
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HIGH :Alt
|
||||
|
||||
STR_CONFIG_SETTING_RECESSIONS :Recessions: {STRING}
|
||||
STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Si està activat, poden haver recessions periòdicament. Durant una recessió, tota la producció és significativament més baixa, tornant al nivell previ quan s'acabi el període de recessió.
|
||||
|
@ -2079,9 +2086,9 @@ STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :La classe de c
|
|||
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Mode de distribució per altres classes de càrrega: {STRING}
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"Asimètric" vol dir que quantitats arbitràries de càrrega poden ser enviades en qualsevol sentit. "Manual" significa que no s'aplicarà cap distribució automàtica a aquestes càrregues.
|
||||
###length 3
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manual
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asimètric
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :simètric
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :Manual
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :Asimètric
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :Simètric
|
||||
|
||||
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Precisió de la distribució: {STRING}
|
||||
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Com més alt el valor indicat, més temps de processador requerirà el càlcul del graf de distribució. Si requereix massa temps podeu notar ralentització. Si indiqueu un valor baix, però, la distribució serà poc acurada, i us podeu trobar que la càrrega no és enviada als llocs que espereu.
|
||||
|
@ -2331,16 +2338,19 @@ STR_FACE_SIMPLE_TOOLTIP :{BLACK}Selecci
|
|||
STR_FACE_LOAD :{BLACK}Carrega
|
||||
STR_FACE_LOAD_TOOLTIP :{BLACK}Carrega la cara preferida
|
||||
STR_FACE_LOAD_DONE :{WHITE}S'ha carregat la cara personalitzada des de l'arxiu de configuració de l'OpenTTD.
|
||||
STR_FACE_FACECODE :{BLACK}Número de la cara
|
||||
STR_FACE_FACECODE_TOOLTIP :{BLACK}Veure i/o assigna el número de la cara del president
|
||||
STR_FACE_FACECODE_CAPTION :{WHITE}Veure i/o assigna el número de la cara del president
|
||||
STR_FACE_FACECODE_SET :{WHITE}El número de la nova cara ha estat assignat
|
||||
STR_FACE_FACECODE_ERR :{WHITE}No s'ha pogut assignar el número de cara del president - ha de ser un nombre entre 0 i 4,294,967,295!
|
||||
STR_FACE_FACECODE :{BLACK}Codi de la cara
|
||||
STR_FACE_FACECODE_TOOLTIP :{BLACK}Veure i/o assigna el codi de la cara del president
|
||||
STR_FACE_FACECODE_CAPTION :{WHITE}Veure i/o assigna el codi de la cara del president
|
||||
STR_FACE_FACECODE_SET :{WHITE}S'ha assignat el codi de la nova cara del president.
|
||||
STR_FACE_FACECODE_ERR :{WHITE}No s'ha pogut assignar el codi de cara del president - ha de ser una etiqueta i nombre vàlids.
|
||||
STR_FACE_SAVE :{BLACK}Desa
|
||||
STR_FACE_SAVE_TOOLTIP :{BLACK}Desa la cara preferida
|
||||
STR_FACE_SAVE_DONE :{WHITE}Es desarà aquesta cara personalitzada a l'arxiu de configuració de l'OpenTTD.
|
||||
STR_FACE_SETTING_TOGGLE :{STRING} {ORANGE}{STRING}
|
||||
STR_FACE_SETTING_NUMERIC :{STRING} {ORANGE}{NUM} / {NUM}
|
||||
STR_FACE_YES :Sí
|
||||
STR_FACE_NO :No
|
||||
STR_FACE_STYLE :Estil:
|
||||
STR_FACE_HAIR :Cabell:
|
||||
STR_FACE_EYEBROWS :Celles:
|
||||
STR_FACE_EYECOLOUR :Color dels ulls:
|
||||
|
@ -2813,6 +2823,10 @@ STR_PICKER_MODE_USED_TOOLTIP :Commuta entre m
|
|||
STR_PICKER_MODE_SAVED :Desats
|
||||
STR_PICKER_MODE_SAVED_TOOLTIP :Commuta entre mostrar tots o bé només els elements desats.
|
||||
|
||||
STR_PICKER_PREVIEW_SHRINK :‒
|
||||
STR_PICKER_PREVIEW_SHRINK_TOOLTIP :Redueix l'alçària de les vistes prèvies. Amb Ctrl+clic, es redueix fins al mínim.
|
||||
STR_PICKER_PREVIEW_EXPAND :+
|
||||
STR_PICKER_PREVIEW_EXPAND_TOOLTIP :Augmenta l'alçària de les vistes prèvies. Amb Ctrl+clic, s'augmenta fins al màxim.
|
||||
|
||||
STR_PICKER_STATION_CLASS_TOOLTIP :Trieu quina classe d'estació voleu veure.
|
||||
STR_PICKER_STATION_TYPE_TOOLTIP :Trieu quin tipus d'estació voleu construir. Amb Ctrl+clic, s'afegeix o es trau l'element de la llista de desats.
|
||||
|
@ -3053,6 +3067,11 @@ STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Seleccio
|
|||
STR_FOUND_TOWN_CITY :{BLACK}Ciutat
|
||||
STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Les ciutats creixen més ràpid que els pobles{}Depenent de la configuració, són més grans quan es funden
|
||||
|
||||
STR_FOUND_TOWN_EXPAND_MODE :{YELLOW}Expansió de la població:
|
||||
STR_FOUND_TOWN_EXPAND_BUILDINGS :Edificis
|
||||
STR_FOUND_TOWN_EXPAND_BUILDINGS_TOOLTIP :Augmenta el nombre d'edificis de les poblacions.
|
||||
STR_FOUND_TOWN_EXPAND_ROADS :Carreteres
|
||||
STR_FOUND_TOWN_EXPAND_ROADS_TOOLTIP :Augmenta el nombre de carreteres de la població.
|
||||
|
||||
STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Disposició de les carreteres de la població:
|
||||
STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP :{BLACK}Selecciona la disposició de les carreteres utilitzades per a aquesta població
|
||||
|
@ -3677,6 +3696,10 @@ STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Canvia e
|
|||
|
||||
STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Eixampla
|
||||
STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Incrementa la mida de la població
|
||||
STR_TOWN_VIEW_EXPAND_BUILDINGS_BUTTON :{BLACK}Expandeix els edificis
|
||||
STR_TOWN_VIEW_EXPAND_BUILDINGS_TOOLTIP :{BLACK}Augmenta el nombre d'edificis de la població.
|
||||
STR_TOWN_VIEW_EXPAND_ROADS_BUTTON :{BLACK}Expandeix les carreteres
|
||||
STR_TOWN_VIEW_EXPAND_ROADS_TOOLTIP :{BLACK}Augmenta el nombre de carreteres de la població.
|
||||
STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Esborra
|
||||
STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Esborra totalment aquesta població
|
||||
|
||||
|
@ -4415,10 +4438,10 @@ STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Mostra l
|
|||
STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Mostra les ordres de l'avió. Ctrl+Clic per mostrar l'horari de l'avió
|
||||
|
||||
###length VEHICLE_TYPES
|
||||
STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del tren
|
||||
STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del vehicle
|
||||
STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del vaixell
|
||||
STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls de l'avió
|
||||
STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del tren. Amb Ctrl+clic, es mostra el grup del tren.
|
||||
STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del vehicle. Amb Ctrl+clic, es mostra el grup del vehicle.
|
||||
STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls del vaixell. Amb Ctrl+clic, es mostra el grup del vaixell.
|
||||
STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Mostra els detalls de l'aeronau. Amb Ctrl+clic, es mostra el grup de l'aeronau.
|
||||
|
||||
###length VEHICLE_TYPES
|
||||
STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP :{BLACK}Acció actual del tren - Feu clic per parar-lo o engegar-lo.
|
||||
|
@ -4742,14 +4765,15 @@ STR_TIMETABLE_TOOLTIP :{BLACK}Horari -
|
|||
STR_TIMETABLE_NO_TRAVEL :Sense viatge
|
||||
STR_TIMETABLE_NOT_TIMETABLEABLE :Viatge (automàtic; programat per la següent ordre manual)
|
||||
STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Viatge (fora d'horari)
|
||||
STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Viatja (sense horari) com a molt a {VELOCITY}
|
||||
STR_TIMETABLE_TRAVEL_FOR :Viatge a {STRING}
|
||||
STR_TIMETABLE_TRAVEL_FOR_SPEED :Viatja durant {STRING} com a molt a {VELOCITY}
|
||||
STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Viatja (durant {STRING}, sense horari)
|
||||
STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Viatja (durant {STRING}, sense horari) com a molt a {VELOCITY}
|
||||
STR_TIMETABLE_STAY_FOR_ESTIMATED :{SPACE}(quedar-s'hi durant {STRING}, sense horari)
|
||||
STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :{SPACE}(viatja durant {STRING}, sense horari)
|
||||
STR_TIMETABLE_STAY_FOR :i estigues {STRING}
|
||||
STR_TIMETABLE_AND_TRAVEL_FOR :i viatge per {STRING}
|
||||
STR_TIMETABLE_STAY_FOR :{SPACE}i estigues {STRING}
|
||||
STR_TIMETABLE_AND_TRAVEL_FOR :{SPACE}i viatja durant {STRING}
|
||||
|
||||
STR_TIMETABLE_APPROX_TIME :{BLACK}L'horari trigara aproximadament {STRING} a completar-se.
|
||||
STR_TIMETABLE_TOTAL_TIME :{BLACK}L'horari tardarà {STRING} a complir-se
|
||||
|
@ -4978,6 +5002,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Es neces
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Terreny inclinat en direcció incorrecta
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}Això no es pot fer...
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}L'edifici s'ha d'enderrocar primer
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... l'edifici està protegit
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}No es pot netejar aquesta àrea...
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... lloc inadequat
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}... ja construït
|
||||
|
@ -5897,3 +5922,11 @@ STR_SHIP :{BLACK}{SHIP}
|
|||
STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY})
|
||||
|
||||
STR_BADGE_NAME_LIST :{STRING}: {GOLD}{STRING}
|
||||
STR_BADGE_CONFIG_MENU_TOOLTIP :Obre la configuració d'insígnies
|
||||
STR_BADGE_CONFIG_RESET :Restableix
|
||||
STR_BADGE_CONFIG_ICONS :{WHITE}Icones d'insígnies
|
||||
STR_BADGE_CONFIG_FILTERS :{WHITE}Filtres d'insígnies
|
||||
STR_BADGE_CONFIG_PREVIEW :Imatge de previsualització
|
||||
STR_BADGE_CONFIG_NAME :Nom
|
||||
STR_BADGE_FILTER_ANY_LABEL :Qualsevol {STRING}
|
||||
STR_BADGE_FILTER_IS_LABEL :{STRING} és {STRING}
|
||||
|
|
|
@ -5001,6 +5001,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Flat lan
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Land sloped in wrong direction
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}Can't do this...
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Building must be demolished first
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... building is protected
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Can't clear this area...
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... site unsuitable
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}... already built
|
||||
|
|
|
@ -5001,6 +5001,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Tarvitaa
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Maa viettää väärään suuntaan.
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}Ei onnistu...
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Rakennus täytyy purkaa ensin.
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}… rakennus on suojattu
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Aluetta ei voi tyhjentää...
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... maasto on sopimaton
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}... se on jo rakennettu
|
||||
|
|
|
@ -5102,6 +5102,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Απαι
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Το έδαφος έχει λάθος κλίση
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}Αυτό δεν γίνεται...
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Το κτίριο πρέπει πρώτα να κατεδαφιστεί
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... το κτίριο προστατεύεται
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Είναι αδύνατο να καθαριστεί αυτή η περιοχή...
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... ακατάλληλη περιοχή
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}... ήδη κατασκευασμένο
|
||||
|
|
|
@ -330,6 +330,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}év
|
|||
STR_UNITS_PERIODS :{NUM}{NBSP}időszak
|
||||
|
||||
STR_LIST_SEPARATOR :,{SPACE}
|
||||
STR_TRUNCATION_ELLIPSIS :...
|
||||
|
||||
# Common window strings
|
||||
STR_LIST_FILTER_TITLE :{BLACK}Szűrő kifejezés:
|
||||
|
|
|
@ -5387,6 +5387,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Wymagany
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Teren pochylony w złym kierunku
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}Nie można tego zrobić...
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Należy najpierw zburzyć budynek
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... budynek jest chroniony
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Nie można wyczyścić terenu...
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... nieodpowiednie miejsce
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}... już zbudowano
|
||||
|
|
|
@ -647,7 +647,7 @@ STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Alternar
|
|||
|
||||
# Company league window
|
||||
STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Classificação de Empresas
|
||||
STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}'
|
||||
STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} “{STRING}”
|
||||
STR_COMPANY_LEAGUE_COMPANY_RANK :{YELLOW}#{NUM}
|
||||
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Engenheiro
|
||||
STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Gestor de Tráfego
|
||||
|
@ -3441,20 +3441,20 @@ STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Mudar al
|
|||
STR_GENERATION_WORLD :{WHITE}A Gerar Mundo...
|
||||
STR_GENERATION_ABORT :{BLACK}Cancelar
|
||||
STR_GENERATION_ABORT_CAPTION :{WHITE}Cancelar criação do mundo
|
||||
STR_GENERATION_ABORT_MESSAGE :{YELLOW}Quer mesmo cancelar a criação?
|
||||
STR_GENERATION_ABORT_MESSAGE :{YELLOW}Quer mesmo cancelar o processo de geração?
|
||||
STR_GENERATION_PROGRESS :{WHITE}{NUM}% completo
|
||||
STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM}
|
||||
STR_GENERATION_WORLD_GENERATION :{BLACK}A gerar mundo
|
||||
STR_GENERATION_LANDSCAPE_GENERATION :{BLACK}Geração de paisagem
|
||||
STR_GENERATION_LANDSCAPE_GENERATION :{BLACK}A gerar paisagem
|
||||
STR_GENERATION_RIVER_GENERATION :{BLACK}A gerar rios
|
||||
STR_GENERATION_CLEARING_TILES :{BLACK}A gerar zonas rochosas e montanhosas
|
||||
STR_GENERATION_TOWN_GENERATION :{BLACK}Geração de localidades
|
||||
STR_GENERATION_INDUSTRY_GENERATION :{BLACK}Geração de indústrias
|
||||
STR_GENERATION_OBJECT_GENERATION :{BLACK}Geração inamovível
|
||||
STR_GENERATION_TOWN_GENERATION :{BLACK}A gerar localidades
|
||||
STR_GENERATION_INDUSTRY_GENERATION :{BLACK}A gerar indústrias
|
||||
STR_GENERATION_OBJECT_GENERATION :{BLACK}A gerar objetos
|
||||
STR_GENERATION_TREE_GENERATION :{BLACK}A gerar árvores
|
||||
STR_GENERATION_SETTINGUP_GAME :{BLACK}Definindo jogo
|
||||
STR_GENERATION_SETTINGUP_GAME :{BLACK}A configurar jogo
|
||||
STR_GENERATION_PREPARING_TILELOOP :{BLACK}A preparar o terreno
|
||||
STR_GENERATION_PREPARING_SCRIPT :{BLACK}Script a correr
|
||||
STR_GENERATION_PREPARING_SCRIPT :{BLACK}A correr script
|
||||
STR_GENERATION_PREPARING_GAME :{BLACK}A preparar jogo
|
||||
|
||||
STR_TOWN_DATA_ERROR_LOAD_FAILED :{WHITE}Falha ao carregar dados da localidade
|
||||
|
@ -5002,6 +5002,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}É neces
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Terreno inclinado na direcção incorrecta
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}Não é possível fazer isto...
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}O edifício deve ser demolido primeiro
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... o edifício está protegido
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Não é possível limpar esta área...
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... sítio inadequado
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}... já está construído
|
||||
|
|
|
@ -5188,6 +5188,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Необ
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Неверный уклон земли
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}Это невозможно...
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Сначала снесите здания
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... это здание защищено от изменений
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Невозможно расчистить данный участок...
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... неподходящее место
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}... уже построено
|
||||
|
|
|
@ -5001,6 +5001,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}需要
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}土地倾斜的方向不对
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}不能这样做……
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}必须先摧毁建筑
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}……建筑物被保护
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}无法清除这个区域……
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}……地点不合适
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}……已经建成
|
||||
|
|
|
@ -1356,8 +1356,8 @@ STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :可以在建築
|
|||
STR_CONFIG_SETTING_CATCHMENT :容許更真實的服務範圍設定:{STRING}
|
||||
STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :使車站和機場的服務範圍根據其種類和大小而改變。
|
||||
|
||||
STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :公司車站可以為自帶車站的工業設施提供服務:{STRING}
|
||||
STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :啟用後,公司車站可以為附近自帶車站的工業設施(如油井)提供服務。禁用後,這些工業設施只能由其自帶的車站提供服務,並且這些車站不會提供除了該工業設施以外的產品
|
||||
STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :公司車站可以服務附設車站的工業設施:{STRING}
|
||||
STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :啟用後,公司車站可以為附近附設車站的工業(如鑽油平台)提供服務。停用後,這些工業只能由其附設的車站提供服務,並且附設車站不會提供除了該工業設施以外的任何服務
|
||||
|
||||
STR_CONFIG_SETTING_EXTRADYNAMITE :允許移除更多市鎮擁有的道路、橋樑及隧道:{STRING}
|
||||
STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :使玩家更容易地移除市鎮擁有的基礎建設和建築物。
|
||||
|
@ -5001,6 +5001,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}需要
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}地面斜坡方向不對
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}不能執行以下動作...
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}必須先摧毀建築物
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}……建築物被保護
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}不能清除這個地段...
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... 地點不適合
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}……經已建成
|
||||
|
|
|
@ -476,7 +476,7 @@ CommandCost GetErrorMessageFromLocationCallbackResult(uint16_t cb_res, std::span
|
|||
/* If this error isn't for the local player then it won't be seen, so don't bother encoding anything. */
|
||||
if (IsLocalCompany()) {
|
||||
StringID stringid = GetGRFStringID(grffile->grfid, text_id);
|
||||
auto params = GetGRFSringTextStackParameters(grffile, stringid, textstack);
|
||||
auto params = GetGRFStringTextStackParameters(grffile, stringid, textstack);
|
||||
res.SetEncodedMessage(GetEncodedStringWithArgs(stringid, params));
|
||||
}
|
||||
|
||||
|
|
|
@ -973,7 +973,7 @@ static void HandleNewGRFStringControlCodes(std::string_view str, TextRefStack &s
|
|||
* @param textstack Text parameter stack.
|
||||
* @returns Parameters for GRF string.
|
||||
*/
|
||||
std::vector<StringParameter> GetGRFSringTextStackParameters(const GRFFile *grffile, StringID stringid, std::span<const int32_t> textstack)
|
||||
std::vector<StringParameter> GetGRFStringTextStackParameters(const GRFFile *grffile, StringID stringid, std::span<const int32_t> textstack)
|
||||
{
|
||||
if (stringid == INVALID_STRING_ID) return {};
|
||||
|
||||
|
@ -998,6 +998,6 @@ std::vector<StringParameter> GetGRFSringTextStackParameters(const GRFFile *grffi
|
|||
std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, std::span<const int32_t> textstack)
|
||||
{
|
||||
StringID stringid = GetGRFStringID(grffile->grfid, grfstringid);
|
||||
auto params = GetGRFSringTextStackParameters(grffile, stringid, textstack);
|
||||
auto params = GetGRFStringTextStackParameters(grffile, stringid, textstack);
|
||||
return GetStringWithArgs(stringid, params);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ void AddGRFTextToList(GRFTextWrapper &list, std::string_view text_to_add);
|
|||
|
||||
bool CheckGrfLangID(uint8_t lang_id, uint8_t grf_version);
|
||||
|
||||
std::vector<StringParameter> GetGRFSringTextStackParameters(const struct GRFFile *grffile, StringID stringid, std::span<const int32_t> textstack);
|
||||
std::vector<StringParameter> GetGRFStringTextStackParameters(const struct GRFFile *grffile, StringID stringid, std::span<const int32_t> textstack);
|
||||
std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, std::span<const int32_t> textstack);
|
||||
|
||||
#endif /* NEWGRF_TEXT_H */
|
||||
|
|
|
@ -315,7 +315,7 @@ static void ShutdownGame()
|
|||
/* No NewGRFs were loaded when it was still bootstrapping. */
|
||||
if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData();
|
||||
|
||||
UninitFontCache();
|
||||
FontCache::UninitializeFontCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -700,7 +700,7 @@ int openttd_main(std::span<std::string_view> arguments)
|
|||
InitializeLanguagePacks();
|
||||
|
||||
/* Initialize the font cache */
|
||||
InitFontCache(false);
|
||||
FontCache::LoadFontCaches(FONTSIZES_REQUIRED);
|
||||
|
||||
/* This must be done early, since functions use the SetWindowDirty* calls */
|
||||
InitWindowSystem();
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "../../blitter/factory.hpp"
|
||||
#include "../../error_func.h"
|
||||
#include "../../fileio_func.h"
|
||||
#include "../../fontdetection.h"
|
||||
#include "../../string_func.h"
|
||||
#include "../../strings_func.h"
|
||||
#include "../../zoom_func.h"
|
||||
|
@ -24,91 +23,6 @@
|
|||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
||||
{
|
||||
/* Determine fallback font using CoreText. This uses the language isocode
|
||||
* to find a suitable font. CoreText is available from 10.5 onwards. */
|
||||
std::string lang;
|
||||
if (language_isocode == "zh_TW") {
|
||||
/* Traditional Chinese */
|
||||
lang = "zh-Hant";
|
||||
} else if (language_isocode == "zh_CN") {
|
||||
/* Simplified Chinese */
|
||||
lang = "zh-Hans";
|
||||
} else {
|
||||
/* Just copy the first part of the isocode. */
|
||||
lang = language_isocode.substr(0, language_isocode.find('_'));
|
||||
}
|
||||
|
||||
/* Create a font descriptor matching the wanted language and latin (english) glyphs.
|
||||
* Can't use CFAutoRelease here for everything due to the way the dictionary has to be created. */
|
||||
CFStringRef lang_codes[2];
|
||||
lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang.c_str(), kCFStringEncodingUTF8);
|
||||
lang_codes[1] = CFSTR("en");
|
||||
CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks);
|
||||
CFAutoRelease<CFDictionaryRef> lang_attribs(CFDictionaryCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
||||
CFAutoRelease<CTFontDescriptorRef> lang_desc(CTFontDescriptorCreateWithAttributes(lang_attribs.get()));
|
||||
CFRelease(lang_arr);
|
||||
CFRelease(lang_codes[0]);
|
||||
|
||||
/* Get array of all font descriptors for the wanted language. */
|
||||
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks));
|
||||
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get()));
|
||||
|
||||
bool result = false;
|
||||
for (int tries = 0; tries < 2; tries++) {
|
||||
for (CFIndex i = 0; descs.get() != nullptr && i < CFArrayGetCount(descs.get()); i++) {
|
||||
CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i);
|
||||
|
||||
/* Get font traits. */
|
||||
CFAutoRelease<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute));
|
||||
CTFontSymbolicTraits symbolic_traits;
|
||||
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
|
||||
|
||||
/* Skip symbol fonts and vertical fonts. */
|
||||
if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue;
|
||||
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
|
||||
if (symbolic_traits & kCTFontBoldTrait) continue;
|
||||
/* Select monospaced fonts if asked for. */
|
||||
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
|
||||
|
||||
/* Get font name. */
|
||||
char buffer[128];
|
||||
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute));
|
||||
CFStringGetCString(font_name.get(), buffer, std::size(buffer), kCFStringEncodingUTF8);
|
||||
|
||||
/* Serif fonts usually look worse on-screen with only small
|
||||
* font sizes. As such, we try for a sans-serif font first.
|
||||
* If we can't find one in the first try, try all fonts. */
|
||||
if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) continue;
|
||||
|
||||
/* There are some special fonts starting with an '.' and the last
|
||||
* resort font that aren't usable. Skip them. */
|
||||
std::string_view name{buffer};
|
||||
if (name.starts_with(".") || name.starts_with("LastResort")) continue;
|
||||
|
||||
/* Save result. */
|
||||
callback->SetFontNames(settings, name);
|
||||
if (!callback->FindMissingGlyphs()) {
|
||||
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
/* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
|
||||
* supports. If we didn't find any other font, just try it, maybe we get lucky. */
|
||||
callback->SetFontNames(settings, "Arial Unicode MS");
|
||||
result = !callback->FindMissingGlyphs();
|
||||
}
|
||||
|
||||
callback->FindMissingGlyphs();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
CoreTextFontCache::CoreTextFontCache(FontSize fs, CFAutoRelease<CTFontDescriptorRef> &&font, int pixels) : TrueTypeFontCache(fs, pixels), font_desc(std::move(font))
|
||||
{
|
||||
this->SetFontSize(pixels);
|
||||
|
@ -287,88 +201,182 @@ const Sprite *CoreTextFontCache::InternalGetGlyph(GlyphID key, bool use_aa)
|
|||
return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
|
||||
}
|
||||
|
||||
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
|
||||
{
|
||||
if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
|
||||
class CoreTextFontCacheFactory : public FontCacheFactory {
|
||||
public:
|
||||
CoreTextFontCacheFactory() : FontCacheFactory("coretext", "CoreText font loader") {}
|
||||
|
||||
/* Might be a font file name, try load it. Direct font loading is
|
||||
* only supported starting on OSX 10.6. */
|
||||
CFAutoRelease<CFStringRef> path;
|
||||
/**
|
||||
* Loads the TrueType font.
|
||||
* If a CoreText font description is present, e.g. from the automatic font
|
||||
* fallback search, use it. Otherwise, try to resolve it by font name.
|
||||
* @param fs The font size to load.
|
||||
*/
|
||||
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||
{
|
||||
if (fonttype != FontType::TrueType) return nullptr;
|
||||
|
||||
/* See if this is an absolute path. */
|
||||
if (FileExists(font_name)) {
|
||||
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
|
||||
} else {
|
||||
/* Scan the search-paths to see if it can be found. */
|
||||
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
|
||||
if (!full_font.empty()) {
|
||||
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
|
||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||
|
||||
std::string font = GetFontCacheFontName(fs);
|
||||
if (font.empty()) return nullptr;
|
||||
|
||||
CFAutoRelease<CTFontDescriptorRef> font_ref;
|
||||
|
||||
if (settings->os_handle != nullptr) {
|
||||
font_ref.reset(static_cast<CTFontDescriptorRef>(const_cast<void *>(settings->os_handle)));
|
||||
CFRetain(font_ref.get()); // Increase ref count to match a later release.
|
||||
}
|
||||
}
|
||||
|
||||
if (path) {
|
||||
/* Try getting a font descriptor to see if the system can use it. */
|
||||
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
|
||||
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
|
||||
|
||||
if (descs && CFArrayGetCount(descs.get()) > 0) {
|
||||
CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
|
||||
CFRetain(font_ref);
|
||||
return font_ref;
|
||||
if (!font_ref && MacOSVersionIsAtLeast(10, 6, 0)) {
|
||||
/* Might be a font file name, try load it. */
|
||||
font_ref.reset(LoadFontFromFile(font));
|
||||
if (!font_ref) ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", font, FontSizeToName(fs));
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
if (!font_ref) {
|
||||
CFAutoRelease<CFStringRef> name(CFStringCreateWithCString(kCFAllocatorDefault, font.c_str(), kCFStringEncodingUTF8));
|
||||
|
||||
/**
|
||||
* Loads the TrueType font.
|
||||
* If a CoreText font description is present, e.g. from the automatic font
|
||||
* fallback search, use it. Otherwise, try to resolve it by font name.
|
||||
* @param fs The font size to load.
|
||||
*/
|
||||
void LoadCoreTextFont(FontSize fs)
|
||||
{
|
||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||
/* Simply creating the font using CTFontCreateWithNameAndSize will *always* return
|
||||
* something, no matter the name. As such, we can't use it to check for existence.
|
||||
* We instead query the list of all font descriptors that match the given name which
|
||||
* does not do this stupid name fallback. */
|
||||
CFAutoRelease<CTFontDescriptorRef> name_desc(CTFontDescriptorCreateWithNameAndSize(name.get(), 0.0));
|
||||
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void * const *>(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks));
|
||||
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(name_desc.get(), mandatory_attribs.get()));
|
||||
|
||||
std::string font = GetFontCacheFontName(fs);
|
||||
if (font.empty()) return;
|
||||
|
||||
CFAutoRelease<CTFontDescriptorRef> font_ref;
|
||||
|
||||
if (settings->os_handle != nullptr) {
|
||||
font_ref.reset(static_cast<CTFontDescriptorRef>(const_cast<void *>(settings->os_handle)));
|
||||
CFRetain(font_ref.get()); // Increase ref count to match a later release.
|
||||
}
|
||||
|
||||
if (!font_ref && MacOSVersionIsAtLeast(10, 6, 0)) {
|
||||
/* Might be a font file name, try load it. */
|
||||
font_ref.reset(LoadFontFromFile(font));
|
||||
if (!font_ref) ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", font, FontSizeToName(fs));
|
||||
}
|
||||
|
||||
if (!font_ref) {
|
||||
CFAutoRelease<CFStringRef> name(CFStringCreateWithCString(kCFAllocatorDefault, font.c_str(), kCFStringEncodingUTF8));
|
||||
|
||||
/* Simply creating the font using CTFontCreateWithNameAndSize will *always* return
|
||||
* something, no matter the name. As such, we can't use it to check for existence.
|
||||
* We instead query the list of all font descriptors that match the given name which
|
||||
* does not do this stupid name fallback. */
|
||||
CFAutoRelease<CTFontDescriptorRef> name_desc(CTFontDescriptorCreateWithNameAndSize(name.get(), 0.0));
|
||||
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void * const *>(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks));
|
||||
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(name_desc.get(), mandatory_attribs.get()));
|
||||
|
||||
/* Assume the first result is the one we want. */
|
||||
if (descs && CFArrayGetCount(descs.get()) > 0) {
|
||||
font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
|
||||
CFRetain(font_ref.get());
|
||||
/* Assume the first result is the one we want. */
|
||||
if (descs && CFArrayGetCount(descs.get()) > 0) {
|
||||
font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
|
||||
CFRetain(font_ref.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (!font_ref) {
|
||||
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<CoreTextFontCache>(fs, std::move(font_ref), GetFontCacheFontSize(fs));
|
||||
}
|
||||
|
||||
if (!font_ref) {
|
||||
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
|
||||
return;
|
||||
bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback) override
|
||||
{
|
||||
/* Determine fallback font using CoreText. This uses the language isocode
|
||||
* to find a suitable font. CoreText is available from 10.5 onwards. */
|
||||
std::string lang;
|
||||
if (language_isocode == "zh_TW") {
|
||||
/* Traditional Chinese */
|
||||
lang = "zh-Hant";
|
||||
} else if (language_isocode == "zh_CN") {
|
||||
/* Simplified Chinese */
|
||||
lang = "zh-Hans";
|
||||
} else {
|
||||
/* Just copy the first part of the isocode. */
|
||||
lang = language_isocode.substr(0, language_isocode.find('_'));
|
||||
}
|
||||
|
||||
/* Create a font descriptor matching the wanted language and latin (english) glyphs.
|
||||
* Can't use CFAutoRelease here for everything due to the way the dictionary has to be created. */
|
||||
CFStringRef lang_codes[2];
|
||||
lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang.c_str(), kCFStringEncodingUTF8);
|
||||
lang_codes[1] = CFSTR("en");
|
||||
CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks);
|
||||
CFAutoRelease<CFDictionaryRef> lang_attribs(CFDictionaryCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
||||
CFAutoRelease<CTFontDescriptorRef> lang_desc(CTFontDescriptorCreateWithAttributes(lang_attribs.get()));
|
||||
CFRelease(lang_arr);
|
||||
CFRelease(lang_codes[0]);
|
||||
|
||||
/* Get array of all font descriptors for the wanted language. */
|
||||
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks));
|
||||
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get()));
|
||||
|
||||
bool result = false;
|
||||
for (int tries = 0; tries < 2; tries++) {
|
||||
for (CFIndex i = 0; descs.get() != nullptr && i < CFArrayGetCount(descs.get()); i++) {
|
||||
CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i);
|
||||
|
||||
/* Get font traits. */
|
||||
CFAutoRelease<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute));
|
||||
CTFontSymbolicTraits symbolic_traits;
|
||||
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
|
||||
|
||||
/* Skip symbol fonts and vertical fonts. */
|
||||
if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue;
|
||||
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
|
||||
if (symbolic_traits & kCTFontBoldTrait) continue;
|
||||
/* Select monospaced fonts if asked for. */
|
||||
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
|
||||
|
||||
/* Get font name. */
|
||||
char buffer[128];
|
||||
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute));
|
||||
CFStringGetCString(font_name.get(), buffer, std::size(buffer), kCFStringEncodingUTF8);
|
||||
|
||||
/* Serif fonts usually look worse on-screen with only small
|
||||
* font sizes. As such, we try for a sans-serif font first.
|
||||
* If we can't find one in the first try, try all fonts. */
|
||||
if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) continue;
|
||||
|
||||
/* There are some special fonts starting with an '.' and the last
|
||||
* resort font that aren't usable. Skip them. */
|
||||
std::string_view name{buffer};
|
||||
if (name.starts_with(".") || name.starts_with("LastResort")) continue;
|
||||
|
||||
/* Save result. */
|
||||
callback->SetFontNames(settings, name);
|
||||
if (!callback->FindMissingGlyphs()) {
|
||||
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
/* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
|
||||
* supports. If we didn't find any other font, just try it, maybe we get lucky. */
|
||||
callback->SetFontNames(settings, "Arial Unicode MS");
|
||||
result = !callback->FindMissingGlyphs();
|
||||
}
|
||||
|
||||
callback->FindMissingGlyphs();
|
||||
return result;
|
||||
}
|
||||
|
||||
new CoreTextFontCache(fs, std::move(font_ref), GetFontCacheFontSize(fs));
|
||||
}
|
||||
private:
|
||||
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
|
||||
{
|
||||
if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
|
||||
|
||||
/* Might be a font file name, try load it. Direct font loading is
|
||||
* only supported starting on OSX 10.6. */
|
||||
CFAutoRelease<CFStringRef> path;
|
||||
|
||||
/* See if this is an absolute path. */
|
||||
if (FileExists(font_name)) {
|
||||
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
|
||||
} else {
|
||||
/* Scan the search-paths to see if it can be found. */
|
||||
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
|
||||
if (!full_font.empty()) {
|
||||
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
|
||||
}
|
||||
}
|
||||
|
||||
if (path) {
|
||||
/* Try getting a font descriptor to see if the system can use it. */
|
||||
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
|
||||
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
|
||||
|
||||
if (descs && CFArrayGetCount(descs.get()) > 0) {
|
||||
CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
|
||||
CFRetain(font_ref);
|
||||
return font_ref;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
static CoreTextFontCacheFactory s_coretext_fontcache_Factory;
|
||||
|
|
|
@ -12,6 +12,7 @@ add_files(
|
|||
|
||||
add_files(
|
||||
font_unix.cpp
|
||||
font_unix.h
|
||||
CONDITION Fontconfig_FOUND
|
||||
)
|
||||
|
||||
|
|
|
@ -11,17 +11,17 @@
|
|||
|
||||
#include "../../misc/autorelease.hpp"
|
||||
#include "../../debug.h"
|
||||
#include "../../fontdetection.h"
|
||||
#include "../../fontcache.h"
|
||||
#include "../../string_func.h"
|
||||
#include "../../strings_func.h"
|
||||
#include "font_unix.h"
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
extern FT_Library _ft_library;
|
||||
|
||||
/**
|
||||
|
@ -61,6 +61,12 @@ static std::tuple<std::string, std::string> SplitFontFamilyAndStyle(std::string_
|
|||
return { std::string(font_name.substr(0, separator)), std::string(font_name.substr(begin)) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a freetype font face with the given font name.
|
||||
* @param font_name The name of the font to load.
|
||||
* @param face The face that has been found.
|
||||
* @return The error we encountered.
|
||||
*/
|
||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face)
|
||||
{
|
||||
FT_Error err = FT_Err_Cannot_Open_Resource;
|
||||
|
@ -117,7 +123,7 @@ FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face)
|
|||
return err;
|
||||
}
|
||||
|
||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
||||
bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
|
@ -182,6 +188,6 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
|
|||
if (best_font == nullptr) return false;
|
||||
|
||||
callback->SetFontNames(settings, best_font, &best_index);
|
||||
InitFontCache(callback->Monospace());
|
||||
FontCache::LoadFontCaches(callback->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file font_unix.h Functions related to detecting/finding the right font. */
|
||||
|
||||
#ifndef FONT_UNIX_H
|
||||
#define FONT_UNIX_H
|
||||
|
||||
#ifdef WITH_FONTCONFIG
|
||||
|
||||
#include "../../fontcache.h"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face);
|
||||
|
||||
bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback);
|
||||
|
||||
#endif /* WITH_FONTCONFIG */
|
||||
|
||||
#endif /* FONT_UNIX_H */
|
|
@ -15,7 +15,6 @@
|
|||
#include "../../fileio_func.h"
|
||||
#include "../../fontcache.h"
|
||||
#include "../../fontcache/truetypefontcache.h"
|
||||
#include "../../fontdetection.h"
|
||||
#include "../../library_loader.h"
|
||||
#include "../../string_func.h"
|
||||
#include "../../strings_func.h"
|
||||
|
@ -85,32 +84,6 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
|
|||
return 0; // stop enumerating
|
||||
}
|
||||
|
||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
||||
{
|
||||
Debug(fontcache, 1, "Trying fallback fonts");
|
||||
EFCParam langInfo;
|
||||
std::wstring lang = OTTD2FS(language_isocode.substr(0, language_isocode.find('_')));
|
||||
if (GetLocaleInfoEx(lang.c_str(), LOCALE_FONTSIGNATURE, reinterpret_cast<LPWSTR>(&langInfo.locale), sizeof(langInfo.locale) / sizeof(wchar_t)) == 0) {
|
||||
/* Invalid isocode or some other mysterious error, can't determine fallback font. */
|
||||
Debug(fontcache, 1, "Can't get locale info for fallback font (isocode={})", language_isocode);
|
||||
return false;
|
||||
}
|
||||
langInfo.settings = settings;
|
||||
langInfo.callback = callback;
|
||||
|
||||
LOGFONT font;
|
||||
/* Enumerate all fonts. */
|
||||
font.lfCharSet = DEFAULT_CHARSET;
|
||||
font.lfFaceName[0] = '\0';
|
||||
font.lfPitchAndFamily = 0;
|
||||
|
||||
HDC dc = GetDC(nullptr);
|
||||
int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
|
||||
ReleaseDC(nullptr, dc);
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new Win32FontCache.
|
||||
* @param fs The font size that is going to be cached.
|
||||
|
@ -293,99 +266,134 @@ void Win32FontCache::ClearFontCache()
|
|||
return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->parent->MapCharToGlyph(key) : 0;
|
||||
}
|
||||
|
||||
class Win32FontCacheFactory : FontCacheFactory {
|
||||
public:
|
||||
Win32FontCacheFactory() : FontCacheFactory("win32", "Win32 font loader") {}
|
||||
|
||||
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
|
||||
{
|
||||
wchar_t fontPath[MAX_PATH] = {};
|
||||
/**
|
||||
* Loads the GDI font.
|
||||
* If a GDI font description is present, e.g. from the automatic font
|
||||
* fallback search, use it. Otherwise, try to resolve it by font name.
|
||||
* @param fs The font size to load.
|
||||
*/
|
||||
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||
{
|
||||
if (fonttype != FontType::TrueType) return nullptr;
|
||||
|
||||
/* See if this is an absolute path. */
|
||||
if (FileExists(font_name)) {
|
||||
convert_to_fs(font_name, fontPath);
|
||||
} else {
|
||||
/* Scan the search-paths to see if it can be found. */
|
||||
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
|
||||
if (!full_font.empty()) {
|
||||
convert_to_fs(font_name, fontPath);
|
||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||
|
||||
std::string font = GetFontCacheFontName(fs);
|
||||
if (font.empty()) return nullptr;
|
||||
|
||||
LOGFONT logfont{};
|
||||
logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
|
||||
logfont.lfCharSet = DEFAULT_CHARSET;
|
||||
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
|
||||
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||
|
||||
if (settings->os_handle != nullptr) {
|
||||
logfont = *(const LOGFONT *)settings->os_handle;
|
||||
} else if (font.find('.') != std::string::npos) {
|
||||
/* Might be a font file name, try load it. */
|
||||
if (!TryLoadFontFromFile(font, logfont)) {
|
||||
ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font, FontSizeToName(fs));
|
||||
}
|
||||
}
|
||||
|
||||
if (logfont.lfFaceName[0] == 0) {
|
||||
logfont.lfWeight = StrContainsIgnoreCase(font, " bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
|
||||
convert_to_fs(font, logfont.lfFaceName);
|
||||
}
|
||||
|
||||
return LoadWin32Font(fs, logfont, GetFontCacheFontSize(fs), font);
|
||||
}
|
||||
|
||||
if (fontPath[0] != 0) {
|
||||
if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
|
||||
/* Try a nice little undocumented function first for getting the internal font name.
|
||||
* Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */
|
||||
static LibraryLoader _gdi32("gdi32.dll");
|
||||
typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
|
||||
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW");
|
||||
bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback) override
|
||||
{
|
||||
Debug(fontcache, 1, "Trying fallback fonts");
|
||||
EFCParam langInfo;
|
||||
std::wstring lang = OTTD2FS(language_isocode.substr(0, language_isocode.find('_')));
|
||||
if (GetLocaleInfoEx(lang.c_str(), LOCALE_FONTSIGNATURE, reinterpret_cast<LPWSTR>(&langInfo.locale), sizeof(langInfo.locale) / sizeof(wchar_t)) == 0) {
|
||||
/* Invalid isocode or some other mysterious error, can't determine fallback font. */
|
||||
Debug(fontcache, 1, "Can't get locale info for fallback font (isocode={})", language_isocode);
|
||||
return false;
|
||||
}
|
||||
langInfo.settings = settings;
|
||||
langInfo.callback = callback;
|
||||
|
||||
if (GetFontResourceInfo != nullptr) {
|
||||
/* Try to query an array of LOGFONTs that describe the file. */
|
||||
DWORD len = 0;
|
||||
if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) {
|
||||
LOGFONT *buf = (LOGFONT *)new uint8_t[len];
|
||||
if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
|
||||
logfont = *buf; // Just use first entry.
|
||||
LOGFONT font;
|
||||
/* Enumerate all fonts. */
|
||||
font.lfCharSet = DEFAULT_CHARSET;
|
||||
font.lfFaceName[0] = '\0';
|
||||
font.lfPitchAndFamily = 0;
|
||||
|
||||
HDC dc = GetDC(nullptr);
|
||||
int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
|
||||
ReleaseDC(nullptr, dc);
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::unique_ptr<FontCache> LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, std::string_view font_name)
|
||||
{
|
||||
HFONT font = CreateFontIndirect(&logfont);
|
||||
if (font == nullptr) {
|
||||
ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
DeleteObject(font);
|
||||
|
||||
return std::make_unique<Win32FontCache>(fs, logfont, size);
|
||||
}
|
||||
|
||||
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
|
||||
{
|
||||
wchar_t fontPath[MAX_PATH] = {};
|
||||
|
||||
/* See if this is an absolute path. */
|
||||
if (FileExists(font_name)) {
|
||||
convert_to_fs(font_name, fontPath);
|
||||
} else {
|
||||
/* Scan the search-paths to see if it can be found. */
|
||||
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
|
||||
if (!full_font.empty()) {
|
||||
convert_to_fs(font_name, fontPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (fontPath[0] != 0) {
|
||||
if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
|
||||
/* Try a nice little undocumented function first for getting the internal font name.
|
||||
* Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */
|
||||
static LibraryLoader _gdi32("gdi32.dll");
|
||||
typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
|
||||
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW");
|
||||
|
||||
if (GetFontResourceInfo != nullptr) {
|
||||
/* Try to query an array of LOGFONTs that describe the file. */
|
||||
DWORD len = 0;
|
||||
if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) {
|
||||
LOGFONT *buf = (LOGFONT *)new uint8_t[len];
|
||||
if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
|
||||
logfont = *buf; // Just use first entry.
|
||||
}
|
||||
delete[](uint8_t *)buf;
|
||||
}
|
||||
delete[](uint8_t *)buf;
|
||||
}
|
||||
|
||||
/* No dice yet. Use the file name as the font face name, hoping it matches. */
|
||||
if (logfont.lfFaceName[0] == 0) {
|
||||
wchar_t fname[_MAX_FNAME];
|
||||
_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
|
||||
|
||||
wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
|
||||
logfont.lfWeight = StrContainsIgnoreCase(font_name, " bold") || StrContainsIgnoreCase(font_name, "-bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
|
||||
}
|
||||
}
|
||||
|
||||
/* No dice yet. Use the file name as the font face name, hoping it matches. */
|
||||
if (logfont.lfFaceName[0] == 0) {
|
||||
wchar_t fname[_MAX_FNAME];
|
||||
_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
|
||||
|
||||
wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
|
||||
logfont.lfWeight = StrContainsIgnoreCase(font_name, " bold") || StrContainsIgnoreCase(font_name, "-bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
|
||||
}
|
||||
}
|
||||
|
||||
return logfont.lfFaceName[0] != 0;
|
||||
}
|
||||
};
|
||||
|
||||
return logfont.lfFaceName[0] != 0;
|
||||
}
|
||||
|
||||
static void LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, std::string_view font_name)
|
||||
{
|
||||
HFONT font = CreateFontIndirect(&logfont);
|
||||
if (font == nullptr) {
|
||||
ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
|
||||
return;
|
||||
}
|
||||
DeleteObject(font);
|
||||
|
||||
new Win32FontCache(fs, logfont, size);
|
||||
}
|
||||
/**
|
||||
* Loads the GDI font.
|
||||
* If a GDI font description is present, e.g. from the automatic font
|
||||
* fallback search, use it. Otherwise, try to resolve it by font name.
|
||||
* @param fs The font size to load.
|
||||
*/
|
||||
void LoadWin32Font(FontSize fs)
|
||||
{
|
||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||
|
||||
std::string font = GetFontCacheFontName(fs);
|
||||
if (font.empty()) return;
|
||||
|
||||
LOGFONT logfont{};
|
||||
logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
|
||||
logfont.lfCharSet = DEFAULT_CHARSET;
|
||||
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
|
||||
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||
|
||||
if (settings->os_handle != nullptr) {
|
||||
logfont = *(const LOGFONT *)settings->os_handle;
|
||||
} else if (font.find('.') != std::string::npos) {
|
||||
/* Might be a font file name, try load it. */
|
||||
if (!TryLoadFontFromFile(font, logfont)) {
|
||||
ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font, FontSizeToName(fs));
|
||||
}
|
||||
}
|
||||
|
||||
if (logfont.lfFaceName[0] == 0) {
|
||||
logfont.lfWeight = StrContainsIgnoreCase(font, " bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
|
||||
convert_to_fs(font, logfont.lfFaceName);
|
||||
}
|
||||
|
||||
LoadWin32Font(fs, logfont, GetFontCacheFontSize(fs), font);
|
||||
}
|
||||
static Win32FontCacheFactory s_win32_fontcache_factory;
|
||||
|
|
|
@ -53,7 +53,7 @@ static ScriptStorage &GetStorage()
|
|||
|
||||
/* static */ ScriptInstance *ScriptObject::ActiveInstance::active = nullptr;
|
||||
|
||||
ScriptObject::ActiveInstance::ActiveInstance(ScriptInstance &instance) : alc_scope(instance.engine)
|
||||
ScriptObject::ActiveInstance::ActiveInstance(ScriptInstance &instance) : alc_scope(instance.engine.get())
|
||||
{
|
||||
this->last_active = ScriptObject::ActiveInstance::active;
|
||||
ScriptObject::ActiveInstance::active = &instance;
|
||||
|
@ -230,8 +230,8 @@ ScriptObject::DisableDoCommandScope::DisableDoCommandScope()
|
|||
|
||||
/* static */ bool ScriptObject::CanSuspend()
|
||||
{
|
||||
Squirrel *squirrel = ScriptObject::GetActiveInstance().engine;
|
||||
return GetStorage().allow_do_command && squirrel->CanSuspend();
|
||||
Squirrel &squirrel = *ScriptObject::GetActiveInstance().engine;
|
||||
return GetStorage().allow_do_command && squirrel.CanSuspend();
|
||||
}
|
||||
|
||||
/* static */ ScriptEventQueue &ScriptObject::GetEventQueue()
|
||||
|
|
|
@ -50,8 +50,8 @@ static void PrintFunc(bool error_msg, std::string_view message)
|
|||
|
||||
ScriptInstance::ScriptInstance(std::string_view api_name)
|
||||
{
|
||||
this->storage = new ScriptStorage();
|
||||
this->engine = new Squirrel(api_name);
|
||||
this->storage = std::make_unique<ScriptStorage>();
|
||||
this->engine = std::make_unique<Squirrel>(api_name);
|
||||
this->engine->SetPrintFunction(&PrintFunc);
|
||||
}
|
||||
|
||||
|
@ -59,10 +59,10 @@ void ScriptInstance::Initialize(const std::string &main_script, const std::strin
|
|||
{
|
||||
ScriptObject::ActiveInstance active(*this);
|
||||
|
||||
this->controller = new ScriptController(company);
|
||||
this->controller = std::make_unique<ScriptController>(company);
|
||||
|
||||
/* Register the API functions and classes */
|
||||
this->engine->SetGlobalPointer(this->engine);
|
||||
this->engine->SetGlobalPointer(this->engine.get());
|
||||
this->RegisterAPI();
|
||||
if (this->IsDead()) {
|
||||
/* Failed to register API; a message has already been logged. */
|
||||
|
@ -81,12 +81,11 @@ void ScriptInstance::Initialize(const std::string &main_script, const std::strin
|
|||
}
|
||||
|
||||
/* Create the main-class */
|
||||
this->instance = new SQObject();
|
||||
if (!this->engine->CreateClassInstance(instance_name, this->controller, this->instance)) {
|
||||
this->instance = std::make_unique<SQObject>();
|
||||
if (!this->engine->CreateClassInstance(instance_name, this->controller.get(), this->instance.get())) {
|
||||
/* If CreateClassInstance has returned false instance has not been
|
||||
* registered with squirrel, so avoid trying to Release it by clearing it now */
|
||||
delete this->instance;
|
||||
this->instance = nullptr;
|
||||
this->instance.reset();
|
||||
this->Died();
|
||||
return;
|
||||
}
|
||||
|
@ -130,6 +129,13 @@ bool ScriptInstance::LoadCompatibilityScripts(Subdirectory dir, std::span<const
|
|||
|
||||
ScriptLog::Info(fmt::format("Downgrading API to be compatible with version {}", this->api_version));
|
||||
|
||||
HSQUIRRELVM vm = this->engine->GetVM();
|
||||
sq_pushroottable(vm);
|
||||
sq_pushstring(vm, "CompatScriptRootTable");
|
||||
sq_pushroottable(vm);
|
||||
sq_newslot(vm, -3, SQFalse);
|
||||
sq_pop(vm, 1);
|
||||
|
||||
/* Downgrade the API till we are the same version as the script. The last
|
||||
* entry in the list is always the current version, so skip that one. */
|
||||
for (auto it = std::rbegin(api_versions) + 1; it != std::rend(api_versions); ++it) {
|
||||
|
@ -138,6 +144,11 @@ bool ScriptInstance::LoadCompatibilityScripts(Subdirectory dir, std::span<const
|
|||
if (*it == this->api_version) break;
|
||||
}
|
||||
|
||||
sq_pushroottable(vm);
|
||||
sq_pushstring(vm, "CompatScriptRootTable");
|
||||
sq_deleteslot(vm, -2, SQFalse);
|
||||
sq_pop(vm, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -146,11 +157,10 @@ ScriptInstance::~ScriptInstance()
|
|||
ScriptObject::ActiveInstance active(*this);
|
||||
this->in_shutdown = true;
|
||||
|
||||
if (instance != nullptr) this->engine->ReleaseObject(this->instance);
|
||||
if (engine != nullptr) delete this->engine;
|
||||
delete this->storage;
|
||||
delete this->controller;
|
||||
delete this->instance;
|
||||
if (instance != nullptr) this->engine->ReleaseObject(this->instance.get());
|
||||
|
||||
/* Engine must be reset explicitly in scope of the active instance. */
|
||||
this->engine.reset();
|
||||
}
|
||||
|
||||
void ScriptInstance::Continue()
|
||||
|
@ -167,11 +177,9 @@ void ScriptInstance::Died()
|
|||
|
||||
this->last_allocated_memory = this->GetAllocatedMemory(); // Update cache
|
||||
|
||||
if (this->instance != nullptr) this->engine->ReleaseObject(this->instance);
|
||||
delete this->instance;
|
||||
delete this->engine;
|
||||
this->instance = nullptr;
|
||||
this->engine = nullptr;
|
||||
if (this->instance != nullptr) this->engine->ReleaseObject(this->instance.get());
|
||||
this->engine.reset();
|
||||
this->instance.reset();
|
||||
}
|
||||
|
||||
void ScriptInstance::GameLoop()
|
||||
|
|
|
@ -256,7 +256,7 @@ public:
|
|||
void ReleaseSQObject(HSQOBJECT *obj);
|
||||
|
||||
protected:
|
||||
class Squirrel *engine = nullptr; ///< A wrapper around the squirrel vm.
|
||||
std::unique_ptr<class Squirrel> engine; ///< A wrapper around the squirrel vm.
|
||||
std::string api_version{}; ///< Current API used by this script.
|
||||
|
||||
/**
|
||||
|
@ -288,9 +288,9 @@ protected:
|
|||
virtual void LoadDummyScript() = 0;
|
||||
|
||||
private:
|
||||
class ScriptController *controller = nullptr; ///< The script main class.
|
||||
class ScriptStorage *storage = nullptr; ///< Some global information for each running script.
|
||||
SQObject *instance = nullptr; ///< Squirrel-pointer to the script main class.
|
||||
std::unique_ptr<class ScriptStorage> storage; ///< Some global information for each running script.
|
||||
std::unique_ptr<class ScriptController> controller; ///< The script main class.
|
||||
std::unique_ptr<SQObject> instance; ///< Squirrel-pointer to the script main class.
|
||||
|
||||
bool is_started = false; ///< Is the scripts constructor executed?
|
||||
bool is_dead = false; ///< True if the script has been stopped.
|
||||
|
|
|
@ -1036,9 +1036,8 @@ struct GameOptionsWindow : Window {
|
|||
this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite);
|
||||
this->SetDirty();
|
||||
|
||||
InitFontCache(false);
|
||||
InitFontCache(true);
|
||||
ClearFontCache();
|
||||
FontCache::LoadFontCaches(FONTSIZES_ALL);
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
CheckForMissingGlyphs();
|
||||
SetupWidgetDimensions();
|
||||
UpdateAllVirtCoords();
|
||||
|
@ -1051,7 +1050,7 @@ struct GameOptionsWindow : Window {
|
|||
this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa);
|
||||
MarkWholeScreenDirty();
|
||||
|
||||
ClearFontCache();
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
break;
|
||||
#endif /* HAS_TRUETYPE_FONT */
|
||||
|
||||
|
|
|
@ -535,7 +535,7 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty
|
|||
|
||||
struct GrfSpriteOffset {
|
||||
size_t file_pos;
|
||||
uint8_t control_flags;
|
||||
SpriteCacheCtrlFlags control_flags{};
|
||||
};
|
||||
|
||||
/** Map from sprite numbers to position in the GRF file. */
|
||||
|
@ -565,7 +565,7 @@ void ReadGRFSpriteOffsets(SpriteFile &file)
|
|||
size_t old_pos = file.GetPos();
|
||||
file.SeekTo(data_offset, SEEK_CUR);
|
||||
|
||||
GrfSpriteOffset offset = { 0, 0 };
|
||||
GrfSpriteOffset offset{0};
|
||||
|
||||
/* Loop over all sprite section entries and store the file
|
||||
* offset for each newly encountered ID. */
|
||||
|
@ -574,7 +574,6 @@ void ReadGRFSpriteOffsets(SpriteFile &file)
|
|||
if (id != prev_id) {
|
||||
_grf_sprite_offsets[prev_id] = offset;
|
||||
offset.file_pos = file.GetPos() - 4;
|
||||
offset.control_flags = 0;
|
||||
}
|
||||
prev_id = id;
|
||||
uint length = file.ReadDword();
|
||||
|
@ -585,11 +584,11 @@ void ReadGRFSpriteOffsets(SpriteFile &file)
|
|||
uint8_t zoom = file.ReadByte();
|
||||
length--;
|
||||
if (colour.Any() && zoom == 0) { // ZoomLevel::Normal (normal zoom)
|
||||
SetBit(offset.control_flags, (colour != SpriteComponent::Palette) ? SCCF_ALLOW_ZOOM_MIN_1X_32BPP : SCCF_ALLOW_ZOOM_MIN_1X_PAL);
|
||||
SetBit(offset.control_flags, (colour != SpriteComponent::Palette) ? SCCF_ALLOW_ZOOM_MIN_2X_32BPP : SCCF_ALLOW_ZOOM_MIN_2X_PAL);
|
||||
offset.control_flags.Set((colour != SpriteComponent::Palette) ? SpriteCacheCtrlFlag::AllowZoomMin1x32bpp : SpriteCacheCtrlFlag::AllowZoomMin1xPal);
|
||||
offset.control_flags.Set((colour != SpriteComponent::Palette) ? SpriteCacheCtrlFlag::AllowZoomMin2x32bpp : SpriteCacheCtrlFlag::AllowZoomMin2xPal);
|
||||
}
|
||||
if (colour.Any() && zoom == 2) { // ZoomLevel::In2x (2x zoomed in)
|
||||
SetBit(offset.control_flags, (colour != SpriteComponent::Palette) ? SCCF_ALLOW_ZOOM_MIN_2X_32BPP : SCCF_ALLOW_ZOOM_MIN_2X_PAL);
|
||||
offset.control_flags.Set((colour != SpriteComponent::Palette) ? SpriteCacheCtrlFlag::AllowZoomMin2x32bpp : SpriteCacheCtrlFlag::AllowZoomMin2xPal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -621,7 +620,7 @@ bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id)
|
|||
uint8_t grf_type = file.ReadByte();
|
||||
|
||||
SpriteType type;
|
||||
uint8_t control_flags = 0;
|
||||
SpriteCacheCtrlFlags control_flags;
|
||||
if (grf_type == 0xFF) {
|
||||
/* Some NewGRF files have "empty" pseudo-sprites which are 1
|
||||
* byte long. Catch these so the sprites won't be displayed. */
|
||||
|
|
|
@ -11,24 +11,9 @@
|
|||
#define SPRITECACHE_H
|
||||
|
||||
#include "gfx_type.h"
|
||||
#include "spritecache_type.h"
|
||||
#include "spriteloader/spriteloader.hpp"
|
||||
|
||||
/** Data structure describing a sprite. */
|
||||
struct Sprite {
|
||||
uint16_t height; ///< Height of the sprite.
|
||||
uint16_t width; ///< Width of the sprite.
|
||||
int16_t x_offs; ///< Number of pixels to shift the sprite to the right.
|
||||
int16_t y_offs; ///< Number of pixels to shift the sprite downwards.
|
||||
std::byte data[]; ///< Sprite data.
|
||||
};
|
||||
|
||||
enum SpriteCacheCtrlFlags : uint8_t {
|
||||
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;
|
||||
|
||||
/** SpriteAllocator that allocates memory via a unique_ptr array. */
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "core/math_func.hpp"
|
||||
#include "gfx_type.h"
|
||||
#include "spritecache_type.h"
|
||||
#include "spriteloader/spriteloader.hpp"
|
||||
|
||||
#include "table/sprites.h"
|
||||
|
@ -27,7 +28,7 @@ struct SpriteCache {
|
|||
uint32_t lru = 0;
|
||||
SpriteType type = SpriteType::Invalid; ///< 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 = false; ///< True iff the user has been warned about incorrect use of this sprite
|
||||
uint8_t control_flags = 0; ///< Control flags, see SpriteCacheCtrlFlags
|
||||
SpriteCacheCtrlFlags control_flags{}; ///< Control flags, see SpriteCacheCtrlFlags
|
||||
|
||||
void ClearSpriteData();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file spritecache_type.h Types related to the sprite cache. */
|
||||
|
||||
#ifndef SPRITECACHE_TYPE_H
|
||||
#define SPRITECACHE_TYPE_H
|
||||
|
||||
#include "core/enum_type.hpp"
|
||||
|
||||
/** Data structure describing a sprite. */
|
||||
struct Sprite {
|
||||
uint16_t height; ///< Height of the sprite.
|
||||
uint16_t width; ///< Width of the sprite.
|
||||
int16_t x_offs; ///< Number of pixels to shift the sprite to the right.
|
||||
int16_t y_offs; ///< Number of pixels to shift the sprite downwards.
|
||||
std::byte data[]; ///< Sprite data.
|
||||
};
|
||||
|
||||
enum class SpriteCacheCtrlFlag : uint8_t {
|
||||
AllowZoomMin1xPal, ///< Allow use of sprite min zoom setting at 1x in palette mode.
|
||||
AllowZoomMin1x32bpp, ///< Allow use of sprite min zoom setting at 1x in 32bpp mode.
|
||||
AllowZoomMin2xPal, ///< Allow use of sprite min zoom setting at 2x in palette mode.
|
||||
AllowZoomMin2x32bpp, ///< Allow use of sprite min zoom setting at 2x in 32bpp mode.
|
||||
};
|
||||
|
||||
using SpriteCacheCtrlFlags = EnumBitSet<SpriteCacheCtrlFlag, uint8_t>;
|
||||
|
||||
#endif /* SPRITECACHE_TYPE_H */
|
|
@ -256,7 +256,7 @@ static ZoomLevels LoadSpriteV1(SpriteLoader::SpriteCollection &sprite, SpriteFil
|
|||
return {};
|
||||
}
|
||||
|
||||
static ZoomLevels LoadSpriteV2(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)
|
||||
static ZoomLevels LoadSpriteV2(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp)
|
||||
{
|
||||
static const ZoomLevel zoom_lvl_map[6] = {ZoomLevel::Normal, ZoomLevel::In4x, ZoomLevel::In2x, ZoomLevel::Out2x, ZoomLevel::Out4x, ZoomLevel::Out8x};
|
||||
|
||||
|
@ -295,11 +295,11 @@ static ZoomLevels LoadSpriteV2(SpriteLoader::SpriteCollection &sprite, SpriteFil
|
|||
is_wanted_zoom_lvl = true;
|
||||
ZoomLevel zoom_min = sprite_type == SpriteType::Font ? ZoomLevel::Min : _settings_client.gui.sprite_zoom_min;
|
||||
if (zoom_min >= ZoomLevel::In2x &&
|
||||
HasBit(control_flags, load_32bpp ? SCCF_ALLOW_ZOOM_MIN_2X_32BPP : SCCF_ALLOW_ZOOM_MIN_2X_PAL) && zoom_lvl < ZoomLevel::In2x) {
|
||||
control_flags.Test(load_32bpp ? SpriteCacheCtrlFlag::AllowZoomMin2x32bpp : SpriteCacheCtrlFlag::AllowZoomMin2xPal) && zoom_lvl < ZoomLevel::In2x) {
|
||||
is_wanted_zoom_lvl = false;
|
||||
}
|
||||
if (zoom_min >= ZoomLevel::Normal &&
|
||||
HasBit(control_flags, load_32bpp ? SCCF_ALLOW_ZOOM_MIN_1X_32BPP : SCCF_ALLOW_ZOOM_MIN_1X_PAL) && zoom_lvl < ZoomLevel::Normal) {
|
||||
control_flags.Test(load_32bpp ? SpriteCacheCtrlFlag::AllowZoomMin1x32bpp : SpriteCacheCtrlFlag::AllowZoomMin1xPal) && zoom_lvl < ZoomLevel::Normal) {
|
||||
is_wanted_zoom_lvl = false;
|
||||
}
|
||||
} else {
|
||||
|
@ -359,7 +359,7 @@ static ZoomLevels LoadSpriteV2(SpriteLoader::SpriteCollection &sprite, SpriteFil
|
|||
return loaded_sprites;
|
||||
}
|
||||
|
||||
ZoomLevels SpriteLoaderGrf::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)
|
||||
ZoomLevels SpriteLoaderGrf::LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp)
|
||||
{
|
||||
if (this->container_ver >= 2) {
|
||||
return LoadSpriteV2(sprite, file, file_pos, sprite_type, load_32bpp, control_flags, avail_8bpp, avail_32bpp);
|
||||
|
|
|
@ -17,7 +17,7 @@ class SpriteLoaderGrf : public SpriteLoader {
|
|||
uint8_t container_ver;
|
||||
public:
|
||||
SpriteLoaderGrf(uint8_t container_ver) : container_ver(container_ver) {}
|
||||
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;
|
||||
ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) override;
|
||||
};
|
||||
|
||||
#endif /* SPRITELOADER_GRF_HPP */
|
||||
|
|
|
@ -48,7 +48,7 @@ static void Convert32bppTo8bpp(SpriteLoader::Sprite &sprite)
|
|||
}
|
||||
}
|
||||
|
||||
ZoomLevels SpriteLoaderMakeIndexed::LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool, uint8_t control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp)
|
||||
ZoomLevels SpriteLoaderMakeIndexed::LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp)
|
||||
{
|
||||
ZoomLevels avail = this->baseloader.LoadSprite(sprite, file, file_pos, sprite_type, true, control_flags, avail_8bpp, avail_32bpp);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class SpriteLoaderMakeIndexed : public SpriteLoader {
|
|||
SpriteLoader &baseloader;
|
||||
public:
|
||||
SpriteLoaderMakeIndexed(SpriteLoader &baseloader) : baseloader(baseloader) {}
|
||||
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;
|
||||
ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) override;
|
||||
};
|
||||
|
||||
#endif /* SPRITELOADER_MAKEINDEXED_H */
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "../core/alloc_type.hpp"
|
||||
#include "../core/enum_type.hpp"
|
||||
#include "../gfx_type.h"
|
||||
#include "../spritecache_type.h"
|
||||
#include "sprite_file_type.hpp"
|
||||
|
||||
struct Sprite;
|
||||
|
@ -94,7 +95,7 @@ public:
|
|||
* @param[out] avail_32bpp Available 32bpp sprites.
|
||||
* @return Available sprites matching \a load_32bpp.
|
||||
*/
|
||||
virtual 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) = 0;
|
||||
virtual ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) = 0;
|
||||
|
||||
virtual ~SpriteLoader() = default;
|
||||
};
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "newgrf_text.h"
|
||||
#include "fileio_func.h"
|
||||
#include "signs_base.h"
|
||||
#include "fontdetection.h"
|
||||
#include "error.h"
|
||||
#include "error_func.h"
|
||||
#include "strings_func.h"
|
||||
|
@ -2278,7 +2277,7 @@ std::string_view GetCurrentLanguageIsoCode()
|
|||
*/
|
||||
bool MissingGlyphSearcher::FindMissingGlyphs()
|
||||
{
|
||||
InitFontCache(this->Monospace());
|
||||
FontCache::LoadFontCaches(this->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||
|
||||
this->Reset();
|
||||
for (auto text = this->NextString(); text.has_value(); text = this->NextString()) {
|
||||
|
@ -2376,7 +2375,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
|
|||
_fcsettings.mono.os_handle = nullptr;
|
||||
_fcsettings.medium.os_handle = nullptr;
|
||||
|
||||
bad_font = !SetFallbackFont(&_fcsettings, _langpack.langpack->isocode, searcher);
|
||||
bad_font = !FontProviderManager::FindFallbackFont(&_fcsettings, _langpack.langpack->isocode, searcher);
|
||||
|
||||
_fcsettings = std::move(backup);
|
||||
|
||||
|
@ -2395,7 +2394,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
|
|||
/* Our fallback font does miss characters too, so keep the
|
||||
* user chosen font as that is more likely to be any good than
|
||||
* the wild guess we made */
|
||||
InitFontCache(searcher->Monospace());
|
||||
FontCache::LoadFontCaches(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -2412,12 +2411,12 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
|
|||
ShowErrorMessage(GetEncodedString(STR_JUST_RAW_STRING, std::move(err_str)), {}, WL_WARNING);
|
||||
|
||||
/* Reset the font width */
|
||||
LoadStringWidthTable(searcher->Monospace());
|
||||
LoadStringWidthTable(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update the font with cache */
|
||||
LoadStringWidthTable(searcher->Monospace());
|
||||
LoadStringWidthTable(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||
|
||||
#if !(defined(WITH_ICU_I18N) && defined(WITH_HARFBUZZ)) && !defined(WITH_UNISCRIBE) && !defined(WITH_COCOA)
|
||||
/*
|
||||
|
|
|
@ -21,8 +21,6 @@ public:
|
|||
this->height = FontCache::GetDefaultFontHeight(this->fs);
|
||||
}
|
||||
|
||||
void SetUnicodeGlyph(char32_t, SpriteID) override {}
|
||||
void InitializeUnicodeGlyphMap() override {}
|
||||
void ClearFontCache() override {}
|
||||
const Sprite *GetGlyph(GlyphID) override { return nullptr; }
|
||||
uint GetGlyphWidth(GlyphID) override { return this->height / 2; }
|
||||
|
@ -34,7 +32,8 @@ public:
|
|||
static void InitializeFontCaches()
|
||||
{
|
||||
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
|
||||
if (FontCache::caches[fs] == nullptr) new MockFontCache(fs); /* FontCache inserts itself into to the cache. */
|
||||
if (FontCache::Get(fs) != nullptr) continue;
|
||||
FontCache::Register(std::make_unique<MockFontCache>(fs));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@ static bool MockLoadNextSprite(SpriteID load_index)
|
|||
sc->id = 0;
|
||||
sc->type = is_mapgen ? SpriteType::MapGen : SpriteType::Normal;
|
||||
sc->warned = false;
|
||||
sc->control_flags = 0;
|
||||
sc->control_flags = {};
|
||||
|
||||
/* Fill with empty sprites up until the default sprite count. */
|
||||
return load_index < SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT;
|
||||
|
|
|
@ -118,7 +118,7 @@ std::optional<std::string_view> VideoDriver_SDL_OpenGL::AllocateContext()
|
|||
}
|
||||
|
||||
this->gl_context = SDL_GL_CreateContext(this->sdl_window);
|
||||
if (this->gl_context == nullptr) return "SDL2: Can't active GL context";
|
||||
if (this->gl_context == nullptr) return "SDL2: Can't activate GL context";
|
||||
|
||||
ToggleVsync(_video_vsync);
|
||||
|
||||
|
|
|
@ -1541,7 +1541,7 @@ std::optional<std::string_view> VideoDriver_Win32OpenGL::AllocateContext()
|
|||
rc = wglCreateContext(this->dc);
|
||||
if (rc == nullptr) return "Can't create OpenGL context";
|
||||
}
|
||||
if (!wglMakeCurrent(this->dc, rc)) return "Can't active GL context";
|
||||
if (!wglMakeCurrent(this->dc, rc)) return "Can't activate GL context";
|
||||
|
||||
this->ToggleVsync(_video_vsync);
|
||||
|
||||
|
|
Loading…
Reference in New Issue