mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
BPM: Add custom background support to Big Picture Mode
Signed-off-by: SternXD <stern@sidestore.io>
This commit is contained in:
parent
5666902638
commit
87a82b16ff
@ -488,6 +488,7 @@ namespace FullscreenUI
|
||||
static ImGuiFullscreen::FileSelectorFilters GetOpenFileFilters();
|
||||
static ImGuiFullscreen::FileSelectorFilters GetDiscImageFilters();
|
||||
static ImGuiFullscreen::FileSelectorFilters GetAudioFileFilters();
|
||||
static ImGuiFullscreen::FileSelectorFilters GetImageFileFilters();
|
||||
static void DoStartPath(
|
||||
const std::string& path, std::optional<s32> state_index = std::nullopt, std::optional<bool> fast_boot = std::nullopt);
|
||||
static void DoStartFile();
|
||||
@ -701,6 +702,16 @@ namespace FullscreenUI
|
||||
static std::vector<const GameList::Entry*> s_game_list_sorted_entries;
|
||||
static GameListView s_game_list_view = GameListView::Grid;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Background
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
static void LoadCustomBackground();
|
||||
static void DrawCustomBackground();
|
||||
|
||||
static std::shared_ptr<GSTexture> s_custom_background_texture;
|
||||
static std::string s_custom_background_path;
|
||||
static bool s_custom_background_enabled = false;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Achievements
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -980,6 +991,8 @@ bool FullscreenUI::Initialize()
|
||||
s_hotkey_list_cache = InputManager::GetHotkeyList();
|
||||
MTGS::SetRunIdle(true);
|
||||
|
||||
LoadCustomBackground();
|
||||
|
||||
if (VMManager::HasValidVM())
|
||||
{
|
||||
UpdateGameDetails(VMManager::GetDiscPath(), VMManager::GetDiscSerial(), VMManager::GetTitle(true), VMManager::GetDiscCRC(),
|
||||
@ -1025,6 +1038,8 @@ void FullscreenUI::CheckForConfigChanges(const Pcsx2Config& old_config)
|
||||
|
||||
ImGuiFullscreen::SetTheme(Host::GetBaseStringSettingValue("UI", "FullscreenUITheme", "Dark"));
|
||||
|
||||
LoadCustomBackground();
|
||||
|
||||
// If achievements got disabled, we might have the menu open...
|
||||
// That means we're going to be reaching achievement state.
|
||||
if (old_config.Achievements.Enabled && !EmuConfig.Achievements.Enabled)
|
||||
@ -1184,6 +1199,11 @@ void FullscreenUI::Shutdown(bool clear_state)
|
||||
s_about_window_open = false;
|
||||
}
|
||||
s_hotkey_list_cache = {};
|
||||
|
||||
s_custom_background_texture.reset();
|
||||
s_custom_background_path.clear();
|
||||
s_custom_background_enabled = false;
|
||||
|
||||
DestroyResources();
|
||||
ImGuiFullscreen::Shutdown(clear_state);
|
||||
s_initialized = false;
|
||||
@ -1195,6 +1215,15 @@ void FullscreenUI::Render()
|
||||
if (!s_initialized)
|
||||
return;
|
||||
|
||||
// see if background setting changed
|
||||
static std::string s_last_background_path;
|
||||
std::string current_path = Host::GetBaseStringSettingValue("UI", "GameListBackgroundPath");
|
||||
if (s_last_background_path != current_path)
|
||||
{
|
||||
s_last_background_path = current_path;
|
||||
LoadCustomBackground();
|
||||
}
|
||||
|
||||
for (std::unique_ptr<GSTexture>& tex : s_cleanup_textures)
|
||||
g_gs_device->Recycle(tex.release());
|
||||
s_cleanup_textures.clear();
|
||||
@ -1202,6 +1231,20 @@ void FullscreenUI::Render()
|
||||
|
||||
ImGuiFullscreen::BeginLayout();
|
||||
|
||||
const bool should_draw_background = (s_current_main_window == MainWindowType::Landing ||
|
||||
s_current_main_window == MainWindowType::StartGame ||
|
||||
s_current_main_window == MainWindowType::Exit ||
|
||||
s_current_main_window == MainWindowType::GameList ||
|
||||
s_current_main_window == MainWindowType::GameListSettings ||
|
||||
s_current_main_window == MainWindowType::Settings) && s_custom_background_enabled && s_custom_background_texture;
|
||||
|
||||
ImVec4 original_background_color;
|
||||
if (should_draw_background)
|
||||
{
|
||||
original_background_color = ImGuiFullscreen::UIBackgroundColor;
|
||||
DrawCustomBackground();
|
||||
}
|
||||
|
||||
// Primed achievements must come first, because we don't want the pause screen to be behind them.
|
||||
if (s_current_main_window == MainWindowType::None && (EmuConfig.Achievements.Overlays || EmuConfig.Achievements.LBOverlays))
|
||||
Achievements::DrawGameOverlays();
|
||||
@ -1297,6 +1340,9 @@ void FullscreenUI::Render()
|
||||
s_game_settings_changed.store(false, std::memory_order_release);
|
||||
}
|
||||
|
||||
if (should_draw_background)
|
||||
ImGuiFullscreen::UIBackgroundColor = original_background_color;
|
||||
|
||||
ImGuiFullscreen::ResetCloseMenuIfNeeded();
|
||||
}
|
||||
|
||||
@ -1383,6 +1429,11 @@ ImGuiFullscreen::FileSelectorFilters FullscreenUI::GetAudioFileFilters()
|
||||
return {"*.wav"};
|
||||
}
|
||||
|
||||
ImGuiFullscreen::FileSelectorFilters FullscreenUI::GetImageFileFilters()
|
||||
{
|
||||
return {"*.png", "*.jpg", "*.jpeg", "*.bmp"};
|
||||
}
|
||||
|
||||
void FullscreenUI::DoStartPath(const std::string& path, std::optional<s32> state_index, std::optional<bool> fast_boot)
|
||||
{
|
||||
VMBootParameters params;
|
||||
@ -1598,6 +1649,158 @@ bool FullscreenUI::ShouldDefaultToGameList()
|
||||
return Host::GetBaseBoolSettingValue("UI", "FullscreenUIDefaultToGameList", false);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Custom Background
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FullscreenUI::LoadCustomBackground()
|
||||
{
|
||||
std::string path = Host::GetBaseStringSettingValue("UI", "GameListBackgroundPath");
|
||||
|
||||
if (path.empty())
|
||||
{
|
||||
s_custom_background_texture.reset();
|
||||
s_custom_background_path.clear();
|
||||
s_custom_background_enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_custom_background_path == path && s_custom_background_texture)
|
||||
{
|
||||
s_custom_background_enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Path::IsAbsolute(path))
|
||||
path = Path::Combine(EmuFolders::DataRoot, path);
|
||||
|
||||
if (!FileSystem::FileExists(path.c_str()))
|
||||
{
|
||||
Console.Warning("Custom background file not found: %s", path.c_str());
|
||||
s_custom_background_texture.reset();
|
||||
s_custom_background_path.clear();
|
||||
s_custom_background_enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (StringUtil::EndsWithNoCase(path, ".gif"))
|
||||
{
|
||||
Console.Warning("GIF files aren't supported as backgrounds: %s", path.c_str());
|
||||
s_custom_background_texture.reset();
|
||||
s_custom_background_path.clear();
|
||||
s_custom_background_enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (StringUtil::EndsWithNoCase(path, ".webp"))
|
||||
{
|
||||
Console.Warning("WebP files aren't supported as backgrounds: %s", path.c_str());
|
||||
s_custom_background_texture.reset();
|
||||
s_custom_background_path.clear();
|
||||
s_custom_background_enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
s_custom_background_texture = LoadTexture(path.c_str());
|
||||
if (s_custom_background_texture)
|
||||
{
|
||||
s_custom_background_path = std::move(path);
|
||||
s_custom_background_enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("Failed to load custom background: %s", path.c_str());
|
||||
s_custom_background_path.clear();
|
||||
s_custom_background_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FullscreenUI::DrawCustomBackground()
|
||||
{
|
||||
if (!s_custom_background_enabled || !s_custom_background_texture)
|
||||
return;
|
||||
|
||||
const ImGuiIO& io = ImGui::GetIO();
|
||||
const ImVec2 display_size = io.DisplaySize;
|
||||
|
||||
const float opacity = Host::GetBaseFloatSettingValue("UI", "GameListBackgroundOpacity", 100.0f) / 100.0f;
|
||||
const std::string mode = Host::GetBaseStringSettingValue("UI", "GameListBackgroundMode", "fit");
|
||||
|
||||
const float tex_width = static_cast<float>(s_custom_background_texture->GetWidth());
|
||||
const float tex_height = static_cast<float>(s_custom_background_texture->GetHeight());
|
||||
|
||||
ImVec2 img_min, img_max;
|
||||
|
||||
if (mode == "stretch")
|
||||
{
|
||||
// stretch to fill entire display (ignores aspect ratio)
|
||||
img_min = ImVec2(0.0f, 0.0f);
|
||||
img_max = display_size;
|
||||
}
|
||||
else if (mode == "fill")
|
||||
{
|
||||
// Fill display while preserving aspect ratio (could crop edges)
|
||||
const float display_aspect = display_size.x / display_size.y;
|
||||
const float tex_aspect = tex_width / tex_height;
|
||||
|
||||
float scale;
|
||||
if (tex_aspect > display_aspect)
|
||||
{
|
||||
// Image is wider scale to height and crop sides
|
||||
scale = display_size.y / tex_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Image is taller scale to width and crop top/bottom
|
||||
scale = display_size.x / tex_width;
|
||||
}
|
||||
|
||||
const float scaled_width = tex_width * scale;
|
||||
const float scaled_height = tex_height * scale;
|
||||
const float offset_x = (display_size.x - scaled_width) * 0.5f;
|
||||
const float offset_y = (display_size.y - scaled_height) * 0.5f;
|
||||
|
||||
img_min = ImVec2(offset_x, offset_y);
|
||||
img_max = ImVec2(offset_x + scaled_width, offset_y + scaled_height);
|
||||
}
|
||||
else // "fit" or default
|
||||
{
|
||||
// Fit on screen while preserving aspect ratio (no cropping)
|
||||
const float display_aspect = display_size.x / display_size.y;
|
||||
const float tex_aspect = tex_width / tex_height;
|
||||
|
||||
float scale;
|
||||
if (tex_aspect > display_aspect)
|
||||
{
|
||||
// Image is wider than display
|
||||
scale = display_size.x / tex_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Image is taller than display
|
||||
scale = display_size.y / tex_height;
|
||||
}
|
||||
|
||||
const float scaled_width = tex_width * scale;
|
||||
const float scaled_height = tex_height * scale;
|
||||
const float offset_x = (display_size.x - scaled_width) * 0.5f;
|
||||
const float offset_y = (display_size.y - scaled_height) * 0.5f;
|
||||
|
||||
img_min = ImVec2(offset_x, offset_y);
|
||||
img_max = ImVec2(offset_x + scaled_width, offset_y + scaled_height);
|
||||
}
|
||||
|
||||
// Override the UIBackgroundColor that windows use
|
||||
// We need to make windows transparent so our background image shows through
|
||||
const ImVec4 transparent_bg = ImVec4(UIBackgroundColor.x, UIBackgroundColor.y, UIBackgroundColor.z, 0.0f);
|
||||
ImGuiFullscreen::UIBackgroundColor = transparent_bg;
|
||||
|
||||
ImDrawList* bg_draw_list = ImGui::GetBackgroundDrawList();
|
||||
const ImU32 col = IM_COL32(255, 255, 255, static_cast<u8>(opacity * 255.0f));
|
||||
bg_draw_list->AddImage(reinterpret_cast<ImTextureID>(s_custom_background_texture->GetNativeHandle()),
|
||||
img_min, img_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), col);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Landing Window
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -3391,13 +3594,15 @@ void FullscreenUI::DrawSettingsWindow()
|
||||
ImVec2(io.DisplaySize.x, LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) +
|
||||
(LayoutScale(LAYOUT_MENU_BUTTON_Y_PADDING) * 2.0f) + LayoutScale(2.0f));
|
||||
|
||||
const float bg_alpha = VMManager::HasValidVM() ? 0.90f : 1.0f;
|
||||
const bool using_custom_bg = s_custom_background_enabled && s_custom_background_texture;
|
||||
const float header_bg_alpha = VMManager::HasValidVM() ? 0.90f : 1.0f;
|
||||
const float content_bg_alpha = using_custom_bg ? 0.0f : (VMManager::HasValidVM() ? 0.90f : 1.0f);
|
||||
SettingsInterface* bsi = GetEditingSettingsInterface();
|
||||
const bool game_settings = IsEditingGameSettings(bsi);
|
||||
const bool show_advanced_settings = ShouldShowAdvancedSettings(bsi);
|
||||
|
||||
if (BeginFullscreenWindow(
|
||||
ImVec2(0.0f, 0.0f), heading_size, "settings_category", ImVec4(UIPrimaryColor.x, UIPrimaryColor.y, UIPrimaryColor.z, bg_alpha)))
|
||||
ImVec2(0.0f, 0.0f), heading_size, "settings_category", ImVec4(UIPrimaryColor.x, UIPrimaryColor.y, UIPrimaryColor.z, header_bg_alpha)))
|
||||
{
|
||||
static constexpr float ITEM_WIDTH = 25.0f;
|
||||
|
||||
@ -3549,7 +3754,7 @@ void FullscreenUI::DrawSettingsWindow()
|
||||
ImVec2(0.0f, heading_size.y),
|
||||
ImVec2(io.DisplaySize.x, io.DisplaySize.y - heading_size.y - LayoutScale(LAYOUT_FOOTER_HEIGHT)),
|
||||
TinyString::from_format("settings_page_{}", static_cast<u32>(s_settings_page)).c_str(),
|
||||
ImVec4(UIBackgroundColor.x, UIBackgroundColor.y, UIBackgroundColor.z, bg_alpha), 0.0f,
|
||||
ImVec4(UIBackgroundColor.x, UIBackgroundColor.y, UIBackgroundColor.z, content_bg_alpha), 0.0f,
|
||||
ImVec2(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING, 0.0f)))
|
||||
{
|
||||
ResetFocusHere();
|
||||
@ -3810,6 +4015,72 @@ void FullscreenUI::DrawInterfaceSettingsPage()
|
||||
FSUI_CSTR("Show a save state selector UI when switching slots instead of showing a notification bubble."),
|
||||
"EmuCore", "UseSavestateSelector", true);
|
||||
|
||||
MenuHeading(FSUI_CSTR("Background"));
|
||||
|
||||
std::string background_path = bsi->GetStringValue("UI", "GameListBackgroundPath", "");
|
||||
const bool background_enabled = bsi->GetBoolValue("UI", "GameListBackgroundEnabled", false);
|
||||
|
||||
std::string background_display = FSUI_STR("None");
|
||||
if (!background_path.empty() && background_enabled)
|
||||
{
|
||||
background_display = Path::GetFileName(background_path);
|
||||
}
|
||||
|
||||
if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_IMAGE, "Background Image"),
|
||||
FSUI_CSTR("Select a custom background image to use in Big Picture Mode menus."),
|
||||
background_display.c_str()))
|
||||
{
|
||||
OpenFileSelector(FSUI_ICONSTR(ICON_FA_IMAGE, "Select Background Image"), false,
|
||||
[](const std::string& path) {
|
||||
if (!path.empty())
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface* bsi = GetEditingSettingsInterface(false);
|
||||
|
||||
std::string relative_path = Path::MakeRelative(path, EmuFolders::DataRoot);
|
||||
bsi->SetStringValue("UI", "GameListBackgroundPath", relative_path.c_str());
|
||||
bsi->SetBoolValue("UI", "GameListBackgroundEnabled", true);
|
||||
SetSettingsChanged(bsi);
|
||||
|
||||
Host::RunOnCPUThread([]() {
|
||||
LoadCustomBackground();
|
||||
});
|
||||
}
|
||||
CloseFileSelector();
|
||||
},
|
||||
GetImageFileFilters());
|
||||
}
|
||||
|
||||
if (MenuButton(FSUI_ICONSTR(ICON_FA_XMARK, "Clear Background Image"),
|
||||
FSUI_CSTR("Removes the custom background image.")))
|
||||
{
|
||||
bsi->DeleteValue("UI", "GameListBackgroundPath");
|
||||
bsi->SetBoolValue("UI", "GameListBackgroundEnabled", false);
|
||||
SetSettingsChanged(bsi);
|
||||
|
||||
s_custom_background_texture.reset();
|
||||
s_custom_background_path.clear();
|
||||
s_custom_background_enabled = false;
|
||||
}
|
||||
|
||||
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_DROPLET, "Background Opacity"),
|
||||
FSUI_CSTR("Sets the transparency of the custom background image."),
|
||||
"UI", "GameListBackgroundOpacity", 100, 0, 100, "%d%%");
|
||||
|
||||
static constexpr const char* s_background_mode_names[] = {
|
||||
FSUI_NSTR("Fit"),
|
||||
FSUI_NSTR("Fill"),
|
||||
FSUI_NSTR("Stretch"),
|
||||
};
|
||||
static constexpr const char* s_background_mode_values[] = {
|
||||
"fit",
|
||||
"fill",
|
||||
"stretch",
|
||||
};
|
||||
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_EXPAND, "Background Mode"),
|
||||
FSUI_CSTR("Select how to display the background image."),
|
||||
"UI", "GameListBackgroundMode", "fit", s_background_mode_names, s_background_mode_values, std::size(s_background_mode_names), true);
|
||||
|
||||
MenuHeading(FSUI_CSTR("Behaviour"));
|
||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_SNOOZE, "Inhibit Screensaver"),
|
||||
FSUI_CSTR("Prevents the screen saver from activating and the host from sleeping while emulation is running."), "EmuCore",
|
||||
@ -7554,9 +7825,12 @@ void FullscreenUI::DrawGameListWindow()
|
||||
|
||||
void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, UIBackgroundColor);
|
||||
|
||||
if (!BeginFullscreenColumns(nullptr, heading_size.y, true, true))
|
||||
{
|
||||
EndFullscreenColumns();
|
||||
ImGui::PopStyleColor();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -7753,6 +8027,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
}
|
||||
EndFullscreenColumnWindow();
|
||||
EndFullscreenColumns();
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user