From f49715c7a043929de8c509af73da25ac4e4ce1db Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sun, 16 Jun 2024 22:41:16 +0200 Subject: [PATCH] impr: Better font loading logic --- lib/libimhex/CMakeLists.txt | 2 +- lib/libimhex/source/api/imhex_api.cpp | 6 +- main/gui/source/window/window.cpp | 1 - plugins/builtin/source/content/init_tasks.cpp | 256 ------------- plugins/fonts/CMakeLists.txt | 1 + plugins/fonts/source/font_loader.cpp | 340 ++++++++++++++++++ plugins/fonts/source/fonts.cpp | 2 +- plugins/fonts/source/library_fonts.cpp | 7 +- 8 files changed, 351 insertions(+), 264 deletions(-) create mode 100644 plugins/fonts/source/font_loader.cpp diff --git a/lib/libimhex/CMakeLists.txt b/lib/libimhex/CMakeLists.txt index 6be34142f..25d8e163a 100644 --- a/lib/libimhex/CMakeLists.txt +++ b/lib/libimhex/CMakeLists.txt @@ -123,7 +123,7 @@ target_link_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_LIBRARY_DIR} if (NOT EMSCRIPTEN) # curl is only used in non-emscripten builds - target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${CURL_LIBRARIES}) + target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} CURL::libcurl) endif() diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index 3d306f898..eec325353 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -932,9 +932,9 @@ namespace hex { s_fontSize = size; } - static AutoReset> s_fontAtlas; + static AutoReset s_fontAtlas; void setFontAtlas(ImFontAtlas* fontAtlas) { - s_fontAtlas = std::unique_ptr(fontAtlas, IM_DELETE); + s_fontAtlas = fontAtlas; } static ImFont *s_boldFont = nullptr; @@ -1017,7 +1017,7 @@ namespace hex { } ImFontAtlas* getFontAtlas() { - return impl::s_fontAtlas->get(); + return impl::s_fontAtlas; } ImFont* Bold() { diff --git a/main/gui/source/window/window.cpp b/main/gui/source/window/window.cpp index c3520b5c7..783a82f03 100644 --- a/main/gui/source/window/window.cpp +++ b/main/gui/source/window/window.cpp @@ -270,7 +270,6 @@ namespace hex { glfwWaitEventsTimeout(targetFrameTime - frameTime); // glfwWaitEventsTimeout might return early if there's an event - const auto frameTime = glfwGetTime() - m_lastStartFrameTime; if (frameTime < targetFrameTime) { const auto timeToSleepMs = (int)((targetFrameTime - frameTime) * 1000); std::this_thread::sleep_for(std::chrono::milliseconds(timeToSleepMs)); diff --git a/plugins/builtin/source/content/init_tasks.cpp b/plugins/builtin/source/content/init_tasks.cpp index 5ea8b3728..785e277ff 100644 --- a/plugins/builtin/source/content/init_tasks.cpp +++ b/plugins/builtin/source/content/init_tasks.cpp @@ -4,18 +4,10 @@ #include #include -#include -#include #include -#include #include -#include -#include - -#include - namespace hex::plugin::builtin { namespace { @@ -119,253 +111,6 @@ namespace hex::plugin::builtin { return true; } - bool loadFontsImpl(bool loadUnicode) { - float defaultFontSize = ImHexApi::Fonts::DefaultFontSize * ImHexApi::System::getGlobalScale(); - - if (defaultFontSize == 0.0F) - defaultFontSize = ImHexApi::Fonts::DefaultFontSize; - - // Reset used font size back to the default size - ImHexApi::Fonts::impl::setFontSize(defaultFontSize); - - // Load custom font related settings - if (ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font_enable", false)) { - auto fontFile = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_path", ""); - if (!fontFile.empty()) { - if (!wolv::io::fs::exists(fontFile) || !wolv::io::fs::isRegularFile(fontFile)) { - log::warn("Custom font file {} not found! Falling back to default font.", wolv::util::toUTF8String(fontFile)); - fontFile.clear(); - } - - log::info("Loading custom font from {}", wolv::util::toUTF8String(fontFile)); - } - - // If no custom font has been specified, search for a file called "font.ttf" in one of the resource folders - if (fontFile.empty()) { - for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Resources)) { - auto path = dir / "font.ttf"; - if (wolv::io::fs::exists(path)) { - log::info("Loading custom font from {}", wolv::util::toUTF8String(path)); - - fontFile = path; - break; - } - } - } - - ImHexApi::Fonts::impl::setCustomFontPath(fontFile); - - // If a custom font has been loaded now, also load the font size - float fontSize = defaultFontSize; - if (!fontFile.empty()) { - fontSize = float(ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_size", 13)) * ImHexApi::System::getGlobalScale(); - } - - ImHexApi::Fonts::impl::setFontSize(fontSize); - } - - float fontSize = ImHexApi::Fonts::getFontSize(); - - const auto &fontFile = ImHexApi::Fonts::getCustomFontPath(); - - // Setup basic font configuration - auto fonts = IM_NEW(ImFontAtlas)(); - ImFontConfig cfg = {}; - cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true; - cfg.SizePixels = fontSize; - - fonts->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight; - fonts->TexDesiredWidth = 4096; - - // Configure font glyph ranges that should be loaded from the default font and unifont - static ImVector defaultGlyphRanges; - defaultGlyphRanges = { }; - { - ImFontGlyphRangesBuilder glyphRangesBuilder; - - { - constexpr static std::array controlCodeRange = { 0x0001, 0x001F, 0 }; - constexpr static std::array extendedAsciiRange = { 0x007F, 0x00FF, 0 }; - constexpr static std::array latinExtendedARange = { 0x0100, 0x017F, 0 }; - - glyphRangesBuilder.AddRanges(controlCodeRange.data()); - glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesDefault()); - glyphRangesBuilder.AddRanges(extendedAsciiRange.data()); - glyphRangesBuilder.AddRanges(latinExtendedARange.data()); - } - - if (loadUnicode) { - constexpr static std::array fullRange = { 0x0180, 0xFFEF, 0 }; - - glyphRangesBuilder.AddRanges(fullRange.data()); - } else { - glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesJapanese()); - glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesChineseFull()); - glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesCyrillic()); - glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesKorean()); - glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesThai()); - glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesVietnamese()); - } - - glyphRangesBuilder.BuildRanges(&defaultGlyphRanges); - } - - std::vector customFontData; - - if (fontFile.empty()) { - fonts->Clear(); - } else { - wolv::io::File file(fontFile, wolv::io::File::Mode::Read); - customFontData = file.readVector(); - } - - if (ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font_enable", false)) { - if (ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_bold", false)) - cfg.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Bold; - if (ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_italic", false)) - cfg.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Oblique; - if (!ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_antialias", true)) - cfg.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting; - } - - auto loadDefaultFont = [&](const char *fontName, u32 flags = 0) { - ImFontConfig defaultConfig = cfg; - - defaultConfig.FontBuilderFlags |= flags; - - std::strncpy(defaultConfig.Name, fontName, sizeof(defaultConfig.Name) - 1); - - if (!fontFile.empty()) { - if (!customFontData.empty()) { - defaultConfig.FontDataOwnedByAtlas = false; - return fonts->AddFontFromMemoryTTF(customFontData.data(), customFontData.size(), 0, &defaultConfig, defaultGlyphRanges.Data); - } - } - - defaultConfig.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting; - defaultConfig.SizePixels = std::floor(ImHexApi::Fonts::getFontSize() / ImHexApi::Fonts::DefaultFontSize) * ImHexApi::Fonts::DefaultFontSize; - - return fonts->AddFontDefault(&defaultConfig); - }; - - // Load main font - // If a custom font has been specified, load it, otherwise load the default ImGui font - ImFont *defaultFont = loadDefaultFont("Default Font"); - if (defaultFont == nullptr) { - log::warn("Failed to load custom font! Falling back to default font."); - - ImHexApi::Fonts::impl::setFontSize(defaultFontSize); - cfg.SizePixels = defaultFontSize; - defaultFont = fonts->AddFontDefault(&cfg); - } - - fonts->Build(); - - cfg.FontDataOwnedByAtlas = false; - - // Add all other fonts to the atlas - auto startFlags = cfg.FontBuilderFlags; - std::list> ranges; - for (auto &font : ImHexApi::Fonts::impl::getFonts()) { - ImVector fontRange; - if (font.glyphRanges.empty()) { - fontRange = defaultGlyphRanges; - } else { - for (const auto &range : font.glyphRanges) { - fontRange.push_back(range.begin); - fontRange.push_back(range.end); - } - fontRange.push_back(0x00); - } - - ranges.push_back(fontRange); - - cfg.FontBuilderFlags = font.flags; - - float descent = [&] { - ImFontAtlas atlas; - - // Disable merge mode for this font but retain the rest of the configuration - cfg.MergeMode = false; - - auto size = fontSize; - if (font.defaultSize.has_value()) - size = font.defaultSize.value() * std::floor(ImHexApi::Fonts::getFontSize() / ImHexApi::Fonts::DefaultFontSize); - else - size = std::max(1.0F, std::floor(size / ImHexApi::Fonts::DefaultFontSize)) * ImHexApi::Fonts::DefaultFontSize; - - cfg.SizePixels = size; - - ON_SCOPE_EXIT { cfg.MergeMode = true; }; - - // Construct a range that only contains the first glyph of the font - ImVector queryRange; - { - auto firstGlyph = font.glyphRanges.empty() ? defaultGlyphRanges.front() : font.glyphRanges.front().begin; - queryRange.push_back(firstGlyph); - queryRange.push_back(firstGlyph); - } - queryRange.push_back(0x00); - - // Build the font atlas with the query range - auto newFont = atlas.AddFontFromMemoryTTF(const_cast(font.fontData.data()), int(font.fontData.size()), 0, &cfg, queryRange.Data); - atlas.Build(); - - return newFont->Descent; - }(); - - - std::memset(cfg.Name, 0x00, sizeof(cfg.Name)); - std::strncpy(cfg.Name, font.name.c_str(), sizeof(cfg.Name) - 1); - cfg.GlyphOffset = { font.offset.x, font.offset.y - defaultFont->Descent + descent }; - fonts->AddFontFromMemoryTTF(const_cast(font.fontData.data()), int(font.fontData.size()), 0, &cfg, ranges.back().Data); - } - cfg.FontBuilderFlags = startFlags; - - // Create bold and italic font - cfg.MergeMode = false; - ImFont *boldFont = loadDefaultFont("Bold Font", ImGuiFreeTypeBuilderFlags_Bold); - ImFont *italicFont = loadDefaultFont("Italic Font", ImGuiFreeTypeBuilderFlags_Oblique); - ImHexApi::Fonts::impl::setFonts(boldFont, italicFont); - - // Try to build the font atlas - if (!fonts->Build()) { - // The main reason the font atlas failed to build is that the font is too big for the GPU to handle - // If unicode support is enabled, therefor try to load the font atlas without unicode support - // If that still didn't work, there's probably something else going on with the graphics drivers - // Especially Intel GPU drivers are known to have various bugs - - if (loadUnicode) { - log::error("Failed to build font atlas! Disabling Unicode support."); - IM_DELETE(fonts); - - // Disable unicode support in settings - ContentRegistry::Settings::write("hex.builtin.setting.font", "hex.builtin.setting.font.load_all_unicode_chars", false); - - // Try to load the font atlas again - return loadFontsImpl(false); - } else { - log::error("Failed to build font atlas! Check your Graphics driver!"); - return false; - } - } - - // Configure ImGui to use the font atlas - ImHexApi::Fonts::impl::setFontAtlas(fonts); - - return true; - } - - bool loadFonts() { - // Check if unicode support is enabled in the settings and that the user doesn't use the No GPU version on Windows - // The Mesa3D software renderer on Windows identifies itself as "VMware, Inc." - bool shouldLoadUnicode = - ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.load_all_unicode_chars", false) && - ImHexApi::System::getGPUVendor() != "VMware, Inc."; - - return loadFontsImpl(shouldLoadUnicode); - } - bool loadWindowSettings() { bool multiWindowEnabled = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", false); ImHexApi::System::impl::setMultiWindowMode(multiWindowEnabled); @@ -392,7 +137,6 @@ namespace hex::plugin::builtin { void addInitTasks() { ImHexApi::System::addStartupTask("Load Window Settings", false, loadWindowSettings); ImHexApi::System::addStartupTask("Configuring UI scale", true, configureUIScale); - ImHexApi::System::addStartupTask("Loading fonts", true, loadFonts); ImHexApi::System::addStartupTask("Checking for updates", true, checkForUpdates); } } \ No newline at end of file diff --git a/plugins/fonts/CMakeLists.txt b/plugins/fonts/CMakeLists.txt index cb76d2a11..0f4cfda12 100644 --- a/plugins/fonts/CMakeLists.txt +++ b/plugins/fonts/CMakeLists.txt @@ -7,6 +7,7 @@ add_imhex_plugin( fonts SOURCES source/library_fonts.cpp + source/font_loader.cpp source/fonts.cpp INCLUDES include diff --git a/plugins/fonts/source/font_loader.cpp b/plugins/fonts/source/font_loader.cpp new file mode 100644 index 000000000..dd6544422 --- /dev/null +++ b/plugins/fonts/source/font_loader.cpp @@ -0,0 +1,340 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include "wolv/io/file.hpp" +#include "hex/api/content_registry.hpp" +#include "hex/helpers/logger.hpp" +#include "wolv/utils/string.hpp" +#include "hex/helpers/fs.hpp" + +namespace hex::fonts { + + namespace { + + class Font { + public: + Font() = default; + + float getDescent() const { + return m_font->Descent; + } + + private: + explicit Font(ImFont *font) : m_font(font) { } + + private: + friend class FontAtlas; + + ImFont *m_font; + }; + + class FontAtlas { + public: + FontAtlas() : m_fontAtlas(IM_NEW(ImFontAtlas)) { + enableUnicodeCharacters(false); + + // Set the default configuration for the font atlas + m_config.OversampleH = m_config.OversampleV = 1; + m_config.PixelSnapH = true; + m_config.MergeMode = false; + + // Make sure the font atlas doesn't get too large, otherwise weaker GPUs might reject it + m_fontAtlas->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight; + m_fontAtlas->TexDesiredWidth = 4096; + } + + ~FontAtlas() { + IM_DELETE(m_fontAtlas); + } + + Font addDefaultFont() { + ImFontConfig config = m_config; + config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting; + config.SizePixels = std::floor(ImHexApi::System::getGlobalScale()) * 13.0F; + + auto font = m_fontAtlas->AddFontDefault(&config); + + m_config.MergeMode = true; + + return Font(font); + } + + Font addFontFromMemory(const std::vector &fontData, float fontSize, ImVec2 offset, bool ownedByImGui = false, const ImVector &glyphRange = {}) { + auto &storedFontData = m_fontData.emplace_back(fontData); + + ImFontConfig config = m_config; + config.FontDataOwnedByAtlas = ownedByImGui; + + config.GlyphOffset = { offset.x, offset.y }; + auto font = m_fontAtlas->AddFontFromMemoryTTF(storedFontData.data(), int(storedFontData.size()), fontSize, &config, !glyphRange.empty() ? glyphRange.Data : m_glyphRange.Data); + + m_config.MergeMode = true; + + return Font(font); + } + + Font addFontFromRomFs(const std::fs::path &path, float fontSize, ImVec2 offset, const ImVector &glyphRange = {}) { + auto data = romfs::get(path).span(); + return addFontFromMemory({ data.begin(), data.end() }, fontSize, offset, false, glyphRange); + } + + Font addFontFromFile(const std::fs::path &path, float fontSize, ImVec2 offset, const ImVector &glyphRange = {}) { + wolv::io::File file(path, wolv::io::File::Mode::Read); + + auto data = file.readVector(); + return addFontFromMemory(data, fontSize, offset, true, glyphRange); + } + + void setBold(bool enabled) { + if (enabled) + m_config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Bold; + else + m_config.FontBuilderFlags &= ~ImGuiFreeTypeBuilderFlags_Bold; + } + + void setItalic(bool enabled) { + if (enabled) + m_config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Oblique; + else + m_config.FontBuilderFlags &= ~ImGuiFreeTypeBuilderFlags_Oblique; + } + + void setAntiAliasing(bool enabled) { + if (enabled) + m_config.FontBuilderFlags &= ~ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting; + else + m_config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting; + } + + void enableUnicodeCharacters(bool enabled) { + ImFontGlyphRangesBuilder glyphRangesBuilder; + + { + constexpr static std::array controlCodeRange = { 0x0001, 0x001F, 0 }; + constexpr static std::array extendedAsciiRange = { 0x007F, 0x00FF, 0 }; + constexpr static std::array latinExtendedARange = { 0x0100, 0x017F, 0 }; + + glyphRangesBuilder.AddRanges(controlCodeRange.data()); + glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesDefault()); + glyphRangesBuilder.AddRanges(extendedAsciiRange.data()); + glyphRangesBuilder.AddRanges(latinExtendedARange.data()); + } + + if (enabled) { + constexpr static std::array fullRange = { 0x0180, 0xFFEF, 0 }; + + glyphRangesBuilder.AddRanges(fullRange.data()); + } else { + glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesJapanese()); + glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesChineseFull()); + glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesCyrillic()); + glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesKorean()); + glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesThai()); + glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesVietnamese()); + } + + m_glyphRange.clear(); + glyphRangesBuilder.BuildRanges(&m_glyphRange); + } + + bool build() const { + return m_fontAtlas->Build(); + } + + [[nodiscard]] ImFontAtlas* getAtlas() const { + return m_fontAtlas; + } + + float calculateFontDescend(const ImHexApi::Fonts::Font &font, float fontSize) const { + auto atlas = std::make_unique(); + auto cfg = m_config; + + // Calculate the expected font size + auto size = fontSize; + if (font.defaultSize.has_value()) + size = font.defaultSize.value() * std::floor(ImHexApi::Fonts::getFontSize() / ImHexApi::Fonts::DefaultFontSize); + else + size = std::max(1.0F, std::floor(size / ImHexApi::Fonts::DefaultFontSize)) * ImHexApi::Fonts::DefaultFontSize; + + cfg.MergeMode = false; + cfg.SizePixels = size; + cfg.FontDataOwnedByAtlas = false; + + // Construct a range that only contains the first glyph of the font + ImVector queryRange; + { + auto firstGlyph = font.glyphRanges.empty() ? m_glyphRange.front() : font.glyphRanges.front().begin; + queryRange.push_back(firstGlyph); + queryRange.push_back(firstGlyph); + } + queryRange.push_back(0x00); + + // Build the font atlas with the query range + auto newFont = atlas->AddFontFromMemoryTTF(const_cast(font.fontData.data()), int(font.fontData.size()), 0, &cfg, queryRange.Data); + atlas->Build(); + + return newFont->Descent; + } + + void reset() { + IM_DELETE(m_fontAtlas); + m_fontAtlas = IM_NEW(ImFontAtlas); + + m_fontData.clear(); + m_config.MergeMode = false; + } + + private: + ImFontAtlas* m_fontAtlas; + ImFontConfig m_config; + ImVector m_glyphRange; + + std::list> m_fontData; + }; + + std::fs::path findCustomFontPath() { + // Find the custom font file specified in the settings + auto fontFile = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_path", ""); + if (!fontFile.empty()) { + if (!wolv::io::fs::exists(fontFile) || !wolv::io::fs::isRegularFile(fontFile)) { + log::warn("Custom font file {} not found! Falling back to default font.", wolv::util::toUTF8String(fontFile)); + fontFile.clear(); + } + + log::info("Loading custom font from {}", wolv::util::toUTF8String(fontFile)); + } + + // If no custom font has been specified, search for a file called "font.ttf" in one of the resource folders + if (fontFile.empty()) { + for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Resources)) { + auto path = dir / "font.ttf"; + if (wolv::io::fs::exists(path)) { + log::info("Loading custom font from {}", wolv::util::toUTF8String(path)); + + fontFile = path; + break; + } + } + } + + return fontFile; + } + + float getFontSize() { + float fontSize = ImHexApi::Fonts::DefaultFontSize * ImHexApi::System::getGlobalScale(); + + // Fall back to the default font if the global scale is 0 + if (fontSize == 0.0F) + fontSize = ImHexApi::Fonts::DefaultFontSize; + + // If a custom font is used, adjust the font size + if (!ImHexApi::Fonts::getCustomFontPath().empty()) { + fontSize = float(ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_size", 13)) * ImHexApi::System::getGlobalScale(); + } + + return fontSize; + } + + } + + bool buildFontAtlasImpl(bool loadUnicodeCharacters) { + static FontAtlas fontAtlas; + fontAtlas.reset(); + + // Check if Unicode support is enabled in the settings and that the user doesn't use the No GPU version on Windows + // The Mesa3D software renderer on Windows identifies itself as "VMware, Inc." + bool shouldLoadUnicode = + ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.load_all_unicode_chars", false) && + ImHexApi::System::getGPUVendor() != "VMware, Inc."; + + if (!loadUnicodeCharacters) + shouldLoadUnicode = false; + + fontAtlas.enableUnicodeCharacters(shouldLoadUnicode); + + // If a custom font is set in the settings, load the rest of the settings as well + if (ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font_enable", false)) { + fontAtlas.setBold(ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_bold", false)); + fontAtlas.setItalic(ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_italic", false)); + fontAtlas.setAntiAliasing(ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_antialias", true)); + + ImHexApi::Fonts::impl::setCustomFontPath(findCustomFontPath()); + } + ImHexApi::Fonts::impl::setFontSize(getFontSize()); + + + const auto fontSize = ImHexApi::Fonts::getFontSize(); + const auto &customFontPath = ImHexApi::Fonts::getCustomFontPath(); + + // Try to load the custom font if one was set + std::optional defaultFont; + if (!customFontPath.empty()) { + defaultFont = fontAtlas.addFontFromFile(customFontPath, fontSize, ImVec2()); + if (!fontAtlas.build()) { + log::error("Failed to load custom font '{}'! Falling back to default font", wolv::util::toUTF8String(customFontPath)); + defaultFont.reset(); + } + } + + // If there's no custom font set, or it failed to load, fall back to the default font + if (!defaultFont.has_value()) { + defaultFont = fontAtlas.addDefaultFont(); + if (!fontAtlas.build()) { + log::fatal("Failed to load default font!"); + return false; + } + } + + + // Add all the built-in fonts + { + static std::list> glyphRanges; + glyphRanges.clear(); + + for (auto &font : ImHexApi::Fonts::impl::getFonts()) { + // Construct the glyph range for the font + ImVector glyphRange; + if (!font.glyphRanges.empty()) { + for (const auto &range : font.glyphRanges) { + glyphRange.push_back(range.begin); + glyphRange.push_back(range.end); + } + glyphRange.push_back(0x00); + } + glyphRanges.push_back(glyphRange); + + // Calculate the glyph offset for the font + ImVec2 offset = { font.offset.x, font.offset.y - defaultFont->getDescent() + fontAtlas.calculateFontDescend(font, fontSize) }; + + // Load the font + fontAtlas.addFontFromMemory(font.fontData, font.defaultSize.value_or(fontSize), offset, false, glyphRanges.back()); + } + } + + // Build the font atlas + const bool result = fontAtlas.build(); + if (result) { + // Set the font atlas if the build was successful + ImHexApi::Fonts::impl::setFontAtlas(fontAtlas.getAtlas()); + return true; + } + + // If the build wasn't successful and Unicode characters are enabled, try again without them + // If they were disabled already, something went wrong, and we can't recover from it + if (!shouldLoadUnicode) + return false; + else + return buildFontAtlasImpl(false); + } + + bool buildFontAtlas() { + return buildFontAtlasImpl(true); + } + +} \ No newline at end of file diff --git a/plugins/fonts/source/fonts.cpp b/plugins/fonts/source/fonts.cpp index 13671c0ed..16e993c69 100644 --- a/plugins/fonts/source/fonts.cpp +++ b/plugins/fonts/source/fonts.cpp @@ -9,7 +9,7 @@ namespace hex::fonts { - void loadFonts() { + void registerFonts() { using namespace ImHexApi::Fonts; /** diff --git a/plugins/fonts/source/library_fonts.cpp b/plugins/fonts/source/library_fonts.cpp index ceee11f02..20fb596dc 100644 --- a/plugins/fonts/source/library_fonts.cpp +++ b/plugins/fonts/source/library_fonts.cpp @@ -6,11 +6,14 @@ #include namespace hex::fonts { - void loadFonts(); + void registerFonts(); + + bool buildFontAtlas(); } IMHEX_LIBRARY_SETUP("Fonts") { hex::log::debug("Using romfs: '{}'", romfs::name()); - hex::fonts::loadFonts(); + hex::ImHexApi::System::addStartupTask("Loading fonts", true, hex::fonts::buildFontAtlas); + hex::fonts::registerFonts(); } \ No newline at end of file