From beb7dd91bad6a153c0fdd496929a4b224a4e35af Mon Sep 17 00:00:00 2001 From: Gliniak Date: Sat, 25 Feb 2023 15:30:15 +0100 Subject: [PATCH] [UI] Allow loading custom font & changed default font on Windows - Unified font size to 12. This causes default UI to look a bit bigger - Set oversample to 2 to make font more readable (especially custom fonts) --- src/xenia/ui/imgui_drawer.cc | 166 ++++++++++++++++++++++++++++------- src/xenia/ui/imgui_drawer.h | 8 ++ 2 files changed, 142 insertions(+), 32 deletions(-) diff --git a/src/xenia/ui/imgui_drawer.cc b/src/xenia/ui/imgui_drawer.cc index f61bce2b5f4..a2eaa5437e4 100644 --- a/src/xenia/ui/imgui_drawer.cc +++ b/src/xenia/ui/imgui_drawer.cc @@ -21,6 +21,15 @@ #include "xenia/ui/ui_event.h" #include "xenia/ui/window.h" +#if XE_PLATFORM_WIN32 +#include +#endif + +DEFINE_path( + custom_font_path, "", + "Allows user to load custom font and use it instead of default one.", "UI"); +DEFINE_uint32(font_size, 12, "Allows user to set custom font size.", "UI"); + namespace xe { namespace ui { @@ -98,38 +107,7 @@ void ImGuiDrawer::Initialize() { internal_state_ = ImGui::CreateContext(); ImGui::SetCurrentContext(internal_state_); - auto& io = ImGui::GetIO(); - - // TODO(gibbed): disable imgui.ini saving for now, - // imgui assumes paths are char* so we can't throw a good path at it on - // Windows. - io.IniFilename = nullptr; - - // Setup the font glyphs. - ImFontConfig font_config; - font_config.OversampleH = font_config.OversampleV = 1; - font_config.PixelSnapH = true; - static const ImWchar font_glyph_ranges[] = { - 0x0020, - 0x00FF, // Basic Latin + Latin Supplement - 0, - }; - io.Fonts->AddFontFromMemoryCompressedBase85TTF( - kProggyTinyCompressedDataBase85, 10.0f, &font_config, font_glyph_ranges); - // TODO(benvanik): jp font on other platforms? - // https://github.com/Koruri/kibitaki looks really good, but is 1.5MiB. - const char* jp_font_path = "C:\\Windows\\Fonts\\msgothic.ttc"; - if (std::filesystem::exists(jp_font_path)) { - ImFontConfig jp_font_config; - jp_font_config.MergeMode = true; - jp_font_config.OversampleH = jp_font_config.OversampleV = 1; - jp_font_config.PixelSnapH = true; - jp_font_config.FontNo = 0; - io.Fonts->AddFontFromFileTTF(jp_font_path, 12.0f, &jp_font_config, - io.Fonts->GetGlyphRangesJapanese()); - } else { - XELOGW("Unable to load Japanese font; JP characters will be boxes"); - } + InitializeFonts(); auto& style = ImGui::GetStyle(); style.ScrollbarRounding = 0; @@ -218,6 +196,130 @@ std::optional ImGuiDrawer::VirtualKeyToImGuiKey(VirtualKey vkey) { } } +static const ImWchar font_glyph_ranges[] = { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0370, 0x03FF, // Greek + 0x0400, 0x044F, // Cyrillic + 0x2000, 0x206F, // General Punctuation + 0, +}; + +const std::filesystem::path ImGuiDrawer::GetWindowsFont(std::string font_name) { + std::filesystem::path font_path = ""; + +#if XE_PLATFORM_WIN32 + PWSTR fonts_dir; + HRESULT result = SHGetKnownFolderPath(FOLDERID_Fonts, 0, NULL, &fonts_dir); + if (FAILED(result)) { + CoTaskMemFree(static_cast(fonts_dir)); + return ""; + } + + font_path = std::wstring(fonts_dir); + CoTaskMemFree(static_cast(fonts_dir)); +#endif + font_path.append(font_name); + if (!std::filesystem::exists(font_path)) { + return ""; + } + + return font_path; +} + +bool ImGuiDrawer::LoadCustomFont(ImGuiIO& io, ImFontConfig& font_config, + const float font_size) { + if (cvars::custom_font_path.empty()) { + return false; + } + + if (!std::filesystem::exists(cvars::custom_font_path)) { + return false; + } + + const std::string font_path = xe::path_to_utf8(cvars::custom_font_path); + ImFont* font = io.Fonts->AddFontFromFileTTF(font_path.c_str(), font_size, + &font_config, font_glyph_ranges); + + io.Fonts->Build(); + + if (!font->IsLoaded()) { + XELOGE("Failed to load custom font: {}", font_path); + io.Fonts->Clear(); + return false; + } + return true; +} + +bool ImGuiDrawer::LoadWindowsFont(ImGuiIO& io, ImFontConfig& font_config, + const float font_size) { + const std::filesystem::path font_path = GetWindowsFont("tahoma.ttf"); + if (!std::filesystem::exists(font_path)) { + XELOGW( + "Unable to find tahoma font in Windows fonts directory. Switching to " + "embedded Xenia font"); + return false; + } + + ImFont* font = + io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(font_path).c_str(), + font_size, &font_config, font_glyph_ranges); + + io.Fonts->Build(); + // Something went wrong while loading custom font. Probably corrupted. + if (!font->IsLoaded()) { + XELOGE("Failed to load custom font: {}", xe::path_to_utf8(font_path)); + io.Fonts->Clear(); + } + return true; +} + +bool ImGuiDrawer::LoadJapaneseFont(ImGuiIO& io, const float font_size) { + // TODO(benvanik): jp font on other platforms? + const std::filesystem::path font_path = GetWindowsFont("msgothic.ttc"); + + if (!std::filesystem::exists(font_path)) { + XELOGW("Unable to load Japanese font; JP characters will be boxes"); + return false; + } + + ImFontConfig jp_font_config; + jp_font_config.MergeMode = true; + jp_font_config.OversampleH = jp_font_config.OversampleV = 2; + jp_font_config.PixelSnapH = true; + jp_font_config.FontNo = 0; + io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(font_path).c_str(), font_size, + &jp_font_config, + io.Fonts->GetGlyphRangesJapanese()); + return true; +}; + +void ImGuiDrawer::InitializeFonts() { + auto& io = ImGui::GetIO(); + + const float font_size = std::max((float)cvars::font_size, 8.f); + // TODO(gibbed): disable imgui.ini saving for now, + // imgui assumes paths are char* so we can't throw a good path at it on + // Windows. + io.IniFilename = nullptr; + + ImFontConfig font_config; + font_config.OversampleH = font_config.OversampleV = 2; + font_config.PixelSnapH = true; + + bool is_font_loaded = LoadCustomFont(io, font_config, font_size); + if (!is_font_loaded) { + is_font_loaded = LoadWindowsFont(io, font_config, font_size); + } + + if (io.Fonts->Fonts.empty()) { + io.Fonts->AddFontFromMemoryCompressedBase85TTF( + kProggyTinyCompressedDataBase85, font_size, &font_config, + io.Fonts->GetGlyphRangesDefault()); + } + + LoadJapaneseFont(io, font_size); +} + void ImGuiDrawer::SetupFontTexture() { if (font_texture_ || !immediate_drawer_) { return; diff --git a/src/xenia/ui/imgui_drawer.h b/src/xenia/ui/imgui_drawer.h index f5057f40338..8988f6f14d7 100644 --- a/src/xenia/ui/imgui_drawer.h +++ b/src/xenia/ui/imgui_drawer.h @@ -16,6 +16,7 @@ #include #include +#include "third_party/imgui/imgui.h" #include "xenia/ui/immediate_drawer.h" #include "xenia/ui/presenter.h" #include "xenia/ui/window.h" @@ -66,6 +67,13 @@ class ImGuiDrawer : public WindowInputListener, public UIDrawer { private: void Initialize(); + void InitializeFonts(); + bool LoadCustomFont(ImGuiIO& io, ImFontConfig& font_config, const float font_size); + bool LoadWindowsFont(ImGuiIO& io, ImFontConfig& font_config, + const float font_size); + bool LoadJapaneseFont(ImGuiIO& io, const float font_size); + + const std::filesystem::path GetWindowsFont(std::string font_name); void SetupFontTexture();