Move ImGui setup to common, and enable fullscreen UI in Qt

This commit is contained in:
Connor McLaughlin 2021-02-22 02:38:16 +10:00
parent d0f6ff03a5
commit 8318cdb3c1
16 changed files with 319 additions and 216 deletions

View File

@ -354,7 +354,7 @@ void AndroidHostInterface::EmulationThreadEntryPoint(JNIEnv* env, jobject emulat
m_emulation_activity_object = emulation_activity; m_emulation_activity_object = emulation_activity;
m_emulation_thread_id = std::this_thread::get_id(); m_emulation_thread_id = std::this_thread::get_id();
} }
CreateImGuiContext();
ApplySettings(true); ApplySettings(true);
// Boot system. // Boot system.
@ -400,8 +400,6 @@ void AndroidHostInterface::EmulationThreadEntryPoint(JNIEnv* env, jobject emulat
} }
env->CallVoidMethod(emulation_activity, s_EmulationActivity_method_onEmulationStopped); env->CallVoidMethod(emulation_activity, s_EmulationActivity_method_onEmulationStopped);
DestroyImGuiContext();
} }
void AndroidHostInterface::EmulationThreadLoop(JNIEnv* env) void AndroidHostInterface::EmulationThreadLoop(JNIEnv* env)
@ -486,6 +484,9 @@ bool AndroidHostInterface::AcquireHostDisplay()
wi.surface_width = ANativeWindow_getWidth(m_surface); wi.surface_width = ANativeWindow_getWidth(m_surface);
wi.surface_height = ANativeWindow_getHeight(m_surface); wi.surface_height = ANativeWindow_getHeight(m_surface);
// TODO: Really need a better way of determining this.
wi.surface_scale = 2.0f;
switch (g_settings.gpu_renderer) switch (g_settings.gpu_renderer)
{ {
case GPURenderer::HardwareVulkan: case GPURenderer::HardwareVulkan:
@ -500,20 +501,20 @@ bool AndroidHostInterface::AcquireHostDisplay()
if (!m_display->CreateRenderDevice(wi, {}, g_settings.gpu_use_debug_device, g_settings.gpu_threaded_presentation) || if (!m_display->CreateRenderDevice(wi, {}, g_settings.gpu_use_debug_device, g_settings.gpu_threaded_presentation) ||
!m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device, !m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device,
g_settings.gpu_threaded_presentation) || g_settings.gpu_threaded_presentation))
!m_display->CreateImGuiContext())
{ {
m_display->DestroyRenderDevice(); m_display->DestroyRenderDevice();
m_display.reset(); m_display.reset();
return false; return false;
} }
// The alignement was set prior to booting. // The alignment was set prior to booting.
m_display->SetDisplayAlignment(m_display_alignment); m_display->SetDisplayAlignment(m_display_alignment);
if (!m_display->UpdateImGuiFontTexture() || !CreateHostDisplayResources()) if (!CreateHostDisplayResources())
{ {
ReportError("Failed to create host display resources"); ReportError("Failed to create host display resources");
ReleaseHostDisplayResources();
ReleaseHostDisplay(); ReleaseHostDisplay();
return false; return false;
} }
@ -524,9 +525,11 @@ bool AndroidHostInterface::AcquireHostDisplay()
void AndroidHostInterface::ReleaseHostDisplay() void AndroidHostInterface::ReleaseHostDisplay()
{ {
ReleaseHostDisplayResources(); ReleaseHostDisplayResources();
m_display->DestroyImGuiContext(); if (m_display)
m_display->DestroyRenderDevice(); {
m_display.reset(); m_display->DestroyRenderDevice();
m_display.reset();
}
} }
std::unique_ptr<AudioStream> AndroidHostInterface::CreateAudioStream(AudioBackend backend) std::unique_ptr<AudioStream> AndroidHostInterface::CreateAudioStream(AudioBackend backend)
@ -611,6 +614,7 @@ void AndroidHostInterface::SurfaceChanged(ANativeWindow* surface, int format, in
wi.window_handle = surface; wi.window_handle = surface;
wi.surface_width = width; wi.surface_width = width;
wi.surface_height = height; wi.surface_height = height;
wi.surface_scale = m_display->GetWindowScale();
m_display->ChangeRenderWindow(wi); m_display->ChangeRenderWindow(wi);
@ -628,27 +632,6 @@ void AndroidHostInterface::SetDisplayAlignment(HostDisplay::Alignment alignment)
m_display->SetDisplayAlignment(alignment); m_display->SetDisplayAlignment(alignment);
} }
void AndroidHostInterface::CreateImGuiContext()
{
ImGui::CreateContext();
const float framebuffer_scale = 2.0f;
auto& io = ImGui::GetIO();
io.IniFilename = nullptr;
io.DisplayFramebufferScale.x = framebuffer_scale;
io.DisplayFramebufferScale.y = framebuffer_scale;
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
ImGui::StyleColorsDarker();
ImGui::AddRobotoRegularFont(15.0f * framebuffer_scale);
}
void AndroidHostInterface::DestroyImGuiContext()
{
ImGui::DestroyContext();
}
void AndroidHostInterface::SetControllerType(u32 index, std::string_view type_name) void AndroidHostInterface::SetControllerType(u32 index, std::string_view type_name)
{ {
ControllerType type = ControllerType type =

View File

@ -82,9 +82,6 @@ protected:
private: private:
void EmulationThreadLoop(JNIEnv* env); void EmulationThreadLoop(JNIEnv* env);
void CreateImGuiContext();
void DestroyImGuiContext();
void LoadSettings(SettingsInterface& si) override; void LoadSettings(SettingsInterface& si) override;
void SetVibration(bool enabled); void SetVibration(bool enabled);
void UpdateVibration(); void UpdateVibration();

View File

@ -63,6 +63,7 @@ public:
ALWAYS_INLINE s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); } ALWAYS_INLINE s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); }
ALWAYS_INLINE s32 GetWindowHeight() const { return static_cast<s32>(m_window_info.surface_height); } ALWAYS_INLINE s32 GetWindowHeight() const { return static_cast<s32>(m_window_info.surface_height); }
ALWAYS_INLINE float GetWindowScale() const { return m_window_info.surface_scale; }
// Position is relative to the top-left corner of the window. // Position is relative to the top-left corner of the window.
ALWAYS_INLINE s32 GetMousePositionX() const { return m_mouse_position_x; } ALWAYS_INLINE s32 GetMousePositionX() const { return m_mouse_position_x; }

View File

@ -11,7 +11,6 @@
#include "frontend-common/controller_interface.h" #include "frontend-common/controller_interface.h"
#include "frontend-common/fullscreen_ui.h" #include "frontend-common/fullscreen_ui.h"
#include "frontend-common/icon.h" #include "frontend-common/icon.h"
#include "frontend-common/imgui_fullscreen.h"
#include "frontend-common/imgui_styles.h" #include "frontend-common/imgui_styles.h"
#include "frontend-common/ini_settings_interface.h" #include "frontend-common/ini_settings_interface.h"
#include "frontend-common/opengl_host_display.h" #include "frontend-common/opengl_host_display.h"
@ -42,18 +41,15 @@ bool NoGUIHostInterface::Initialize()
m_settings_interface = std::make_unique<INISettingsInterface>(GetSettingsFileName()); m_settings_interface = std::make_unique<INISettingsInterface>(GetSettingsFileName());
// TODO: Make command line. // TODO: Make command line.
m_fullscreen_ui_enabled = true; m_flags.force_fullscreen_ui = true;
if (!CommonHostInterface::Initialize()) if (!CommonHostInterface::Initialize())
return false; return false;
CreateImGuiContext(); const bool start_fullscreen = m_flags.start_fullscreen || g_settings.start_fullscreen;
const bool start_fullscreen = m_command_line_flags.start_fullscreen || g_settings.start_fullscreen;
if (!CreatePlatformWindow(start_fullscreen)) if (!CreatePlatformWindow(start_fullscreen))
{ {
Log_ErrorPrintf("Failed to create platform window"); Log_ErrorPrintf("Failed to create platform window");
ImGui::DestroyContext();
return false; return false;
} }
@ -61,10 +57,12 @@ bool NoGUIHostInterface::Initialize()
{ {
Log_ErrorPrintf("Failed to create host display"); Log_ErrorPrintf("Failed to create host display");
DestroyPlatformWindow(); DestroyPlatformWindow();
ImGui::DestroyContext();
return false; return false;
} }
if (m_fullscreen_ui_enabled)
FullscreenUI::QueueGameListRefresh();
// process events to pick up controllers before updating input map // process events to pick up controllers before updating input map
PollAndUpdate(); PollAndUpdate();
UpdateInputMap(); UpdateInputMap();
@ -73,45 +71,10 @@ bool NoGUIHostInterface::Initialize()
void NoGUIHostInterface::Shutdown() void NoGUIHostInterface::Shutdown()
{ {
CommonHostInterface::Shutdown(); DestroyDisplay();
if (m_display)
{
DestroyDisplay();
ImGui::DestroyContext();
}
DestroyPlatformWindow(); DestroyPlatformWindow();
}
void NoGUIHostInterface::CreateImGuiContext() CommonHostInterface::Shutdown();
{
ImGui::CreateContext();
ImGui::GetIO().IniFilename = nullptr;
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
}
void NoGUIHostInterface::OnPlatformWindowResized(u32 new_width, u32 new_height, float new_scale)
{
if (new_scale != ImGui::GetIO().DisplayFramebufferScale.x)
{
ImGui::GetIO().DisplayFramebufferScale = ImVec2(new_scale, new_scale);
ImGui::GetStyle() = ImGuiStyle();
ImGui::StyleColorsDarker();
ImGui::GetStyle().ScaleAllSizes(new_scale);
}
if (ImGuiFullscreen::UpdateLayoutScale())
{
if (ImGuiFullscreen::UpdateFonts())
{
if (!m_display->UpdateImGuiFontTexture())
Panic("Failed to update font texture");
}
}
if (!System::IsShutdown())
g_gpu->UpdateResolutionScale();
} }
bool NoGUIHostInterface::CreateDisplay() bool NoGUIHostInterface::CreateDisplay()
@ -163,33 +126,19 @@ bool NoGUIHostInterface::CreateDisplay()
return false; return false;
} }
if (!m_display->CreateImGuiContext() || if (!CreateHostDisplayResources())
(m_fullscreen_ui_enabled && !FullscreenUI::Initialize(this)) || Log_WarningPrint("Failed to create host display resources");
!m_display->UpdateImGuiFontTexture())
{
if (m_fullscreen_ui_enabled)
FullscreenUI::Shutdown();
m_display->DestroyImGuiContext();
m_display->DestroyRenderDevice();
m_display.reset();
ReportError("Failed to initialize imgui/fonts/fullscreen UI");
return false;
}
return true; return true;
} }
void NoGUIHostInterface::DestroyDisplay() void NoGUIHostInterface::DestroyDisplay()
{ {
if (m_fullscreen_ui_enabled) ReleaseHostDisplayResources();
FullscreenUI::Shutdown();
if (m_display) if (m_display)
{
m_display->DestroyImGuiContext();
m_display->DestroyRenderDevice(); m_display->DestroyRenderDevice();
}
m_display.reset(); m_display.reset();
} }
@ -235,42 +184,15 @@ bool NoGUIHostInterface::AcquireHostDisplay()
Panic("Failed to recreate display on GPU renderer switch"); Panic("Failed to recreate display on GPU renderer switch");
} }
if (!CreateHostDisplayResources())
return false;
return true; return true;
} }
void NoGUIHostInterface::ReleaseHostDisplay() void NoGUIHostInterface::ReleaseHostDisplay()
{ {
ReleaseHostDisplayResources();
// restore vsync, since we don't want to burn cycles at the menu // restore vsync, since we don't want to burn cycles at the menu
m_display->SetVSync(true); m_display->SetVSync(true);
} }
void NoGUIHostInterface::OnSystemCreated()
{
CommonHostInterface::OnSystemCreated();
if (m_fullscreen_ui_enabled)
FullscreenUI::SystemCreated();
}
void NoGUIHostInterface::OnSystemPaused(bool paused)
{
CommonHostInterface::OnSystemPaused(paused);
if (m_fullscreen_ui_enabled)
FullscreenUI::SystemPaused(paused);
}
void NoGUIHostInterface::OnSystemDestroyed()
{
CommonHostInterface::OnSystemDestroyed();
ReportFormattedMessage("System shut down.");
if (m_fullscreen_ui_enabled)
FullscreenUI::SystemDestroyed();
}
void NoGUIHostInterface::OnRunningGameChanged(const std::string& path, CDImage* image, const std::string& game_code, void NoGUIHostInterface::OnRunningGameChanged(const std::string& path, CDImage* image, const std::string& game_code,
const std::string& game_title) const std::string& game_title)
{ {

View File

@ -41,9 +41,6 @@ protected:
bool AcquireHostDisplay() override; bool AcquireHostDisplay() override;
void ReleaseHostDisplay() override; void ReleaseHostDisplay() override;
void OnSystemCreated() override;
void OnSystemPaused(bool paused) override;
void OnSystemDestroyed() override;
void OnRunningGameChanged(const std::string& path, CDImage* image, const std::string& game_code, void OnRunningGameChanged(const std::string& path, CDImage* image, const std::string& game_code,
const std::string& game_title) override; const std::string& game_title) override;
@ -53,11 +50,9 @@ protected:
virtual bool CreatePlatformWindow(bool fullscreen) = 0; virtual bool CreatePlatformWindow(bool fullscreen) = 0;
virtual void DestroyPlatformWindow() = 0; virtual void DestroyPlatformWindow() = 0;
virtual std::optional<WindowInfo> GetPlatformWindowInfo() = 0; virtual std::optional<WindowInfo> GetPlatformWindowInfo() = 0;
void OnPlatformWindowResized(u32 new_width, u32 new_height, float new_scale);
bool CreateDisplay(); bool CreateDisplay();
void DestroyDisplay(); void DestroyDisplay();
void CreateImGuiContext();
void RunCallbacks(); void RunCallbacks();
std::deque<std::function<void()>> m_queued_callbacks; std::deque<std::function<void()>> m_queued_callbacks;

View File

@ -98,7 +98,7 @@ bool SDLHostInterface::SetFullscreen(bool enabled)
int window_width, window_height; int window_width, window_height;
SDL_GetWindowSize(m_window, &window_width, &window_height); SDL_GetWindowSize(m_window, &window_width, &window_height);
m_display->ResizeRenderWindow(window_width, window_height); m_display->ResizeRenderWindow(window_width, window_height);
OnPlatformWindowResized(window_width, window_height, GetDPIScaleFactor(m_window)); OnHostDisplayResized(window_width, window_height, GetDPIScaleFactor(m_window));
m_fullscreen = enabled; m_fullscreen = enabled;
return true; return true;
@ -289,7 +289,7 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
if (event->window.event == SDL_WINDOWEVENT_RESIZED) if (event->window.event == SDL_WINDOWEVENT_RESIZED)
{ {
m_display->ResizeRenderWindow(event->window.data1, event->window.data2); m_display->ResizeRenderWindow(event->window.data1, event->window.data2);
OnPlatformWindowResized(event->window.data1, event->window.data2, GetDPIScaleFactor(m_window)); OnHostDisplayResized(event->window.data1, event->window.data2, GetDPIScaleFactor(m_window));
} }
else if (event->window.event == SDL_WINDOWEVENT_MOVED) else if (event->window.event == SDL_WINDOWEVENT_MOVED)
{ {

View File

@ -33,6 +33,8 @@ GeneralSettingsWidget::GeneralSettingsWidget(QtHostInterface* host_interface, QW
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.applyGameSettings, "Main", "ApplyGameSettings", SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.applyGameSettings, "Main", "ApplyGameSettings",
true); true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.autoLoadCheats, "Main", "AutoLoadCheats", false); SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.autoLoadCheats, "Main", "AutoLoadCheats", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.enableFullscreenUI, "Main", "EnableFullscreenUI",
false);
SettingWidgetBinder::BindWidgetToEnumSetting( SettingWidgetBinder::BindWidgetToEnumSetting(
m_host_interface, m_ui.controllerBackend, "Main", "ControllerBackend", &ControllerInterface::ParseBackendName, m_host_interface, m_ui.controllerBackend, "Main", "ControllerBackend", &ControllerInterface::ParseBackendName,
@ -74,9 +76,12 @@ GeneralSettingsWidget::GeneralSettingsWidget(QtHostInterface* host_interface, QW
ControllerInterface::GetDefaultBackend())), ControllerInterface::GetDefaultBackend())),
tr("Determines the backend which is used for controller input. Windows users may prefer " tr("Determines the backend which is used for controller input. Windows users may prefer "
"to use XInput over SDL2 for compatibility.")); "to use XInput over SDL2 for compatibility."));
dialog->registerWidgetHelp(
m_ui.enableFullscreenUI, tr("Enable Fullscreen UI"), tr("Unchecked"),
tr("Enables the fullscreen UI mode, suitable for controller operation which is used in the NoGUI frontend."));
// Since this one is compile-time selected, we don't put it in the .ui file. // Since this one is compile-time selected, we don't put it in the .ui file.
int current_col = 0; int current_col = 1;
int current_row = m_ui.formLayout_4->rowCount() - current_col; int current_row = m_ui.formLayout_4->rowCount() - current_col;
#ifdef WITH_DISCORD_PRESENCE #ifdef WITH_DISCORD_PRESENCE
{ {

View File

@ -102,6 +102,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0">
<widget class="QCheckBox" name="enableFullscreenUI">
<property name="text">
<string>Enable Fullscreen UI</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -10,6 +10,7 @@
#include "core/gpu.h" #include "core/gpu.h"
#include "core/system.h" #include "core/system.h"
#include "frontend-common/game_list.h" #include "frontend-common/game_list.h"
#include "frontend-common/imgui_fullscreen.h"
#include "frontend-common/imgui_styles.h" #include "frontend-common/imgui_styles.h"
#include "frontend-common/ini_settings_interface.h" #include "frontend-common/ini_settings_interface.h"
#include "frontend-common/opengl_host_display.h" #include "frontend-common/opengl_host_display.h"
@ -97,6 +98,10 @@ bool QtHostInterface::initializeOnThread()
if (!CommonHostInterface::Initialize()) if (!CommonHostInterface::Initialize())
return false; return false;
// imgui setup
setImGuiFont();
setImGuiKeyMap();
// make sure the controllers have been detected // make sure the controllers have been detected
if (m_controller_interface) if (m_controller_interface)
m_controller_interface->PollEvents(); m_controller_interface->PollEvents();
@ -294,7 +299,7 @@ void QtHostInterface::ApplySettings(bool display_osd_messages)
m_is_rendering_to_main = render_to_main; m_is_rendering_to_main = render_to_main;
updateDisplayState(); updateDisplayState();
} }
else else if (!m_fullscreen_ui_enabled)
{ {
renderDisplay(); renderDisplay();
} }
@ -367,6 +372,11 @@ void QtHostInterface::resumeSystemFromMostRecentState()
void QtHostInterface::onDisplayWindowKeyEvent(int key, bool pressed) void QtHostInterface::onDisplayWindowKeyEvent(int key, bool pressed)
{ {
DebugAssert(isOnWorkerThread()); DebugAssert(isOnWorkerThread());
const u32 masked_key = static_cast<u32>(key) & IMGUI_KEY_MASK;
if (masked_key < countof(ImGuiIO::KeysDown))
ImGui::GetIO().KeysDown[masked_key] = pressed;
HandleHostKeyEvent(key, pressed); HandleHostKeyEvent(key, pressed);
} }
@ -377,14 +387,11 @@ void QtHostInterface::onDisplayWindowMouseMoveEvent(int x, int y)
if (!m_display) if (!m_display)
return; return;
m_display->SetMousePosition(x, y); ImGuiIO& io = ImGui::GetIO();
io.MousePos[0] = static_cast<float>(x);
io.MousePos[1] = static_cast<float>(y);
if (ImGui::GetCurrentContext()) m_display->SetMousePosition(x, y);
{
ImGuiIO& io = ImGui::GetIO();
io.MousePos[0] = static_cast<float>(x);
io.MousePos[1] = static_cast<float>(y);
}
} }
void QtHostInterface::onDisplayWindowMouseButtonEvent(int button, bool pressed) void QtHostInterface::onDisplayWindowMouseButtonEvent(int button, bool pressed)
@ -413,6 +420,7 @@ void QtHostInterface::onHostDisplayWindowResized(int width, int height)
return; return;
m_display->ResizeRenderWindow(width, height); m_display->ResizeRenderWindow(width, height);
OnHostDisplayResized(width, height, m_display->GetWindowScale());
// re-render the display, since otherwise it will be out of date and stretched if paused // re-render the display, since otherwise it will be out of date and stretched if paused
if (!System::IsShutdown()) if (!System::IsShutdown())
@ -426,8 +434,9 @@ void QtHostInterface::onHostDisplayWindowResized(int width, int height)
updateDisplayState(); updateDisplayState();
} }
g_gpu->UpdateResolutionScale(); // force redraw if we're paused
renderDisplay(); if (!m_fullscreen_ui_enabled)
renderDisplay();
} }
} }
@ -470,16 +479,12 @@ bool QtHostInterface::AcquireHostDisplay()
return false; return false;
} }
createImGuiContext(display_widget->devicePixelRatioFromScreen());
if (!m_display->MakeRenderContextCurrent() || if (!m_display->MakeRenderContextCurrent() ||
!m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device, !m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device,
g_settings.gpu_threaded_presentation) || g_settings.gpu_threaded_presentation) ||
!m_display->CreateImGuiContext() || !m_display->UpdateImGuiFontTexture() || !CreateHostDisplayResources()) !CreateHostDisplayResources())
{ {
ReleaseHostDisplayResources(); ReleaseHostDisplayResources();
m_display->DestroyImGuiContext();
destroyImGuiContext();
m_display->DestroyRenderDevice(); m_display->DestroyRenderDevice();
emit destroyDisplayRequested(); emit destroyDisplayRequested();
m_display.reset(); m_display.reset();
@ -545,12 +550,16 @@ void QtHostInterface::updateDisplayState()
connectDisplaySignals(display_widget); connectDisplaySignals(display_widget);
m_is_exclusive_fullscreen = m_display->IsFullscreen(); m_is_exclusive_fullscreen = m_display->IsFullscreen();
OnHostDisplayResized(m_display->GetWindowWidth(), m_display->GetWindowHeight(), m_display->GetWindowScale());
if (!System::IsShutdown()) if (!System::IsShutdown())
{ {
g_gpu->UpdateResolutionScale();
UpdateSoftwareCursor(); UpdateSoftwareCursor();
redrawDisplayWindow();
if (!m_fullscreen_ui_enabled)
redrawDisplayWindow();
} }
UpdateSpeedLimiterState(); UpdateSpeedLimiterState();
} }
@ -559,9 +568,7 @@ void QtHostInterface::ReleaseHostDisplay()
Assert(m_display); Assert(m_display);
ReleaseHostDisplayResources(); ReleaseHostDisplayResources();
m_display->DestroyImGuiContext();
m_display->DestroyRenderDevice(); m_display->DestroyRenderDevice();
destroyImGuiContext();
emit destroyDisplayRequested(); emit destroyDisplayRequested();
m_display.reset(); m_display.reset();
m_is_fullscreen = false; m_is_fullscreen = false;
@ -1370,32 +1377,40 @@ void QtHostInterface::threadEntryPoint()
// TODO: Event which flags the thread as ready // TODO: Event which flags the thread as ready
while (!m_shutdown_flag.load()) while (!m_shutdown_flag.load())
{ {
if (!System::IsRunning()) if (System::IsRunning())
{ {
// wait until we have a system before running if (m_display_all_frames)
m_worker_thread_event_loop->exec(); System::RunFrame();
continue; else
} System::RunFrames();
if (m_display_all_frames) UpdateControllerRumble();
System::RunFrame(); if (m_frame_step_request)
{
m_frame_step_request = false;
PauseSystem(true);
}
renderDisplay();
System::UpdatePerformanceCounters();
if (m_throttler_enabled)
System::Throttle();
}
else else
System::RunFrames();
UpdateControllerRumble();
if (m_frame_step_request)
{ {
m_frame_step_request = false; // we want to keep rendering the UI when paused and fullscreen UI is enabled
PauseSystem(true); if (!m_fullscreen_ui_enabled || !System::IsValid())
{
// wait until we have a system before running
m_worker_thread_event_loop->exec();
continue;
}
renderDisplay();
} }
renderDisplay();
System::UpdatePerformanceCounters();
if (m_throttler_enabled)
System::Throttle();
m_worker_thread_event_loop->processEvents(QEventLoop::AllEvents); m_worker_thread_event_loop->processEvents(QEventLoop::AllEvents);
PollAndUpdate(); PollAndUpdate();
} }
@ -1447,8 +1462,10 @@ static std::string GetFontPath(const char* name)
#endif #endif
} }
static bool AddImGuiFont(const std::string& language, float size, float framebuffer_scale) void QtHostInterface::setImGuiFont()
{ {
std::string language(GetStringSettingValue("Main", "Language", ""));
std::string path; std::string path;
const ImWchar* range = nullptr; const ImWchar* range = nullptr;
#ifdef WIN32 #ifdef WIN32
@ -1465,34 +1482,35 @@ static bool AddImGuiFont(const std::string& language, float size, float framebuf
#endif #endif
if (!path.empty()) if (!path.empty())
{ ImGuiFullscreen::SetFontFilename(std::move(path));
return (ImGui::GetIO().Fonts->AddFontFromFileTTF(path.c_str(), size * framebuffer_scale, nullptr, range) != if (range)
nullptr); ImGuiFullscreen::SetFontGlyphRanges(range);
}
return false;
} }
void QtHostInterface::createImGuiContext(float framebuffer_scale) void QtHostInterface::setImGuiKeyMap()
{ {
ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO();
io.KeyMap[ImGuiKey_Tab] = Qt::Key_Tab & IMGUI_KEY_MASK;
auto& io = ImGui::GetIO(); io.KeyMap[ImGuiKey_LeftArrow] = Qt::Key_Left & IMGUI_KEY_MASK;
io.IniFilename = nullptr; io.KeyMap[ImGuiKey_RightArrow] = Qt::Key_Right & IMGUI_KEY_MASK;
io.DisplayFramebufferScale.x = framebuffer_scale; io.KeyMap[ImGuiKey_UpArrow] = Qt::Key_Up & IMGUI_KEY_MASK;
io.DisplayFramebufferScale.y = framebuffer_scale; io.KeyMap[ImGuiKey_DownArrow] = Qt::Key_Down & IMGUI_KEY_MASK;
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale); io.KeyMap[ImGuiKey_PageUp] = Qt::Key_PageUp & IMGUI_KEY_MASK;
io.KeyMap[ImGuiKey_PageDown] = Qt::Key_PageDown & IMGUI_KEY_MASK;
ImGui::StyleColorsDarker(); io.KeyMap[ImGuiKey_Home] = Qt::Key_Home & IMGUI_KEY_MASK;
io.KeyMap[ImGuiKey_End] = Qt::Key_End & IMGUI_KEY_MASK;
std::string language = GetStringSettingValue("Main", "Language", ""); io.KeyMap[ImGuiKey_Insert] = Qt::Key_Insert & IMGUI_KEY_MASK;
if (!AddImGuiFont(language, 15.0f, framebuffer_scale)) io.KeyMap[ImGuiKey_Delete] = Qt::Key_Delete & IMGUI_KEY_MASK;
ImGui::AddRobotoRegularFont(15.0f * framebuffer_scale); io.KeyMap[ImGuiKey_Backspace] = Qt::Key_Backspace & IMGUI_KEY_MASK;
} io.KeyMap[ImGuiKey_Space] = Qt::Key_Space & IMGUI_KEY_MASK;
io.KeyMap[ImGuiKey_Enter] = Qt::Key_Enter & IMGUI_KEY_MASK;
void QtHostInterface::destroyImGuiContext() io.KeyMap[ImGuiKey_Escape] = Qt::Key_Escape & IMGUI_KEY_MASK;
{ io.KeyMap[ImGuiKey_A] = Qt::Key_A & IMGUI_KEY_MASK;
ImGui::DestroyContext(); io.KeyMap[ImGuiKey_C] = Qt::Key_C & IMGUI_KEY_MASK;
io.KeyMap[ImGuiKey_V] = Qt::Key_V & IMGUI_KEY_MASK;
io.KeyMap[ImGuiKey_X] = Qt::Key_X & IMGUI_KEY_MASK;
io.KeyMap[ImGuiKey_Y] = Qt::Key_Y & IMGUI_KEY_MASK;
io.KeyMap[ImGuiKey_Z] = Qt::Key_Z & IMGUI_KEY_MASK;
} }
TinyString QtHostInterface::TranslateString(const char* context, const char* str) const TinyString QtHostInterface::TranslateString(const char* context, const char* str) const

View File

@ -213,7 +213,10 @@ private:
BACKGROUND_CONTROLLER_POLLING_INTERVAL = BACKGROUND_CONTROLLER_POLLING_INTERVAL =
100, /// Interval at which the controllers are polled when the system is not active. 100, /// Interval at which the controllers are polled when the system is not active.
SETTINGS_SAVE_DELAY = 1000 SETTINGS_SAVE_DELAY = 1000,
/// Crappy solution to the Qt indices being massive.
IMGUI_KEY_MASK = 511,
}; };
using InputButtonHandler = std::function<void(bool)>; using InputButtonHandler = std::function<void(bool)>;
@ -242,8 +245,8 @@ private:
void startBackgroundControllerPollTimer(); void startBackgroundControllerPollTimer();
void stopBackgroundControllerPollTimer(); void stopBackgroundControllerPollTimer();
void createImGuiContext(float framebuffer_scale); void setImGuiFont();
void destroyImGuiContext(); void setImGuiKeyMap();
void createThread(); void createThread();
void stopThread(); void stopThread();

View File

@ -25,6 +25,8 @@
#include "game_list.h" #include "game_list.h"
#include "icon.h" #include "icon.h"
#include "imgui.h" #include "imgui.h"
#include "imgui_fullscreen.h"
#include "imgui_styles.h"
#include "ini_settings_interface.h" #include "ini_settings_interface.h"
#include "save_state_selector_ui.h" #include "save_state_selector_ui.h"
#include "scmversion/scmversion.h" #include "scmversion/scmversion.h"
@ -84,6 +86,9 @@ bool CommonHostInterface::Initialize()
RegisterHotkeys(); RegisterHotkeys();
UpdateControllerInterface(); UpdateControllerInterface();
CreateImGuiContext();
return true; return true;
} }
@ -91,6 +96,8 @@ void CommonHostInterface::Shutdown()
{ {
HostInterface::Shutdown(); HostInterface::Shutdown();
ImGui::DestroyContext();
#ifdef WITH_DISCORD_PRESENCE #ifdef WITH_DISCORD_PRESENCE
ShutdownDiscordPresence(); ShutdownDiscordPresence();
#endif #endif
@ -139,7 +146,7 @@ void CommonHostInterface::InitializeUserDirectory()
bool CommonHostInterface::BootSystem(const SystemBootParameters& parameters) bool CommonHostInterface::BootSystem(const SystemBootParameters& parameters)
{ {
// If the fullscreen UI is enabled, make sure it's finished loading the game list so we don't race it. // If the fullscreen UI is enabled, make sure it's finished loading the game list so we don't race it.
if (m_fullscreen_ui_enabled) if (m_display && m_fullscreen_ui_enabled)
FullscreenUI::EnsureGameListLoaded(); FullscreenUI::EnsureGameListLoaded();
if (!HostInterface::BootSystem(parameters)) if (!HostInterface::BootSystem(parameters))
@ -268,7 +275,7 @@ bool CommonHostInterface::ParseCommandLineParameters(int argc, char* argv[],
else if (CHECK_ARG("-batch")) else if (CHECK_ARG("-batch"))
{ {
Log_InfoPrintf("Enabling batch mode."); Log_InfoPrintf("Enabling batch mode.");
m_command_line_flags.batch_mode = true; m_flags.batch_mode = true;
continue; continue;
} }
else if (CHECK_ARG("-fastboot")) else if (CHECK_ARG("-fastboot"))
@ -286,7 +293,7 @@ bool CommonHostInterface::ParseCommandLineParameters(int argc, char* argv[],
else if (CHECK_ARG("-nocontroller")) else if (CHECK_ARG("-nocontroller"))
{ {
Log_InfoPrintf("Disabling controller support."); Log_InfoPrintf("Disabling controller support.");
m_command_line_flags.disable_controller_interface = true; m_flags.disable_controller_interface = true;
continue; continue;
} }
else if (CHECK_ARG("-resume")) else if (CHECK_ARG("-resume"))
@ -307,7 +314,7 @@ bool CommonHostInterface::ParseCommandLineParameters(int argc, char* argv[],
else if (CHECK_ARG("-fullscreen")) else if (CHECK_ARG("-fullscreen"))
{ {
Log_InfoPrintf("Going fullscreen after booting."); Log_InfoPrintf("Going fullscreen after booting.");
m_command_line_flags.start_fullscreen = true; m_flags.start_fullscreen = true;
force_fullscreen = true; force_fullscreen = true;
continue; continue;
} }
@ -444,6 +451,16 @@ bool CommonHostInterface::SetFullscreen(bool enabled)
return false; return false;
} }
void CommonHostInterface::CreateImGuiContext()
{
ImGui::CreateContext();
ImGui::GetIO().IniFilename = nullptr;
#ifndef __ANDROID__
// Android has no keyboard, nor are we using ImGui for any actual user-interactable windows.
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
#endif
}
bool CommonHostInterface::CreateHostDisplayResources() bool CommonHostInterface::CreateHostDisplayResources()
{ {
m_logo_texture = m_display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, 1, 1, 1, HostDisplayPixelFormat::RGBA8, m_logo_texture = m_display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, 1, 1, 1, HostDisplayPixelFormat::RGBA8,
@ -451,14 +468,83 @@ bool CommonHostInterface::CreateHostDisplayResources()
if (!m_logo_texture) if (!m_logo_texture)
Log_WarningPrintf("Failed to create logo texture"); Log_WarningPrintf("Failed to create logo texture");
const float framebuffer_scale = m_display->GetWindowScale();
ImGui::GetIO().DisplayFramebufferScale = ImVec2(framebuffer_scale, framebuffer_scale);
ImGui::GetStyle() = ImGuiStyle();
ImGui::StyleColorsDarker();
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
if (!m_display->CreateImGuiContext())
{
Log_ErrorPrintf("Failed to create ImGui device context");
return false;
}
if (m_fullscreen_ui_enabled)
{
if (!FullscreenUI::Initialize(this))
{
Log_ErrorPrintf("Failed to initialize fullscreen UI, disabling.");
m_fullscreen_ui_enabled = false;
}
}
if (!m_fullscreen_ui_enabled)
ImGuiFullscreen::ResetFonts();
if (!m_display->UpdateImGuiFontTexture())
{
Log_ErrorPrintf("Failed to create ImGui font text");
if (m_fullscreen_ui_enabled)
FullscreenUI::Shutdown();
m_display->DestroyImGuiContext();
return false;
}
return true; return true;
} }
void CommonHostInterface::ReleaseHostDisplayResources() void CommonHostInterface::ReleaseHostDisplayResources()
{ {
if (m_fullscreen_ui_enabled)
FullscreenUI::Shutdown();
if (m_display)
m_display->DestroyImGuiContext();
m_logo_texture.reset(); m_logo_texture.reset();
} }
void CommonHostInterface::OnHostDisplayResized(u32 new_width, u32 new_height, float new_scale)
{
if (new_scale != ImGui::GetIO().DisplayFramebufferScale.x)
{
ImGui::GetIO().DisplayFramebufferScale = ImVec2(new_scale, new_scale);
ImGui::GetStyle() = ImGuiStyle();
ImGui::StyleColorsDarker();
ImGui::GetStyle().ScaleAllSizes(new_scale);
ImGuiFullscreen::ResetFonts();
if (!m_display->UpdateImGuiFontTexture())
Panic("Failed to recreate font texture after resize");
}
if (m_fullscreen_ui_enabled)
{
if (ImGuiFullscreen::UpdateLayoutScale())
{
if (ImGuiFullscreen::UpdateFonts())
{
if (!m_display->UpdateImGuiFontTexture())
Panic("Failed to update font texture");
}
}
}
if (!System::IsShutdown())
g_gpu->UpdateResolutionScale();
}
std::unique_ptr<AudioStream> CommonHostInterface::CreateAudioStream(AudioBackend backend) std::unique_ptr<AudioStream> CommonHostInterface::CreateAudioStream(AudioBackend backend)
{ {
switch (backend) switch (backend)
@ -492,7 +578,7 @@ void CommonHostInterface::UpdateControllerInterface()
ControllerInterface::ParseBackendName(backend_str.c_str()); ControllerInterface::ParseBackendName(backend_str.c_str());
const ControllerInterface::Backend current_backend = const ControllerInterface::Backend current_backend =
(m_controller_interface ? m_controller_interface->GetBackend() : ControllerInterface::Backend::None); (m_controller_interface ? m_controller_interface->GetBackend() : ControllerInterface::Backend::None);
if (new_backend == current_backend || m_command_line_flags.disable_controller_interface) if (new_backend == current_backend || m_flags.disable_controller_interface)
return; return;
if (m_controller_interface) if (m_controller_interface)
@ -781,6 +867,9 @@ void CommonHostInterface::OnSystemCreated()
{ {
HostInterface::OnSystemCreated(); HostInterface::OnSystemCreated();
if (m_fullscreen_ui_enabled)
FullscreenUI::SystemCreated();
if (g_settings.display_post_processing && !m_display->SetPostProcessingChain(g_settings.display_post_process_chain)) if (g_settings.display_post_processing && !m_display->SetPostProcessingChain(g_settings.display_post_process_chain))
AddOSDMessage(TranslateStdString("OSDMessage", "Failed to load post processing shader chain."), 20.0f); AddOSDMessage(TranslateStdString("OSDMessage", "Failed to load post processing shader chain."), 20.0f);
} }
@ -789,6 +878,9 @@ void CommonHostInterface::OnSystemPaused(bool paused)
{ {
ReportFormattedMessage("System %s.", paused ? "paused" : "resumed"); ReportFormattedMessage("System %s.", paused ? "paused" : "resumed");
if (m_fullscreen_ui_enabled)
FullscreenUI::SystemPaused(paused);
if (paused) if (paused)
{ {
if (IsFullscreen() && !m_fullscreen_ui_enabled) if (IsFullscreen() && !m_fullscreen_ui_enabled)
@ -808,6 +900,9 @@ void CommonHostInterface::OnSystemDestroyed()
HostInterface::OnSystemDestroyed(); HostInterface::OnSystemDestroyed();
if (m_fullscreen_ui_enabled)
FullscreenUI::SystemDestroyed();
StopControllerRumble(); StopControllerRumble();
} }
@ -837,6 +932,9 @@ void CommonHostInterface::OnControllerTypeChanged(u32 slot)
void CommonHostInterface::DrawImGuiWindows() void CommonHostInterface::DrawImGuiWindows()
{ {
if (m_save_state_selector_ui->IsOpen())
m_save_state_selector_ui->Draw();
if (m_fullscreen_ui_enabled) if (m_fullscreen_ui_enabled)
{ {
FullscreenUI::Render(); FullscreenUI::Render();
@ -850,9 +948,6 @@ void CommonHostInterface::DrawImGuiWindows()
} }
DrawOSDMessages(); DrawOSDMessages();
if (m_save_state_selector_ui->IsOpen())
m_save_state_selector_ui->Draw();
} }
void CommonHostInterface::DrawFPSWindow() void CommonHostInterface::DrawFPSWindow()
@ -2383,6 +2478,36 @@ void CommonHostInterface::LoadSettings(SettingsInterface& si)
#ifdef WITH_DISCORD_PRESENCE #ifdef WITH_DISCORD_PRESENCE
SetDiscordPresenceEnabled(si.GetBoolValue("Main", "EnableDiscordPresence", false)); SetDiscordPresenceEnabled(si.GetBoolValue("Main", "EnableDiscordPresence", false));
#endif #endif
const bool fullscreen_ui_enabled =
si.GetBoolValue("Main", "EnableFullscreenUI", false) || m_flags.force_fullscreen_ui;
if (fullscreen_ui_enabled != m_fullscreen_ui_enabled)
{
m_fullscreen_ui_enabled = fullscreen_ui_enabled;
if (m_display)
{
if (!fullscreen_ui_enabled)
{
FullscreenUI::Shutdown();
ImGuiFullscreen::ResetFonts();
if (!m_display->UpdateImGuiFontTexture())
Panic("Failed to recreate font texture after fullscreen UI disable");
}
else
{
if (FullscreenUI::Initialize(this))
{
if (!m_display->UpdateImGuiFontTexture())
Panic("Failed to recreate font textre after fullscreen UI enable");
}
else
{
Log_ErrorPrintf("Failed to initialize fullscreen UI. Disabling.");
m_fullscreen_ui_enabled = false;
}
}
}
}
} }
void CommonHostInterface::SaveSettings(SettingsInterface& si) void CommonHostInterface::SaveSettings(SettingsInterface& si)

View File

@ -122,6 +122,7 @@ public:
virtual bool SetFullscreen(bool enabled); virtual bool SetFullscreen(bool enabled);
virtual bool Initialize() override; virtual bool Initialize() override;
virtual void Shutdown() override; virtual void Shutdown() override;
virtual bool BootSystem(const SystemBootParameters& parameters) override; virtual bool BootSystem(const SystemBootParameters& parameters) override;
@ -141,7 +142,7 @@ public:
ALWAYS_INLINE ControllerInterface* GetControllerInterface() const { return m_controller_interface.get(); } ALWAYS_INLINE ControllerInterface* GetControllerInterface() const { return m_controller_interface.get(); }
/// Returns true if running in batch mode, i.e. exit after emulation. /// Returns true if running in batch mode, i.e. exit after emulation.
ALWAYS_INLINE bool InBatchMode() const { return m_command_line_flags.batch_mode; } ALWAYS_INLINE bool InBatchMode() const { return m_flags.batch_mode; }
/// Returns true if the fullscreen UI is enabled. /// Returns true if the fullscreen UI is enabled.
ALWAYS_INLINE bool IsFullscreenUIEnabled() const { return m_fullscreen_ui_enabled; } ALWAYS_INLINE bool IsFullscreenUIEnabled() const { return m_fullscreen_ui_enabled; }
@ -390,6 +391,7 @@ protected:
bool CreateHostDisplayResources(); bool CreateHostDisplayResources();
void ReleaseHostDisplayResources(); void ReleaseHostDisplayResources();
void OnHostDisplayResized(u32 new_width, u32 new_height, float new_scale);
virtual void DrawImGuiWindows(); virtual void DrawImGuiWindows();
@ -430,7 +432,10 @@ protected:
// starting fullscreen (outside of boot options) // starting fullscreen (outside of boot options)
BitField<u8, bool, 2, 1> start_fullscreen; BitField<u8, bool, 2, 1> start_fullscreen;
} m_command_line_flags = {};
// force fullscreen UI enabled (nogui)
BitField<u8, bool, 3, 1> force_fullscreen_ui;
} m_flags = {};
private: private:
void LoadSettings(); void LoadSettings();
@ -444,6 +449,7 @@ private:
bool UpdateControllerInputMapFromGameSettings(); bool UpdateControllerInputMapFromGameSettings();
void UpdateHotkeyInputMap(SettingsInterface& si); void UpdateHotkeyInputMap(SettingsInterface& si);
void ClearAllControllerBindings(); void ClearAllControllerBindings();
void CreateImGuiContext();
#ifdef WITH_DISCORD_PRESENCE #ifdef WITH_DISCORD_PRESENCE
void SetDiscordPresenceEnabled(bool enabled); void SetDiscordPresenceEnabled(bool enabled);

View File

@ -35,6 +35,8 @@ Log_SetChannel(FullscreenUI);
static constexpr float LAYOUT_MAIN_MENU_BAR_SIZE = 20.0f; // Should be DPI scaled, not layout scaled! static constexpr float LAYOUT_MAIN_MENU_BAR_SIZE = 20.0f; // Should be DPI scaled, not layout scaled!
using ImGuiFullscreen::g_large_font; using ImGuiFullscreen::g_large_font;
using ImGuiFullscreen::g_layout_padding_left;
using ImGuiFullscreen::g_layout_padding_top;
using ImGuiFullscreen::g_medium_font; using ImGuiFullscreen::g_medium_font;
using ImGuiFullscreen::LAYOUT_LARGE_FONT_SIZE; using ImGuiFullscreen::LAYOUT_LARGE_FONT_SIZE;
using ImGuiFullscreen::LAYOUT_MEDIUM_FONT_SIZE; using ImGuiFullscreen::LAYOUT_MEDIUM_FONT_SIZE;
@ -171,7 +173,6 @@ static bool s_save_state_selector_loading = true;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
static void DrawGameListWindow(); static void DrawGameListWindow();
static void SwitchToGameList(); static void SwitchToGameList();
static void QueueGameListRefresh();
static void SortGameList(); static void SortGameList();
static HostDisplayTexture* GetTextureForGameListEntryType(GameListEntryType type); static HostDisplayTexture* GetTextureForGameListEntryType(GameListEntryType type);
static HostDisplayTexture* GetGameListCover(const GameListEntry* entry); static HostDisplayTexture* GetGameListCover(const GameListEntry* entry);
@ -194,12 +195,16 @@ bool Initialize(CommonHostInterface* host_interface)
s_settings_copy.Load(*s_host_interface->GetSettingsInterface()); s_settings_copy.Load(*s_host_interface->GetSettingsInterface());
SetDebugMenuEnabled(s_host_interface->GetSettingsInterface()->GetBoolValue("Main", "ShowDebugMenu", false)); SetDebugMenuEnabled(s_host_interface->GetSettingsInterface()->GetBoolValue("Main", "ShowDebugMenu", false));
QueueGameListRefresh();
ImGuiFullscreen::UpdateLayoutScale(); ImGuiFullscreen::UpdateLayoutScale();
ImGuiFullscreen::UpdateFonts(); ImGuiFullscreen::UpdateFonts();
ImGuiFullscreen::SetResolveTextureFunction(ResolveTextureHandle); ImGuiFullscreen::SetResolveTextureFunction(ResolveTextureHandle);
if (System::IsValid())
SystemCreated();
if (System::IsPaused())
SystemPaused(true);
return true; return true;
} }

View File

@ -54,6 +54,7 @@ bool InvalidateCachedTexture(const std::string& path);
bool DrawErrorWindow(const char* message); bool DrawErrorWindow(const char* message);
bool DrawConfirmWindow(const char* message, bool* result); bool DrawConfirmWindow(const char* message, bool* result);
void QueueGameListRefresh();
void EnsureGameListLoaded(); void EnsureGameListLoaded();
Settings& GetSettingsCopy(); Settings& GetSettingsCopy();

View File

@ -47,10 +47,18 @@ void SetFontFilename(const char* filename)
std::string().swap(s_font_filename); std::string().swap(s_font_filename);
} }
void SetIconFontFilename(const char* icon_font_filename) void SetFontFilename(std::string filename)
{ {
if (icon_font_filename) if (!filename.empty())
s_icon_font_filename = icon_font_filename; s_font_filename = std::move(filename);
else
std::string().swap(s_font_filename);
}
void SetIconFontFilename(std::string icon_font_filename)
{
if (!icon_font_filename.empty())
s_icon_font_filename = std::move(icon_font_filename);
else else
std::string().swap(s_icon_font_filename); std::string().swap(s_icon_font_filename);
} }
@ -111,8 +119,8 @@ bool UpdateFonts()
const float medium_font_size = std::ceil(LayoutScale(LAYOUT_MEDIUM_FONT_SIZE)); const float medium_font_size = std::ceil(LayoutScale(LAYOUT_MEDIUM_FONT_SIZE));
const float large_font_size = std::ceil(LayoutScale(LAYOUT_LARGE_FONT_SIZE)); const float large_font_size = std::ceil(LayoutScale(LAYOUT_LARGE_FONT_SIZE));
if (g_standard_font && g_standard_font->FontSize == standard_font_size && medium_font_size && if (g_standard_font && g_standard_font->FontSize == standard_font_size && g_medium_font &&
g_medium_font->FontSize == medium_font_size && large_font_size && g_large_font->FontSize == large_font_size) g_medium_font->FontSize == medium_font_size && g_large_font && g_large_font->FontSize == large_font_size)
{ {
return false; return false;
} }
@ -147,6 +155,30 @@ bool UpdateFonts()
return true; return true;
} }
void ResetFonts()
{
const float standard_font_size = std::ceil(DPIScale(s_font_size));
ImGuiIO& io = ImGui::GetIO();
io.Fonts->Clear();
if (s_font_filename.empty())
{
g_standard_font = ImGui::AddRobotoRegularFont(standard_font_size);
}
else
{
g_standard_font =
io.Fonts->AddFontFromFileTTF(s_font_filename.c_str(), standard_font_size, nullptr, s_font_glyph_range);
}
g_medium_font = nullptr;
g_large_font = nullptr;
if (!io.Fonts->Build())
Panic("Failed to rebuild font atlas");
}
bool UpdateLayoutScale() bool UpdateLayoutScale()
{ {
static constexpr float LAYOUT_RATIO = LAYOUT_SCREEN_WIDTH / LAYOUT_SCREEN_HEIGHT; static constexpr float LAYOUT_RATIO = LAYOUT_SCREEN_WIDTH / LAYOUT_SCREEN_HEIGHT;

View File

@ -141,6 +141,9 @@ void SetResolveTextureFunction(ResolveTextureHandleCallback callback);
/// Rebuilds fonts to a new scale if needed. Returns true if fonts have changed and the texture needs updating. /// Rebuilds fonts to a new scale if needed. Returns true if fonts have changed and the texture needs updating.
bool UpdateFonts(); bool UpdateFonts();
/// Removes the fullscreen fonts, leaving only the standard font.
void ResetFonts();
bool UpdateLayoutScale(); bool UpdateLayoutScale();
void BeginLayout(); void BeginLayout();