/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2022 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef XENIA_APP_EMULATOR_WINDOW_H_ #define XENIA_APP_EMULATOR_WINDOW_H_ #include #include #include "xenia/emulator.h" #include "xenia/gpu/command_processor.h" #include "xenia/ui/imgui_dialog.h" #include "xenia/ui/imgui_drawer.h" #include "xenia/ui/immediate_drawer.h" #include "xenia/ui/menu_item.h" #include "xenia/ui/presenter.h" #include "xenia/ui/window.h" #include "xenia/ui/window_listener.h" #include "xenia/ui/windowed_app_context.h" #include "xenia/xbox.h" #define MAX_USERS 4 namespace xe { namespace app { struct RecentTitleEntry { std::string title_name; std::filesystem::path path_to_file; std::time_t last_run_time; }; class EmulatorWindow { public: enum : size_t { // The UI is on top of the game and is open in special cases, so // lowest-priority. kZOrderHidInput, kZOrderImGui, kZOrderProfiler, // Emulator window controls are expected to be always accessible by the // user, so highest-priority. kZOrderEmulatorWindowInput, }; virtual ~EmulatorWindow(); static std::unique_ptr Create( Emulator* emulator, ui::WindowedAppContext& app_context); std::unique_ptr Gamepad_HotKeys_Listener; int selected_title_index = -1; Emulator* emulator() const { return emulator_; } ui::WindowedAppContext& app_context() const { return app_context_; } ui::Window* window() const { return window_.get(); } ui::ImGuiDrawer* imgui_drawer() const { return imgui_drawer_.get(); } ui::Presenter* GetGraphicsSystemPresenter() const; void SetupGraphicsSystemPresenterPainting(); void ShutdownGraphicsSystemPresenterPainting(); void OnEmulatorInitialized(); void UpdateTitle(); void SetFullscreen(bool fullscreen); void ToggleFullscreen(); void SetInitializingShaderStorage(bool initializing); // Types of button functions for hotkeys. enum class ButtonFunctions { ToggleFullscreen, RunTitle, CpuTimeScalarSetHalf, CpuTimeScalarSetDouble, CpuTimeScalarReset, ClearGPUCache, ToggleControllerVibration, ClearMemoryPageState, ReadbackResolve, CloseWindow, IncTitleSelect, DecTitleSelect, Unknown }; enum class gpu_cvar { ClearMemoryPageState, ReadbackResolve, }; class ControllerHotKey { public: // If true the hotkey can be activated while a title is running, otherwise // false. bool title_passthru; // If true vibrate the controller after activating the hotkey, otherwise // false. bool rumble; std::string pretty; ButtonFunctions function; ControllerHotKey(ButtonFunctions fn = ButtonFunctions::Unknown, std::string pretty = "", bool rumble = false, bool active = true) { function = fn; this->pretty = pretty; title_passthru = active; this->rumble = rumble; } }; private: class EmulatorWindowListener final : public ui::WindowListener, public ui::WindowInputListener { public: explicit EmulatorWindowListener(EmulatorWindow& emulator_window) : emulator_window_(emulator_window) {} void OnClosing(ui::UIEvent& e) override; void OnFileDrop(ui::FileDropEvent& e) override; void OnKeyDown(ui::KeyEvent& e) override; private: EmulatorWindow& emulator_window_; }; class DisplayConfigGameConfigLoadCallback : public Emulator::GameConfigLoadCallback { public: DisplayConfigGameConfigLoadCallback(Emulator& emulator, EmulatorWindow& emulator_window) : Emulator::GameConfigLoadCallback(emulator), emulator_window_(emulator_window) {} void PostGameConfigLoad() override; private: EmulatorWindow& emulator_window_; }; class DisplayConfigDialog final : public ui::ImGuiDialog { public: DisplayConfigDialog(ui::ImGuiDrawer* imgui_drawer, EmulatorWindow& emulator_window) : ui::ImGuiDialog(imgui_drawer), emulator_window_(emulator_window) {} protected: void OnDraw(ImGuiIO& io) override; private: EmulatorWindow& emulator_window_; }; explicit EmulatorWindow(Emulator* emulator, ui::WindowedAppContext& app_context); bool Initialize(); // For comparisons, use GetSwapPostEffectForCvarValue instead as the default // fallback may be used for multiple values. static const char* GetCvarValueForSwapPostEffect( gpu::CommandProcessor::SwapPostEffect effect); static gpu::CommandProcessor::SwapPostEffect GetSwapPostEffectForCvarValue( const std::string& cvar_value); // For comparisons, use GetGuestOutputPaintEffectForCvarValue instead as the // default fallback may be used for multiple values. static const char* GetCvarValueForGuestOutputPaintEffect( ui::Presenter::GuestOutputPaintConfig::Effect effect); static ui::Presenter::GuestOutputPaintConfig::Effect GetGuestOutputPaintEffectForCvarValue(const std::string& cvar_value); static ui::Presenter::GuestOutputPaintConfig GetGuestOutputPaintConfigForCvars(); void ApplyDisplayConfigForCvars(); void OnKeyDown(ui::KeyEvent& e); void FileDrop(const std::filesystem::path& filename); void FileOpen(); void FileClose(); void InstallContent(); void ShowContentDirectory(); void CpuTimeScalarReset(); void CpuTimeScalarSetHalf(); void CpuTimeScalarSetDouble(); void CpuBreakIntoDebugger(); void CpuBreakIntoHostDebugger(); void GpuTraceFrame(); void GpuClearCaches(); void ToggleDisplayConfigDialog(); void ToggleControllerVibration(); void ShowCompatibility(); void ShowFAQ(); void ShowBuildCommit(); EmulatorWindow::ControllerHotKey ProcessControllerHotkey(int buttons); void VibrateController(xe::hid::InputSystem* input_sys, uint32_t user_index, bool vibrate = true); void GamepadHotKeys(); void ToggleGPUSetting(gpu_cvar index); bool IsUseNexusForGameBarEnabled(); std::string BoolToString(bool value); void DisplayHotKeysConfig(); xe::X_STATUS RunTitle(std::filesystem::path path); void RunPreviouslyPlayedTitle(); void RunRecentlyPlayedTitle(std::filesystem::path path_to_file); void FillRecentlyLaunchedTitlesMenu(xe::ui::MenuItem* recent_menu); void LoadRecentlyLaunchedTitles(); void AddRecentlyLaunchedTitle(std::filesystem::path path_to_file, std::string title_name); Emulator* emulator_; ui::WindowedAppContext& app_context_; EmulatorWindowListener window_listener_; std::unique_ptr window_; std::unique_ptr imgui_drawer_; std::unique_ptr display_config_game_config_load_callback_; // Creation may fail, in this case immediate drawer UI must not be drawn. std::unique_ptr immediate_drawer_; bool emulator_initialized_ = false; std::string base_title_; bool initializing_shader_storage_ = false; std::unique_ptr display_config_dialog_; std::vector recently_launched_titles_; }; } // namespace app } // namespace xe #endif // XENIA_APP_EMULATOR_WINDOW_H_