mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-04-29 23:41:19 -06:00
Big Picture Mode (#4250)
* imguitest * button tests * fix gamepad nav * placeholder hardcoded eboot path * set focus correctly, move to own files * get installed game information * dynamically adjust rows * use slider for ui scale * launch big picture with CLI arg * Use emulator settings for UI scale and window size * center scrolling on focused item * fix item focus on scrolling when navigating with keyboard or pad * minor fixups and comments * fix performance degradation * adjust fonts to show TM symbol and higher overscale * reuse and clang * add exists check before iterator * flatten navigation (gamepad navigation crosses child window container) * cleanup and comments * simplify update checker a bit --------- Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
This commit is contained in:
parent
1c8ace6619
commit
cead66d3c6
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -129,6 +129,9 @@
|
||||
[submodule "externals/openal-soft"]
|
||||
path = externals/openal-soft
|
||||
url = https://github.com/shadexternals/openal-soft.git
|
||||
[submodule "externals/sdl3_image"]
|
||||
path = externals/sdl3_image
|
||||
url = https://github.com/libsdl-org/SDL_image
|
||||
[submodule "externals/libusb"]
|
||||
path = externals/libusb
|
||||
url = https://github.com/shadexternals/libusb.git
|
||||
|
||||
@ -234,6 +234,7 @@ find_package(PNG 1.6 MODULE)
|
||||
find_package(OpenAL CONFIG)
|
||||
find_package(RenderDoc 1.6.0 MODULE)
|
||||
find_package(SDL3_mixer 2.8.1 CONFIG)
|
||||
find_package(SDL3_image CONFIG)
|
||||
if (SDL3_mixer_FOUND)
|
||||
find_package(SDL3 3.1.2 CONFIG)
|
||||
endif()
|
||||
@ -1099,10 +1100,16 @@ set(IMGUI src/imgui/imgui_config.h
|
||||
src/imgui/renderer/imgui_core.h
|
||||
src/imgui/renderer/imgui_impl_sdl3.cpp
|
||||
src/imgui/renderer/imgui_impl_sdl3.h
|
||||
src/imgui/renderer/imgui_impl_sdl3_bpm.cpp
|
||||
src/imgui/renderer/imgui_impl_sdl3_bpm.h
|
||||
src/imgui/renderer/imgui_impl_sdlrenderer3.cpp
|
||||
src/imgui/renderer/imgui_impl_sdlrenderer3.h
|
||||
src/imgui/renderer/imgui_impl_vulkan.cpp
|
||||
src/imgui/renderer/imgui_impl_vulkan.h
|
||||
src/imgui/renderer/texture_manager.cpp
|
||||
src/imgui/renderer/texture_manager.h
|
||||
src/imgui/big_picture.cpp
|
||||
src/imgui/big_picture.h
|
||||
)
|
||||
|
||||
set(INPUT src/input/controller.cpp
|
||||
@ -1140,7 +1147,7 @@ add_executable(shadps4
|
||||
create_target_directory_groups(shadps4)
|
||||
|
||||
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG)
|
||||
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 SDL3_mixer::SDL3_mixer pugixml::pugixml)
|
||||
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer pugixml::pugixml)
|
||||
target_link_libraries(shadps4 PRIVATE stb::headers lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json miniz::miniz fdk-aac CLI11::CLI11 OpenAL::OpenAL Cpp_Httplib)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
|
||||
23
externals/CMakeLists.txt
vendored
23
externals/CMakeLists.txt
vendored
@ -63,6 +63,29 @@ if (NOT TARGET SDL3::SDL3)
|
||||
add_subdirectory(sdl3)
|
||||
endif()
|
||||
|
||||
# SDL3_image
|
||||
if (NOT TARGET SDL3_image::SDL3_image)
|
||||
set(SDLIMAGE_VENDORED OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_ANI OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_AVIF OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_BMP OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_GIF OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_JPG OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_JXL OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_LBM OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_PCX OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_PNM OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_QOI OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_SVG OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_TGA OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_TIF OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_WEBP OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_XCF OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_XPM OFF CACHE BOOL "" FORCE)
|
||||
set(SDLIMAGE_XV OFF CACHE BOOL "" FORCE)
|
||||
add_subdirectory(sdl3_image)
|
||||
endif()
|
||||
|
||||
# SDL3_mixer
|
||||
if (NOT TARGET SDL3_mixer::SDL3_mixer)
|
||||
set(SDLMIXER_FLAC OFF)
|
||||
|
||||
1
externals/sdl3_image
vendored
Submodule
1
externals/sdl3_image
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 1aedddcbd205c4e1ea0f99fdb2c785acc8e2489b
|
||||
@ -436,7 +436,7 @@ void L::Draw() {
|
||||
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration |
|
||||
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking)) {
|
||||
SetWindowFontScale(1.5f);
|
||||
TextCentered("Are you sure you want to quit?");
|
||||
Overlay::TextCentered("Are you sure you want to quit?");
|
||||
NewLine();
|
||||
Text("Press Escape or Circle/B button to cancel");
|
||||
Text("Press Enter or Cross/A button to quit");
|
||||
@ -481,7 +481,9 @@ void L::Draw() {
|
||||
PopID();
|
||||
}
|
||||
|
||||
void L::TextCentered(const std::string& text) {
|
||||
namespace Overlay {
|
||||
|
||||
void TextCentered(const std::string& text) {
|
||||
float window_width = GetWindowSize().x;
|
||||
float text_width = CalcTextSize(text.c_str()).x;
|
||||
float text_indentation = (window_width - text_width) * 0.5f;
|
||||
@ -490,8 +492,6 @@ void L::TextCentered(const std::string& text) {
|
||||
Text("%s", text.c_str());
|
||||
}
|
||||
|
||||
namespace Overlay {
|
||||
|
||||
void ToggleSimpleFps() {
|
||||
show_simple_fps = !show_simple_fps;
|
||||
visibility_toggled = true;
|
||||
|
||||
@ -21,8 +21,6 @@ private:
|
||||
static void DrawMenuBar();
|
||||
static void DrawAdvanced();
|
||||
static void DrawSimple();
|
||||
|
||||
static void TextCentered(const std::string& text);
|
||||
};
|
||||
|
||||
} // namespace Core::Devtools
|
||||
@ -34,4 +32,6 @@ void SetSimpleFps(bool enabled);
|
||||
void ToggleQuitWindow();
|
||||
void ShowVolume();
|
||||
|
||||
void TextCentered(const std::string& text);
|
||||
|
||||
} // namespace Overlay
|
||||
|
||||
@ -187,6 +187,7 @@ struct GeneralSettings {
|
||||
Setting<bool> discord_rpc_enabled{false};
|
||||
Setting<bool> show_fps_counter{false};
|
||||
Setting<int> console_language{1};
|
||||
Setting<int> big_picture_scale{1000};
|
||||
|
||||
// return a vector of override descriptors (runtime, but tiny)
|
||||
std::vector<OverrideItem> GetOverrideableFields() const {
|
||||
@ -218,7 +219,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GeneralSettings, install_dirs, addon_install_
|
||||
trophy_notification_duration, log_filter, log_type, show_splash,
|
||||
identical_log_grouped, trophy_notification_side,
|
||||
connected_to_network, discord_rpc_enabled, show_fps_counter,
|
||||
console_language)
|
||||
console_language, big_picture_scale)
|
||||
|
||||
// -------------------------------
|
||||
// Debug settings
|
||||
@ -557,6 +558,7 @@ public:
|
||||
SETTING_FORWARD_BOOL(m_general, DiscordRPCEnabled, discord_rpc_enabled)
|
||||
SETTING_FORWARD_BOOL(m_general, ShowFpsCounter, show_fps_counter)
|
||||
SETTING_FORWARD(m_general, ConsoleLanguage, console_language)
|
||||
SETTING_FORWARD(m_general, BigPictureScale, big_picture_scale)
|
||||
|
||||
// Audio settings
|
||||
SETTING_FORWARD(m_audio, AudioBackend, audio_backend)
|
||||
|
||||
339
src/imgui/big_picture.cpp
Normal file
339
src/imgui/big_picture.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <imgui.h>
|
||||
|
||||
#include "big_picture.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/devtools/layer.h"
|
||||
#include "core/file_format/psf.h"
|
||||
#include "emulator.h"
|
||||
#include "imgui/renderer/imgui_impl_sdl3_bpm.h"
|
||||
#include "imgui/renderer/imgui_impl_sdlrenderer3.h"
|
||||
|
||||
#include "imgui_fonts/notosansjp_regular.ttf.g.cpp"
|
||||
#include "imgui_fonts/proggyvector_regular.ttf.g.cpp"
|
||||
|
||||
namespace BigPictureMode {
|
||||
|
||||
const float gameImageSize = 200.f;
|
||||
|
||||
static bool done = false;
|
||||
static bool runGame = false;
|
||||
static std::filesystem::path runEbootPath = "";
|
||||
static std::vector<Game> gameVec = {};
|
||||
static std::vector<bool> focusState = {};
|
||||
|
||||
static float uiScale = 1.0f;
|
||||
static int scaleSelected = 1;
|
||||
|
||||
static SDL_Window* window = nullptr;
|
||||
static SDL_Renderer* renderer = nullptr;
|
||||
|
||||
void Launch() {
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
LOG_ERROR(ImGui, "SDL_INIT_VIDEO Error: {}", SDL_GetError());
|
||||
SDL_Quit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SDL_Init(SDL_INIT_GAMEPAD)) {
|
||||
LOG_ERROR(ImGui, "SDL_INIT_GAMEPAD Error: {}", SDL_GetError());
|
||||
SDL_Quit();
|
||||
return;
|
||||
}
|
||||
|
||||
window = SDL_CreateWindow("shadPS4 Big Picture Mode", EmulatorSettings.GetWindowWidth(),
|
||||
EmulatorSettings.GetWindowHeight(), SDL_WINDOW_RESIZABLE);
|
||||
renderer = SDL_CreateRenderer(window, nullptr);
|
||||
|
||||
if (EmulatorSettings.IsFullScreen()) {
|
||||
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
|
||||
}
|
||||
|
||||
// Check if window creation failed
|
||||
if (window == nullptr) {
|
||||
LOG_ERROR(ImGui, "SDL Window Creation Error: {}", SDL_GetError());
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_Quit();
|
||||
return;
|
||||
}
|
||||
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGui::StyleColorsDark();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
io.ConfigNavCursorVisibleAlways = true;
|
||||
|
||||
ImFontConfig config;
|
||||
config.OversampleH = 3;
|
||||
config.OversampleV = 3;
|
||||
config.MergeMode = true;
|
||||
|
||||
ImFontConfig config2;
|
||||
config.OversampleH = 3;
|
||||
config.OversampleV = 3;
|
||||
|
||||
// tm symbol
|
||||
static const ImWchar icon_ranges[] = {0x2122, 0x2122, 0x3000, 0x30FF, 0};
|
||||
|
||||
ImFontGlyphRangesBuilder rb{};
|
||||
rb.AddRanges(io.Fonts->GetGlyphRangesDefault());
|
||||
rb.AddRanges(io.Fonts->GetGlyphRangesGreek());
|
||||
rb.AddRanges(io.Fonts->GetGlyphRangesKorean());
|
||||
rb.AddRanges(io.Fonts->GetGlyphRangesJapanese());
|
||||
rb.AddRanges(io.Fonts->GetGlyphRangesCyrillic());
|
||||
|
||||
ImVector<ImWchar> ranges{};
|
||||
rb.BuildRanges(&ranges);
|
||||
|
||||
ImFont* myFont = io.Fonts->AddFontFromMemoryCompressedTTF(
|
||||
imgui_font_notosansjp_regular_compressed_data,
|
||||
imgui_font_notosansjp_regular_compressed_size, 32.0f, &config2, icon_ranges);
|
||||
|
||||
io.Fonts->AddFontFromMemoryCompressedTTF(imgui_font_notosansjp_regular_compressed_data,
|
||||
imgui_font_notosansjp_regular_compressed_size, 32.0f,
|
||||
&config, ranges.Data);
|
||||
|
||||
io.Fonts->AddFontFromMemoryCompressedTTF(imgui_font_proggyvector_regular_compressed_data,
|
||||
imgui_font_proggyvector_regular_compressed_size, 32.0f,
|
||||
&config, io.Fonts->GetGlyphRangesDefault());
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
ImVec4* colors = style.Colors;
|
||||
|
||||
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 1.00f); // black
|
||||
colors[ImGuiCol_Header] = ImVec4(0.20f, 0.40f, 0.70f, 1.00f); // blue
|
||||
colors[ImGuiCol_HeaderHovered] = ImVec4(0.25f, 0.50f, 0.85f, 1.00f); // lighter blue
|
||||
|
||||
style.WindowRounding = 0.0f;
|
||||
style.FrameRounding = 5.0f;
|
||||
style.ItemSpacing = ImVec2(10.0f * uiScale, 10.0f * uiScale);
|
||||
style.FramePadding = ImVec2(10.0f * uiScale, 10.0f * uiScale);
|
||||
style.WindowBorderSize = 0.0f;
|
||||
style.WindowPadding = ImVec2(20.0f * uiScale, 20.0f * uiScale);
|
||||
|
||||
ImGui_ImplSDL3_InitForSDLRenderer(window, renderer);
|
||||
ImGui_ImplSDLRenderer3_Init(renderer);
|
||||
GetGameInfo();
|
||||
|
||||
uiScale = static_cast<float>(EmulatorSettings.GetBigPictureScale() / 1000.f);
|
||||
float tempScale = uiScale;
|
||||
|
||||
while (!done) {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
ImGui_ImplSDL3_ProcessEvent(&event);
|
||||
if (event.type == SDL_EVENT_QUIT) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui_ImplSDLRenderer3_NewFrame();
|
||||
ImGui_ImplSDL3_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(viewport->WorkPos);
|
||||
ImGui::SetNextWindowSize(viewport->WorkSize);
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration;
|
||||
|
||||
ImGui::PushFont(myFont);
|
||||
ImGui::Begin("Game Window", &done, window_flags);
|
||||
ImGui::SetWindowFontScale(uiScale);
|
||||
|
||||
ImGuiWindowFlags child_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NavFlattened;
|
||||
|
||||
if (ImGui::IsWindowAppearing()) {
|
||||
ImGui::SetNextWindowFocus();
|
||||
}
|
||||
|
||||
ImGui::BeginChild("ContentRegion", ImVec2(0, -ImGui::GetFrameHeightWithSpacing()), true,
|
||||
child_flags);
|
||||
Overlay::TextCentered("Select Game");
|
||||
ImGui::Dummy(ImVec2(0.0f, 10.f * uiScale));
|
||||
|
||||
if (ImGui::IsWindowAppearing()) {
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
}
|
||||
|
||||
SetGameIcons();
|
||||
ImGui::EndChild();
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::SetNextItemWidth(300.0f * uiScale);
|
||||
if (ImGui::SliderFloat("UI Scale", &tempScale, 0.25f, 3.0f)) {
|
||||
// Dynamically changes UI scale
|
||||
}
|
||||
|
||||
// Only update when user is not interacting with slider
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
uiScale = tempScale;
|
||||
tempScale = uiScale;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
// Align buttons right
|
||||
float buttonsWidth =
|
||||
ImGui::CalcTextSize("Settings (Under Construction)").x + ImGui::CalcTextSize("Exit").x +
|
||||
ImGui::GetStyle().FramePadding.x * 4.0f + ImGui::GetStyle().ItemSpacing.x;
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x - buttonsWidth);
|
||||
|
||||
if (ImGui::Button("Settings (Under Construction)")) {
|
||||
// Todo
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Exit")) {
|
||||
ImGui::OpenPopup("Confirm Exit");
|
||||
}
|
||||
|
||||
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
if (ImGui::BeginPopupModal("Confirm Exit", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text("This will exit shadPS4!\nAre you sure?");
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Button("OK", ImVec2(120 * uiScale, 0))) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
done = true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Cancel", ImVec2(120 * uiScale, 0))) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowAppearing()) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::PopFont();
|
||||
ImGui::End();
|
||||
ImGui::Render();
|
||||
SDL_SetRenderDrawColor(renderer, 100, 100, 100, 255);
|
||||
SDL_RenderClear(renderer);
|
||||
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
ImGui_ImplSDLRenderer3_Shutdown();
|
||||
ImGui_ImplSDL3_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_Quit();
|
||||
|
||||
EmulatorSettings.SetBigPictureScale(static_cast<int>(uiScale * 1000));
|
||||
EmulatorSettings.Save();
|
||||
|
||||
if (runGame) {
|
||||
auto* emulator = Common::Singleton<Core::Emulator>::Instance();
|
||||
emulator->Run(runEbootPath);
|
||||
}
|
||||
}
|
||||
|
||||
void SetGameIcons() {
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
const float maxAvailableWidth = ImGui::GetContentRegionAvail().x;
|
||||
const float itemSpacing = style.ItemSpacing.x; // already scaled
|
||||
const float padding = 10.0f * uiScale;
|
||||
float rowContentWidth = gameImageSize * uiScale + itemSpacing;
|
||||
|
||||
// Use same line if content fits horizontally, move to next line if not
|
||||
for (int i = 0; i < gameVec.size(); i++) {
|
||||
ImGui::BeginGroup();
|
||||
|
||||
std::string ButtonName = "Button" + std::to_string(i);
|
||||
const char* ButtonNameChar = ButtonName.c_str();
|
||||
|
||||
if (ImGui::ImageButton(ButtonNameChar, (ImTextureID)gameVec[i].iconTexture,
|
||||
ImVec2(gameImageSize * uiScale, gameImageSize * uiScale))) {
|
||||
runGame = true;
|
||||
done = true;
|
||||
runEbootPath = gameVec[i].ebootPath;
|
||||
}
|
||||
|
||||
// Scroll to item only when newly-focused
|
||||
if (ImGui::IsItemFocused() && !focusState[i]) {
|
||||
ImGui::SetScrollHereY(0.5f);
|
||||
}
|
||||
focusState[i] = ImGui::IsItemFocused();
|
||||
|
||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + gameImageSize * uiScale);
|
||||
ImGui::TextWrapped("%s", gameVec[i].title.c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndGroup();
|
||||
|
||||
rowContentWidth += (gameImageSize * uiScale + itemSpacing * 2 + padding);
|
||||
if (rowContentWidth < maxAvailableWidth) {
|
||||
ImGui::SameLine(0.0f, padding);
|
||||
} else {
|
||||
ImGui::Dummy(ImVec2(0.0f, padding));
|
||||
rowContentWidth = gameImageSize * uiScale + itemSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path UpdateChecker(const std::string sceItem, std::filesystem::path game_folder) {
|
||||
std::filesystem::path outputPath;
|
||||
auto update_folder = game_folder;
|
||||
update_folder += "-UPDATE";
|
||||
|
||||
auto patch_folder = game_folder;
|
||||
patch_folder += "-patch";
|
||||
|
||||
if (std::filesystem::exists(update_folder / "sce_sys" / sceItem)) {
|
||||
outputPath = update_folder / "sce_sys" / sceItem;
|
||||
} else if (std::filesystem::exists(patch_folder / "sce_sys" / sceItem)) {
|
||||
outputPath = patch_folder / "sce_sys" / sceItem;
|
||||
} else {
|
||||
outputPath = game_folder / "sce_sys" / sceItem;
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
void GetGameInfo() {
|
||||
gameVec.clear();
|
||||
for (const auto& installLoc : EmulatorSettings.GetAllGameInstallDirs()) {
|
||||
if (installLoc.enabled && std::filesystem::exists(installLoc.path)) {
|
||||
for (const auto& entry : std::filesystem::directory_iterator(installLoc.path)) {
|
||||
if (entry.path().filename().string().ends_with("-UPDATE") ||
|
||||
entry.path().filename().string().ends_with("-patch") || !entry.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Game game;
|
||||
game.ebootPath = entry.path() / "eboot.bin";
|
||||
|
||||
const std::string iconFileName = "icon0.png";
|
||||
std::filesystem::path iconPath = UpdateChecker(iconFileName, entry.path());
|
||||
game.iconTexture = IMG_LoadTexture(renderer, iconPath.string().c_str());
|
||||
|
||||
PSF psf;
|
||||
const std::string sfoFileName = "param.sfo";
|
||||
std::filesystem::path sfoPath = UpdateChecker(sfoFileName, entry.path());
|
||||
|
||||
if (psf.Open(sfoPath)) {
|
||||
if (const auto title = psf.GetString("TITLE"); title.has_value()) {
|
||||
game.title = *title;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
gameVec.push_back(game);
|
||||
focusState.push_back(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace BigPictureMode
|
||||
22
src/imgui/big_picture.h
Normal file
22
src/imgui/big_picture.h
Normal file
@ -0,0 +1,22 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
|
||||
namespace BigPictureMode {
|
||||
|
||||
struct Game {
|
||||
SDL_Texture* iconTexture;
|
||||
std::filesystem::path ebootPath;
|
||||
std::string title;
|
||||
};
|
||||
|
||||
void Launch();
|
||||
void SetGameIcons();
|
||||
void GetGameInfo();
|
||||
std::filesystem::path UpdateChecker(const std::string sceItem, std::filesystem::path game_folder);
|
||||
|
||||
} // namespace BigPictureMode
|
||||
1313
src/imgui/renderer/imgui_impl_sdl3_bpm.cpp
Normal file
1313
src/imgui/renderer/imgui_impl_sdl3_bpm.cpp
Normal file
File diff suppressed because it is too large
Load Diff
39
src/imgui/renderer/imgui_impl_sdl3_bpm.h
Normal file
39
src/imgui/renderer/imgui_impl_sdl3_bpm.h
Normal file
@ -0,0 +1,39 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Based on imgui_impl_sdl3.h from Dear ImGui repository
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
struct SDL_Window;
|
||||
struct SDL_Renderer;
|
||||
struct SDL_Gamepad;
|
||||
typedef union SDL_Event SDL_Event;
|
||||
|
||||
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForMetal(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLGPU(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOther(SDL_Window* window);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL3_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL3_NewFrame();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event);
|
||||
|
||||
// Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad.You
|
||||
// may override this. When using manual mode, caller is responsible for opening/closing gamepad.
|
||||
enum ImGui_ImplSDL3_GamepadMode {
|
||||
ImGui_ImplSDL3_GamepadMode_AutoFirst,
|
||||
ImGui_ImplSDL3_GamepadMode_AutoAll,
|
||||
ImGui_ImplSDL3_GamepadMode_Manual
|
||||
};
|
||||
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode,
|
||||
SDL_Gamepad** manual_gamepads_array = nullptr,
|
||||
int manual_gamepads_count = -1);
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
289
src/imgui/renderer/imgui_impl_sdlrenderer3.cpp
Normal file
289
src/imgui/renderer/imgui_impl_sdlrenderer3.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Based on imgui_impl_sdlrenderer3.cpp from Dear ImGui repository
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include <stdint.h> // intptr_t
|
||||
#include "imgui_impl_sdlrenderer3.h"
|
||||
|
||||
// Clang warnings with -Weverything
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored \
|
||||
"-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#endif
|
||||
|
||||
// SDL
|
||||
#include <SDL3/SDL.h>
|
||||
#if !SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
#error This backend requires SDL 3.0.0+
|
||||
#endif
|
||||
|
||||
// SDL_Renderer data
|
||||
struct ImGui_ImplSDLRenderer3_Data {
|
||||
SDL_Renderer* Renderer; // Main viewport's renderer
|
||||
SDL_Texture* FontTexture;
|
||||
ImVector<SDL_FColor> ColorBuffer;
|
||||
|
||||
ImGui_ImplSDLRenderer3_Data() {
|
||||
memset((void*)this, 0, sizeof(*this));
|
||||
}
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui
|
||||
// contexts It is STRONGLY preferred that you use docking branch with multi-viewports (==single Dear
|
||||
// ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplSDLRenderer3_Data* ImGui_ImplSDLRenderer3_GetBackendData() {
|
||||
return ImGui::GetCurrentContext()
|
||||
? (ImGui_ImplSDLRenderer3_Data*)ImGui::GetIO().BackendRendererUserData
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IMGUI_CHECKVERSION();
|
||||
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||
IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplSDLRenderer3_Data* bd = IM_NEW(ImGui_ImplSDLRenderer3_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_sdlrenderer3";
|
||||
io.BackendFlags |=
|
||||
ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset
|
||||
// field, allowing for large meshes.
|
||||
|
||||
bd->Renderer = renderer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer3_Shutdown() {
|
||||
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplSDLRenderer3_DestroyDeviceObjects();
|
||||
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDLRenderer3_SetupRenderState(SDL_Renderer* renderer) {
|
||||
// Clear out any viewports and cliprect set by the user
|
||||
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore
|
||||
// during our render process.
|
||||
SDL_SetRenderViewport(renderer, nullptr);
|
||||
SDL_SetRenderClipRect(renderer, nullptr);
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer3_NewFrame() {
|
||||
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr &&
|
||||
"Context or backend not initialized! Did you call ImGui_ImplSDLRenderer3_Init()?");
|
||||
|
||||
if (!bd->FontTexture)
|
||||
ImGui_ImplSDLRenderer3_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
// https://github.com/libsdl-org/SDL/issues/9009
|
||||
static int SDL_RenderGeometryRaw8BitColor(SDL_Renderer* renderer, ImVector<SDL_FColor>& colors_out,
|
||||
SDL_Texture* texture, const float* xy, int xy_stride,
|
||||
const SDL_Color* color, int color_stride, const float* uv,
|
||||
int uv_stride, int num_vertices, const void* indices,
|
||||
int num_indices, int size_indices) {
|
||||
const Uint8* color2 = (const Uint8*)color;
|
||||
colors_out.resize(num_vertices);
|
||||
SDL_FColor* color3 = colors_out.Data;
|
||||
for (int i = 0; i < num_vertices; i++) {
|
||||
color3[i].r = color->r / 255.0f;
|
||||
color3[i].g = color->g / 255.0f;
|
||||
color3[i].b = color->b / 255.0f;
|
||||
color3[i].a = color->a / 255.0f;
|
||||
color2 += color_stride;
|
||||
color = (const SDL_Color*)color2;
|
||||
}
|
||||
return SDL_RenderGeometryRaw(renderer, texture, xy, xy_stride, color3, sizeof(*color3), uv,
|
||||
uv_stride, num_vertices, indices, num_indices, size_indices);
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer) {
|
||||
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
|
||||
|
||||
// If there's a scale factor set by the user, use that instead
|
||||
// If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(),
|
||||
// SDL will scale whatever we pass to SDL_RenderGeometryRaw() by that scale factor. In that case
|
||||
// we don't want to be also scaling it ourselves here.
|
||||
float rsx = 1.0f;
|
||||
float rsy = 1.0f;
|
||||
SDL_GetRenderScale(renderer, &rsx, &rsy);
|
||||
ImVec2 render_scale;
|
||||
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
|
||||
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
|
||||
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates !=
|
||||
// framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y);
|
||||
if (fb_width == 0 || fb_height == 0)
|
||||
return;
|
||||
|
||||
// Backup SDL_Renderer state that will be modified to restore it afterwards
|
||||
struct BackupSDLRendererState {
|
||||
SDL_Rect Viewport;
|
||||
bool ViewportEnabled;
|
||||
bool ClipEnabled;
|
||||
SDL_Rect ClipRect;
|
||||
};
|
||||
BackupSDLRendererState old = {};
|
||||
old.ViewportEnabled = SDL_RenderViewportSet(renderer);
|
||||
old.ClipEnabled = SDL_RenderClipEnabled(renderer);
|
||||
SDL_GetRenderViewport(renderer, &old.Viewport);
|
||||
SDL_GetRenderClipRect(renderer, &old.ClipRect);
|
||||
|
||||
// Setup desired state
|
||||
ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
|
||||
|
||||
// Setup render state structure (for callbacks and custom texture bindings)
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
ImGui_ImplSDLRenderer3_RenderState render_state;
|
||||
render_state.Renderer = renderer;
|
||||
platform_io.Renderer_RenderState = &render_state;
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = render_scale;
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++) {
|
||||
const ImDrawList* draw_list = draw_data->CmdLists[n];
|
||||
const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data;
|
||||
const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data;
|
||||
|
||||
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) {
|
||||
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback) {
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to
|
||||
// request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
|
||||
else
|
||||
pcmd->UserCallback(draw_list, pcmd);
|
||||
} else {
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x,
|
||||
(pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x,
|
||||
(pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_min.x < 0.0f) {
|
||||
clip_min.x = 0.0f;
|
||||
}
|
||||
if (clip_min.y < 0.0f) {
|
||||
clip_min.y = 0.0f;
|
||||
}
|
||||
if (clip_max.x > (float)fb_width) {
|
||||
clip_max.x = (float)fb_width;
|
||||
}
|
||||
if (clip_max.y > (float)fb_height) {
|
||||
clip_max.y = (float)fb_height;
|
||||
}
|
||||
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||
continue;
|
||||
|
||||
SDL_Rect r = {(int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x),
|
||||
(int)(clip_max.y - clip_min.y)};
|
||||
SDL_SetRenderClipRect(renderer, &r);
|
||||
|
||||
const float* xy =
|
||||
(const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) +
|
||||
offsetof(ImDrawVert, pos));
|
||||
const float* uv =
|
||||
(const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) +
|
||||
offsetof(ImDrawVert, uv));
|
||||
const SDL_Color* color =
|
||||
(const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) +
|
||||
offsetof(ImDrawVert, col)); // SDL 2.0.19+
|
||||
|
||||
// Bind texture, Draw
|
||||
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
|
||||
SDL_RenderGeometryRaw8BitColor(
|
||||
renderer, bd->ColorBuffer, tex, xy, (int)sizeof(ImDrawVert), color,
|
||||
(int)sizeof(ImDrawVert), uv, (int)sizeof(ImDrawVert),
|
||||
draw_list->VtxBuffer.Size - pcmd->VtxOffset, idx_buffer + pcmd->IdxOffset,
|
||||
pcmd->ElemCount, sizeof(ImDrawIdx));
|
||||
}
|
||||
}
|
||||
}
|
||||
platform_io.Renderer_RenderState = nullptr;
|
||||
|
||||
// Restore modified SDL_Renderer state
|
||||
SDL_SetRenderViewport(renderer, old.ViewportEnabled ? &old.Viewport : nullptr);
|
||||
SDL_SetRenderClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr);
|
||||
}
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
bool ImGui_ImplSDLRenderer3_CreateFontsTexture() {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
|
||||
|
||||
// Build texture atlas
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(
|
||||
&pixels, &width,
|
||||
&height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small)
|
||||
// because it is more likely to be compatible with user's existing shaders. If
|
||||
// your ImTextureId represent a higher-level concept than just a GL texture id,
|
||||
// consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |=
|
||||
// ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow
|
||||
// point/nearest sampling)
|
||||
bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32,
|
||||
SDL_TEXTUREACCESS_STATIC, width, height);
|
||||
if (bd->FontTexture == nullptr) {
|
||||
SDL_Log("error creating texture");
|
||||
return false;
|
||||
}
|
||||
SDL_UpdateTexture(bd->FontTexture, nullptr, pixels, 4 * width);
|
||||
SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureScaleMode(bd->FontTexture, SDL_SCALEMODE_LINEAR);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer3_DestroyFontsTexture() {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
|
||||
if (bd->FontTexture) {
|
||||
io.Fonts->SetTexID(0);
|
||||
SDL_DestroyTexture(bd->FontTexture);
|
||||
bd->FontTexture = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDLRenderer3_CreateDeviceObjects() {
|
||||
return ImGui_ImplSDLRenderer3_CreateFontsTexture();
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer3_DestroyDeviceObjects() {
|
||||
ImGui_ImplSDLRenderer3_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
33
src/imgui/renderer/imgui_impl_sdlrenderer3.h
Normal file
33
src/imgui/renderer/imgui_impl_sdlrenderer3.h
Normal file
@ -0,0 +1,33 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Based on imgui_impl_sdlrenderer3.h from Dear ImGui repository
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
struct SDL_Renderer;
|
||||
|
||||
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data,
|
||||
SDL_Renderer* renderer);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_DestroyDeviceObjects();
|
||||
|
||||
// [BETA] Selected render state data shared with callbacks.
|
||||
// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the
|
||||
// ImGui_ImplSDLRenderer3_RenderDrawData() call. (Please open an issue if you feel you need access
|
||||
// to more data)
|
||||
struct ImGui_ImplSDLRenderer3_RenderState {
|
||||
SDL_Renderer* Renderer;
|
||||
};
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
21
src/main.cpp
21
src/main.cpp
@ -20,6 +20,8 @@
|
||||
#include "core/file_sys/fs.h"
|
||||
#include "core/ipc/ipc.h"
|
||||
#include "emulator.h"
|
||||
#include "imgui/big_picture.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
@ -73,6 +75,7 @@ int main(int argc, char* argv[]) {
|
||||
bool configClean = false;
|
||||
bool configGlobal = false;
|
||||
bool logAppend = false;
|
||||
bool bigPicture = false;
|
||||
|
||||
std::optional<std::filesystem::path> addGameFolder;
|
||||
std::optional<std::filesystem::path> setAddonFolder;
|
||||
@ -84,6 +87,8 @@ int main(int argc, char* argv[]) {
|
||||
app.add_flag("-i,--ignore-game-patch", ignoreGamePatch,
|
||||
"Disable automatic loading of game patches");
|
||||
|
||||
app.add_flag("-b,--big-picture", bigPicture, "Start in Big Picture Mode");
|
||||
|
||||
// FULLSCREEN: behavior-identical
|
||||
app.add_option("-f,--fullscreen", fullscreenStr, "Fullscreen mode (true|false)");
|
||||
|
||||
@ -140,7 +145,7 @@ int main(int argc, char* argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!gamePath.has_value()) {
|
||||
if (!gamePath.has_value() && !bigPicture) {
|
||||
if (!gameArgs.empty()) {
|
||||
gamePath = gameArgs.front();
|
||||
gameArgs.erase(gameArgs.begin());
|
||||
@ -200,7 +205,7 @@ int main(int argc, char* argv[]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (!found && !bigPicture) {
|
||||
std::cerr << "Error: Game ID or file path not found: " << *gamePath << "\n";
|
||||
return 1;
|
||||
}
|
||||
@ -209,10 +214,14 @@ int main(int argc, char* argv[]) {
|
||||
if (waitPid)
|
||||
Core::Debugger::WaitForPid(*waitPid);
|
||||
|
||||
auto* emulator = Common::Singleton<Core::Emulator>::Instance();
|
||||
emulator->executableName = argv[0];
|
||||
emulator->waitForDebuggerBeforeRun = waitForDebugger;
|
||||
emulator->Run(ebootPath, gameArgs, overrideRoot);
|
||||
if (bigPicture) {
|
||||
BigPictureMode::Launch();
|
||||
} else {
|
||||
auto* emulator = Common::Singleton<Core::Emulator>::Instance();
|
||||
emulator->executableName = argv[0];
|
||||
emulator->waitForDebuggerBeforeRun = waitForDebugger;
|
||||
emulator->Run(ebootPath, gameArgs, overrideRoot);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user