mirror of https://github.com/OpenTTD/OpenTTD
Compare commits
5 Commits
1a8a4c5782
...
604a7fb496
Author | SHA1 | Date |
---|---|---|
|
604a7fb496 | |
|
10eeba86a6 | |
|
d99dad9e9e | |
|
d5e0fa7a73 | |
|
b32f46f36e |
|
@ -187,7 +187,6 @@ add_files(
|
|||
fios_gui.cpp
|
||||
fontcache.cpp
|
||||
fontcache.h
|
||||
fontdetection.h
|
||||
framerate_gui.cpp
|
||||
framerate_type.h
|
||||
gamelog.cpp
|
||||
|
|
|
@ -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);
|
||||
FontCache::LoadFontCaches(fs);
|
||||
fc = FontCache::Get(fs);
|
||||
}
|
||||
IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** Clean everything up. */
|
||||
FontCache::~FontCache()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,7 +144,7 @@ void SetFont(FontSize fontsize, const std::string &font, uint size)
|
|||
CheckForMissingGlyphs();
|
||||
_fcsettings = std::move(backup);
|
||||
} else {
|
||||
InitFontCache(fontsize);
|
||||
FontCache::LoadFontCaches(fontsize);
|
||||
}
|
||||
|
||||
LoadStringWidthTable(fontsize);
|
||||
|
@ -136,15 +154,6 @@ void SetFont(FontSize fontsize, const std::string &font, uint size)
|
|||
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.
|
||||
|
@ -211,43 +220,55 @@ std::string GetFontCacheFontName(FontSize fs)
|
|||
return GetDefaultTruetypeFontFile(fs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a FontCache for its font size.
|
||||
* @param fc FontCache to register.
|
||||
*/
|
||||
/* 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.
|
||||
*/
|
||||
void InitFontCache(FontSizes fontsizes)
|
||||
/* static */ void FontCache::LoadFontCaches(FontSizes fontsizes)
|
||||
{
|
||||
FontCache::InitializeFontCaches();
|
||||
|
||||
for (FontSize fs : fontsizes) {
|
||||
FontCache *fc = FontCache::Get(fs);
|
||||
if (fc->HasParent()) delete fc;
|
||||
Layouter::ResetFontCache(fs);
|
||||
|
||||
#ifdef WITH_FREETYPE
|
||||
LoadFreeTypeFont(fs);
|
||||
#elif defined(_WIN32)
|
||||
LoadWin32Font(fs);
|
||||
#elif defined(WITH_COCOA)
|
||||
LoadCoreTextFont(fs);
|
||||
#endif
|
||||
/* Unload everything except the sprite font cache. */
|
||||
while (FontCache::Get(fs)->HasParent()) {
|
||||
FontCache::caches[fs] = std::move(FontCache::caches[fs]->parent);
|
||||
}
|
||||
|
||||
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);
|
||||
std::ranges::generate(FontCache::caches, []() { return nullptr; });
|
||||
}
|
||||
|
||||
#ifdef WITH_FREETYPE
|
||||
UninitFreeType();
|
||||
#endif /* WITH_FREETYPE */
|
||||
}
|
||||
|
||||
#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.
|
||||
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];
|
||||
|
@ -124,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);
|
||||
|
@ -143,13 +149,6 @@ public:
|
|||
virtual bool IsBuiltInFont() = 0;
|
||||
};
|
||||
|
||||
inline void ClearFontCache(FontSizes fontsizes)
|
||||
{
|
||||
for (FontSize fs : fontsizes) {
|
||||
FontCache::Get(fs)->ClearFontCache();
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the Sprite for a glyph */
|
||||
inline const Sprite *GetGlyph(FontSize size, char32_t key)
|
||||
{
|
||||
|
@ -207,12 +206,39 @@ inline FontCacheSubSetting *GetFontCacheSubSetting(FontSize fs)
|
|||
|
||||
uint GetFontCacheFontSize(FontSize fs);
|
||||
std::string GetFontCacheFontName(FontSize fs);
|
||||
void InitFontCache(FontSizes fontsizes);
|
||||
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);
|
||||
|
|
|
@ -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_Library _ft_library = nullptr;
|
||||
|
||||
class FreeTypeFontCacheFactory : public FontCacheFactory {
|
||||
public:
|
||||
FreeTypeFontCacheFactory() : FontCacheFactory("freetype", "FreeType font provider") {}
|
||||
|
||||
virtual ~FreeTypeFontCacheFactory()
|
||||
{
|
||||
FT_Done_FreeType(_ft_library);
|
||||
_ft_library = nullptr;
|
||||
}
|
||||
|
||||
#if !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;
|
||||
|
||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face) { return FT_Err_Cannot_Open_Resource; }
|
||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||
|
||||
#endif /* !defined(WITH_FONTCONFIG) */
|
||||
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 */
|
||||
|
|
|
@ -151,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;
|
||||
|
|
|
@ -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
|
|
@ -1253,7 +1253,7 @@ static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode,
|
|||
*/
|
||||
void LoadStringWidthTable(FontSizes fontsizes)
|
||||
{
|
||||
ClearFontCache(fontsizes);
|
||||
FontCache::ClearFontCaches(fontsizes);
|
||||
|
||||
for (FontSize fs : fontsizes) {
|
||||
for (uint i = 0; i != 224; i++) {
|
||||
|
@ -1820,7 +1820,7 @@ bool AdjustGUIZoom(bool automatic)
|
|||
if (old_font_zoom != _font_zoom) {
|
||||
GfxClearFontSpriteCache();
|
||||
}
|
||||
ClearFontCache(FONTSIZES_ALL);
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
LoadStringWidthTable();
|
||||
|
||||
SetupWidgetDimensions();
|
||||
|
|
|
@ -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(FONTSIZES_ALL);
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
GfxClearSpriteCache();
|
||||
ReInitAllWindows(false);
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ void CheckBlitter()
|
|||
{
|
||||
if (!SwitchNewGRFBlitter()) return;
|
||||
|
||||
ClearFontCache(FONTSIZES_ALL);
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
GfxClearSpriteCache();
|
||||
ReInitAllWindows(false);
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ void GfxLoadSprites()
|
|||
|
||||
SwitchNewGRFBlitter();
|
||||
VideoDriver::GetInstance()->ClearSystemSprites();
|
||||
ClearFontCache(FONTSIZES_ALL);
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
GfxInitSpriteMem();
|
||||
LoadSpriteTables();
|
||||
GfxInitPalettes();
|
||||
|
|
|
@ -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(FONTSIZES_REQUIRED);
|
||||
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,39 +201,9 @@ 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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
class CoreTextFontCacheFactory : public FontCacheFactory {
|
||||
public:
|
||||
CoreTextFontCacheFactory() : FontCacheFactory("coretext", "CoreText font loader") {}
|
||||
|
||||
/**
|
||||
* Loads the TrueType font.
|
||||
|
@ -327,12 +211,14 @@ static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
|
|||
* fallback search, use it. Otherwise, try to resolve it by font name.
|
||||
* @param fs The font size to load.
|
||||
*/
|
||||
void LoadCoreTextFont(FontSize fs)
|
||||
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;
|
||||
if (font.empty()) return nullptr;
|
||||
|
||||
CFAutoRelease<CTFontDescriptorRef> font_ref;
|
||||
|
||||
|
@ -367,8 +253,130 @@ void LoadCoreTextFont(FontSize fs)
|
|||
|
||||
if (!font_ref) {
|
||||
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
new CoreTextFontCache(fs, std::move(font_ref), GetFontCacheFontSize(fs));
|
||||
return std::make_unique<CoreTextFontCache>(fs, std::move(font_ref), GetFontCacheFontSize(fs));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||
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,6 +266,85 @@ 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") {}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -342,50 +394,6 @@ static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
|
|||
|
||||
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;
|
||||
|
|
|
@ -1036,8 +1036,8 @@ struct GameOptionsWindow : Window {
|
|||
this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite);
|
||||
this->SetDirty();
|
||||
|
||||
InitFontCache(FONTSIZES_ALL);
|
||||
ClearFontCache(FONTSIZES_ALL);
|
||||
FontCache::LoadFontCaches(FONTSIZES_ALL);
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
CheckForMissingGlyphs();
|
||||
SetupWidgetDimensions();
|
||||
UpdateAllVirtCoords();
|
||||
|
@ -1050,7 +1050,7 @@ struct GameOptionsWindow : Window {
|
|||
this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa);
|
||||
MarkWholeScreenDirty();
|
||||
|
||||
ClearFontCache(FONTSIZES_ALL);
|
||||
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||
break;
|
||||
#endif /* HAS_TRUETYPE_FONT */
|
||||
|
||||
|
|
|
@ -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() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||
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() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||
FontCache::LoadFontCaches(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -36,9 +36,14 @@
|
|||
# define MW(a) {a, PALETTE_TO_STRUCT_WHITE}
|
||||
# define MC(a) {a, PALETTE_TO_STRUCT_CONCRETE}
|
||||
|
||||
static const PalSpriteID _aqueduct_sprites[] = {
|
||||
{ SPR_AQUEDUCT_MIDDLE_X, PAL_NONE }, { 0x0, PAL_NONE }, { SPR_AQUEDUCT_PILLAR_X, PAL_NONE }, { 0x0, PAL_NONE },
|
||||
{ SPR_AQUEDUCT_MIDDLE_Y, PAL_NONE }, { 0x0, PAL_NONE }, { SPR_AQUEDUCT_PILLAR_Y, PAL_NONE }, { 0x0, PAL_NONE },
|
||||
/* Sprite table for middle part of aqueduct. */
|
||||
static const PalSpriteID _aqueduct_sprite_table_middle[] = {
|
||||
{SPR_AQUEDUCT_MIDDLE_X, PAL_NONE}, {0x0, PAL_NONE}, {SPR_AQUEDUCT_PILLAR_X, PAL_NONE}, {0x0, PAL_NONE}, // AXIS_X
|
||||
{SPR_AQUEDUCT_MIDDLE_Y, PAL_NONE}, {0x0, PAL_NONE}, {SPR_AQUEDUCT_PILLAR_Y, PAL_NONE}, {0x0, PAL_NONE}, // AIXS_Y
|
||||
};
|
||||
|
||||
/* Sprite table for head part of aqueduct. */
|
||||
static const PalSpriteID _aqueduct_sprite_table_heads[] = {
|
||||
{SPR_AQUEDUCT_RAMP_SW, PAL_NONE}, {SPR_AQUEDUCT_RAMP_SE, PAL_NONE}, {SPR_AQUEDUCT_RAMP_NE, PAL_NONE}, {SPR_AQUEDUCT_RAMP_NW, PAL_NONE},
|
||||
};
|
||||
|
||||
|
|
|
@ -32,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));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -138,15 +138,58 @@ bool HasBridgeFlatRamp(Slope tileh, Axis axis)
|
|||
return (tileh != SLOPE_FLAT);
|
||||
}
|
||||
|
||||
static inline std::span<const PalSpriteID> GetBridgeSpriteTable(int index, BridgePieces table)
|
||||
/**
|
||||
* Get the sprite table for a rail/road bridge piece.
|
||||
* @param bridge_type Bridge type.
|
||||
* @param piece Bridge piece.
|
||||
* @return Sprite table for the bridge piece.
|
||||
*/
|
||||
static std::span<const PalSpriteID> GetBridgeSpriteTable(BridgeType bridge_type, BridgePieces piece)
|
||||
{
|
||||
const BridgeSpec *bridge = GetBridgeSpec(index);
|
||||
assert(table < NUM_BRIDGE_PIECES);
|
||||
if (table < bridge->sprite_table.size() && !bridge->sprite_table[table].empty()) return bridge->sprite_table[table];
|
||||
assert(piece < NUM_BRIDGE_PIECES);
|
||||
|
||||
return _bridge_sprite_table[index][table];
|
||||
const BridgeSpec *bridge = GetBridgeSpec(bridge_type);
|
||||
if (piece < bridge->sprite_table.size() && !bridge->sprite_table[piece].empty()) return bridge->sprite_table[piece];
|
||||
|
||||
return _bridge_sprite_table[bridge_type][piece];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sprite table transport type base offset for a rail/road bridge.
|
||||
* @param transport_type Transport type of bridge.
|
||||
* @param ramp Tile of bridge ramp.
|
||||
* @return Offset for transport type.
|
||||
*/
|
||||
static uint8_t GetBridgeSpriteTableBaseOffset(TransportType transport_type, TileIndex ramp)
|
||||
{
|
||||
switch (transport_type) {
|
||||
case TRANSPORT_RAIL: return GetRailTypeInfo(GetRailType(ramp))->bridge_offset;
|
||||
case TRANSPORT_ROAD: return 8;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bridge sprite table base offset for the ramp part of bridge.
|
||||
* @param diagdir Direction of ramp.
|
||||
* @return Offset for direction.
|
||||
*/
|
||||
static uint8_t GetBridgeRampDirectionBaseOffset(DiagDirection diagdir)
|
||||
{
|
||||
/* Bridge ramps are ordered SW, SE, NE, NW instead of NE, SE, SW, NW. */
|
||||
static constexpr uint8_t ramp_offsets[DIAGDIR_END] = {2, 1, 0, 3};
|
||||
return ramp_offsets[diagdir];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bridge sprite table base offset for the middle part of bridge.
|
||||
* @param axis Axis of bridge.
|
||||
* @return Offset for axis.
|
||||
*/
|
||||
static uint8_t GetBridgeMiddleAxisBaseOffset(Axis axis)
|
||||
{
|
||||
return axis == AXIS_X ? 0 : 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the foundation for the bridge head, and tests if the resulting slope is valid.
|
||||
|
@ -1017,10 +1060,10 @@ static CommandCost ClearTile_TunnelBridge(TileIndex tile, DoCommandFlags flags)
|
|||
* @param h Bounding box size in Y direction
|
||||
* @param subsprite Optional subsprite for drawing halfpillars
|
||||
*/
|
||||
static inline void DrawPillar(const PalSpriteID *psid, int x, int y, int z, uint8_t w, uint8_t h, const SubSprite *subsprite)
|
||||
static inline void DrawPillar(const PalSpriteID &psid, int x, int y, int z, uint8_t w, uint8_t h, const SubSprite *subsprite)
|
||||
{
|
||||
static const int PILLAR_Z_OFFSET = TILE_HEIGHT - BRIDGE_Z_START; ///< Start offset of pillar wrt. bridge (downwards)
|
||||
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, -PILLAR_Z_OFFSET}, {w, h, BB_HEIGHT_UNDER_BRIDGE}, {0, 0, PILLAR_Z_OFFSET}}, IsTransparencySet(TO_BRIDGES), subsprite);
|
||||
AddSortableSpriteToDraw(psid.sprite, psid.pal, x, y, z, {{0, 0, -PILLAR_Z_OFFSET}, {w, h, BB_HEIGHT_UNDER_BRIDGE}, {0, 0, PILLAR_Z_OFFSET}}, IsTransparencySet(TO_BRIDGES), subsprite);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1034,7 +1077,7 @@ static inline void DrawPillar(const PalSpriteID *psid, int x, int y, int z, uint
|
|||
* @param h Bounding box size in Y direction
|
||||
* @return Reached Z at the bottom
|
||||
*/
|
||||
static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID *psid, int x, int y, int w, int h)
|
||||
static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID &psid, int x, int y, int w, int h)
|
||||
{
|
||||
int cur_z;
|
||||
for (cur_z = z_top; cur_z >= z_bottom; cur_z -= TILE_HEIGHT) {
|
||||
|
@ -1054,7 +1097,7 @@ static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID *psid, in
|
|||
* @param y Sprite Y position of front pillar.
|
||||
* @param z_bridge Absolute height of bridge bottom.
|
||||
*/
|
||||
static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo *ti, Axis axis, bool drawfarpillar, int x, int y, int z_bridge)
|
||||
static void DrawBridgePillars(const PalSpriteID &psid, const TileInfo *ti, Axis axis, bool drawfarpillar, int x, int y, int z_bridge)
|
||||
{
|
||||
static const int bounding_box_size[2] = {16, 2}; ///< bounding box size of pillars along bridge direction
|
||||
static const int back_pillar_offset[2] = { 0, 9}; ///< sprite position offset of back facing pillar
|
||||
|
@ -1065,7 +1108,7 @@ static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo *ti, Axis
|
|||
{ { -INF, -INF, 15, INF }, { 16, -INF, INF, INF } }, // Y axis, north and south
|
||||
};
|
||||
|
||||
if (psid->sprite == 0) return;
|
||||
if (psid.sprite == 0) return;
|
||||
|
||||
/* Determine ground height under pillars */
|
||||
DiagDirection south_dir = AxisToDiagDir(axis);
|
||||
|
@ -1404,34 +1447,20 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
|
|||
|
||||
DrawBridgeMiddle(ti);
|
||||
} else { // IsBridge(ti->tile)
|
||||
const PalSpriteID *psid;
|
||||
int base_offset;
|
||||
bool ice = HasTunnelBridgeSnowOrDesert(ti->tile);
|
||||
|
||||
if (transport_type == TRANSPORT_RAIL) {
|
||||
base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset;
|
||||
assert(base_offset != 8); // This one is used for roads
|
||||
} else {
|
||||
base_offset = 8;
|
||||
}
|
||||
|
||||
/* as the lower 3 bits are used for other stuff, make sure they are clear */
|
||||
assert( (base_offset & 0x07) == 0x00);
|
||||
|
||||
DrawFoundation(ti, GetBridgeFoundation(ti->tileh, DiagDirToAxis(tunnelbridge_direction)));
|
||||
|
||||
/* HACK Wizardry to convert the bridge ramp direction into a sprite offset */
|
||||
base_offset += (6 - tunnelbridge_direction) % 4;
|
||||
|
||||
/* Table number BRIDGE_PIECE_HEAD always refers to the bridge heads for any bridge type */
|
||||
uint base_offset = GetBridgeRampDirectionBaseOffset(tunnelbridge_direction);
|
||||
std::span<const PalSpriteID> psid;
|
||||
if (transport_type != TRANSPORT_WATER) {
|
||||
if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
|
||||
psid = &GetBridgeSpriteTable(GetBridgeType(ti->tile), BRIDGE_PIECE_HEAD)[base_offset];
|
||||
base_offset += GetBridgeSpriteTableBaseOffset(transport_type, ti->tile);
|
||||
psid = GetBridgeSpriteTable(GetBridgeType(ti->tile), BRIDGE_PIECE_HEAD);
|
||||
} else {
|
||||
psid = _aqueduct_sprites + base_offset;
|
||||
psid = _aqueduct_sprite_table_heads;
|
||||
}
|
||||
psid = psid.subspan(base_offset, 1);
|
||||
|
||||
if (!ice) {
|
||||
if (!HasTunnelBridgeSnowOrDesert(ti->tile)) {
|
||||
TileIndex next = ti->tile + TileOffsByDiagDir(tunnelbridge_direction);
|
||||
if (ti->tileh != SLOPE_FLAT && ti->z == 0 && HasTileWaterClass(next) && GetWaterClass(next) == WATER_CLASS_SEA) {
|
||||
DrawShoreTile(ti->tileh);
|
||||
|
@ -1451,7 +1480,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
|
|||
* it doesn't disappear behind it
|
||||
*/
|
||||
/* Bridge heads are drawn solid no matter how invisibility/transparency is set */
|
||||
AddSortableSpriteToDraw(psid->sprite, psid->pal, *ti, {{}, {TILE_SIZE, TILE_SIZE, static_cast<uint8_t>(ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)}, {}});
|
||||
AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, *ti, {{}, {TILE_SIZE, TILE_SIZE, static_cast<uint8_t>(ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)}, {}});
|
||||
|
||||
if (transport_type == TRANSPORT_ROAD) {
|
||||
uint offset = tunnelbridge_direction;
|
||||
|
@ -1572,33 +1601,21 @@ void DrawBridgeMiddle(const TileInfo *ti)
|
|||
TileIndex rampnorth = GetNorthernBridgeEnd(ti->tile);
|
||||
TileIndex rampsouth = GetSouthernBridgeEnd(ti->tile);
|
||||
TransportType transport_type = GetTunnelBridgeTransportType(rampsouth);
|
||||
|
||||
Axis axis = GetBridgeAxis(ti->tile);
|
||||
BridgePieces piece = CalcBridgePiece(
|
||||
GetTunnelBridgeLength(ti->tile, rampnorth) + 1,
|
||||
GetTunnelBridgeLength(ti->tile, rampsouth) + 1
|
||||
);
|
||||
|
||||
const PalSpriteID *psid;
|
||||
uint base_offset = GetBridgeMiddleAxisBaseOffset(axis);
|
||||
std::span<const PalSpriteID> psid;
|
||||
bool drawfarpillar;
|
||||
if (transport_type != TRANSPORT_WATER) {
|
||||
BridgeType type = GetBridgeType(rampsouth);
|
||||
drawfarpillar = !HasBit(GetBridgeSpec(type)->flags, 0);
|
||||
|
||||
uint base_offset;
|
||||
if (transport_type == TRANSPORT_RAIL) {
|
||||
base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
|
||||
} else {
|
||||
base_offset = 8;
|
||||
}
|
||||
|
||||
psid = &GetBridgeSpriteTable(type, piece)[base_offset];
|
||||
BridgeType bridge_type = GetBridgeType(rampsouth);
|
||||
drawfarpillar = !HasBit(GetBridgeSpec(bridge_type)->flags, 0);
|
||||
base_offset += GetBridgeSpriteTableBaseOffset(transport_type, rampsouth);
|
||||
psid = GetBridgeSpriteTable(bridge_type, CalcBridgePiece(GetTunnelBridgeLength(ti->tile, rampnorth) + 1, GetTunnelBridgeLength(ti->tile, rampsouth) + 1));
|
||||
} else {
|
||||
drawfarpillar = true;
|
||||
psid = _aqueduct_sprites;
|
||||
psid = _aqueduct_sprite_table_middle;
|
||||
}
|
||||
|
||||
if (axis != AXIS_X) psid += 4;
|
||||
psid = psid.subspan(base_offset, 3);
|
||||
|
||||
int x = ti->x;
|
||||
int y = ti->y;
|
||||
|
@ -1614,14 +1631,12 @@ void DrawBridgeMiddle(const TileInfo *ti)
|
|||
/* Draw floor and far part of bridge*/
|
||||
if (!IsInvisibilitySet(TO_BRIDGES)) {
|
||||
if (axis == AXIS_X) {
|
||||
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
|
||||
AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
|
||||
} else {
|
||||
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
|
||||
AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
|
||||
}
|
||||
}
|
||||
|
||||
psid++;
|
||||
|
||||
if (transport_type == TRANSPORT_ROAD) {
|
||||
/* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */
|
||||
DrawBridgeRoadBits(rampsouth, x, y, bridge_z, axis ^ 1, false);
|
||||
|
@ -1654,10 +1669,10 @@ void DrawBridgeMiddle(const TileInfo *ti)
|
|||
if (!IsInvisibilitySet(TO_BRIDGES)) {
|
||||
if (axis == AXIS_X) {
|
||||
y += 12;
|
||||
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 3, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, -3, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
|
||||
if (psid[1].sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid[1].sprite, psid[1].pal, x, y, z, {{0, 3, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, -3, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
|
||||
} else {
|
||||
x += 12;
|
||||
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{3, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {-3, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
|
||||
if (psid[1].sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid[1].sprite, psid[1].pal, x, y, z, {{3, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {-3, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1667,8 +1682,7 @@ void DrawBridgeMiddle(const TileInfo *ti)
|
|||
/* Do not draw anything more if bridges are invisible */
|
||||
if (IsInvisibilitySet(TO_BRIDGES)) return;
|
||||
|
||||
psid++;
|
||||
DrawBridgePillars(psid, ti, axis, drawfarpillar, x, y, z);
|
||||
DrawBridgePillars(psid[2], ti, axis, drawfarpillar, x, y, z);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue