Frontend: Add settings window

This commit is contained in:
Connor McLaughlin 2019-11-07 23:52:19 +10:00
parent 57c4101ff4
commit 36b7690056
5 changed files with 240 additions and 31 deletions

View File

@ -22,8 +22,8 @@ void Settings::SetDefaults()
bios_path = "scph1001.bin"; bios_path = "scph1001.bin";
memory_card_a_filename = "memory_card_a.mcd"; memory_card_a_path = "memory_card_a.mcd";
memory_card_b_filename.clear(); memory_card_b_path.clear();
} }
void Settings::Load(const char* filename) void Settings::Load(const char* filename)
@ -46,8 +46,8 @@ void Settings::Load(const char* filename)
bios_path = ini.GetValue("BIOS", "Path", "scph1001.bin"); bios_path = ini.GetValue("BIOS", "Path", "scph1001.bin");
memory_card_a_filename = ini.GetValue("MemoryCard", "CardAPath", "memory_card_a.mcd"); memory_card_a_path = ini.GetValue("MemoryCard", "CardAPath", "memory_card_a.mcd");
memory_card_b_filename = ini.GetValue("MemoryCard", "CardBPath", ""); memory_card_b_path = ini.GetValue("MemoryCard", "CardBPath", "");
} }
bool Settings::Save(const char* filename) const bool Settings::Save(const char* filename) const
@ -67,13 +67,13 @@ bool Settings::Save(const char* filename) const
ini.SetValue("BIOS", "Path", bios_path.c_str()); ini.SetValue("BIOS", "Path", bios_path.c_str());
if (!memory_card_a_filename.empty()) if (!memory_card_a_path.empty())
ini.SetValue("MemoryCard", "CardAPath", memory_card_a_filename.c_str()); ini.SetValue("MemoryCard", "CardAPath", memory_card_a_path.c_str());
else else
ini.DeleteValue("MemoryCard", "CardAPath", nullptr); ini.DeleteValue("MemoryCard", "CardAPath", nullptr);
if (!memory_card_b_filename.empty()) if (!memory_card_b_path.empty())
ini.SetValue("MemoryCard", "CardBPath", memory_card_b_filename.c_str()); ini.SetValue("MemoryCard", "CardBPath", memory_card_b_path.c_str());
else else
ini.DeleteValue("MemoryCard", "CardBPath", nullptr); ini.DeleteValue("MemoryCard", "CardBPath", nullptr);
@ -82,6 +82,8 @@ bool Settings::Save(const char* filename) const
} }
static std::array<const char*, 3> s_gpu_renderer_names = {{"D3D11", "OpenGL", "Software"}}; static std::array<const char*, 3> s_gpu_renderer_names = {{"D3D11", "OpenGL", "Software"}};
static std::array<const char*, 3> s_gpu_renderer_display_names = {
{"Hardware (D3D11)", "Hardware (OpenGL)", "Software"}};
std::optional<Settings::GPURenderer> Settings::ParseRendererName(const char* str) std::optional<Settings::GPURenderer> Settings::ParseRendererName(const char* str)
{ {
@ -101,3 +103,8 @@ const char* Settings::GetRendererName(GPURenderer renderer)
{ {
return s_gpu_renderer_names[static_cast<int>(renderer)]; return s_gpu_renderer_names[static_cast<int>(renderer)];
} }
const char* Settings::GetRendererDisplayName(GPURenderer renderer)
{
return s_gpu_renderer_display_names[static_cast<int>(renderer)];
}

View File

@ -8,12 +8,14 @@ struct Settings
{ {
HardwareD3D11, HardwareD3D11,
HardwareOpenGL, HardwareOpenGL,
Software Software,
Count
}; };
Settings(); Settings();
bool start_paused = false; bool start_paused = false;
bool speed_limiter_enabled = true;
GPURenderer gpu_renderer = GPURenderer::Software; GPURenderer gpu_renderer = GPURenderer::Software;
u32 gpu_resolution_scale = 1; u32 gpu_resolution_scale = 1;
@ -21,6 +23,7 @@ struct Settings
bool gpu_vsync = true; bool gpu_vsync = true;
bool gpu_true_color = false; bool gpu_true_color = false;
bool display_linear_filtering = true; bool display_linear_filtering = true;
bool display_fullscreen = false;
struct DebugSettings struct DebugSettings
{ {
@ -38,8 +41,8 @@ struct Settings
// TODO: Controllers, memory cards, etc. // TODO: Controllers, memory cards, etc.
std::string bios_path; std::string bios_path;
std::string memory_card_a_filename; std::string memory_card_a_path;
std::string memory_card_b_filename; std::string memory_card_b_path;
void SetDefaults(); void SetDefaults();
void Load(const char* filename); void Load(const char* filename);
@ -47,4 +50,5 @@ struct Settings
static std::optional<GPURenderer> ParseRendererName(const char* str); static std::optional<GPURenderer> ParseRendererName(const char* str);
static const char* GetRendererName(GPURenderer renderer); static const char* GetRendererName(GPURenderer renderer);
static const char* GetRendererDisplayName(GPURenderer renderer);
}; };

View File

@ -376,16 +376,16 @@ void System::UpdateMemoryCards()
m_pad->SetMemoryCard(0, nullptr); m_pad->SetMemoryCard(0, nullptr);
m_pad->SetMemoryCard(1, nullptr); m_pad->SetMemoryCard(1, nullptr);
if (!m_settings.memory_card_a_filename.empty()) if (!m_settings.memory_card_a_path.empty())
{ {
std::shared_ptr<MemoryCard> card = MemoryCard::Open(this, m_settings.memory_card_a_filename); std::shared_ptr<MemoryCard> card = MemoryCard::Open(this, m_settings.memory_card_a_path);
if (card) if (card)
m_pad->SetMemoryCard(0, std::move(card)); m_pad->SetMemoryCard(0, std::move(card));
} }
if (!m_settings.memory_card_b_filename.empty()) if (!m_settings.memory_card_b_path.empty())
{ {
std::shared_ptr<MemoryCard> card = MemoryCard::Open(this, m_settings.memory_card_b_filename); std::shared_ptr<MemoryCard> card = MemoryCard::Open(this, m_settings.memory_card_b_path);
if (card) if (card)
m_pad->SetMemoryCard(1, std::move(card)); m_pad->SetMemoryCard(1, std::move(card));
} }

View File

@ -21,14 +21,10 @@
#include <cinttypes> #include <cinttypes>
#include <imgui.h> #include <imgui.h>
#include <imgui_impl_sdl.h> #include <imgui_impl_sdl.h>
#include <imgui_stdlib.h>
#include <nfd.h> #include <nfd.h>
Log_SetChannel(SDLHostInterface); Log_SetChannel(SDLHostInterface);
static constexpr std::array<std::pair<Settings::GPURenderer, const char*>, 3> s_gpu_renderer_names = {
{{Settings::GPURenderer::HardwareD3D11, "Hardware (Direct3D 11)"},
{Settings::GPURenderer::HardwareOpenGL, "Hardware (OpenGL)"},
{Settings::GPURenderer::Software, "Software"}}};
SDLHostInterface::SDLHostInterface() = default; SDLHostInterface::SDLHostInterface() = default;
SDLHostInterface::~SDLHostInterface() SDLHostInterface::~SDLHostInterface()
@ -111,7 +107,8 @@ bool SDLHostInterface::CreateAudioStream()
void SDLHostInterface::UpdateAudioVisualSync() void SDLHostInterface::UpdateAudioVisualSync()
{ {
const bool speed_limiter_enabled = m_speed_limiter_enabled && !m_speed_limiter_temp_disabled; const bool speed_limiter_enabled =
!m_system || (m_system->GetSettings().speed_limiter_enabled && !m_speed_limiter_temp_disabled);
const bool audio_sync_enabled = speed_limiter_enabled; const bool audio_sync_enabled = speed_limiter_enabled;
const bool vsync_enabled = !m_system || (speed_limiter_enabled && m_system->GetSettings().gpu_vsync); const bool vsync_enabled = !m_system || (speed_limiter_enabled && m_system->GetSettings().gpu_vsync);
Log_InfoPrintf("Syncing to %s%s", audio_sync_enabled ? "audio" : "", Log_InfoPrintf("Syncing to %s%s", audio_sync_enabled ? "audio" : "",
@ -182,6 +179,8 @@ void SDLHostInterface::ResetPerformanceCounters()
m_fps_timer.Reset(); m_fps_timer.Reset();
} }
void SDLHostInterface::SwitchGPURenderer() {}
void SDLHostInterface::ShutdownSystem() void SDLHostInterface::ShutdownSystem()
{ {
m_system.reset(); m_system.reset();
@ -518,9 +517,10 @@ void SDLHostInterface::HandleSDLKeyEvent(const SDL_Event* event)
{ {
if (pressed && !repeat && m_system) if (pressed && !repeat && m_system)
{ {
m_speed_limiter_enabled = !m_speed_limiter_enabled; m_system->GetSettings().speed_limiter_enabled = !m_system->GetSettings().speed_limiter_enabled;
UpdateAudioVisualSync(); UpdateAudioVisualSync();
AddOSDMessage(m_speed_limiter_enabled ? "Speed limiter enabled." : "Speed limiter disabled."); AddOSDMessage(m_system->GetSettings().speed_limiter_enabled ? "Speed limiter enabled." :
"Speed limiter disabled.");
} }
} }
break; break;
@ -558,6 +558,9 @@ void SDLHostInterface::DrawImGui()
else else
DrawPoweredOffWindow(); DrawPoweredOffWindow();
if (m_settings_window_open)
DrawSettingsWindow();
if (m_about_window_open) if (m_about_window_open)
DrawAboutWindow(); DrawAboutWindow();
@ -637,8 +640,11 @@ void SDLHostInterface::DrawMainMenuBar()
if (ImGui::BeginMenu("Settings")) if (ImGui::BeginMenu("Settings"))
{ {
if (ImGui::MenuItem("Enable Speed Limiter", nullptr, &m_speed_limiter_enabled, system_enabled)) Settings& settings = m_system ? m_system->GetSettings() : m_settings;
if (ImGui::MenuItem("Enable Speed Limiter", nullptr, &settings.speed_limiter_enabled, system_enabled))
{
UpdateAudioVisualSync(); UpdateAudioVisualSync();
}
ImGui::Separator(); ImGui::Separator();
@ -652,11 +658,12 @@ void SDLHostInterface::DrawMainMenuBar()
if (ImGui::BeginMenu("Renderer")) if (ImGui::BeginMenu("Renderer"))
{ {
const Settings::GPURenderer current = m_system->GetSettings().gpu_renderer; const Settings::GPURenderer current = m_system->GetSettings().gpu_renderer;
for (const auto& it : s_gpu_renderer_names) for (u32 i = 0; i < static_cast<u32>(Settings::GPURenderer::Count); i++)
{ {
if (ImGui::MenuItem(it.second, nullptr, current == it.first)) if (ImGui::MenuItem(Settings::GetRendererDisplayName(static_cast<Settings::GPURenderer>(i)), nullptr,
i == static_cast<u32>(current)))
{ {
m_system->GetSettings().gpu_renderer = it.first; m_system->GetSettings().gpu_renderer = static_cast<Settings::GPURenderer>(i);
m_system->RecreateGPU(); m_system->RecreateGPU();
} }
} }
@ -810,7 +817,8 @@ void SDLHostInterface::DrawPoweredOffWindow()
ImGui::NewLine(); ImGui::NewLine();
ImGui::SetCursorPosX(button_left); ImGui::SetCursorPosX(button_left);
ImGui::Button("Settings", button_size); if (ImGui::Button("Settings", button_size))
m_settings_window_open = true;
ImGui::NewLine(); ImGui::NewLine();
ImGui::SetCursorPosX(button_left); ImGui::SetCursorPosX(button_left);
@ -825,11 +833,178 @@ void SDLHostInterface::DrawPoweredOffWindow()
ImGui::End(); ImGui::End();
} }
static bool DrawSettingsSectionHeader(const char* title)
{
return ImGui::CollapsingHeader(title, ImGuiTreeNodeFlags_DefaultOpen /* | ImGuiTreeNodeFlags_Leaf*/);
}
void SDLHostInterface::DrawSettingsWindow()
{
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f),
ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Settings", &m_settings_window_open, ImGuiWindowFlags_NoResize))
{
ImGui::End();
return;
}
Settings& settings = m_system ? m_system->GetSettings() : m_settings;
bool settings_changed = false;
bool gpu_settings_changed = false;
if (ImGui::BeginTabBar("SettingsTabBar", 0))
{
const float indent = 150.0f;
if (ImGui::BeginTabItem("General"))
{
ImGui::Text("Region:");
ImGui::SameLine(indent);
static int region = 0;
ImGui::Combo("##region", &region, "NTSC-U (US)\0NTSC-J (Japan)\0PAL (Europe, Australia)");
ImGui::Text("BIOS Path:");
ImGui::SameLine(indent);
DrawFileChooser("##bios_path", &settings.bios_path);
ImGui::Checkbox("Enable Speed Limiter", &settings.speed_limiter_enabled);
ImGui::Checkbox("Pause On Start", &settings.start_paused);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Memory Cards"))
{
for (int i = 0; i < 2; i++)
{
if (!DrawSettingsSectionHeader(TinyString::FromFormat("Card %c", 'A' + i)))
continue;
ImGui::Text("Card %c", 'A' + i);
ImGui::Text("Path:");
ImGui::SameLine(indent);
std::string* path_ptr = (i == 0) ? &settings.memory_card_a_path : &settings.memory_card_b_path;
if (DrawFileChooser(TinyString::FromFormat("##memcard_%c_path", 'a' + i), path_ptr))
{
settings_changed = true;
if (m_system)
m_system->UpdateMemoryCards();
}
if (ImGui::Button("Eject"))
{
path_ptr->clear();
settings_changed = true;
if (m_system)
m_system->UpdateMemoryCards();
}
ImGui::NewLine();
}
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("GPU"))
{
if (DrawSettingsSectionHeader("Basic"))
{
ImGui::Text("Renderer:");
ImGui::SameLine(indent);
int gpu_renderer = static_cast<int>(settings.gpu_renderer);
if (ImGui::Combo(
"##gpu_renderer", &gpu_renderer,
[](void*, int index, const char** out_text) {
*out_text = Settings::GetRendererDisplayName(static_cast<Settings::GPURenderer>(index));
return true;
},
nullptr, static_cast<int>(Settings::GPURenderer::Count)))
{
settings.gpu_renderer = static_cast<Settings::GPURenderer>(gpu_renderer);
SwitchGPURenderer();
}
}
ImGui::NewLine();
if (DrawSettingsSectionHeader("Display Output"))
{
ImGui::Checkbox("Fullscreen", &settings.display_fullscreen);
if (ImGui::Checkbox("VSync", &settings.gpu_vsync))
UpdateAudioVisualSync();
ImGui::Checkbox("Linear Filtering", &settings.display_linear_filtering);
}
ImGui::NewLine();
if (DrawSettingsSectionHeader("Enhancements"))
{
ImGui::Text("Resolution Scale:");
ImGui::SameLine(indent);
static constexpr std::array<const char*, 16> resolutions = {{
"1x (1024x512)",
"2x (2048x1024)",
"3x (3072x1536)",
"4x (4096x2048)",
"5x (5120x2560)",
"6x (6144x3072)",
"7x (7168x3584)",
"8x (8192x4096)",
"9x (9216x4608)",
"10x (10240x5120)",
"11x (11264x5632)",
"12x (12288x6144)",
"13x (13312x6656)",
"14x (14336x7168)",
"15x (15360x7680)",
"16x (16384x8192)",
}};
int current_resolution_index = static_cast<int>(settings.gpu_resolution_scale) - 1;
if (ImGui::Combo("##gpu_resolution_scale", &current_resolution_index, resolutions.data(),
static_cast<int>(resolutions.size())))
{
settings.gpu_resolution_scale = static_cast<u32>(current_resolution_index + 1);
gpu_settings_changed = true;
}
ImGui::Checkbox("True 24-bit Color (disables dithering)", &settings.gpu_true_color);
}
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
const auto window_size = ImGui::GetWindowSize();
ImGui::SetCursorPosX(window_size.x - 50.0f);
ImGui::SetCursorPosY(window_size.y - 30.0f);
if (ImGui::Button("Close"))
m_settings_window_open = false;
ImGui::End();
if (settings_changed)
{
// TODO: Save to file
}
if (gpu_settings_changed && m_system)
m_system->GetGPU()->UpdateSettings();
}
void SDLHostInterface::DrawAboutWindow() void SDLHostInterface::DrawAboutWindow()
{ {
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f), ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f),
ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
if (!ImGui::Begin("About DuckStation", &m_about_window_open)) if (!ImGui::Begin("About DuckStation", &m_about_window_open, ImGuiWindowFlags_NoResize))
{ {
ImGui::End(); ImGui::End();
return; return;
@ -903,6 +1078,26 @@ void SDLHostInterface::DrawDebugWindows()
m_system->GetMDEC()->DrawDebugStateWindow(); m_system->GetMDEC()->DrawDebugStateWindow();
} }
bool SDLHostInterface::DrawFileChooser(const char* label, std::string* path, const char* filter /* = nullptr */)
{
ImGui::SetNextItemWidth(ImGui::CalcItemWidth() - 50.0f);
bool result = ImGui::InputText(label, path);
ImGui::SameLine();
ImGui::SetNextItemWidth(50.0f);
if (ImGui::Button("..."))
{
nfdchar_t* out_path = nullptr;
if (NFD_OpenDialog(filter, path->c_str(), &out_path) == NFD_OKAY)
{
path->assign(out_path);
result = true;
}
}
return result;
}
void SDLHostInterface::AddOSDMessage(const char* message, float duration /*= 2.0f*/) void SDLHostInterface::AddOSDMessage(const char* message, float duration /*= 2.0f*/)
{ {
OSDMessage msg; OSDMessage msg;

View File

@ -68,6 +68,7 @@ private:
bool InitializeSystem(const char* filename = nullptr, const char* exp1_filename = nullptr); bool InitializeSystem(const char* filename = nullptr, const char* exp1_filename = nullptr);
void ConnectDevices(); void ConnectDevices();
void ResetPerformanceCounters(); void ResetPerformanceCounters();
void SwitchGPURenderer();
void ShutdownSystem(); void ShutdownSystem();
// We only pass mouse input through if it's grabbed // We only pass mouse input through if it's grabbed
@ -92,10 +93,12 @@ private:
void DrawMainMenuBar(); void DrawMainMenuBar();
void DrawPoweredOffWindow(); void DrawPoweredOffWindow();
void DrawSettingsWindow();
void DrawAboutWindow(); void DrawAboutWindow();
void DrawOSDMessages(); void DrawOSDMessages();
void DrawDebugMenu(); void DrawDebugMenu();
void DrawDebugWindows(); void DrawDebugWindows();
bool DrawFileChooser(const char* label, std::string* path, const char* filter = nullptr);
SDL_Window* m_window = nullptr; SDL_Window* m_window = nullptr;
std::unique_ptr<HostDisplay> m_display; std::unique_ptr<HostDisplay> m_display;
@ -120,7 +123,7 @@ private:
bool m_quit_request = false; bool m_quit_request = false;
bool m_frame_step_request = false; bool m_frame_step_request = false;
bool m_focus_main_menu_bar = false; bool m_focus_main_menu_bar = false;
bool m_settings_window_open = false;
bool m_about_window_open = false; bool m_about_window_open = false;
bool m_speed_limiter_enabled = true;
bool m_speed_limiter_temp_disabled = false; bool m_speed_limiter_temp_disabled = false;
}; };