diff --git a/CREDITS.md b/CREDITS.md index 8826c9dcfe..1988223bf9 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -56,6 +56,7 @@ - George - Canal/Lock graphics - Andrew Parkhouse (andythenorth) - River graphics - David Dallaston (Pikka) - Tram tracks +- Richard Wheeler (zephyris) - OpenTTD TrueType font - All Translators - For their support to make OpenTTD a truly international game - Bug Reporters - Thanks for all bug reports - Chris Sawyer - For an amazing game! diff --git a/docs/openttd.6 b/docs/openttd.6 index f45021503b..c1cbd88791 100644 --- a/docs/openttd.6 +++ b/docs/openttd.6 @@ -16,7 +16,6 @@ .Op Fl g Op Ar savegame .Op Fl G Ar seed .Op Fl I Ar graphicsset -.Op Fl l Ar host Ns Op : Ns Ar port .Op Fl m Ar driver .Op Fl M Ar musicset .Op Fl n Ar host Ns Oo : Ns Ar port Oc Ns Op # Ns Ar company @@ -82,9 +81,6 @@ Select the graphics set see .Fl h for a full list. -.It Fl l Ar host Ns Op : Ns Ar port -Redirect debug output; see -.Fl d . .It Fl m Ar driver Select the music driver .Ar driver ; diff --git a/media/baseset/CMakeLists.txt b/media/baseset/CMakeLists.txt index c01f080349..405e9bb039 100644 --- a/media/baseset/CMakeLists.txt +++ b/media/baseset/CMakeLists.txt @@ -17,6 +17,10 @@ set(BASESET_OTHER_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/openttd.grf ${CMAKE_CURRENT_SOURCE_DIR}/opntitle.dat ${CMAKE_CURRENT_SOURCE_DIR}/orig_extra.grf + ${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Sans.ttf + ${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Serif.ttf + ${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Small.ttf + ${CMAKE_CURRENT_SOURCE_DIR}/OpenTTD-Mono.ttf ${CMAKE_CURRENT_SOURCE_DIR}/innerhighlight.grf ${CMAKE_CURRENT_SOURCE_DIR}/progsignals.grf ${CMAKE_CURRENT_SOURCE_DIR}/extra_signals.grf @@ -73,7 +77,7 @@ foreach(BASESET_OTHER_SOURCE_FILE IN LISTS BASESET_OTHER_SOURCE_FILES) get_filename_component(BASESET_OTHER_SOURCE_FILE_NAME "${BASESET_OTHER_SOURCE_FILE}" NAME) set(BASESET_OTHER_BINARY_FILE "${CMAKE_BINARY_DIR}/baseset/${BASESET_OTHER_SOURCE_FILE_NAME}") - add_custom_command(OUTPUT ${BASESET_OTHER_BINARY_FILE} + add_custom_command_timestamp(OUTPUT ${BASESET_OTHER_BINARY_FILE} COMMAND ${CMAKE_COMMAND} -E copy ${BASESET_OTHER_SOURCE_FILE} ${BASESET_OTHER_BINARY_FILE} diff --git a/media/baseset/OpenTTD-Mono.ttf b/media/baseset/OpenTTD-Mono.ttf new file mode 100644 index 0000000000..678050e512 Binary files /dev/null and b/media/baseset/OpenTTD-Mono.ttf differ diff --git a/media/baseset/OpenTTD-Sans.ttf b/media/baseset/OpenTTD-Sans.ttf new file mode 100644 index 0000000000..3c97a65e14 Binary files /dev/null and b/media/baseset/OpenTTD-Sans.ttf differ diff --git a/media/baseset/OpenTTD-Serif.ttf b/media/baseset/OpenTTD-Serif.ttf new file mode 100644 index 0000000000..5a139b99f1 Binary files /dev/null and b/media/baseset/OpenTTD-Serif.ttf differ diff --git a/media/baseset/OpenTTD-Small.ttf b/media/baseset/OpenTTD-Small.ttf new file mode 100644 index 0000000000..5e702c1850 Binary files /dev/null and b/media/baseset/OpenTTD-Small.ttf differ diff --git a/media/baseset/OpenTTD-font.md b/media/baseset/OpenTTD-font.md new file mode 100644 index 0000000000..04cc878cf3 --- /dev/null +++ b/media/baseset/OpenTTD-font.md @@ -0,0 +1,6 @@ +# OpenTTD TrueType font + +The OpenTTD TrueType font was created by Zephyris and is maintained on [Github](https://github.com/zephyris/openttd-ttf). +It is licensed under GPL-2.0. + +The currently included files correspond to release v0.3. diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index f3da72a095..96f481576d 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1307,7 +1307,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li * @param selected Currently selected sort criterion. * @param button Widget button. */ -void DisplayVehicleSortDropDown(Window *w, const VehicleType vehicle_type, const int selected, const int button) +void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, WidgetID button) { uint32_t hidden_mask = 0; /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */ diff --git a/src/console.cpp b/src/console.cpp index 2b4f4a0cf0..cc86a8f725 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -96,7 +96,6 @@ void IConsolePrint(TextColour colour_code, const char *string) { assert(IsValidConsoleColour(colour_code)); - char *str; if (_redirect_console_to_client != INVALID_CLIENT_ID) { /* Redirect the string to the client */ NetworkServerSendRcon(_redirect_console_to_client, colour_code, string); @@ -110,22 +109,18 @@ void IConsolePrint(TextColour colour_code, const char *string) /* Create a copy of the string, strip it of colours and invalid * characters and (when applicable) assign it to the console buffer */ - str = stredup(string); - str_strip_colours(str); - StrMakeValidInPlace(str); + std::string str = StrMakeValid(string, SVS_NONE); if (_network_dedicated) { NetworkAdminConsole("console", str); - fprintf(stdout, "%s%s\n", log_prefix().GetLogPrefix(), str); + fprintf(stdout, "%s%s\n", log_prefix().GetLogPrefix(), str.c_str()); fflush(stdout); - IConsoleWriteToLogFile(str); - free(str); // free duplicated string since it's not used anymore + IConsoleWriteToLogFile(str.c_str()); return; } - IConsoleWriteToLogFile(str); - IConsoleGUIPrint(colour_code, str); - free(str); + IConsoleWriteToLogFile(str.c_str()); + IConsoleGUIPrint(colour_code, std::move(str)); } /** diff --git a/src/console_gui.cpp b/src/console_gui.cpp index 8723dee46f..167b83c87e 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -528,9 +528,9 @@ static void IConsoleTabCompletion() * @param colour_code the colour of the command. Red in case of errors, etc. * @param str the message entered or output on the console (notice, error, etc.) */ -void IConsoleGUIPrint(TextColour colour_code, char *str) +void IConsoleGUIPrint(TextColour colour_code, std::string str) { - _iconsole_buffer.push_front(IConsoleLine(str, colour_code)); + _iconsole_buffer.push_front(IConsoleLine(std::move(str), colour_code)); SetWindowDirty(WC_CONSOLE, 0); } diff --git a/src/console_internal.h b/src/console_internal.h index ac7c9caf54..91b837edb7 100644 --- a/src/console_internal.h +++ b/src/console_internal.h @@ -88,6 +88,6 @@ bool GetArgumentInteger(uint32_t *value, const char *arg); void IConsoleGUIInit(); void IConsoleGUIFree(); -void IConsoleGUIPrint(TextColour colour_code, char *string); +void IConsoleGUIPrint(TextColour colour_code, std::string str); #endif /* CONSOLE_INTERNAL_H */ diff --git a/src/debug.cpp b/src/debug.cpp index 2affce019d..4b4682bff4 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -26,7 +26,6 @@ #include "walltime_func.h" #include "network/network_admin.h" -SOCKET _debug_socket = INVALID_SOCKET; #if defined(RANDOM_DEBUG) && defined(UNIX) && defined(__GLIBC__) #include @@ -140,20 +139,7 @@ char *DumpDebugFacilityNames(char *buf, char *last) */ void debug_print(const char *dbg, const char *buf) { - if (_debug_socket != INVALID_SOCKET) { - char buf2[1024 + 32]; - seprintf(buf2, lastof(buf2), "%sdbg: [%s] %s\n", log_prefix().GetLogPrefix(), dbg, buf); - - /* Prevent sending a message concurrently, as that might cause interleaved messages. */ - static std::mutex _debug_socket_mutex; - std::lock_guard lock(_debug_socket_mutex); - - /* Sending out an error when this fails would be nice, however... the error - * would have to be send over this failing socket which won't work. */ - send(_debug_socket, buf2, (int)strlen(buf2), 0); - return; - } if (strcmp(dbg, "desync") == 0) { static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR); if (f != nullptr) { diff --git a/src/engine_gui.h b/src/engine_gui.h index 6abd3b986c..f36b2ea900 100644 --- a/src/engine_gui.h +++ b/src/engine_gui.h @@ -52,6 +52,6 @@ extern const StringID _engine_sort_listing[][14]; extern EngList_SortTypeFunction * const _engine_sort_functions[][13]; uint GetEngineListHeight(VehicleType type); -void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, int button); +void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, WidgetID button); #endif /* ENGINE_GUI_H */ diff --git a/src/fontcache.cpp b/src/fontcache.cpp index f95d1bcab3..543ed7d73e 100644 --- a/src/fontcache.cpp +++ b/src/fontcache.cpp @@ -18,6 +18,7 @@ #include "strings_func.h" #include "viewport_func.h" #include "window_func.h" +#include "fileio_func.h" #include "safeguards.h" @@ -78,7 +79,7 @@ bool GetFontAAState(FontSize size, bool check_blitter) /* AA is only supported for 32 bpp */ if (check_blitter && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false; - return GetFontCacheSubSetting(size)->aa; + return _fcsettings.global_aa || GetFontCacheSubSetting(size)->aa; } void SetFont(FontSize fontsize, const std::string &font, uint size, bool aa) @@ -126,13 +127,52 @@ void SetFont(FontSize fontsize, const std::string &font, uint size, bool aa) #ifdef WITH_FREETYPE extern void LoadFreeTypeFont(FontSize fs); +extern void LoadFreeTypeFont(FontSize fs, const std::string &file_name, uint size); extern void UninitFreeType(); #elif defined(_WIN32) extern void LoadWin32Font(FontSize fs); +extern void LoadWin32Font(FontSize fs, const std::string &file_name, uint size); #elif defined(WITH_COCOA) extern void LoadCoreTextFont(FontSize fs); +extern void LoadCoreTextFont(FontSize fs, const std::string &file_name, uint size); #endif +static void TryLoadDefaultTrueTypeFont([[maybe_unused]] FontSize fs) +{ +#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA) + std::string font_name{}; + switch (fs) { + case FS_NORMAL: + font_name = "OpenTTD-Sans.ttf"; + break; + case FS_SMALL: + font_name = "OpenTTD-Small.ttf"; + break; + case FS_LARGE: + font_name = "OpenTTD-Serif.ttf"; + break; + case FS_MONO: + font_name = "OpenTTD-Mono.ttf"; + break; + + default: NOT_REACHED(); + } + + /* Find font file. */ + std::string full_font = FioFindFullPath(BASESET_DIR, font_name); + if (!full_font.empty()) { + int size = FontCache::GetDefaultFontHeight(fs); +#ifdef WITH_FREETYPE + LoadFreeTypeFont(fs, full_font, size); +#elif defined(_WIN32) + LoadWin32Font(fs, full_font, size); +#elif defined(WITH_COCOA) + LoadCoreTextFont(fs, full_font, size); +#endif + } +#endif /* defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA) */ +} + /** * (Re)initialize the font cache related things, i.e. load the non-sprite fonts. * @param monospace Whether to initialise the monospace or regular fonts. @@ -147,13 +187,17 @@ void InitFontCache(bool monospace) FontCache *fc = FontCache::Get(fs); if (fc->HasParent()) delete fc; + if (!_fcsettings.prefer_sprite && GetFontCacheSubSetting(fs)->font.empty()) { + TryLoadDefaultTrueTypeFont(fs); + } else { #ifdef WITH_FREETYPE - LoadFreeTypeFont(fs); + LoadFreeTypeFont(fs); #elif defined(_WIN32) - LoadWin32Font(fs); + LoadWin32Font(fs); #elif defined(WITH_COCOA) - LoadCoreTextFont(fs); + LoadCoreTextFont(fs); #endif + } } } diff --git a/src/fontcache.h b/src/fontcache.h index 948bd2f8d1..6c47953105 100644 --- a/src/fontcache.h +++ b/src/fontcache.h @@ -114,9 +114,10 @@ public: /** * Map a character into a glyph. * @param key The character. + * @param fallback Allow fallback to the parent font. * @return The glyph ID used to draw the character. */ - virtual GlyphID MapCharToGlyph(char32_t key) = 0; + virtual GlyphID MapCharToGlyph(char32_t key, bool fallback = true) = 0; /** * Read a font table from the font. @@ -221,6 +222,8 @@ struct FontCacheSettings { FontCacheSubSetting medium; ///< The normal font size. FontCacheSubSetting large; ///< The largest font; mostly used for newspapers. FontCacheSubSetting mono; ///< The mono space font used for license/readme viewers. + bool prefer_sprite; ///< Whether to prefer the built-in sprite font over resizable fonts. + bool global_aa; ///< Whether to anti alias all font sizes. }; extern FontCacheSettings _fcsettings; diff --git a/src/fontcache/freetypefontcache.cpp b/src/fontcache/freetypefontcache.cpp index 4a64217224..3b1833eb0c 100644 --- a/src/fontcache/freetypefontcache.cpp +++ b/src/fontcache/freetypefontcache.cpp @@ -9,6 +9,7 @@ #include "../stdafx.h" #include "../debug.h" +#include "../debug_fmt.h" #include "../fontcache.h" #include "../fontdetection.h" #include "../blitter/factory.hpp" @@ -41,7 +42,7 @@ public: FreeTypeFontCache(FontSize fs, FT_Face face, int pixels); ~FreeTypeFontCache(); void ClearFontCache() override; - GlyphID MapCharToGlyph(char32_t key) override; + GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override; std::string GetFontName() override { return stdstr_fmt("%s, %s", face->family_name, face->style_name); } bool IsBuiltInFont() override { return false; } const void *GetOSHandle() override { return &face; } @@ -117,6 +118,42 @@ void FreeTypeFontCache::SetFontSize(FontSize, FT_Face, int pixels) font_height_cache[this->fs] = this->GetHeight(); } +static FT_Error LoadFont(FontSize fs, FT_Face face, const char *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, @@ -159,40 +196,40 @@ void LoadFreeTypeFont(FontSize fs) if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, &face); if (error == FT_Err_Ok) { - DEBUG(fontcache, 2, "Requested '%s', using '%s %s'", font_name, face->family_name, face->style_name); - - /* Attempt to select the unicode character map */ - 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; - } + error = LoadFont(fs, face, font_name, settings->size); + if (error != FT_Err_Ok) { + ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), error); } + } else { + FT_Done_Face(face); } +} - FT_Done_Face(face); +/** + * Load a TrueType font from a file. + * @param fs The font size to load. + * @param file_name Path to the font file. + * @param size Requested font size. + */ +void LoadFreeTypeFont(FontSize fs, const std::string &file_name, uint size) +{ + if (_library == nullptr) { + if (FT_Init_FreeType(&_library) != FT_Err_Ok) { + ShowInfo("Unable to initialize FreeType, using sprite fonts instead"); + return; + } - ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name, FontSizeToName(fs), error); - return; + Debug(fontcache, 2, "Initialized"); + } -found_face: - new FreeTypeFontCache(fs, face, settings->size); + FT_Face face = nullptr; + int32_t index = 0; + FT_Error error = FT_New_Face(_library, file_name.c_str(), index, &face); + if (error == FT_Err_Ok) { + LoadFont(fs, face, file_name.c_str(), size); + } else { + FT_Done_Face(face); + } } @@ -278,15 +315,17 @@ const Sprite *FreeTypeFontCache::InternalGetGlyph(GlyphID key, bool aa) } -GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key) +GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key, bool allow_fallback) { assert(IsPrintable(key)); - if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { + FT_UInt glyph = FT_Get_Char_Index(this->face, key); + + if (glyph == 0 && allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { return this->parent->MapCharToGlyph(key); } - return FT_Get_Char_Index(this->face, key); + return glyph; } const void *FreeTypeFontCache::InternalGetFontTable(uint32_t tag, size_t &length) diff --git a/src/fontcache/spritefontcache.h b/src/fontcache/spritefontcache.h index 628a6d08e1..e35cb1a5d6 100644 --- a/src/fontcache/spritefontcache.h +++ b/src/fontcache/spritefontcache.h @@ -29,7 +29,7 @@ public: const Sprite *GetGlyph(GlyphID key) override; uint GetGlyphWidth(GlyphID key) override; bool GetDrawGlyphShadow() override; - GlyphID MapCharToGlyph(char32_t key) override { assert(IsPrintable(key)); return SPRITE_GLYPH | key; } + GlyphID MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback = true) override { assert(IsPrintable(key)); return SPRITE_GLYPH | key; } const void *GetFontTable(uint32_t, size_t &length) override { length = 0; return nullptr; } std::string GetFontName() override { return "sprite"; } bool IsBuiltInFont() override { return true; } diff --git a/src/gfx.cpp b/src/gfx.cpp index 40e6ac28a3..fadd6d750a 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -600,6 +600,8 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left, bool draw_shadow = false; for (int run_index = 0; run_index < line.CountRuns(); run_index++) { const ParagraphLayouter::VisualRun &run = line.GetVisualRun(run_index); + const auto &glyphs = run.GetGlyphs(); + const auto &positions = run.GetPositions(); const Font *f = run.GetFont(); FontCache *fc = f->fc; @@ -613,14 +615,14 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left, draw_shadow = fc->GetDrawGlyphShadow() && (colour & TC_NO_SHADE) == 0 && (colour & ~TC_FORCED) != TC_BLACK; for (int i = 0; i < run.GetGlyphCount(); i++) { - GlyphID glyph = run.GetGlyphs()[i]; + GlyphID glyph = glyphs[i]; /* Not a valid glyph (empty) */ if (glyph == 0xFFFF) continue; - int begin_x = (int)run.GetPositions()[i * 2] + left - offset_x; - int end_x = (int)run.GetPositions()[i * 2 + 2] + left - offset_x - 1; - int top = (int)run.GetPositions()[i * 2 + 1] + y; + int begin_x = (int)positions[i * 2] + left - offset_x; + int end_x = (int)positions[i * 2 + 2] + left - offset_x - 1; + int top = (int)positions[i * 2 + 1] + y; /* Truncated away. */ if (truncation && (begin_x < min_x || end_x > max_x)) continue; @@ -2131,6 +2133,10 @@ bool ToggleFullScreen(bool fs) void SortResolutions() { std::sort(_resolutions.begin(), _resolutions.end()); + + /* Remove any duplicates from the list. */ + auto last = std::unique(_resolutions.begin(), _resolutions.end()); + _resolutions.erase(last, _resolutions.end()); } /** diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp index d8b4caa74d..b6f7519efe 100644 --- a/src/gfx_layout.cpp +++ b/src/gfx_layout.cpp @@ -257,11 +257,13 @@ Point Layouter::GetCharPosition(std::string_view::const_iterator ch) const /* Scan all runs until we've found our code point index. */ for (int run_index = 0; run_index < line->CountRuns(); run_index++) { const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index); + const auto &positions = run.GetPositions(); + const auto &charmap = run.GetGlyphToCharMap(); for (int i = 0; i < run.GetGlyphCount(); i++) { /* Matching glyph? Return position. */ - if ((size_t)run.GetGlyphToCharMap()[i] == index) { - Point p = { (int)run.GetPositions()[i * 2], (int)run.GetPositions()[i * 2 + 1] }; + if ((size_t)charmap[i] == index) { + Point p = { (int)positions[i * 2], (int)positions[i * 2 + 1] }; return p; } } @@ -285,17 +287,20 @@ ptrdiff_t Layouter::GetCharAtPosition(int x, size_t line_index) const for (int run_index = 0; run_index < line->CountRuns(); run_index++) { const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index); + const auto &glyphs = run.GetGlyphs(); + const auto &positions = run.GetPositions(); + const auto &charmap = run.GetGlyphToCharMap(); for (int i = 0; i < run.GetGlyphCount(); i++) { /* Not a valid glyph (empty). */ - if (run.GetGlyphs()[i] == 0xFFFF) continue; + if (glyphs[i] == 0xFFFF) continue; - int begin_x = (int)run.GetPositions()[i * 2]; - int end_x = (int)run.GetPositions()[i * 2 + 2]; + int begin_x = (int)positions[i * 2]; + int end_x = (int)positions[i * 2 + 2]; if (IsInsideMM(x, begin_x, end_x)) { /* Found our glyph, now convert to UTF-8 string index. */ - size_t index = run.GetGlyphToCharMap()[i]; + size_t index = charmap[i]; size_t cur_idx = 0; for (auto str = this->string.begin(); str != this->string.end();) { diff --git a/src/gfx_layout_icu.cpp b/src/gfx_layout_icu.cpp index 14cbf38294..5156a120f1 100644 --- a/src/gfx_layout_icu.cpp +++ b/src/gfx_layout_icu.cpp @@ -193,7 +193,7 @@ void ICURun::Shape(UChar *buff, size_t buff_length) for (unsigned int i = 0; i < glyph_count; i++) { int x_advance; - if (buff[glyph_info[i].cluster] >= SCC_SPRITE_START && buff[glyph_info[i].cluster] <= SCC_SPRITE_END) { + if (buff[glyph_info[i].cluster] >= SCC_SPRITE_START && buff[glyph_info[i].cluster] <= SCC_SPRITE_END && glyph_info[i].codepoint == 0) { auto glyph = this->font->fc->MapCharToGlyph(buff[glyph_info[i].cluster]); this->glyphs.push_back(glyph); diff --git a/src/gui.h b/src/gui.h index 2d63ca2d05..0cbf9ef9f0 100644 --- a/src/gui.h +++ b/src/gui.h @@ -43,17 +43,31 @@ void ShowHeightmapLoad(); /* misc_gui.cpp */ void ShowLandInfo(TileIndex tile); void ShowAboutWindow(); +void ShowEstimatedCostOrIncome(Money cost, int x, int y); + +/* tree_gui.cpp */ void ShowBuildTreesToolbar(); + +/* town_gui.cpp */ void ShowTownDirectory(); +void ShowFoundTownWindow(); + +/* industry_gui.cpp */ void ShowIndustryDirectory(); void ShowIndustryCargoesWindow(); +void ShowBuildIndustryWindow(); + +/* subsidy_gui.cpp */ void ShowSubsidiesList(); + +/* goal_gui.cpp */ void ShowGoalsList(CompanyID company); void ShowGoalQuestion(uint16_t id, byte type, uint32_t button_mask, const std::string &question); -void ShowStoryBook(CompanyID company, uint16_t page_id = INVALID_STORY_PAGE); -void ShowEstimatedCostOrIncome(Money cost, int x, int y); +/* story_gui.cpp */ +void ShowStoryBook(CompanyID company, uint16_t page_id = INVALID_STORY_PAGE); +/* viewport_gui.cpp */ void ShowExtraViewportWindow(TileIndex tile = INVALID_TILE); void ShowExtraViewportWindowForTileUnderCursor(); @@ -62,8 +76,7 @@ void ShowModifierKeyToggleWindow(); /* bridge_gui.cpp */ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte bridge_type); -void ShowBuildIndustryWindow(); -void ShowFoundTownWindow(); +/* music_gui.cpp */ void ShowMusicWindow(); #endif /* GUI_H */ diff --git a/src/help_gui.cpp b/src/help_gui.cpp index 60fde1db92..3c34b0fb0a 100644 --- a/src/help_gui.cpp +++ b/src/help_gui.cpp @@ -160,7 +160,7 @@ struct HelpWindow : public Window { } private: - void EnableTextfileButton(std::string_view filename, int button_widget) + void EnableTextfileButton(std::string_view filename, WidgetID button_widget) { this->GetWidget(button_widget)->SetDisabled(!FindGameManualFilePath(filename).has_value()); } diff --git a/src/lang/danish.txt b/src/lang/danish.txt index 01f78b0cd7..3a76f963b6 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -1002,6 +1002,7 @@ STR_GAME_OPTIONS_CURRENCY_HKD :Hong Kong Dolla STR_GAME_OPTIONS_CURRENCY_INR :Indisk rupi STR_GAME_OPTIONS_CURRENCY_IDR :Indonesisk Rupiah STR_GAME_OPTIONS_CURRENCY_MYR :Malaysisk Ringgit +STR_GAME_OPTIONS_CURRENCY_LVL :lettiske lats STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Automatisk gemning STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Vælg interval imellem automatisk gemning @@ -3016,7 +3017,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Ejer af STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Lokal myndighed: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ingen STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinater: {LTBLUE}{NUM}x{NUM}x{NUM} ({STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Produceret: {LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Bygget/renoveret: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stationsklasse: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stationstype: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Lufthavnsklasse: {LTBLUE}{STRING} diff --git a/src/lang/english.txt b/src/lang/english.txt index 05e58029a0..17eafcb7cc 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1044,6 +1044,11 @@ STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}Check th STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Scale bevels STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Check this box to scale bevels by interface size +STR_GAME_OPTIONS_GUI_FONT_SPRITE :{BLACK}Use traditional sprite font +STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Check this box if you prefer to use the tradition fixed-size sprite font. +STR_GAME_OPTIONS_GUI_FONT_AA :{BLACK}Anti-alias fonts +STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :{BLACK}Check this box to anti-alias resizable fonts. + STR_GAME_OPTIONS_GUI_SCALE_1X :1x STR_GAME_OPTIONS_GUI_SCALE_2X :2x STR_GAME_OPTIONS_GUI_SCALE_3X :3x diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index ceeec96b0c..32db2da2c0 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -3017,7 +3017,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Railway STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Local authority: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :None STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinates: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built/renovated: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Station class: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Station type: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Airport class: {LTBLUE}{STRING} diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 74201473de..d95cdb1a76 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -3017,7 +3017,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Railroad STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Local authority: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :None STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Co-ordinates: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built/renovated: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Station class: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Station type: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Airport class: {LTBLUE}{STRING} diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index e89aed2e72..a5065187e3 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -3017,7 +3017,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Rautatie STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Kunta: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Ei mitään STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaatit: {LTBLUE}{NUM}×{NUM}×{NUM} ({STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Rakennettu: {LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Rakennettu/peruskorjattu: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Aseman luokka: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Aseman tyyppi: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Lentokentän luokka: {LTBLUE}{STRING} diff --git a/src/lang/french.txt b/src/lang/french.txt index 886770b6e0..30bca63088 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -1003,7 +1003,7 @@ STR_GAME_OPTIONS_CURRENCY_HKD :Dollar de Hong STR_GAME_OPTIONS_CURRENCY_INR :Roupie indienne STR_GAME_OPTIONS_CURRENCY_IDR :Roupie indonésienne STR_GAME_OPTIONS_CURRENCY_MYR :Malaysian Ringgit -STR_GAME_OPTIONS_CURRENCY_LVL :Lats +STR_GAME_OPTIONS_CURRENCY_LVL :Lats letton STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Sauvegarde automatique STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Sélectionner l'intervalle de temps entre les sauvegardes automatiques @@ -3018,7 +3018,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Proprié STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Municipalité{NBSP}: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Aucune STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordonnées{NBSP}: {LTBLUE}{NUM} × {NUM} × {NUM} ({STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construit le{NBSP}: {LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construit/rénové le{NBSP}: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Type de station{NBSP}: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Type de station{NBSP}: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Type d'aéroport{NBSP}: {LTBLUE}{STRING} diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 30d3166d21..80dca843e0 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -2727,7 +2727,7 @@ STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}자동 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}차량기지를 건설합니다. 차량을 구입하거나 점검을 할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}선로에 경유지를 설치합니다. CTRL 키를 사용하면 같은 이름의 경유지를 서로 떨어진 곳에 지을 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}철도역을 짓습니다. CTRL 키를 사용하면 같은 이름의 역을 서로 떨어진 곳에 지을 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}신호기를 설치합니다. CTRL 키를 누르면 구식/전자식으로 전환합니다.{}선로를 따라 드래그해서 설치할 수 있습니다. CTRL 키를 누른 채로 드래그하면 다음 분기점이나 다음 신호기까지 신호기를 설치합니다.{}CTRL 키를 누른 채 클릭하면 신호기 선택 창을 전환합니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}선로에 신호기를 설치합니다. CTRL 키를 누르면 구식/전자식으로 전환합니다.{}선로를 따라 드래그해서 설치할 수 있습니다. CTRL 키를 누른 채로 드래그하면 다음 분기점이나 다음 신호기까지 신호기를 설치합니다.{}CTRL 키를 누른 채 클릭하면 신호기 선택 창을 전환합니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}철교를 짓습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}터널을 짓습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}선로, 신호기, 경유지, 역 등의 철도 시설 건설/철거 모드를 켜거나 끌 수 있습니다. CTRL 키를 누르고 있어도 선로에서 경유지와 역을 제거할 수 있습니다 diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index b8f669a30c..fc91c0bbcc 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -3018,7 +3018,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Dono da STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Autoridade local: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nenhum STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construído: {LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construído/renovado: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Tipo de estação: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Tipo de estação: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Tipo de aeroporto: {LTBLUE}{STRING} diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 93e988d6dd..51be414a6c 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -3192,7 +3192,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Влад STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Администрация: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Нет STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Координаты: {LTBLUE}{NUM} × {NUM} × {NUM} ({STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Построено: {LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Построено/обновлено: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Класс станции: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Тип станции: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Класс аэропорта: {LTBLUE}{STRING.nom} diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index f4eb7d732b..1b98880ebc 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -350,7 +350,7 @@ STR_SORT_BY_CARGO_CAPACITY :运载能力 STR_SORT_BY_RANGE :航行距离 STR_SORT_BY_POPULATION :人口 STR_SORT_BY_RATING :评价 -STR_SORT_BY_NUM_VEHICLES :交通工具数量 +STR_SORT_BY_NUM_VEHICLES :载具数量 STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :去年总利润 STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :今年总利润 STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :去年平均利润 @@ -1325,7 +1325,7 @@ STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :汽车斜坡坡度: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :设置对汽车而言,一格斜坡的坡度大小。数值越高,坡度越大,汽车越难爬上斜坡。 -STR_CONFIG_SETTING_FORBID_90_DEG :禁止列车 90 度转弯:{STRING} +STR_CONFIG_SETTING_FORBID_90_DEG :禁止列车直角转向:{STRING} STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :当水平方向轨道与垂直方向轨道交叉时,没有采用45度的轨道组合连接,而是采用轨道90度直接连接时,列车通过时需要90度转弯,当本设置”打开“时,将禁止火车90度转弯。 STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :允许非毗邻站台合并:{STRING} @@ -1344,7 +1344,7 @@ STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :隧道最大长 STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :建设隧道时允许的最大长度 STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :原料工业建设方式: {STRING} -STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :建立重工业企业的的设定. '禁止'表示不能建立; '勘探'表示可以建立但是只能在地图上一随机处, 并可能会失败; '像别的工业一样'表示采矿业也能像其它加工业那样可以随意在任何地方建立. +STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :设定原料工业的建造方式。“禁止”表示不能建造;“勘探”表示可以建立但是只能在地图上一随机处,并可能会失败;“同其他工业”表示可以和随意建造。 ###length 3 STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :不允许 STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :同其他工业 @@ -1911,7 +1911,7 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :四倍(原版 STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :线性 STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :树木自动生长: {STRING} -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :控制游戏中数目的随机生长,这将影响依赖树木的工业,比如木材厂 +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :控制游戏内树木的生长。此选项可能会影响一些依赖树木的工业,例如伐木场。 ###length 4 STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :生长但不扩散 {RED}(损坏伐木场) STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :仅在雨林扩散 @@ -2826,7 +2826,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}建设/ STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}转换/升级 公路类型。按住 Shift 键显示预计费用。 STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :转换/升级 电车道类型。按住 Shift 键显示预计费用。 -STR_ROAD_NAME_ROAD :路 +STR_ROAD_NAME_ROAD :公路 STR_ROAD_NAME_TRAM :电车轨道 # Road depot construction window @@ -3017,7 +3017,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}铁路 STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}地方政府:{LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :没有 STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}坐标: {LTBLUE}{NUM} × {NUM} × {NUM} ({STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}建造时间:{LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}建造/翻新于:{LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}车站分类: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}车站类型: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}飞机场分类: {LTBLUE}{STRING} @@ -3246,7 +3246,7 @@ STR_MAPGEN_DESERT_COVERAGE_TEXT :{BLACK}{NUM}% STR_MAPGEN_TERRAIN_TYPE :{BLACK}地形特点: STR_MAPGEN_SEA_LEVEL :{BLACK}海洋面积: STR_MAPGEN_SEA_LEVEL_TOOLTIP :{BLACK}选择海洋覆盖率 -STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}河流数量: +STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}河流数量: STR_MAPGEN_SMOOTHNESS :{BLACK}平滑程度: STR_MAPGEN_VARIETY :{BLACK}多样地形: STR_MAPGEN_GENERATE :{WHITE}生成 @@ -3854,7 +3854,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}运河 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}站台: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}车站 STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}机场 -STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}每年{CURRENCY_LONG} +STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/年 # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}工业设施 @@ -5625,7 +5625,7 @@ STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Powernaut 直 # Formatting of some strings STR_FORMAT_DATE_TINY :{ZEROFILL_NUM}-{ZEROFILL_NUM}-{NUM} STR_FORMAT_DATE_SHORT :{STRING} {NUM} -STR_FORMAT_DATE_LONG :{2:NUM}年 {1:STRING}月 {0:STRING}日 +STR_FORMAT_DATE_LONG :{2:NUM} 年 {1:STRING} 月 {0:STRING} 日 STR_FORMAT_DATE_ISO :{2:NUM}-{1:ZEROFILL_NUM}-{0:ZEROFILL_NUM} STR_FORMAT_COMPANY_NUM :(公司 {COMMA}) diff --git a/src/network/core/config.h b/src/network/core/config.h index bbf32e02e0..ccc962081a 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -24,7 +24,6 @@ static const uint16_t NETWORK_TURN_SERVER_PORT = 3974; ///< The static const uint16_t NETWORK_CONTENT_SERVER_PORT = 3978; ///< The default port of the content server (TCP) static const uint16_t NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP) static const uint16_t NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network -static const uint16_t NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP) static const uint16_t UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet static const uint16_t UDP_MTU_SHORT = 1400; ///< Number of bytes we can pack in a single UDP packet (conservative) diff --git a/src/network/network.cpp b/src/network/network.cpp index c47ae7a9fe..6c2b00084f 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -1376,32 +1376,6 @@ std::string NetworkGenerateRandomKeyString(uint bytes) return FormatArrayAsHex({key, bytes}); } -class TCPNetworkDebugConnecter : TCPConnecter { -private: - std::string connection_string; - -public: - TCPNetworkDebugConnecter(const std::string &connection_string) : TCPConnecter(connection_string, NETWORK_DEFAULT_DEBUGLOG_PORT), connection_string(connection_string) {} - - void OnFailure() override - { - DEBUG(net, 0, "Failed to open connection to %s for redirecting DEBUG()", this->connection_string.c_str()); - } - - void OnConnect(SOCKET s) override - { - DEBUG(net, 3, "Redirecting DEBUG() to %s", this->connection_string.c_str()); - - extern SOCKET _debug_socket; - _debug_socket = s; - } -}; - -void NetworkStartDebugLog(const std::string &connection_string) -{ - new TCPNetworkDebugConnecter(connection_string); -} - /** This tries to launch the network for a given OS */ void NetworkStartUp() { diff --git a/src/network/network_func.h b/src/network/network_func.h index a793654527..a4999b86ce 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -51,7 +51,6 @@ void NetworkDisconnect(bool close_admins = true); void NetworkGameLoop(); void NetworkBackgroundLoop(); std::string_view ParseFullConnectionString(const std::string &connection_string, uint16_t &port, CompanyID *company_id = nullptr); -void NetworkStartDebugLog(const std::string &connection_string); void NetworkPopulateCompanyStats(NetworkCompanyStats *stats); void NetworkUpdateClientInfo(ClientID client_id); diff --git a/src/openttd.cpp b/src/openttd.cpp index 8d46d260ff..4175b7ee78 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -290,7 +290,6 @@ static void ShowHelp() " -p password = Password to join server\n" " -P password = Password to join company\n" " -D [host][:port] = Start dedicated server\n" - " -l host[:port] = Redirect DEBUG()\n" #if !defined(_WIN32) " -f = Fork into the background (dedicated only)\n" #endif @@ -732,7 +731,6 @@ static const OptionData _options[] = { GETOPT_SHORT_VALUE('b'), GETOPT_SHORT_OPTVAL('D'), GETOPT_SHORT_VALUE('n'), - GETOPT_SHORT_VALUE('l'), GETOPT_SHORT_VALUE('p'), GETOPT_SHORT_VALUE('P'), #if !defined(_WIN32) @@ -777,7 +775,6 @@ int openttd_main(int argc, char *argv[]) Dimension resolution = {0, 0}; std::unique_ptr scanner(new AfterNewGRFScan()); bool dedicated = false; - char *debuglog_conn = nullptr; bool only_local_path = false; extern bool _dedicated_forks; @@ -814,9 +811,6 @@ int openttd_main(int argc, char *argv[]) case 'n': scanner->connection_string = mgo.opt; // host:port#company parameter break; - case 'l': - debuglog_conn = mgo.opt; - break; case 'p': scanner->join_server_password = mgo.opt; break; @@ -1028,10 +1022,6 @@ int openttd_main(int argc, char *argv[]) NetworkStartUp(); // initialize network-core - if (debuglog_conn != nullptr && _network_available) { - NetworkStartDebugLog(debuglog_conn); - } - if (!HandleBootstrap()) { ShutdownGame(); return ret; diff --git a/src/os/macosx/font_osx.cpp b/src/os/macosx/font_osx.cpp index b5b4c82630..ee9a4cb20f 100644 --- a/src/os/macosx/font_osx.cpp +++ b/src/os/macosx/font_osx.cpp @@ -9,6 +9,7 @@ #include "../../stdafx.h" #include "../../debug.h" +#include "../../debug_fmt.h" #include "font_osx.h" #include "../../core/math_func.hpp" #include "../../blitter/factory.hpp" @@ -182,14 +183,10 @@ void CoreTextFontCache::SetFontSize(int pixels) DEBUG(fontcache, 2, "Loaded font '%s' with size %d", this->font_name.c_str(), pixels); } -GlyphID CoreTextFontCache::MapCharToGlyph(char32_t key) +GlyphID CoreTextFontCache::MapCharToGlyph(char32_t key, bool allow_fallback) { assert(IsPrintable(key)); - if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { - return this->parent->MapCharToGlyph(key); - } - /* Convert characters outside of the Basic Multilingual Plane into surrogate pairs. */ UniChar chars[2]; if (key >= 0x010000U) { @@ -204,6 +201,10 @@ GlyphID CoreTextFontCache::MapCharToGlyph(char32_t key) return glyph[0]; } + if (allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { + return this->parent->MapCharToGlyph(key); + } + return 0; } @@ -300,6 +301,40 @@ const Sprite *CoreTextFontCache::InternalGetGlyph(GlyphID key, bool use_aa) return new_glyph.sprite; } +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 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 url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false)); + CFAutoRelease 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; +} + /** * Loads the TrueType font. * If a CoreText font description is present, e.g. from the automatic font @@ -320,33 +355,9 @@ void LoadCoreTextFont(FontSize fs) } if (!font_ref && MacOSVersionIsAtLeast(10, 6, 0)) { - /* Might be a font file name, try load it. Direct font loading is - * only supported starting on OSX 10.6. */ - CFAutoRelease path; - - /* See if this is an absolute path. */ - if (FileExists(settings->font)) { - path.reset(CFStringCreateWithCString(kCFAllocatorDefault, settings->font.c_str(), kCFStringEncodingUTF8)); - } else { - /* Scan the search-paths to see if it can be found. */ - std::string full_font = FioFindFullPath(BASE_DIR, settings->font); - 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 url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false)); - CFAutoRelease descs(CTFontManagerCreateFontDescriptorsFromURL(url.get())); - - if (descs && CFArrayGetCount(descs.get()) > 0) { - font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0)); - CFRetain(font_ref.get()); - } else { - ShowInfoF("Unable to load file '%s' for %s font, using default OS font selection instead", settings->font.c_str(), FontSizeToName(fs)); - } - } + /* Might be a font file name, try load it. */ + font_ref.reset(LoadFontFromFile(settings->font)); + if (!font_ref) ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", settings->font, FontSizeToName(fs)); } if (!font_ref) { @@ -374,3 +385,17 @@ void LoadCoreTextFont(FontSize fs) new CoreTextFontCache(fs, std::move(font_ref), settings->size); } + +/** + * Load a TrueType font from a file. + * @param fs The font size to load. + * @param file_name Path to the font file. + * @param size Requested font size. + */ +void LoadCoreTextFont(FontSize fs, const std::string &file_name, uint size) +{ + CFAutoRelease font_ref{LoadFontFromFile(file_name)}; + if (font_ref) { + new CoreTextFontCache(fs, std::move(font_ref), size); + } +} diff --git a/src/os/macosx/font_osx.h b/src/os/macosx/font_osx.h index ae1cb8feda..ca2ac1d5e9 100644 --- a/src/os/macosx/font_osx.h +++ b/src/os/macosx/font_osx.h @@ -29,12 +29,13 @@ public: ~CoreTextFontCache() {} void ClearFontCache() override; - GlyphID MapCharToGlyph(char32_t key) override; + GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override; std::string GetFontName() override { return font_name; } bool IsBuiltInFont() override { return false; } const void *GetOSHandle() override { return font.get(); } }; void LoadCoreTextFont(FontSize fs); +void LoadCoreTextFont(FontSize fs, const std::string &file_name, uint size); #endif /* FONT_OSX_H */ diff --git a/src/os/macosx/string_osx.cpp b/src/os/macosx/string_osx.cpp index 4a4d4cc80b..2426e6fd18 100644 --- a/src/os/macosx/string_osx.cpp +++ b/src/os/macosx/string_osx.cpp @@ -170,6 +170,9 @@ static CTRunDelegateCallbacks _sprite_font_callback = { CFAutoRelease base(CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buff, length, kCFAllocatorNull)); CFAttributedStringReplaceString(str.get(), CFRangeMake(0, 0), base.get()); + const UniChar replacment_char = 0xFFFC; + CFAutoRelease replacment_str(CFStringCreateWithCharacters(kCFAllocatorDefault, &replacment_char, 1)); + /* Apply font and colour ranges to our string. This is important to make sure * that we get proper glyph boundaries on style changes. */ int last = 0; @@ -191,10 +194,12 @@ static CTRunDelegateCallbacks _sprite_font_callback = { CFAttributedStringSetAttribute(str.get(), CFRangeMake(last, i.first - last), kCTForegroundColorAttributeName, color); CGColorRelease(color); - /* Install a size callback for our special sprite glyphs. */ + /* Install a size callback for our special private-use sprite glyphs in case the font does not provide them. */ for (ssize_t c = last; c < i.first; c++) { - if (buff[c] >= SCC_SPRITE_START && buff[c] <= SCC_SPRITE_END) { + if (buff[c] >= SCC_SPRITE_START && buff[c] <= SCC_SPRITE_END && i.second->fc->MapCharToGlyph(buff[c], false) == 0) { CFAutoRelease del(CTRunDelegateCreate(&_sprite_font_callback, (void *)(size_t)(buff[c] | (i.second->fc->GetSize() << 24)))); + /* According to the offical documentation, if a run delegate is used, the char should always be 0xFFFC. */ + CFAttributedStringReplaceString(str.get(), CFRangeMake(c, 1), replacment_str.get()); CFAttributedStringSetAttribute(str.get(), CFRangeMake(c, 1), kCTRunDelegateAttributeName, del.get()); } } @@ -244,7 +249,8 @@ CoreTextParagraphLayout::CoreTextVisualRun::CoreTextVisualRun(CTRunRef run, Font CGGlyph gl[this->glyphs.size()]; CTRunGetGlyphs(run, CFRangeMake(0, 0), gl); for (size_t i = 0; i < this->glyphs.size(); i++) { - if (buff[this->glyph_to_char[i]] >= SCC_SPRITE_START && buff[this->glyph_to_char[i]] <= SCC_SPRITE_END) { + if (buff[this->glyph_to_char[i]] >= SCC_SPRITE_START && buff[this->glyph_to_char[i]] <= SCC_SPRITE_END && (gl[i] == 0 || gl[i] == 3)) { + /* A glyph of 0 indidicates not found, while apparently 3 is what char 0xFFFC maps to. */ this->glyphs[i] = font->fc->MapCharToGlyph(buff[this->glyph_to_char[i]]); this->positions[i * 2 + 0] = pts[i].x; this->positions[i * 2 + 1] = (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2; // Align sprite font to centre diff --git a/src/os/windows/font_win32.cpp b/src/os/windows/font_win32.cpp index 132d51059b..c2172f861e 100644 --- a/src/os/windows/font_win32.cpp +++ b/src/os/windows/font_win32.cpp @@ -9,6 +9,7 @@ #include "../../stdafx.h" #include "../../debug.h" +#include "../../debug_fmt.h" #include "../../blitter/factory.hpp" #include "../../core/alloc_func.hpp" #include "../../core/math_func.hpp" @@ -279,14 +280,10 @@ void Win32FontCache::ClearFontCache() return new_glyph.sprite; } -/* virtual */ GlyphID Win32FontCache::MapCharToGlyph(char32_t key) +/* virtual */ GlyphID Win32FontCache::MapCharToGlyph(char32_t key, bool allow_fallback) { assert(IsPrintable(key)); - if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { - return this->parent->MapCharToGlyph(key); - } - /* Convert characters outside of the BMP into surrogate pairs. */ WCHAR chars[2]; if (key >= 0x010000U) { @@ -299,7 +296,8 @@ void Win32FontCache::ClearFontCache() WORD glyphs[2] = { 0, 0 }; GetGlyphIndicesW(this->dc, chars, key >= 0x010000U ? 2 : 1, glyphs, GGI_MARK_NONEXISTING_GLYPHS); - return glyphs[0] != 0xFFFF ? glyphs[0] : 0; + if (glyphs[0] != 0xFFFF) return glyphs[0]; + return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->parent->MapCharToGlyph(key) : 0; } /* virtual */ const void *Win32FontCache::InternalGetFontTable(uint32_t tag, size_t &length) @@ -317,6 +315,66 @@ void Win32FontCache::ClearFontCache() } +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, lengthof(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, lengthof(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 byte[len]; + if (GetFontResourceInfo(fontPath, &len, buf, 2)) { + logfont = *buf; // Just use first entry. + } + delete[](byte *)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 = strcasestr(font_name.c_str(), " bold") != nullptr || strcasestr(font_name.c_str(), "-bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts. + } + } + } + + return logfont.lfFaceName[0] != 0; +} + +static void LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, const char *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 @@ -341,50 +399,8 @@ void LoadWin32Font(FontSize fs) logfont = *(const LOGFONT *)settings->os_handle; } else if (strchr(font_name, '.') != nullptr) { /* Might be a font file name, try load it. */ - - wchar_t fontPath[MAX_PATH] = {}; - - /* See if this is an absolute path. */ - if (FileExists(settings->font)) { - convert_to_fs(font_name, fontPath, lengthof(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, lengthof(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 *)AllocaM(byte, len); - if (GetFontResourceInfo(fontPath, &len, buf, 2)) { - logfont = *buf; // Just use first entry. - } - } - } - - /* 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 = strcasestr(font_name, " bold") != nullptr || strcasestr(font_name, "-bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts. - } - } else { - ShowInfoF("Unable to load file '%s' for %s font, using default windows font selection instead", font_name, FontSizeToName(fs)); - } + if (!TryLoadFontFromFile(settings->font, logfont)) { + ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font_name, FontSizeToName(fs)); } } @@ -393,12 +409,25 @@ void LoadWin32Font(FontSize fs) convert_to_fs(font_name, logfont.lfFaceName, lengthof(logfont.lfFaceName)); } - HFONT font = CreateFontIndirect(&logfont); - if (font == nullptr) { - ShowInfoF("Unable to use '%s' for %s font, Win32 reported error 0x%lX, using sprite font instead", font_name, FontSizeToName(fs), GetLastError()); - return; - } - DeleteObject(font); + LoadWin32Font(fs, logfont, settings->size, font_name); +} + +/** + * Load a TrueType font from a file. + * @param fs The font size to load. + * @param file_name Path to the font file. + * @param size Requested font size. + */ +void LoadWin32Font(FontSize fs, const std::string &file_name, uint size) +{ + LOGFONT logfont; + MemSetT(&logfont, 0); + logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH; + logfont.lfCharSet = DEFAULT_CHARSET; + logfont.lfOutPrecision = OUT_OUTLINE_PRECIS; + logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; - new Win32FontCache(fs, logfont, settings->size); + if (TryLoadFontFromFile(file_name, logfont)) { + LoadWin32Font(fs, logfont, size, file_name.c_str()); + } } diff --git a/src/os/windows/font_win32.h b/src/os/windows/font_win32.h index 02a84b63fc..bdb2cc9a9b 100644 --- a/src/os/windows/font_win32.h +++ b/src/os/windows/font_win32.h @@ -35,11 +35,12 @@ public: Win32FontCache(FontSize fs, const LOGFONT &logfont, int pixels); ~Win32FontCache(); void ClearFontCache() override; - GlyphID MapCharToGlyph(char32_t key) override; + GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override; std::string GetFontName() override { return this->fontname; } const void *GetOSHandle() override { return &this->logfont; } }; void LoadWin32Font(FontSize fs); +void LoadWin32Font(FontSize fs, const std::string &file_name, uint size); #endif /* FONT_WIN32_H */ diff --git a/src/os/windows/string_uniscribe.cpp b/src/os/windows/string_uniscribe.cpp index b41fa75415..63da9c0bab 100644 --- a/src/os/windows/string_uniscribe.cpp +++ b/src/os/windows/string_uniscribe.cpp @@ -195,9 +195,11 @@ static bool UniscribeShapeRun(const UniscribeParagraphLayoutFactory::CharType *b for (int i = 0; i < range.len; i++) { if (buff[range.pos + i] >= SCC_SPRITE_START && buff[range.pos + i] <= SCC_SPRITE_END) { auto pos = range.char_to_glyph[i]; - range.ft_glyphs[pos] = range.font->fc->MapCharToGlyph(buff[range.pos + i]); - range.offsets[pos].dv = (range.font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(range.font->fc->GetSize()))) / 2; // Align sprite font to centre - range.advances[pos] = range.font->fc->GetGlyphWidth(range.ft_glyphs[pos]); + if (range.ft_glyphs[pos] == 0) { // Font doesn't have our special glyph, so remap. + range.ft_glyphs[pos] = range.font->fc->MapCharToGlyph(buff[range.pos + i]); + range.offsets[pos].dv = (range.font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(range.font->fc->GetSize()))) / 2; // Align sprite font to centre + range.advances[pos] = range.font->fc->GetGlyphWidth(range.ft_glyphs[pos]); + } } } diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index cbed715453..2508121b53 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -42,7 +42,7 @@ struct OskWindow : public Window { std::string orig_str; ///< Original string. bool shift; ///< Is the shift effectively pressed? - OskWindow(WindowDesc *desc, Window *parent, int button) : Window(desc) + OskWindow(WindowDesc *desc, Window *parent, WidgetID button) : Window(desc) { this->parent = parent; assert(parent != nullptr); diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 29ac0474de..1f580fec33 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -58,6 +58,10 @@ extern void FlushDeparturesWindowTextCaches(); +#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA) +# define HAS_TRUETYPE_FONT +#endif + static const StringID _autosave_dropdown[] = { STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_10_MINUTES, @@ -581,6 +585,31 @@ struct GameOptionsWindow : Window { break; } +#ifdef HAS_TRUETYPE_FONT + case WID_GO_GUI_FONT_SPRITE: + _fcsettings.prefer_sprite = !_fcsettings.prefer_sprite; + + this->SetWidgetLoweredState(WID_GO_GUI_FONT_SPRITE, _fcsettings.prefer_sprite); + this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite); + this->SetDirty(); + + InitFontCache(false); + InitFontCache(true); + ClearFontCache(); + SetupWidgetDimensions(); + ReInitAllWindows(true); + break; + + case WID_GO_GUI_FONT_AA: + _fcsettings.global_aa = !_fcsettings.global_aa; + + this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa); + this->SetDirty(); + + ClearFontCache(); + break; +#endif /* HAS_TRUETYPE_FONT */ + case WID_GO_GUI_SCALE_MAIN_TOOLBAR: { _settings_client.gui.bigger_main_toolbar = !_settings_client.gui.bigger_main_toolbar; @@ -813,6 +842,12 @@ struct GameOptionsWindow : Window { this->SetWidgetLoweredState(WID_GO_GUI_SCALE_AUTO, _gui_scale_cfg == -1); this->SetWidgetLoweredState(WID_GO_GUI_SCALE_BEVEL_BUTTON, _settings_client.gui.scale_bevels); +#ifdef HAS_TRUETYPE_FONT + this->SetWidgetLoweredState(WID_GO_GUI_FONT_SPRITE, _fcsettings.prefer_sprite); + this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa); + this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite); +#endif /* HAS_TRUETYPE_FONT */ + this->SetWidgetLoweredState(WID_GO_GUI_SCALE_MAIN_TOOLBAR, _settings_client.gui.bigger_main_toolbar); this->SetWidgetDisabledState(WID_GO_BASE_GRF_DROPDOWN, _game_mode != GM_MENU); @@ -892,6 +927,16 @@ static const NWidgetPart _nested_game_options_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(1, 0), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_SCALE_MAIN_TOOLBAR), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_SCALE_MAIN_TOOLBAR_TOOLTIP), EndContainer(), +#ifdef HAS_TRUETYPE_FONT + NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_GUI_FONT_SPRITE, STR_NULL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_FONT_SPRITE), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_GUI_FONT_AA, STR_NULL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_GUI_FONT_AA), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP), + EndContainer(), +#endif /* HAS_TRUETYPE_FONT */ EndContainer(), EndContainer(), diff --git a/src/table/settings/misc_settings.ini b/src/table/settings/misc_settings.ini index ce28aa57bf..8cbc50a696 100644 --- a/src/table/settings/misc_settings.ini +++ b/src/table/settings/misc_settings.ini @@ -268,6 +268,18 @@ name = ""mono_aa"" var = _fcsettings.mono.aa def = false +[SDTG_BOOL] +ifdef = HAS_TRUETYPE_FONT +name = ""global_aa"" +var = _fcsettings.global_aa +def = true + +[SDTG_BOOL] +ifdef = HAS_TRUETYPE_FONT +name = ""prefer_sprite_font"" +var = _fcsettings.prefer_sprite +def = false + [SDTG_VAR] name = ""sprite_cache_size_px"" type = SLE_UINT diff --git a/src/tests/mock_fontcache.h b/src/tests/mock_fontcache.h index c9eb326029..e6cee2d022 100644 --- a/src/tests/mock_fontcache.h +++ b/src/tests/mock_fontcache.h @@ -29,7 +29,7 @@ public: const Sprite *GetGlyph(GlyphID) override { return nullptr; } uint GetGlyphWidth(GlyphID) override { return this->height / 2; } bool GetDrawGlyphShadow() override { return false; } - GlyphID MapCharToGlyph(char32_t key) override { return key; } + GlyphID MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback = true) override { return key; } const void *GetFontTable(uint32_t, size_t &length) override { length = 0; return nullptr; } std::string GetFontName() override { return "mock"; } bool IsBuiltInFont() override { return true; } diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp index ff7f7ebd12..53f9788153 100644 --- a/src/video/sdl2_v.cpp +++ b/src/video/sdl2_v.cpp @@ -274,13 +274,15 @@ static void FindResolutions() { _resolutions.clear(); - for (int i = 0; i < SDL_GetNumDisplayModes(0); i++) { - SDL_DisplayMode mode; - SDL_GetDisplayMode(0, i, &mode); - - if (mode.w < 640 || mode.h < 480) continue; - if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(mode.w, mode.h)) != _resolutions.end()) continue; - _resolutions.emplace_back(mode.w, mode.h); + for (int display = 0; display < SDL_GetNumVideoDisplays(); display++) { + for (int i = 0; i < SDL_GetNumDisplayModes(display); i++) { + SDL_DisplayMode mode; + SDL_GetDisplayMode(display, i, &mode); + + if (mode.w < 640 || mode.h < 480) continue; + if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(mode.w, mode.h)) != _resolutions.end()) continue; + _resolutions.emplace_back(mode.w, mode.h); + } } /* We have found no resolutions, show the default list */ @@ -1003,7 +1005,7 @@ bool VideoDriver_SDL_Base::ToggleFullscreen(bool fullscreen) if (fullscreen) { /* Find fullscreen window size */ SDL_DisplayMode dm; - if (SDL_GetCurrentDisplayMode(0, &dm) < 0) { + if (SDL_GetCurrentDisplayMode(SDL_GetWindowDisplayIndex(this->sdl_window), &dm) < 0) { DEBUG(driver, 0, "SDL_GetCurrentDisplayMode() failed: %s", SDL_GetError()); } else { SDL_SetWindowSize(this->sdl_window, dm.w, dm.h); diff --git a/src/widgets/settings_widget.h b/src/widgets/settings_widget.h index 6bc7072c33..a3f8e6f559 100644 --- a/src/widgets/settings_widget.h +++ b/src/widgets/settings_widget.h @@ -25,6 +25,8 @@ enum GameOptionsWidgets : WidgetID { WID_GO_GUI_SCALE, ///< GUI Scale slider. WID_GO_GUI_SCALE_AUTO, ///< Autodetect GUI scale button. WID_GO_GUI_SCALE_BEVEL_BUTTON, ///< Toggle for chunky bevels. + WID_GO_GUI_FONT_SPRITE, ///< Toggle whether to prefer the sprite font over TTF fonts. + WID_GO_GUI_FONT_AA, ///< Toggle whether to anti-alias fonts. WID_GO_GUI_SCALE_MAIN_TOOLBAR, ///< Toggle for bigger main toolbar. WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF. WID_GO_BASE_GRF_PARAMETERS, ///< Base GRF parameters.