FSUI: Use SVG icons for flags and stars
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 144 B |
|
Before Width: | Height: | Size: 322 B |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 261 B |
|
Before Width: | Height: | Size: 334 B |
|
Before Width: | Height: | Size: 361 B |
|
Before Width: | Height: | Size: 655 B |
|
Before Width: | Height: | Size: 247 B |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 265 B |
|
Before Width: | Height: | Size: 675 B |
|
Before Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 140 B |
|
Before Width: | Height: | Size: 265 B |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 587 B |
|
Before Width: | Height: | Size: 331 B |
|
Before Width: | Height: | Size: 751 B |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 296 B |
|
Before Width: | Height: | Size: 442 B |
|
Before Width: | Height: | Size: 534 B |
|
Before Width: | Height: | Size: 505 B |
|
Before Width: | Height: | Size: 442 B |
|
Before Width: | Height: | Size: 297 B |
@@ -94,6 +94,7 @@ using ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING;
|
||||
using ImGuiFullscreen::LAYOUT_MENU_BUTTON_Y_PADDING;
|
||||
using ImGuiFullscreen::LAYOUT_SCREEN_HEIGHT;
|
||||
using ImGuiFullscreen::LAYOUT_SCREEN_WIDTH;
|
||||
using ImGuiFullscreen::SvgScaling;
|
||||
using ImGuiFullscreen::UIBackgroundColor;
|
||||
using ImGuiFullscreen::UIBackgroundHighlightColor;
|
||||
using ImGuiFullscreen::UIBackgroundLineColor;
|
||||
@@ -131,6 +132,8 @@ using ImGuiFullscreen::EndNavBar;
|
||||
using ImGuiFullscreen::EnumChoiceButton;
|
||||
using ImGuiFullscreen::FloatingButton;
|
||||
using ImGuiFullscreen::ForceKeyNavEnabled;
|
||||
using ImGuiFullscreen::GetCachedSvgTexture;
|
||||
using ImGuiFullscreen::GetCachedSvgTextureAsync;
|
||||
using ImGuiFullscreen::GetCachedTexture;
|
||||
using ImGuiFullscreen::GetCachedTextureAsync;
|
||||
using ImGuiFullscreen::GetPlaceholderTexture;
|
||||
@@ -139,6 +142,7 @@ using ImGuiFullscreen::HorizontalMenuItem;
|
||||
using ImGuiFullscreen::IsFocusResetQueued;
|
||||
using ImGuiFullscreen::IsGamepadInputSource;
|
||||
using ImGuiFullscreen::LayoutScale;
|
||||
using ImGuiFullscreen::LoadSvgTexture;
|
||||
using ImGuiFullscreen::LoadTexture;
|
||||
using ImGuiFullscreen::MenuButton;
|
||||
using ImGuiFullscreen::MenuButtonFrame;
|
||||
@@ -237,6 +241,11 @@ namespace FullscreenUI
|
||||
static void GetStandardSelectionFooterText(SmallStringBase& dest, bool back_instead_of_cancel);
|
||||
static void ApplyLayoutSettings(const SettingsInterface* bsi = nullptr);
|
||||
|
||||
void DrawSvgTexture(GSTexture* padded_texture, ImVec2 unpadded_size);
|
||||
void DrawSvgTexture_UV(GSTexture* padded_texture, ImVec2 unpadded_size, ImVec2 unpadded_uv0, ImVec2 unpadded_uv1);
|
||||
void DrawCachedSvgTexture(const std::string& path, ImVec2 size, SvgScaling mode);
|
||||
void DrawCachedSvgTextureAsync(const std::string& path, ImVec2 size, SvgScaling mode);
|
||||
|
||||
static MainWindowType s_current_main_window = MainWindowType::None;
|
||||
static PauseSubMenu s_current_pause_submenu = PauseSubMenu::None;
|
||||
static bool s_initialized = false;
|
||||
@@ -256,6 +265,7 @@ namespace FullscreenUI
|
||||
// Resources
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
static bool LoadResources();
|
||||
static bool LoadSvgResources();
|
||||
static void DestroyResources();
|
||||
|
||||
static std::array<std::shared_ptr<GSTexture>, static_cast<u32>(GameDatabaseSchema::Compatibility::Perfect)>
|
||||
@@ -678,6 +688,34 @@ void FullscreenUI::GamepadLayoutChanged()
|
||||
ApplyLayoutSettings();
|
||||
}
|
||||
|
||||
// When drawing an svg to a non-integer size, we get a padded texture.
|
||||
// This function crops off this padding by setting the image UV for the draw.
|
||||
// We currently only use integer sizes for images, but I wrote this before checking that.
|
||||
void FullscreenUI::DrawSvgTexture(GSTexture* padded_texture, ImVec2 unpadded_size)
|
||||
{
|
||||
if (padded_texture != GetPlaceholderTexture().get())
|
||||
{
|
||||
const ImVec2 padded_size(padded_texture->GetWidth(), padded_texture->GetHeight());
|
||||
const ImVec2 uv1 = unpadded_size / padded_size;
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(padded_texture->GetNativeHandle()), unpadded_size, ImVec2(0.0f, 0.0f), uv1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Placeholder is a png file and should be scaled by ImGui
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(padded_texture->GetNativeHandle()), unpadded_size);
|
||||
}
|
||||
}
|
||||
|
||||
void FullscreenUI::DrawCachedSvgTexture(const std::string& path, ImVec2 size, SvgScaling mode)
|
||||
{
|
||||
DrawSvgTexture(GetCachedSvgTexture(path, size, mode), size);
|
||||
}
|
||||
|
||||
void FullscreenUI::DrawCachedSvgTextureAsync(const std::string& path, ImVec2 size, SvgScaling mode)
|
||||
{
|
||||
DrawSvgTexture(GetCachedSvgTextureAsync(path, size, mode), size);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Main
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -727,6 +765,11 @@ bool FullscreenUI::IsInitialized()
|
||||
return s_initialized;
|
||||
}
|
||||
|
||||
void FullscreenUI::ReloadSvgResources()
|
||||
{
|
||||
LoadSvgResources();
|
||||
}
|
||||
|
||||
bool FullscreenUI::HasActiveWindow()
|
||||
{
|
||||
return s_initialized && (s_current_main_window != MainWindowType::None || AreAnyDialogsOpen());
|
||||
@@ -1049,10 +1092,15 @@ bool FullscreenUI::LoadResources()
|
||||
s_fallback_disc_texture = LoadTexture("fullscreenui/media-cdrom.png");
|
||||
s_fallback_exe_texture = LoadTexture("fullscreenui/applications-system.png");
|
||||
|
||||
return LoadSvgResources();
|
||||
}
|
||||
|
||||
bool FullscreenUI::LoadSvgResources()
|
||||
{
|
||||
for (u32 i = static_cast<u32>(GameDatabaseSchema::Compatibility::Nothing);
|
||||
i <= static_cast<u32>(GameDatabaseSchema::Compatibility::Perfect); i++)
|
||||
{
|
||||
s_game_compatibility_textures[i - 1] = LoadTexture(fmt::format("fullscreenui/star-{}.png", i - 1).c_str());
|
||||
s_game_compatibility_textures[i - 1] = LoadSvgTexture(fmt::format("icons/star-{}.svg", i - 1).c_str(), LayoutScale(64.0f, 16.0f), SvgScaling::Fit);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -6497,10 +6545,13 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
|
||||
// region
|
||||
{
|
||||
std::string flag_texture(fmt::format("fullscreenui/flags/{}.png", GameList::RegionToString(selected_entry->region)));
|
||||
std::string flag_texture(fmt::format("icons/flags/{}.svg", GameList::RegionToString(selected_entry->region)));
|
||||
ImGui::TextUnformatted(FSUI_CSTR("Region: "));
|
||||
ImGui::SameLine();
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(GetCachedTextureAsync(flag_texture.c_str())->GetNativeHandle()), LayoutScale(23.0f, 16.0f));
|
||||
if (selected_entry->region == GameList::Region::Other)
|
||||
DrawCachedSvgTextureAsync(flag_texture, LayoutScale(23.0f, 16.0f), SvgScaling::Fit);
|
||||
else
|
||||
DrawCachedSvgTextureAsync(flag_texture, LayoutScale(23.0f, 16.0f), SvgScaling::ZoomFill);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text(" (%s)", GameList::RegionToString(selected_entry->region));
|
||||
}
|
||||
@@ -6510,8 +6561,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
ImGui::SameLine();
|
||||
if (selected_entry->compatibility_rating != GameDatabaseSchema::Compatibility::Unknown)
|
||||
{
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(s_game_compatibility_textures[static_cast<u32>(selected_entry->compatibility_rating) - 1]->GetNativeHandle()),
|
||||
LayoutScale(64.0f, 16.0f));
|
||||
DrawSvgTexture(s_game_compatibility_textures[static_cast<u32>(selected_entry->compatibility_rating) - 1].get(), LayoutScale(64.0f, 16.0f));
|
||||
ImGui::SameLine();
|
||||
}
|
||||
ImGui::Text(" (%s)", GameList::EntryCompatibilityRatingToString(selected_entry->compatibility_rating));
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace FullscreenUI
|
||||
{
|
||||
bool Initialize();
|
||||
bool IsInitialized();
|
||||
void ReloadSvgResources();
|
||||
bool HasActiveWindow();
|
||||
void CheckForConfigChanges(const Pcsx2Config& old_config);
|
||||
void OnVMStarted();
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include "imgui_internal.h"
|
||||
#include "imgui_stdlib.h"
|
||||
|
||||
#include <plutovg.h>
|
||||
#include <plutosvg.h>
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <condition_variable>
|
||||
@@ -41,6 +44,7 @@ namespace ImGuiFullscreen
|
||||
|
||||
static std::optional<RGBA8Image> LoadTextureImage(const char* path);
|
||||
static std::shared_ptr<GSTexture> UploadTexture(const char* path, const RGBA8Image& image);
|
||||
static std::optional<RGBA8Image> LoadSvgTextureImage(const char* path, ImVec2 size, SvgScaling mode);
|
||||
static void TextureLoaderThread();
|
||||
|
||||
static void DrawFileSelector();
|
||||
@@ -88,11 +92,13 @@ namespace ImGuiFullscreen
|
||||
static FocusResetType s_focus_reset_queued = FocusResetType::None;
|
||||
|
||||
static LRUCache<std::string, std::shared_ptr<GSTexture>> s_texture_cache(128, true);
|
||||
static LRUCache<std::string, std::vector<u8>> s_svg_data_cache(64, true);
|
||||
static std::shared_ptr<GSTexture> s_placeholder_texture;
|
||||
static std::atomic_bool s_texture_load_thread_quit{false};
|
||||
static std::mutex s_texture_load_mutex;
|
||||
static std::condition_variable s_texture_load_cv;
|
||||
static std::deque<std::string> s_texture_load_queue;
|
||||
static std::deque<std::tuple<std::string, ImVec2, SvgScaling>> s_svg_texture_load_queue;
|
||||
static std::deque<std::pair<std::string, RGBA8Image>> s_texture_upload_queue;
|
||||
static Threading::Thread s_texture_load_thread;
|
||||
|
||||
@@ -367,6 +373,166 @@ GSTexture* ImGuiFullscreen::GetCachedTextureAsync(std::string_view name)
|
||||
return tex_ptr->get();
|
||||
}
|
||||
|
||||
// Renders an SVG image to specified size into a texture of ceil(size).
|
||||
// The region donated by size is positioned top left of the image when size != ceil(size).
|
||||
// The image is scaled to fit within, and rendered center of, size.
|
||||
std::optional<RGBA8Image> ImGuiFullscreen::LoadSvgTextureImage(const char* path, ImVec2 size, SvgScaling mode)
|
||||
{
|
||||
std::optional<RGBA8Image> image;
|
||||
|
||||
// Cache SVG files as we may need to re-render at a new size later.
|
||||
std::vector<u8>* data_ptr = s_svg_data_cache.Lookup(path);
|
||||
if (!data_ptr)
|
||||
{
|
||||
std::optional<std::vector<u8>> data;
|
||||
if (Path::IsAbsolute(path))
|
||||
data = FileSystem::ReadBinaryFile(path);
|
||||
else
|
||||
data = FileSystem::ReadBinaryFile(Path::Combine(EmuFolders::Resources, path).c_str());
|
||||
if (data.has_value())
|
||||
data_ptr = s_svg_data_cache.Insert(std::string(path), std::move(data.value()));
|
||||
}
|
||||
|
||||
if (data_ptr)
|
||||
{
|
||||
// Load SVG
|
||||
plutosvg_document_t* pluto_svg = plutosvg_document_load_from_data(reinterpret_cast<char*>(data_ptr->data()),
|
||||
data_ptr->size(), -1, -1, nullptr, nullptr);
|
||||
|
||||
if (pluto_svg == nullptr)
|
||||
{
|
||||
Console.Error("Failed to load svg '%s'", path);
|
||||
return image;
|
||||
}
|
||||
|
||||
const float base_width = plutosvg_document_get_width(pluto_svg);
|
||||
const float base_height = plutosvg_document_get_height(pluto_svg);
|
||||
|
||||
// Create a surface large enough to store the SVG.
|
||||
const int px_width = std::ceil(size.x);
|
||||
const int px_height = std::ceil(size.y);
|
||||
|
||||
std::vector<u32> pixel_data;
|
||||
pixel_data.resize(px_width * px_height);
|
||||
|
||||
plutovg_surface_t* pluto_surface = plutovg_surface_create_for_data(reinterpret_cast<unsigned char*>(pixel_data.data()),
|
||||
px_width, px_height, px_width * 4);
|
||||
if (pluto_surface == nullptr)
|
||||
{
|
||||
plutosvg_document_destroy(pluto_svg);
|
||||
Console.Error("Failed to create plutovg surface '%s'", path);
|
||||
return image;
|
||||
}
|
||||
|
||||
// Create a drawing canvas.
|
||||
plutovg_canvas_t* pluto_canvas = plutovg_canvas_create(pluto_surface);
|
||||
if (pluto_canvas == nullptr)
|
||||
{
|
||||
plutovg_surface_destroy(pluto_surface);
|
||||
plutosvg_document_destroy(pluto_svg);
|
||||
Console.Error("Failed to create plutovg canvas '%s'", path);
|
||||
return image;
|
||||
}
|
||||
|
||||
// Scale & position SVG.
|
||||
// ImGui positions images from top left, so we can ignore integer size of surface.
|
||||
switch (mode)
|
||||
{
|
||||
case SvgScaling::Stretch:
|
||||
plutovg_canvas_scale(pluto_canvas, size.x / base_width, size.y / base_height);
|
||||
break;
|
||||
case SvgScaling::Fit:
|
||||
{
|
||||
const ImRect rect = CenterImage(size, {base_width, base_height}, false);
|
||||
const float scale = (rect.Max.y - rect.Min.y) / base_height;
|
||||
plutovg_canvas_scale(pluto_canvas, scale, scale);
|
||||
plutovg_canvas_translate(pluto_canvas, rect.Min.x / scale, rect.Min.y / scale);
|
||||
break;
|
||||
}
|
||||
case SvgScaling::ZoomFill:
|
||||
{
|
||||
const ImRect rect = CenterImage(size, {base_width, base_height}, true);
|
||||
const float scale = (rect.Max.y - rect.Min.y) / base_height;
|
||||
plutovg_canvas_scale(pluto_canvas, scale, scale);
|
||||
plutovg_canvas_translate(pluto_canvas, rect.Min.x / scale, rect.Min.y / scale);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Render
|
||||
const bool success = plutosvg_document_render(pluto_svg, nullptr, pluto_canvas, nullptr, nullptr, nullptr);
|
||||
|
||||
// Free pluto objects
|
||||
plutovg_canvas_destroy(pluto_canvas);
|
||||
plutovg_surface_destroy(pluto_surface);
|
||||
plutosvg_document_destroy(pluto_svg);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
Console.Error("Failed to render svg '%s'", path);
|
||||
return image;
|
||||
}
|
||||
|
||||
// Convert to RGBA8Image
|
||||
plutovg_convert_argb_to_rgba(reinterpret_cast<unsigned char*>(pixel_data.data()), reinterpret_cast<unsigned char*>(pixel_data.data()),
|
||||
px_width, px_height, px_width * 4);
|
||||
image = RGBA8Image(px_width, px_height, std::move(pixel_data));
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("Failed to open texture resource '%s'", path);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
std::shared_ptr<GSTexture> ImGuiFullscreen::LoadSvgTexture(std::string_view path, ImVec2 size, SvgScaling mode)
|
||||
{
|
||||
std::string path_str(path);
|
||||
std::optional<RGBA8Image> image(LoadSvgTextureImage(path_str.c_str(), size, mode));
|
||||
if (image.has_value())
|
||||
{
|
||||
std::shared_ptr<GSTexture> ret(UploadTexture(path_str.c_str(), image.value()));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return s_placeholder_texture;
|
||||
}
|
||||
|
||||
GSTexture* ImGuiFullscreen::GetCachedSvgTexture(std::string_view name, ImVec2 size, SvgScaling mode)
|
||||
{
|
||||
std::string svg_key = fmt::format("{}_{}x{}_{}", name, size.x, size.y, static_cast<u8>(mode));
|
||||
|
||||
std::shared_ptr<GSTexture>* tex_ptr = s_texture_cache.Lookup(svg_key);
|
||||
if (!tex_ptr)
|
||||
{
|
||||
std::shared_ptr<GSTexture> tex(LoadSvgTexture(name, size, mode));
|
||||
tex_ptr = s_texture_cache.Insert(std::string(svg_key), std::move(tex));
|
||||
}
|
||||
|
||||
return tex_ptr->get();
|
||||
}
|
||||
|
||||
GSTexture* ImGuiFullscreen::GetCachedSvgTextureAsync(std::string_view name, ImVec2 size, SvgScaling mode)
|
||||
{
|
||||
std::string svg_key = fmt::format("{}_{}x{}_{}", name, size.x, size.y, static_cast<u8>(mode));
|
||||
|
||||
std::shared_ptr<GSTexture>* tex_ptr = s_texture_cache.Lookup(svg_key);
|
||||
if (!tex_ptr)
|
||||
{
|
||||
// insert the placeholder
|
||||
tex_ptr = s_texture_cache.Insert(std::string(svg_key), s_placeholder_texture);
|
||||
|
||||
// queue the actual load
|
||||
std::unique_lock lock(s_texture_load_mutex);
|
||||
s_svg_texture_load_queue.emplace_back(std::tuple(name, size, mode));
|
||||
s_texture_load_cv.notify_one();
|
||||
}
|
||||
|
||||
return tex_ptr->get();
|
||||
}
|
||||
|
||||
bool ImGuiFullscreen::InvalidateCachedTexture(const std::string& path)
|
||||
{
|
||||
return s_texture_cache.Remove(path);
|
||||
@@ -398,7 +564,12 @@ void ImGuiFullscreen::TextureLoaderThread()
|
||||
for (;;)
|
||||
{
|
||||
s_texture_load_cv.wait(
|
||||
lock, []() { return (s_texture_load_thread_quit.load(std::memory_order_acquire) || !s_texture_load_queue.empty()); });
|
||||
lock, []() {
|
||||
return (
|
||||
s_texture_load_thread_quit.load(std::memory_order_acquire) ||
|
||||
!s_texture_load_queue.empty() ||
|
||||
!s_svg_texture_load_queue.empty());
|
||||
});
|
||||
|
||||
if (s_texture_load_thread_quit.load(std::memory_order_acquire))
|
||||
break;
|
||||
@@ -416,9 +587,30 @@ void ImGuiFullscreen::TextureLoaderThread()
|
||||
if (image)
|
||||
s_texture_upload_queue.emplace_back(std::move(path), std::move(image.value()));
|
||||
}
|
||||
|
||||
while (!s_svg_texture_load_queue.empty())
|
||||
{
|
||||
std::string path;
|
||||
ImVec2 size;
|
||||
SvgScaling mode;
|
||||
std::tie(path, size, mode) = std::move(s_svg_texture_load_queue.front());
|
||||
s_svg_texture_load_queue.pop_front();
|
||||
|
||||
lock.unlock();
|
||||
std::optional<RGBA8Image> image(LoadSvgTextureImage(path.c_str(), size, mode));
|
||||
lock.lock();
|
||||
|
||||
// don't bother queuing back if it doesn't exist
|
||||
if (image)
|
||||
{
|
||||
std::string svg_key = fmt::format("{}_{}x{}_{}", path, size.x, size.y, static_cast<u8>(mode));
|
||||
s_texture_upload_queue.emplace_back(std::move(svg_key), std::move(image.value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_texture_load_queue.clear();
|
||||
s_svg_texture_load_queue.clear();
|
||||
}
|
||||
|
||||
bool ImGuiFullscreen::UpdateLayoutScale()
|
||||
@@ -451,13 +643,13 @@ bool ImGuiFullscreen::UpdateLayoutScale()
|
||||
return g_layout_scale != old_scale;
|
||||
}
|
||||
|
||||
ImRect ImGuiFullscreen::CenterImage(const ImVec2& fit_size, const ImVec2& image_size)
|
||||
ImRect ImGuiFullscreen::CenterImage(const ImVec2& fit_size, const ImVec2& image_size, bool fill)
|
||||
{
|
||||
const float fit_ar = fit_size.x / fit_size.y;
|
||||
const float image_ar = image_size.x / image_size.y;
|
||||
|
||||
ImRect ret;
|
||||
if (fit_ar > image_ar)
|
||||
if ((fit_ar > image_ar) ^ fill)
|
||||
{
|
||||
// center horizontally
|
||||
const float width = fit_size.y * image_ar;
|
||||
@@ -477,7 +669,7 @@ ImRect ImGuiFullscreen::CenterImage(const ImVec2& fit_size, const ImVec2& image_
|
||||
return ret;
|
||||
}
|
||||
|
||||
ImRect ImGuiFullscreen::CenterImage(const ImRect& fit_rect, const ImVec2& image_size)
|
||||
ImRect ImGuiFullscreen::CenterImage(const ImRect& fit_rect, const ImVec2& image_size, bool fill)
|
||||
{
|
||||
ImRect ret(CenterImage(fit_rect.Max - fit_rect.Min, image_size));
|
||||
ret.Translate(fit_rect.Min);
|
||||
|
||||
@@ -86,8 +86,8 @@ namespace ImGuiFullscreen
|
||||
}
|
||||
|
||||
/// Centers an image within the specified bounds, scaling up or down as needed.
|
||||
ImRect CenterImage(const ImVec2& fit_size, const ImVec2& image_size);
|
||||
ImRect CenterImage(const ImRect& fit_rect, const ImVec2& image_size);
|
||||
ImRect CenterImage(const ImVec2& fit_size, const ImVec2& image_size, bool fill = false);
|
||||
ImRect CenterImage(const ImRect& fit_rect, const ImVec2& image_size, bool fill = false);
|
||||
|
||||
/// Initializes, setting up any state.
|
||||
bool Initialize(const char* placeholder_image_path);
|
||||
@@ -104,6 +104,15 @@ namespace ImGuiFullscreen
|
||||
std::shared_ptr<GSTexture> LoadTexture(std::string_view path);
|
||||
GSTexture* GetCachedTexture(std::string_view name);
|
||||
GSTexture* GetCachedTextureAsync(std::string_view name);
|
||||
enum class SvgScaling : u8
|
||||
{
|
||||
Stretch,
|
||||
Fit,
|
||||
ZoomFill,
|
||||
};
|
||||
std::shared_ptr<GSTexture> LoadSvgTexture(std::string_view path, ImVec2 size, SvgScaling mode = SvgScaling::Stretch);
|
||||
GSTexture* GetCachedSvgTexture(std::string_view name, ImVec2 size, SvgScaling mode = SvgScaling::Stretch);
|
||||
GSTexture* GetCachedSvgTextureAsync(std::string_view name, ImVec2 size, SvgScaling mode = SvgScaling::Stretch);
|
||||
bool InvalidateCachedTexture(const std::string& path);
|
||||
void UploadAsyncTextures();
|
||||
|
||||
|
||||
@@ -255,6 +255,9 @@ void ImGuiManager::UpdateScale()
|
||||
|
||||
if (!g_gs_device->UpdateImGuiFontTexture())
|
||||
pxFailRel("Failed to recreate font texture after scale+resize");
|
||||
|
||||
if (FullscreenUI::IsInitialized())
|
||||
FullscreenUI::ReloadSvgResources();
|
||||
}
|
||||
|
||||
void ImGuiManager::NewFrame()
|
||||
|
||||