ImGuiManager: Pack state in struct

This commit is contained in:
Stenzek 2025-01-02 21:33:53 +10:00
parent d3fe1dfc2c
commit ba15a76d7b
No known key found for this signature in database
1 changed files with 232 additions and 217 deletions

View File

@ -89,61 +89,71 @@ static void UpdateSoftwareCursorTexture(u32 index);
static void DestroySoftwareCursorTextures();
static void DrawSoftwareCursor(const SoftwareCursor& sc, const std::pair<float, float>& pos);
static float s_global_prescale = 0.0f; // before window scale
static float s_global_scale = 0.0f;
static float s_screen_margin = 0.0f;
static constexpr std::array<ImWchar, 4> s_ascii_font_range = {{0x20, 0x7F, 0x00, 0x00}};
static std::string s_font_path;
static std::vector<WCharType> s_font_range;
static std::vector<WCharType> s_emoji_range;
static ImGuiContext* s_imgui_context;
static ImFont* s_debug_font;
static ImFont* s_osd_font;
static ImFont* s_fixed_font;
static ImFont* s_medium_font;
static ImFont* s_large_font;
static DynamicHeapArray<u8> s_standard_font_data;
static DynamicHeapArray<u8> s_fixed_font_data;
static DynamicHeapArray<u8> s_icon_fa_font_data;
static DynamicHeapArray<u8> s_icon_pf_font_data;
static DynamicHeapArray<u8> s_emoji_font_data;
static float s_window_width;
static float s_window_height;
static Timer s_last_render_time;
// cached copies of WantCaptureKeyboard/Mouse, used to know when to dispatch events
static std::atomic_bool s_imgui_wants_keyboard{false};
static std::atomic_bool s_imgui_wants_mouse{false};
static std::atomic_bool s_imgui_wants_text{false};
// mapping of host key -> imgui key
static std::unordered_map<u32, ImGuiKey> s_imgui_key_map;
static constexpr float OSD_FADE_IN_TIME = 0.1f;
static constexpr float OSD_FADE_OUT_TIME = 0.4f;
static std::deque<OSDMessage> s_osd_active_messages;
static std::deque<OSDMessage> s_osd_posted_messages;
static std::mutex s_osd_messages_lock;
static bool s_show_osd_messages = true;
static bool s_scale_changed = false;
static constexpr std::array<ImWchar, 4> s_ascii_font_range = {{0x20, 0x7F, 0x00, 0x00}};
namespace {
struct ALIGN_TO_CACHE_LINE State
{
float global_prescale = 0.0f; // before window scale
float global_scale = 0.0f;
float screen_margin = 0.0f;
std::string font_path;
std::vector<WCharType> font_range;
std::vector<WCharType> emoji_range;
ImGuiContext* imgui_context;
ImFont* debug_font;
ImFont* osd_font;
ImFont* fixed_font;
ImFont* medium_font;
ImFont* large_font;
DynamicHeapArray<u8> standard_font_data;
DynamicHeapArray<u8> fixed_font_data;
DynamicHeapArray<u8> icon_fa_font_data;
DynamicHeapArray<u8> icon_pf_font_data;
DynamicHeapArray<u8> emoji_font_data;
float window_width;
float window_height;
Timer::Value last_render_time;
// cached copies of WantCaptureKeyboard/Mouse, used to know when to dispatch events
std::atomic_bool imgui_wants_keyboard{false};
std::atomic_bool imgui_wants_mouse{false};
std::atomic_bool imgui_wants_text{false};
// mapping of host key -> imgui key
std::unordered_map<u32, ImGuiKey> imgui_key_map;
std::deque<OSDMessage> osd_active_messages;
std::deque<OSDMessage> osd_posted_messages;
std::mutex osd_messages_lock;
bool show_osd_messages = true;
bool scale_changed = false;
std::array<ImGuiManager::SoftwareCursor, InputManager::MAX_SOFTWARE_CURSORS> software_cursors = {};
};
} // namespace
static State s_state;
static std::array<ImGuiManager::SoftwareCursor, InputManager::MAX_SOFTWARE_CURSORS> s_software_cursors = {};
} // namespace ImGuiManager
void ImGuiManager::SetFontPathAndRange(std::string path, std::vector<WCharType> range)
{
if (s_font_path == path && s_font_range == range)
if (s_state.font_path == path && s_state.font_range == range)
return;
s_font_path = std::move(path);
s_font_range = std::move(range);
s_standard_font_data = {};
s_state.font_path = std::move(path);
s_state.font_range = std::move(range);
s_state.standard_font_data = {};
ReloadFontDataIfActive();
}
@ -154,23 +164,23 @@ void ImGuiManager::SetEmojiFontRange(std::vector<WCharType> range)
if (runtime_size == 0)
{
if (s_emoji_range.empty())
if (s_state.emoji_range.empty())
return;
s_emoji_range = {};
s_state.emoji_range = {};
}
else
{
if (!s_emoji_range.empty() && (s_emoji_range.size() - builtin_size) == range.size() &&
std::memcmp(s_emoji_range.data(), range.data(), range.size() * sizeof(ImWchar)) == 0)
if (!s_state.emoji_range.empty() && (s_state.emoji_range.size() - builtin_size) == range.size() &&
std::memcmp(s_state.emoji_range.data(), range.data(), range.size() * sizeof(ImWchar)) == 0)
{
// no change
return;
}
s_emoji_range = std::move(range);
s_emoji_range.resize(s_emoji_range.size() + builtin_size);
std::memcpy(&s_emoji_range[runtime_size], EMOJI_ICON_RANGE, sizeof(EMOJI_ICON_RANGE));
s_state.emoji_range = std::move(range);
s_state.emoji_range.resize(s_state.emoji_range.size() + builtin_size);
std::memcpy(&s_state.emoji_range[runtime_size], EMOJI_ICON_RANGE, sizeof(EMOJI_ICON_RANGE));
}
ReloadFontDataIfActive();
@ -210,24 +220,24 @@ std::vector<ImGuiManager::WCharType> ImGuiManager::CompactFontRange(std::span<co
void ImGuiManager::SetGlobalScale(float global_scale)
{
if (s_global_prescale == global_scale)
if (s_state.global_prescale == global_scale)
return;
s_global_prescale = global_scale;
s_scale_changed = true;
s_state.global_prescale = global_scale;
s_state.scale_changed = true;
}
bool ImGuiManager::IsShowingOSDMessages()
{
return s_show_osd_messages;
return s_state.show_osd_messages;
}
void ImGuiManager::SetShowOSDMessages(bool enable)
{
if (s_show_osd_messages == enable)
if (s_state.show_osd_messages == enable)
return;
s_show_osd_messages = enable;
s_state.show_osd_messages = enable;
if (!enable)
Host::ClearOSDMessages(false);
}
@ -240,15 +250,15 @@ bool ImGuiManager::Initialize(float global_scale, float screen_margin, Error* er
return false;
}
s_global_prescale = global_scale;
s_global_scale = std::max(
s_state.global_prescale = global_scale;
s_state.global_scale = std::max(
(g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetScale() : 1.0f) * global_scale, 1.0f);
s_screen_margin = std::max(screen_margin, 0.0f);
s_scale_changed = false;
s_state.screen_margin = std::max(screen_margin, 0.0f);
s_state.scale_changed = false;
s_imgui_context = ImGui::CreateContext();
s_state.imgui_context = ImGui::CreateContext();
ImGuiIO& io = s_imgui_context->IO;
ImGuiIO& io = s_state.imgui_context->IO;
io.IniFilename = nullptr;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_RendererHasVtxOffset;
#ifndef __ANDROID__
@ -260,15 +270,16 @@ bool ImGuiManager::Initialize(float global_scale, float screen_margin, Error* er
#endif
SetCommonIOOptions(io);
s_window_width =
s_state.last_render_time = Timer::GetCurrentValue();
s_state.window_width =
g_gpu_device->HasMainSwapChain() ? static_cast<float>(g_gpu_device->GetMainSwapChain()->GetWidth()) : 0.0f;
s_window_height =
s_state.window_height =
g_gpu_device->HasMainSwapChain() ? static_cast<float>(g_gpu_device->GetMainSwapChain()->GetHeight()) : 0.0f;
io.DisplayFramebufferScale = ImVec2(1, 1); // We already scale things ourselves, this would double-apply scaling
io.DisplaySize = ImVec2(s_window_width, s_window_height);
io.DisplaySize = ImVec2(s_state.window_width, s_state.window_height);
SetKeyMap();
SetStyle(s_imgui_context->Style, s_global_scale);
SetStyle(s_state.imgui_context->Style, s_state.global_scale);
if (!AddImGuiFonts(false, false) || !g_gpu_device->UpdateImGuiFontTexture())
{
@ -290,43 +301,43 @@ void ImGuiManager::Shutdown()
{
DestroySoftwareCursorTextures();
if (s_imgui_context)
if (s_state.imgui_context)
{
ImGui::DestroyContext(s_imgui_context);
s_imgui_context = nullptr;
ImGui::DestroyContext(s_state.imgui_context);
s_state.imgui_context = nullptr;
}
s_debug_font = nullptr;
s_fixed_font = nullptr;
s_medium_font = nullptr;
s_large_font = nullptr;
s_state.debug_font = nullptr;
s_state.fixed_font = nullptr;
s_state.medium_font = nullptr;
s_state.large_font = nullptr;
ImGuiFullscreen::SetFonts(nullptr, nullptr);
}
ImGuiContext* ImGuiManager::GetMainContext()
{
return s_imgui_context;
return s_state.imgui_context;
}
void ImGuiManager::SetScreenMargin(float margin)
{
s_screen_margin = std::max(margin, 0.0f);
s_state.screen_margin = std::max(margin, 0.0f);
}
float ImGuiManager::GetWindowWidth()
{
return s_window_width;
return s_state.window_width;
}
float ImGuiManager::GetWindowHeight()
{
return s_window_height;
return s_state.window_height;
}
void ImGuiManager::WindowResized(float width, float height)
{
s_window_width = width;
s_window_height = height;
s_state.window_width = width;
s_state.window_height = height;
ImGui::GetIO().DisplaySize = ImVec2(width, height);
// Scale might have changed as a result of window resize.
@ -336,20 +347,20 @@ void ImGuiManager::WindowResized(float width, float height)
void ImGuiManager::RequestScaleUpdate()
{
// Might need to update the scale.
s_scale_changed = true;
s_state.scale_changed = true;
}
void ImGuiManager::UpdateScale()
{
const float window_scale =
(g_gpu_device && g_gpu_device->HasMainSwapChain()) ? g_gpu_device->GetMainSwapChain()->GetScale() : 1.0f;
const float scale = std::max(window_scale * s_global_prescale, 1.0f);
const float scale = std::max(window_scale * s_state.global_prescale, 1.0f);
if ((!HasFullscreenFonts() || !ImGuiFullscreen::UpdateLayoutScale()) && scale == s_global_scale)
if ((!HasFullscreenFonts() || !ImGuiFullscreen::UpdateLayoutScale()) && scale == s_state.global_scale)
return;
s_global_scale = scale;
SetStyle(s_imgui_context->Style, s_global_scale);
s_state.global_scale = scale;
SetStyle(s_state.imgui_context->Style, s_state.global_scale);
if (!AddImGuiFonts(HasDebugFont(), HasFullscreenFonts()))
Panic("Failed to create ImGui font text");
@ -360,12 +371,15 @@ void ImGuiManager::UpdateScale()
void ImGuiManager::NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
io.DeltaTime = static_cast<float>(s_last_render_time.GetTimeSecondsAndReset());
const Timer::Value current_time = Timer::GetCurrentValue();
if (s_scale_changed)
ImGuiIO& io = ImGui::GetIO();
io.DeltaTime = static_cast<float>(Timer::ConvertValueToSeconds(current_time - s_state.last_render_time));
s_state.last_render_time = current_time;
if (s_state.scale_changed)
{
s_scale_changed = false;
s_state.scale_changed = false;
UpdateScale();
}
@ -374,13 +388,13 @@ void ImGuiManager::NewFrame()
// Disable nav input on the implicit (Debug##Default) window. Otherwise we end up requesting keyboard
// focus when there's nothing there. We use GetCurrentWindowRead() because otherwise it'll make it visible.
ImGui::GetCurrentWindowRead()->Flags |= ImGuiWindowFlags_NoNavInputs;
s_imgui_wants_keyboard.store(io.WantCaptureKeyboard, std::memory_order_relaxed);
s_imgui_wants_mouse.store(io.WantCaptureMouse, std::memory_order_release);
s_state.imgui_wants_keyboard.store(io.WantCaptureKeyboard, std::memory_order_relaxed);
s_state.imgui_wants_mouse.store(io.WantCaptureMouse, std::memory_order_release);
const bool wants_text_input = io.WantTextInput;
if (s_imgui_wants_text.load(std::memory_order_relaxed) != wants_text_input)
if (s_state.imgui_wants_text.load(std::memory_order_relaxed) != wants_text_input)
{
s_imgui_wants_text.store(wants_text_input, std::memory_order_release);
s_state.imgui_wants_text.store(wants_text_input, std::memory_order_release);
if (wants_text_input)
Host::BeginTextInput();
else
@ -560,65 +574,65 @@ void ImGuiManager::SetKeyMap()
{ImGuiKey_KeypadEnter, "KeypadReturn", nullptr},
{ImGuiKey_KeypadEqual, "KeypadEqual", nullptr}};
s_imgui_key_map.clear();
s_state.imgui_key_map.clear();
for (const KeyMapping& km : mapping)
{
std::optional<u32> map(InputManager::ConvertHostKeyboardStringToCode(km.name));
if (!map.has_value() && km.alt_name)
map = InputManager::ConvertHostKeyboardStringToCode(km.alt_name);
if (map.has_value())
s_imgui_key_map[map.value()] = km.index;
s_state.imgui_key_map[map.value()] = km.index;
}
}
bool ImGuiManager::LoadFontData(Error* error)
{
if (s_standard_font_data.empty())
if (s_state.standard_font_data.empty())
{
std::optional<DynamicHeapArray<u8>> font_data = s_font_path.empty() ?
std::optional<DynamicHeapArray<u8>> font_data = s_state.font_path.empty() ?
Host::ReadResourceFile("fonts/Roboto-Regular.ttf", true, error) :
FileSystem::ReadBinaryFile(s_font_path.c_str(), error);
FileSystem::ReadBinaryFile(s_state.font_path.c_str(), error);
if (!font_data.has_value())
return false;
s_standard_font_data = std::move(font_data.value());
s_state.standard_font_data = std::move(font_data.value());
}
if (s_fixed_font_data.empty())
if (s_state.fixed_font_data.empty())
{
std::optional<DynamicHeapArray<u8>> font_data = Host::ReadResourceFile("fonts/RobotoMono-Medium.ttf", true, error);
if (!font_data.has_value())
return false;
s_fixed_font_data = std::move(font_data.value());
s_state.fixed_font_data = std::move(font_data.value());
}
if (s_icon_fa_font_data.empty())
if (s_state.icon_fa_font_data.empty())
{
std::optional<DynamicHeapArray<u8>> font_data = Host::ReadResourceFile("fonts/fa-solid-900.ttf", true, error);
if (!font_data.has_value())
return false;
s_icon_fa_font_data = std::move(font_data.value());
s_state.icon_fa_font_data = std::move(font_data.value());
}
if (s_icon_pf_font_data.empty())
if (s_state.icon_pf_font_data.empty())
{
std::optional<DynamicHeapArray<u8>> font_data = Host::ReadResourceFile("fonts/promptfont.otf", true, error);
if (!font_data.has_value())
return false;
s_icon_pf_font_data = std::move(font_data.value());
s_state.icon_pf_font_data = std::move(font_data.value());
}
if (s_emoji_font_data.empty())
if (s_state.emoji_font_data.empty())
{
std::optional<DynamicHeapArray<u8>> font_data =
Host::ReadCompressedResourceFile("fonts/TwitterColorEmoji-SVGinOT.ttf.zst", true, error);
if (!font_data.has_value())
return false;
s_emoji_font_data = std::move(font_data.value());
s_state.emoji_font_data = std::move(font_data.value());
}
return true;
@ -628,17 +642,18 @@ ImFont* ImGuiManager::AddTextFont(float size, bool full_glyph_range)
{
ImFontConfig cfg;
cfg.FontDataOwnedByAtlas = false;
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_standard_font_data.data(),
static_cast<int>(s_standard_font_data.size()), size, &cfg,
full_glyph_range ? s_font_range.data() : s_ascii_font_range.data());
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
s_state.standard_font_data.data(), static_cast<int>(s_state.standard_font_data.size()), size, &cfg,
full_glyph_range ? s_state.font_range.data() : s_ascii_font_range.data());
}
ImFont* ImGuiManager::AddFixedFont(float size)
{
ImFontConfig cfg;
cfg.FontDataOwnedByAtlas = false;
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
s_fixed_font_data.data(), static_cast<int>(s_fixed_font_data.size()), size, &cfg, s_ascii_font_range.data());
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_state.fixed_font_data.data(),
static_cast<int>(s_state.fixed_font_data.size()), size, &cfg,
s_ascii_font_range.data());
}
bool ImGuiManager::AddIconFonts(float size)
@ -651,9 +666,9 @@ bool ImGuiManager::AddIconFonts(float size)
cfg.GlyphMaxAdvanceX = size;
cfg.FontDataOwnedByAtlas = false;
if (!ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
s_icon_fa_font_data.data(), static_cast<int>(s_icon_fa_font_data.size()), size * 0.75f, &cfg, FA_ICON_RANGE))
[[unlikely]]
if (!ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_state.icon_fa_font_data.data(),
static_cast<int>(s_state.icon_fa_font_data.size()), size * 0.75f,
&cfg, FA_ICON_RANGE)) [[unlikely]]
{
return false;
}
@ -667,9 +682,9 @@ bool ImGuiManager::AddIconFonts(float size)
cfg.GlyphMaxAdvanceX = size;
cfg.FontDataOwnedByAtlas = false;
if (!ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
s_icon_pf_font_data.data(), static_cast<int>(s_icon_pf_font_data.size()), size * 1.2f, &cfg, PF_ICON_RANGE))
[[unlikely]]
if (!ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_state.icon_pf_font_data.data(),
static_cast<int>(s_state.icon_pf_font_data.size()), size * 1.2f,
&cfg, PF_ICON_RANGE)) [[unlikely]]
{
return false;
}
@ -685,8 +700,8 @@ bool ImGuiManager::AddIconFonts(float size)
cfg.FontBuilderFlags = ImGuiFreeTypeBuilderFlags_LoadColor | ImGuiFreeTypeBuilderFlags_Bitmap;
if (!ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
s_emoji_font_data.data(), static_cast<int>(s_emoji_font_data.size()), size * 0.9f, &cfg,
s_emoji_range.empty() ? EMOJI_ICON_RANGE : s_emoji_range.data())) [[unlikely]]
s_state.emoji_font_data.data(), static_cast<int>(s_state.emoji_font_data.size()), size * 0.9f, &cfg,
s_state.emoji_range.empty() ? EMOJI_ICON_RANGE : s_state.emoji_range.data())) [[unlikely]]
{
return false;
}
@ -700,10 +715,10 @@ bool ImGuiManager::AddImGuiFonts(bool debug_font, bool fullscreen_fonts)
const float window_scale =
(g_gpu_device && g_gpu_device->HasMainSwapChain()) ? g_gpu_device->GetMainSwapChain()->GetScale() : 1.0f;
const float debug_font_size = std::ceil(15.0f * window_scale);
const float standard_font_size = std::ceil(15.0f * s_global_scale);
const float osd_font_size = std::ceil(17.0f * s_global_scale);
const float standard_font_size = std::ceil(15.0f * s_state.global_scale);
const float osd_font_size = std::ceil(17.0f * s_state.global_scale);
INFO_LOG("Allocating fonts winscale={} globalscale={} debug={} fullscreen={}", window_scale, s_global_scale,
INFO_LOG("Allocating fonts winscale={} globalscale={} debug={} fullscreen={}", window_scale, s_state.global_scale,
debug_font, fullscreen_fonts);
ImGuiIO& io = ImGui::GetIO();
@ -711,47 +726,47 @@ bool ImGuiManager::AddImGuiFonts(bool debug_font, bool fullscreen_fonts)
if (debug_font)
{
s_debug_font = AddTextFont(debug_font_size, false);
if (!s_debug_font)
s_state.debug_font = AddTextFont(debug_font_size, false);
if (!s_state.debug_font)
return false;
}
s_fixed_font = AddFixedFont(standard_font_size);
if (!s_fixed_font)
s_state.fixed_font = AddFixedFont(standard_font_size);
if (!s_state.fixed_font)
return false;
s_osd_font = AddTextFont(osd_font_size, true);
if (!s_osd_font || !AddIconFonts(osd_font_size))
s_state.osd_font = AddTextFont(osd_font_size, true);
if (!s_state.osd_font || !AddIconFonts(osd_font_size))
return false;
if (!debug_font)
s_debug_font = s_osd_font;
s_state.debug_font = s_state.osd_font;
if (fullscreen_fonts)
{
const float medium_font_size = ImGuiFullscreen::LayoutScale(ImGuiFullscreen::LAYOUT_MEDIUM_FONT_SIZE);
s_medium_font = AddTextFont(medium_font_size, true);
if (!s_medium_font || !AddIconFonts(medium_font_size))
s_state.medium_font = AddTextFont(medium_font_size, true);
if (!s_state.medium_font || !AddIconFonts(medium_font_size))
return false;
const float large_font_size = ImGuiFullscreen::LayoutScale(ImGuiFullscreen::LAYOUT_LARGE_FONT_SIZE);
s_large_font = AddTextFont(large_font_size, true);
if (!s_large_font || !AddIconFonts(large_font_size))
s_state.large_font = AddTextFont(large_font_size, true);
if (!s_state.large_font || !AddIconFonts(large_font_size))
return false;
}
else
{
s_medium_font = nullptr;
s_large_font = nullptr;
s_state.medium_font = nullptr;
s_state.large_font = nullptr;
}
ImGuiFullscreen::SetFonts(s_medium_font, s_large_font);
ImGuiFullscreen::SetFonts(s_state.medium_font, s_state.large_font);
return io.Fonts->Build();
}
void ImGuiManager::ReloadFontDataIfActive()
{
if (!s_imgui_context)
if (!s_state.imgui_context)
return;
ImGui::EndFrame();
@ -791,7 +806,7 @@ bool ImGuiManager::AddFullscreenFontsIfMissing()
bool ImGuiManager::HasDebugFont()
{
return (s_debug_font != s_osd_font);
return (s_state.debug_font != s_state.osd_font);
}
bool ImGuiManager::AddDebugFontIfMissing()
@ -817,7 +832,7 @@ bool ImGuiManager::AddDebugFontIfMissing()
bool ImGuiManager::HasFullscreenFonts()
{
return (s_medium_font && s_large_font);
return (s_state.medium_font && s_state.large_font);
}
void ImGuiManager::AddOSDMessage(std::string key, std::string message, float duration, bool is_warning)
@ -827,7 +842,7 @@ void ImGuiManager::AddOSDMessage(std::string key, std::string message, float dur
else
INFO_LOG("OSD: {}", message);
if (!s_show_osd_messages && !is_warning)
if (!s_state.show_osd_messages && !is_warning)
return;
const Timer::Value current_time = Timer::GetCurrentValue();
@ -842,13 +857,13 @@ void ImGuiManager::AddOSDMessage(std::string key, std::string message, float dur
msg.last_y = -1.0f;
msg.is_warning = is_warning;
std::unique_lock<std::mutex> lock(s_osd_messages_lock);
s_osd_posted_messages.push_back(std::move(msg));
std::unique_lock<std::mutex> lock(s_state.osd_messages_lock);
s_state.osd_posted_messages.push_back(std::move(msg));
}
void ImGuiManager::RemoveKeyedOSDMessage(std::string key, bool is_warning)
{
if (!s_show_osd_messages && !is_warning)
if (!s_state.show_osd_messages && !is_warning)
return;
ImGuiManager::OSDMessage msg = {};
@ -856,24 +871,24 @@ void ImGuiManager::RemoveKeyedOSDMessage(std::string key, bool is_warning)
msg.duration = 0.0f;
msg.is_warning = is_warning;
std::unique_lock<std::mutex> lock(s_osd_messages_lock);
s_osd_posted_messages.push_back(std::move(msg));
std::unique_lock<std::mutex> lock(s_state.osd_messages_lock);
s_state.osd_posted_messages.push_back(std::move(msg));
}
void ImGuiManager::ClearOSDMessages(bool clear_warnings)
{
{
std::unique_lock<std::mutex> lock(s_osd_messages_lock);
std::unique_lock<std::mutex> lock(s_state.osd_messages_lock);
if (clear_warnings)
{
s_osd_posted_messages.clear();
s_state.osd_posted_messages.clear();
}
else
{
for (auto iter = s_osd_posted_messages.begin(); iter != s_osd_posted_messages.end();)
for (auto iter = s_state.osd_posted_messages.begin(); iter != s_state.osd_posted_messages.end();)
{
if (!iter->is_warning)
iter = s_osd_posted_messages.erase(iter);
iter = s_state.osd_posted_messages.erase(iter);
else
++iter;
}
@ -882,14 +897,14 @@ void ImGuiManager::ClearOSDMessages(bool clear_warnings)
if (clear_warnings)
{
s_osd_active_messages.clear();
s_state.osd_active_messages.clear();
}
else
{
for (auto iter = s_osd_active_messages.begin(); iter != s_osd_active_messages.end();)
for (auto iter = s_state.osd_active_messages.begin(); iter != s_state.osd_active_messages.end();)
{
if (!iter->is_warning)
s_osd_active_messages.erase(iter);
s_state.osd_active_messages.erase(iter);
else
++iter;
}
@ -899,21 +914,21 @@ void ImGuiManager::ClearOSDMessages(bool clear_warnings)
void ImGuiManager::AcquirePendingOSDMessages(Timer::Value current_time)
{
std::atomic_thread_fence(std::memory_order_consume);
if (s_osd_posted_messages.empty())
if (s_state.osd_posted_messages.empty())
return;
std::unique_lock lock(s_osd_messages_lock);
std::unique_lock lock(s_state.osd_messages_lock);
for (;;)
{
if (s_osd_posted_messages.empty())
if (s_state.osd_posted_messages.empty())
break;
OSDMessage& new_msg = s_osd_posted_messages.front();
OSDMessage& new_msg = s_state.osd_posted_messages.front();
std::deque<OSDMessage>::iterator iter;
if (!new_msg.key.empty() && (iter = std::find_if(s_osd_active_messages.begin(), s_osd_active_messages.end(),
[&new_msg](const OSDMessage& other) {
return new_msg.key == other.key;
})) != s_osd_active_messages.end())
if (!new_msg.key.empty() &&
(iter = std::find_if(s_state.osd_active_messages.begin(), s_state.osd_active_messages.end(),
[&new_msg](const OSDMessage& other) { return new_msg.key == other.key; })) !=
s_state.osd_active_messages.end())
{
iter->text = std::move(new_msg.text);
iter->duration = new_msg.duration;
@ -924,14 +939,14 @@ void ImGuiManager::AcquirePendingOSDMessages(Timer::Value current_time)
}
else
{
s_osd_active_messages.push_back(std::move(new_msg));
s_state.osd_active_messages.push_back(std::move(new_msg));
}
s_osd_posted_messages.pop_front();
s_state.osd_posted_messages.pop_front();
static constexpr size_t MAX_ACTIVE_OSD_MESSAGES = 512;
if (s_osd_active_messages.size() > MAX_ACTIVE_OSD_MESSAGES)
s_osd_active_messages.pop_front();
if (s_state.osd_active_messages.size() > MAX_ACTIVE_OSD_MESSAGES)
s_state.osd_active_messages.pop_front();
}
}
@ -939,24 +954,24 @@ void ImGuiManager::DrawOSDMessages(Timer::Value current_time)
{
static constexpr float MOVE_DURATION = 0.5f;
ImFont* const font = s_osd_font;
const float scale = s_global_scale;
ImFont* const font = s_state.osd_font;
const float scale = s_state.global_scale;
const float spacing = std::ceil(6.0f * scale);
const float margin = std::ceil(s_screen_margin * scale);
const float margin = std::ceil(s_state.screen_margin * scale);
const float padding = std::ceil(9.0f * scale);
const float rounding = std::ceil(6.0f * scale);
const float max_width = s_window_width - (margin + padding) * 2.0f;
const float max_width = s_state.window_width - (margin + padding) * 2.0f;
float position_x = margin;
float position_y = margin;
auto iter = s_osd_active_messages.begin();
while (iter != s_osd_active_messages.end())
auto iter = s_state.osd_active_messages.begin();
while (iter != s_state.osd_active_messages.end())
{
OSDMessage& msg = *iter;
const float time_passed = static_cast<float>(Timer::ConvertValueToSeconds(current_time - msg.start_time));
if (time_passed >= msg.duration)
{
iter = s_osd_active_messages.erase(iter);
iter = s_state.osd_active_messages.erase(iter);
continue;
}
@ -1074,68 +1089,68 @@ void Host::ClearOSDMessages(bool clear_warnings)
float ImGuiManager::GetGlobalScale()
{
return s_global_scale;
return s_state.global_scale;
}
float ImGuiManager::GetScreenMargin()
{
return s_screen_margin;
return s_state.screen_margin;
}
ImFont* ImGuiManager::GetDebugFont()
{
return s_debug_font;
return s_state.debug_font;
}
ImFont* ImGuiManager::GetOSDFont()
{
return s_osd_font;
return s_state.osd_font;
}
ImFont* ImGuiManager::GetFixedFont()
{
return s_fixed_font;
return s_state.fixed_font;
}
ImFont* ImGuiManager::GetMediumFont()
{
AddFullscreenFontsIfMissing();
return s_medium_font;
return s_state.medium_font;
}
ImFont* ImGuiManager::GetLargeFont()
{
AddFullscreenFontsIfMissing();
return s_large_font;
return s_state.large_font;
}
bool ImGuiManager::WantsTextInput()
{
return s_imgui_wants_keyboard.load(std::memory_order_acquire);
return s_state.imgui_wants_keyboard.load(std::memory_order_acquire);
}
bool ImGuiManager::WantsMouseInput()
{
return s_imgui_wants_mouse.load(std::memory_order_acquire);
return s_state.imgui_wants_mouse.load(std::memory_order_acquire);
}
void ImGuiManager::AddTextInput(std::string str)
{
if (!s_imgui_context)
if (!s_state.imgui_context)
return;
if (!s_imgui_wants_keyboard.load(std::memory_order_acquire))
if (!s_state.imgui_wants_keyboard.load(std::memory_order_acquire))
return;
s_imgui_context->IO.AddInputCharactersUTF8(str.c_str());
s_state.imgui_context->IO.AddInputCharactersUTF8(str.c_str());
}
void ImGuiManager::UpdateMousePosition(float x, float y)
{
if (!s_imgui_context)
if (!s_state.imgui_context)
return;
s_imgui_context->IO.MousePos = ImVec2(x, y);
s_state.imgui_context->IO.MousePos = ImVec2(x, y);
std::atomic_thread_fence(std::memory_order_release);
}
@ -1150,53 +1165,53 @@ void ImGuiManager::SetCommonIOOptions(ImGuiIO& io)
bool ImGuiManager::ProcessPointerButtonEvent(InputBindingKey key, float value)
{
if (!s_imgui_context || key.data >= std::size(ImGui::GetIO().MouseDown))
if (!s_state.imgui_context || key.data >= std::size(ImGui::GetIO().MouseDown))
return false;
// still update state anyway
s_imgui_context->IO.AddMouseButtonEvent(key.data, value != 0.0f);
s_state.imgui_context->IO.AddMouseButtonEvent(key.data, value != 0.0f);
return s_imgui_wants_mouse.load(std::memory_order_acquire);
return s_state.imgui_wants_mouse.load(std::memory_order_acquire);
}
bool ImGuiManager::ProcessPointerAxisEvent(InputBindingKey key, float value)
{
if (!s_imgui_context || key.data < static_cast<u32>(InputPointerAxis::WheelX))
if (!s_state.imgui_context || key.data < static_cast<u32>(InputPointerAxis::WheelX))
return false;
// still update state anyway
const bool horizontal = (key.data == static_cast<u32>(InputPointerAxis::WheelX));
s_imgui_context->IO.AddMouseWheelEvent(horizontal ? value : 0.0f, horizontal ? 0.0f : value);
s_state.imgui_context->IO.AddMouseWheelEvent(horizontal ? value : 0.0f, horizontal ? 0.0f : value);
return s_imgui_wants_mouse.load(std::memory_order_acquire);
return s_state.imgui_wants_mouse.load(std::memory_order_acquire);
}
bool ImGuiManager::ProcessHostKeyEvent(InputBindingKey key, float value)
{
if (!s_imgui_context)
if (!s_state.imgui_context)
return false;
// still update state anyway
SetImKeyState(s_imgui_context->IO, key.data, (value != 0.0f));
SetImKeyState(s_state.imgui_context->IO, key.data, (value != 0.0f));
return s_imgui_wants_keyboard.load(std::memory_order_acquire);
return s_state.imgui_wants_keyboard.load(std::memory_order_acquire);
}
void ImGuiManager::SetImKeyState(ImGuiIO& io, u32 key, bool pressed)
{
const auto iter = s_imgui_key_map.find(key);
if (iter == s_imgui_key_map.end())
const auto iter = s_state.imgui_key_map.find(key);
if (iter == s_state.imgui_key_map.end())
return;
const ImGuiKey imkey = iter->second;
s_imgui_context->IO.AddKeyEvent(imkey, pressed);
s_state.imgui_context->IO.AddKeyEvent(imkey, pressed);
// modifier keys need to be handled separately
if ((imkey >= ImGuiKey_LeftCtrl && imkey <= ImGuiKey_LeftSuper) ||
(imkey >= ImGuiKey_RightCtrl && imkey <= ImGuiKey_RightSuper))
{
const u32 idx = imkey - ((imkey >= ImGuiKey_RightCtrl) ? ImGuiKey_RightCtrl : ImGuiKey_LeftCtrl);
s_imgui_context->IO.AddKeyEvent(static_cast<ImGuiKey>(static_cast<u32>(ImGuiMod_Ctrl) << idx), pressed);
s_state.imgui_context->IO.AddKeyEvent(static_cast<ImGuiKey>(static_cast<u32>(ImGuiMod_Ctrl) << idx), pressed);
}
}
@ -1231,14 +1246,14 @@ bool ImGuiManager::ProcessGenericInputEvent(GenericInputBinding key, float value
ImGuiKey_GamepadL2, // R2
};
if (!s_imgui_context)
if (!s_state.imgui_context)
return false;
if (static_cast<u32>(key) >= std::size(key_map) || key_map[static_cast<u32>(key)] == ImGuiKey_None)
return false;
s_imgui_context->IO.AddKeyAnalogEvent(key_map[static_cast<u32>(key)], (value > 0.0f), value);
return s_imgui_wants_keyboard.load(std::memory_order_acquire);
s_state.imgui_context->IO.AddKeyAnalogEvent(key_map[static_cast<u32>(key)], (value > 0.0f), value);
return s_state.imgui_wants_keyboard.load(std::memory_order_acquire);
}
const char* ImGuiManager::GetClipboardTextImpl(void* userdata)
@ -1265,22 +1280,22 @@ void ImGuiManager::SetClipboardTextImpl(void* userdata, const char* text)
void ImGuiManager::CreateSoftwareCursorTextures()
{
for (u32 i = 0; i < static_cast<u32>(s_software_cursors.size()); i++)
for (u32 i = 0; i < static_cast<u32>(s_state.software_cursors.size()); i++)
{
if (!s_software_cursors[i].image_path.empty())
if (!s_state.software_cursors[i].image_path.empty())
UpdateSoftwareCursorTexture(i);
}
}
void ImGuiManager::DestroySoftwareCursorTextures()
{
for (SoftwareCursor& sc : s_software_cursors)
for (SoftwareCursor& sc : s_state.software_cursors)
sc.texture.reset();
}
void ImGuiManager::UpdateSoftwareCursorTexture(u32 index)
{
SoftwareCursor& sc = s_software_cursors[index];
SoftwareCursor& sc = s_state.software_cursors[index];
if (sc.image_path.empty())
{
sc.texture.reset();
@ -1305,8 +1320,8 @@ void ImGuiManager::UpdateSoftwareCursorTexture(u32 index)
return;
}
sc.extent_x = std::ceil(static_cast<float>(image.GetWidth()) * sc.scale * s_global_scale) / 2.0f;
sc.extent_y = std::ceil(static_cast<float>(image.GetHeight()) * sc.scale * s_global_scale) / 2.0f;
sc.extent_x = std::ceil(static_cast<float>(image.GetWidth()) * sc.scale * s_state.global_scale) / 2.0f;
sc.extent_y = std::ceil(static_cast<float>(image.GetHeight()) * sc.scale * s_state.global_scale) / 2.0f;
}
void ImGuiManager::DrawSoftwareCursor(const SoftwareCursor& sc, const std::pair<float, float>& pos)
@ -1328,16 +1343,16 @@ void ImGuiManager::RenderSoftwareCursors()
// This one's okay to race, worst that happens is we render the wrong number of cursors for a frame.
const u32 pointer_count = InputManager::GetPointerCount();
for (u32 i = 0; i < pointer_count; i++)
DrawSoftwareCursor(s_software_cursors[i], InputManager::GetPointerAbsolutePosition(i));
DrawSoftwareCursor(s_state.software_cursors[i], InputManager::GetPointerAbsolutePosition(i));
for (u32 i = InputManager::MAX_POINTER_DEVICES; i < InputManager::MAX_SOFTWARE_CURSORS; i++)
DrawSoftwareCursor(s_software_cursors[i], s_software_cursors[i].pos);
DrawSoftwareCursor(s_state.software_cursors[i], s_state.software_cursors[i].pos);
}
void ImGuiManager::SetSoftwareCursor(u32 index, std::string image_path, float image_scale, u32 multiply_color)
{
DebugAssert(index < std::size(s_software_cursors));
SoftwareCursor& sc = s_software_cursors[index];
DebugAssert(index < std::size(s_state.software_cursors));
SoftwareCursor& sc = s_state.software_cursors[index];
sc.color = multiply_color | 0xFF000000;
if (sc.image_path == image_path && sc.scale == image_scale)
return;
@ -1355,7 +1370,7 @@ void ImGuiManager::SetSoftwareCursor(u32 index, std::string image_path, float im
bool ImGuiManager::HasSoftwareCursor(u32 index)
{
return (index < s_software_cursors.size() && !s_software_cursors[index].image_path.empty());
return (index < s_state.software_cursors.size() && !s_state.software_cursors[index].image_path.empty());
}
void ImGuiManager::ClearSoftwareCursor(u32 index)
@ -1366,7 +1381,7 @@ void ImGuiManager::ClearSoftwareCursor(u32 index)
void ImGuiManager::SetSoftwareCursorPosition(u32 index, float pos_x, float pos_y)
{
DebugAssert(index >= InputManager::MAX_POINTER_DEVICES);
SoftwareCursor& sc = s_software_cursors[index];
SoftwareCursor& sc = s_state.software_cursors[index];
sc.pos.first = pos_x;
sc.pos.second = pos_y;
}
@ -1436,7 +1451,7 @@ bool ImGuiManager::CreateAuxiliaryRenderWindow(AuxiliaryRenderWindowState* state
AddDebugFontIfMissing();
state->imgui_context = ImGui::CreateContext(s_imgui_context->IO.Fonts);
state->imgui_context = ImGui::CreateContext(s_state.imgui_context->IO.Fonts);
state->imgui_context->IO.DisplaySize =
ImVec2(static_cast<float>(state->swap_chain->GetWidth()), static_cast<float>(state->swap_chain->GetHeight()));
state->imgui_context->IO.IniFilename = nullptr;
@ -1505,7 +1520,7 @@ bool ImGuiManager::RenderAuxiliaryRenderWindow(AuxiliaryRenderWindowState* state
ImGui::SetCurrentContext(state->imgui_context);
ImGui::NewFrame();
ImGui::PushFont(s_debug_font);
ImGui::PushFont(s_state.debug_font);
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiCond_Always);
ImGui::SetNextWindowSize(state->imgui_context->IO.DisplaySize, ImGuiCond_Always);
if (ImGui::Begin("AuxRenderWindowMain", nullptr,