From fdf252990021fe80fd38686d6208e5eb50501aa2 Mon Sep 17 00:00:00 2001 From: Colin Snover Date: Mon, 15 Jul 2024 00:49:47 -0500 Subject: [PATCH] feat: Render SVGs at native resolution --- .../include/hex/ui/imgui_imhex_extensions.h | 9 +++-- .../source/ui/imgui_imhex_extensions.cpp | 39 +++++++++++++++++-- .../source/content/out_of_box_experience.cpp | 3 +- .../builtin/source/content/welcome_screen.cpp | 4 +- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h b/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h index 304b45c21b823..42f0fa94075e5 100644 --- a/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h +++ b/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h @@ -86,9 +86,9 @@ namespace ImGuiExt { static Texture fromGLTexture(unsigned int texture, int width, int height); static Texture fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter = Filter::Nearest); static Texture fromBitmap(std::span buffer, int width, int height, Filter filter = Filter::Nearest); - static Texture fromSVG(const char *path, int width = 0, int height = 0, Filter filter = Filter::Nearest); - static Texture fromSVG(const std::fs::path &path, int width = 0, int height = 0, Filter filter = Filter::Nearest); - static Texture fromSVG(std::span buffer, int width = 0, int height = 0, Filter filter = Filter::Nearest); + static Texture fromSVG(const char *path, int width = 0, int height = 0, float scale = 1.0f, Filter filter = Filter::Nearest); + static Texture fromSVG(const std::fs::path &path, int width = 0, int height = 0, float scale = 1.0f, Filter filter = Filter::Nearest); + static Texture fromSVG(std::span buffer, int width = 0, int height = 0, float scale = 1.0f, Filter filter = Filter::Nearest); ~Texture(); @@ -109,7 +109,7 @@ namespace ImGuiExt { } [[nodiscard]] auto getSize() const noexcept { - return ImVec2(m_width, m_height); + return ImVec2(float(m_width) / m_scale, float(m_height) / m_scale); } [[nodiscard]] constexpr auto getAspectRatio() const noexcept { @@ -121,6 +121,7 @@ namespace ImGuiExt { private: ImTextureID m_textureId = nullptr; int m_width = 0, m_height = 0; + float m_scale = 1.0f; }; float GetTextWrapPos(); diff --git a/lib/libimhex/source/ui/imgui_imhex_extensions.cpp b/lib/libimhex/source/ui/imgui_imhex_extensions.cpp index 5d4d6a589d484..c6083ae396de6 100644 --- a/lib/libimhex/source/ui/imgui_imhex_extensions.cpp +++ b/lib/libimhex/source/ui/imgui_imhex_extensions.cpp @@ -31,6 +31,23 @@ namespace ImGuiExt { namespace { + void adjustSVGScale(const lunasvg::Document *document, int &width, int &height, int scale) { + if (document->width() == 0 || document->height() == 0) + return; + + if (width == 0 && height == 0) { + width = document->width(); + height = document->height(); + } else if (width != 0 && height == 0) { + height = std::ceil(double(width) * document->height() / document->width()); + } else if (height != 0 && width == 0) { + width = std::ceil(double(height) * document->width() / document->height()); + } + + width *= scale; + height *= scale; + } + bool isOpenGLExtensionSupported(const char *name) { static std::set extensions; @@ -221,8 +238,13 @@ namespace ImGuiExt { return result; } - Texture Texture::fromSVG(const char *path, int width, int height, Filter filter) { + Texture Texture::fromSVG(const char *path, int width, int height, float scale, Filter filter) { auto document = lunasvg::Document::loadFromFile(path); + if (!document) + return {}; + + adjustSVGScale(document.get(), width, height, scale); + auto bitmap = document->renderToBitmap(width, height); auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter); @@ -230,17 +252,23 @@ namespace ImGuiExt { Texture result; result.m_width = bitmap.width(); result.m_height = bitmap.height(); + result.m_scale = scale; result.m_textureId = reinterpret_cast(static_cast(texture)); return result; } - Texture Texture::fromSVG(const std::fs::path &path, int width, int height, Filter filter) { - return Texture::fromSVG(wolv::util::toUTF8String(path).c_str(), width, height, filter); + Texture Texture::fromSVG(const std::fs::path &path, int width, int height, float scale, Filter filter) { + return Texture::fromSVG(wolv::util::toUTF8String(path).c_str(), width, height, scale, filter); } - Texture Texture::fromSVG(std::span buffer, int width, int height, Filter filter) { + Texture Texture::fromSVG(std::span buffer, int width, int height, float scale, Filter filter) { auto document = lunasvg::Document::loadFromData(reinterpret_cast(buffer.data()), buffer.size()); + if (!document) + return {}; + + adjustSVGScale(document.get(), width, height, scale); + auto bitmap = document->renderToBitmap(width, height); bitmap.convertToRGBA(); @@ -249,6 +277,7 @@ namespace ImGuiExt { Texture result; result.m_width = bitmap.width(); result.m_height = bitmap.height(); + result.m_scale = scale; result.m_textureId = reinterpret_cast(static_cast(texture)); return result; @@ -261,6 +290,7 @@ namespace ImGuiExt { m_textureId = other.m_textureId; m_width = other.m_width; m_height = other.m_height; + m_scale = other.m_scale; other.m_textureId = nullptr; } @@ -272,6 +302,7 @@ namespace ImGuiExt { m_textureId = other.m_textureId; m_width = other.m_width; m_height = other.m_height; + m_scale = other.m_scale; other.m_textureId = nullptr; diff --git a/plugins/builtin/source/content/out_of_box_experience.cpp b/plugins/builtin/source/content/out_of_box_experience.cpp index f57e43ba2e5e9..e32febaf21e66 100644 --- a/plugins/builtin/source/content/out_of_box_experience.cpp +++ b/plugins/builtin/source/content/out_of_box_experience.cpp @@ -442,7 +442,8 @@ namespace hex::plugin::builtin { ImHexApi::System::setWindowResizable(false); const auto imageTheme = ThemeManager::getImageTheme(); - s_imhexBanner = ImGuiExt::Texture::fromSVG(romfs::get(hex::format("assets/{}/banner.svg", imageTheme)).span()); + const auto scale = ImHexApi::System::getContentScale(); + s_imhexBanner = ImGuiExt::Texture::fromSVG(romfs::get(hex::format("assets/{}/banner.svg", imageTheme)).span(), 0, 0, scale); s_compassTexture = ImGuiExt::Texture::fromImage(romfs::get("assets/common/compass.png").span()); s_globeTexture = ImGuiExt::Texture::fromImage(romfs::get("assets/common/globe.png").span()); s_screenshotDescriptions = nlohmann::json::parse(romfs::get("assets/screenshot_descriptions.json").string()); diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index 320c13d156d29..48e01986c8772 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -524,7 +524,9 @@ namespace hex::plugin::builtin { }; auto changeTextureSvg = [&](const std::string &path, float width) { - return ImGuiExt::Texture::fromSVG(romfs::get(path).span(), width, 0, ImGuiExt::Texture::Filter::Linear); + // UI scaling is already baked into the width + const auto scale = ImHexApi::System::getContentScale(); + return ImGuiExt::Texture::fromSVG(romfs::get(path).span(), width, 0, scale, ImGuiExt::Texture::Filter::Linear); }; ThemeManager::changeTheme(theme);