From 76fb04eaf3a1cd715af9f77f79968f6d031deec5 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 14 May 2018 10:07:05 -0500 Subject: [PATCH] [Qt] Initial Qt main window --- src/xenia/app/emulator_window.cc | 412 ++----------------------------- src/xenia/app/emulator_window.h | 64 ++--- src/xenia/app/premake5.lua | 15 ++ src/xenia/app/xenia.qrc | 4 + src/xenia/app/xenia_main.cc | 198 +-------------- src/xenia/ui/qt/premake5.lua | 1 + 6 files changed, 82 insertions(+), 612 deletions(-) create mode 100644 src/xenia/app/xenia.qrc diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index 668c30db3..0860fc02c 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -2,411 +2,51 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2015 Ben Vanik. All rights reserved. * + * Copyright 2018 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ +#include + #include "xenia/app/emulator_window.h" -// Autogenerated by `xb premake`. -#include "build/version.h" +#include "xenia/ui/vulkan/vulkan_instance.h" +#include "xenia/ui/vulkan/vulkan_provider.h" -#include "third_party/imgui/imgui.h" -#include "xenia/base/clock.h" -#include "xenia/base/logging.h" -#include "xenia/base/platform.h" -#include "xenia/base/profiling.h" -#include "xenia/base/threading.h" -#include "xenia/emulator.h" -#include "xenia/gpu/graphics_system.h" +#include -#include "xenia/ui/file_picker.h" -#include "xenia/ui/imgui_dialog.h" -#include "xenia/ui/imgui_drawer.h" +DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]"); +DEFINE_string(gpu, "any", "Graphics system. Use: [any, vulkan, null]"); +DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]"); + +DEFINE_string(target, "", "Specifies the target .xex or .iso to execute."); +DEFINE_bool(fullscreen, false, "Toggles fullscreen"); namespace xe { namespace app { -using xe::ui::FileDropEvent; -using xe::ui::KeyEvent; -using xe::ui::MenuItem; -using xe::ui::MouseEvent; -using xe::ui::UIEvent; +EmulatorWindow::EmulatorWindow() {} -const std::wstring kBaseTitle = L"xenia"; - -EmulatorWindow::EmulatorWindow(Emulator* emulator) - : emulator_(emulator), - loop_(ui::Loop::Create()), - window_(ui::Window::Create(loop_.get(), kBaseTitle)) { - base_title_ = kBaseTitle + -#ifdef DEBUG -#if _NO_DEBUG_HEAP == 1 - L" DEBUG" + -#else - L" CHECKED" + -#endif -#endif - L" (" + xe::to_wstring(XE_BUILD_BRANCH) + L"/" + - xe::to_wstring(XE_BUILD_COMMIT_SHORT) + L"/" + - xe::to_wstring(XE_BUILD_DATE) + L")"; +bool EmulatorWindow::Setup() { + // TODO(DrChat): We own xe::Emulator. Create it and set it up. + return false; } -EmulatorWindow::~EmulatorWindow() { - loop_->PostSynchronous([this]() { window_.reset(); }); -} +bool EmulatorWindow::InitializeVulkan() { + auto provider = xe::ui::vulkan::VulkanProvider::Create(nullptr); + auto device = provider->device(); -std::unique_ptr EmulatorWindow::Create(Emulator* emulator) { - std::unique_ptr emulator_window(new EmulatorWindow(emulator)); + // Create a Qt wrapper around our vulkan instance. + vulkan_instance_ = std::make_unique(); + vulkan_instance_->setVkInstance(*provider->instance()); - emulator_window->loop()->PostSynchronous([&emulator_window]() { - xe::threading::set_name("Win32 Loop"); - xe::Profiler::ThreadEnter("Win32 Loop"); - - if (!emulator_window->Initialize()) { - xe::FatalError("Failed to initialize main window"); - return; - } - }); - - return emulator_window; -} - -bool EmulatorWindow::Initialize() { - if (!window_->Initialize()) { - XELOGE("Failed to initialize platform window"); - return false; - } - - UpdateTitle(); - - window_->on_closed.AddListener([this](UIEvent* e) { loop_->Quit(); }); - loop_->on_quit.AddListener([this](UIEvent* e) { window_.reset(); }); - - window_->on_file_drop.AddListener( - [this](FileDropEvent* e) { FileDrop(e->filename()); }); - - window_->on_key_down.AddListener([this](KeyEvent* e) { - bool handled = true; - switch (e->key_code()) { - case 0x4F: { // o - if (e->is_ctrl_pressed()) { - FileOpen(); - } - } break; - case 0x6A: { // numpad * - CpuTimeScalarReset(); - } break; - case 0x6D: { // numpad minus - CpuTimeScalarSetHalf(); - } break; - case 0x6B: { // numpad plus - CpuTimeScalarSetDouble(); - } break; - - case 0x72: { // F3 - Profiler::ToggleDisplay(); - } break; - - case 0x73: { // VK_F4 - GpuTraceFrame(); - } break; - case 0x74: { // VK_F5 - GpuClearCaches(); - } break; - case 0x76: { // VK_F7 - // Save to file - // TODO: Choose path based on user input, or from options - // TODO: Spawn a new thread to do this. - emulator()->SaveToFile(L"test.sav"); - } break; - case 0x77: { // VK_F8 - // Restore from file - // TODO: Choose path from user - // TODO: Spawn a new thread to do this. - emulator()->RestoreFromFile(L"test.sav"); - } break; - case 0x7A: { // VK_F11 - ToggleFullscreen(); - } break; - case 0x1B: { // VK_ESCAPE - // Allow users to escape fullscreen (but not enter it). - if (window_->is_fullscreen()) { - window_->ToggleFullscreen(false); - } else { - handled = false; - } - } break; - - case 0x13: { // VK_PAUSE - CpuBreakIntoDebugger(); - } break; - - case 0x70: { // VK_F1 - ShowHelpWebsite(); - } break; - - default: { handled = false; } break; - } - e->set_handled(handled); - }); - - window_->on_mouse_move.AddListener([this](MouseEvent* e) { - if (window_->is_fullscreen() && (e->dx() > 2 || e->dy() > 2)) { - if (!window_->is_cursor_visible()) { - window_->set_cursor_visible(true); - } - - cursor_hide_time_ = Clock::QueryHostSystemTime() + 30000000; - } - - e->set_handled(false); - }); - - window_->on_paint.AddListener([this](UIEvent* e) { CheckHideCursor(); }); - - // Main menu. - // FIXME: This code is really messy. - auto main_menu = MenuItem::Create(MenuItem::Type::kNormal); - auto file_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&File"); - { - file_menu->AddChild( - MenuItem::Create(MenuItem::Type::kString, L"&Open", L"Ctrl+O", - std::bind(&EmulatorWindow::FileOpen, this))); - file_menu->AddChild( - MenuItem::Create(MenuItem::Type::kString, L"Close", - std::bind(&EmulatorWindow::FileClose, this))); - file_menu->AddChild(MenuItem::Create(MenuItem::Type::kString, L"E&xit", - L"Alt+F4", - [this]() { window_->Close(); })); - } - main_menu->AddChild(std::move(file_menu)); - - // CPU menu. - auto cpu_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&CPU"); - { - cpu_menu->AddChild(MenuItem::Create( - MenuItem::Type::kString, L"&Reset Time Scalar", L"Numpad *", - std::bind(&EmulatorWindow::CpuTimeScalarReset, this))); - cpu_menu->AddChild(MenuItem::Create( - MenuItem::Type::kString, L"Time Scalar /= 2", L"Numpad -", - std::bind(&EmulatorWindow::CpuTimeScalarSetHalf, this))); - cpu_menu->AddChild(MenuItem::Create( - MenuItem::Type::kString, L"Time Scalar *= 2", L"Numpad +", - std::bind(&EmulatorWindow::CpuTimeScalarSetDouble, this))); - } - cpu_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator)); - { - cpu_menu->AddChild(MenuItem::Create(MenuItem::Type::kString, - L"Toggle Profiler &Display", L"F3", - []() { Profiler::ToggleDisplay(); })); - cpu_menu->AddChild(MenuItem::Create(MenuItem::Type::kString, - L"&Pause/Resume Profiler", L"`", - []() { Profiler::TogglePause(); })); - } - cpu_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator)); - { - cpu_menu->AddChild(MenuItem::Create( - MenuItem::Type::kString, L"&Break and Show Debugger", L"Pause/Break", - std::bind(&EmulatorWindow::CpuBreakIntoDebugger, this))); - } - main_menu->AddChild(std::move(cpu_menu)); - - // GPU menu. - auto gpu_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&GPU"); - { - gpu_menu->AddChild( - MenuItem::Create(MenuItem::Type::kString, L"&Trace Frame", L"F4", - std::bind(&EmulatorWindow::GpuTraceFrame, this))); - } - gpu_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator)); - { - gpu_menu->AddChild( - MenuItem::Create(MenuItem::Type::kString, L"&Clear Caches", L"F5", - std::bind(&EmulatorWindow::GpuClearCaches, this))); - } - main_menu->AddChild(std::move(gpu_menu)); - - // Window menu. - auto window_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&Window"); - { - window_menu->AddChild( - MenuItem::Create(MenuItem::Type::kString, L"&Fullscreen", L"F11", - std::bind(&EmulatorWindow::ToggleFullscreen, this))); - } - main_menu->AddChild(std::move(window_menu)); - - // Help menu. - auto help_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&Help"); - { - help_menu->AddChild(MenuItem::Create( - MenuItem::Type::kString, L"Build commit on GitHub...", [this]() { - std::string url = - std::string("https://github.com/benvanik/xenia/tree/") + - XE_BUILD_COMMIT + "/"; - LaunchBrowser(url.c_str()); - })); - help_menu->AddChild(MenuItem::Create( - MenuItem::Type::kString, L"Recent changes on GitHub...", [this]() { - std::string url = - std::string("https://github.com/benvanik/xenia/compare/") + - XE_BUILD_COMMIT + "..." + XE_BUILD_BRANCH; - LaunchBrowser(url.c_str()); - })); - help_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator)); - help_menu->AddChild( - MenuItem::Create(MenuItem::Type::kString, L"&Website...", L"F1", - std::bind(&EmulatorWindow::ShowHelpWebsite, this))); - help_menu->AddChild(MenuItem::Create( - MenuItem::Type::kString, L"&About...", - [this]() { LaunchBrowser("http://xenia.jp/about/"); })); - } - main_menu->AddChild(std::move(help_menu)); - - window_->set_main_menu(std::move(main_menu)); - - window_->Resize(1280, 720); - - window_->DisableMainMenu(); + graphics_window_ = std::make_unique(); + graphics_window_->setVulkanInstance(vulkan_instance_.get()); + graphics_provider_ = std::move(provider); return true; } -void EmulatorWindow::FileDrop(wchar_t* filename) { - std::wstring path = filename; - auto result = emulator_->LaunchPath(path); - if (XFAILED(result)) { - // TODO: Display a message box. - XELOGE("Failed to launch target: %.8X", result); - } -} - -void EmulatorWindow::FileOpen() { - std::wstring path; - - auto file_picker = xe::ui::FilePicker::Create(); - file_picker->set_mode(ui::FilePicker::Mode::kOpen); - file_picker->set_type(ui::FilePicker::Type::kFile); - file_picker->set_multi_selection(false); - file_picker->set_title(L"Select Content Package"); - file_picker->set_extensions({ - {L"Supported Files", L"*.iso;*.xex;*.xcp;*.*"}, - {L"Disc Image (*.iso)", L"*.iso"}, - {L"Xbox Executable (*.xex)", L"*.xex"}, - //{ L"Content Package (*.xcp)", L"*.xcp" }, - {L"All Files (*.*)", L"*.*"}, - }); - if (file_picker->Show(window_->native_handle())) { - auto selected_files = file_picker->selected_files(); - if (!selected_files.empty()) { - path = selected_files[0]; - } - } - - if (!path.empty()) { - // Normalize the path and make absolute. - std::wstring abs_path = xe::to_absolute_path(path); - - auto result = emulator_->LaunchPath(abs_path); - if (XFAILED(result)) { - // TODO: Display a message box. - XELOGE("Failed to launch target: %.8X", result); - } - } -} - -void EmulatorWindow::FileClose() { - if (emulator_->is_title_open()) { - emulator_->TerminateTitle(); - } -} - -void EmulatorWindow::CheckHideCursor() { - if (!window_->is_fullscreen()) { - // Only hide when fullscreen. - return; - } - - if (Clock::QueryHostSystemTime() > cursor_hide_time_) { - window_->set_cursor_visible(false); - } -} - -void EmulatorWindow::CpuTimeScalarReset() { - Clock::set_guest_time_scalar(1.0); - UpdateTitle(); -} - -void EmulatorWindow::CpuTimeScalarSetHalf() { - Clock::set_guest_time_scalar(Clock::guest_time_scalar() / 2.0); - UpdateTitle(); -} - -void EmulatorWindow::CpuTimeScalarSetDouble() { - Clock::set_guest_time_scalar(Clock::guest_time_scalar() * 2.0); - UpdateTitle(); -} - -void EmulatorWindow::CpuBreakIntoDebugger() { - if (!FLAGS_debug) { - xe::ui::ImGuiDialog::ShowMessageBox(window_.get(), "Xenia Debugger", - "Xenia must be launched with the " - "--debug flag in order to enable " - "debugging."); - return; - } - auto processor = emulator()->processor(); - if (processor->execution_state() == cpu::ExecutionState::kRunning) { - // Currently running, so interrupt (and show the debugger). - processor->Pause(); - } else { - // Not running, so just bring the debugger into focus. - processor->ShowDebugger(); - } -} - -void EmulatorWindow::GpuTraceFrame() { - emulator()->graphics_system()->RequestFrameTrace(); -} - -void EmulatorWindow::GpuClearCaches() { - emulator()->graphics_system()->ClearCaches(); -} - -void EmulatorWindow::ToggleFullscreen() { - window_->ToggleFullscreen(!window_->is_fullscreen()); - - // Hide the cursor after a second if we're going fullscreen - cursor_hide_time_ = Clock::QueryHostSystemTime() + 30000000; - if (!window_->is_fullscreen()) { - window_->set_cursor_visible(true); - } -} - -void EmulatorWindow::ShowHelpWebsite() { LaunchBrowser("http://xenia.jp"); } - -void EmulatorWindow::UpdateTitle() { - std::wstring title(base_title_); - - if (emulator()->is_title_open()) { - auto game_title = emulator()->game_title(); - title += xe::format_string(L" | [%.8X] %s", emulator()->title_id(), - game_title.c_str()); - } - - auto graphics_system = emulator()->graphics_system(); - if (graphics_system) { - auto graphics_name = graphics_system->name(); - title += L" <" + graphics_name + L">"; - } - - if (Clock::guest_time_scalar() != 1.0) { - title += xe::format_string(L" (@%.2fx)", Clock::guest_time_scalar()); - } - - window_->set_title(title); -} - } // namespace app -} // namespace xe +} // namespace xe \ No newline at end of file diff --git a/src/xenia/app/emulator_window.h b/src/xenia/app/emulator_window.h index ff081175f..45a57bf38 100644 --- a/src/xenia/app/emulator_window.h +++ b/src/xenia/app/emulator_window.h @@ -2,67 +2,51 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2015 Ben Vanik. All rights reserved. * + * Copyright 2018 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_ +#ifndef XENIA_APP_MAIN_WINDOW_H_ +#define XENIA_APP_MAIN_WINDOW_H_ -#include -#include +#include +#include +#include -#include "xenia/ui/loop.h" -#include "xenia/ui/menu_item.h" -#include "xenia/ui/window.h" -#include "xenia/xbox.h" - -namespace xe { -class Emulator; -} // namespace xe +#include "xenia/emulator.h" +#include "xenia/ui/graphics_context.h" +#include "xenia/ui/graphics_provider.h" namespace xe { namespace app { -class EmulatorWindow { +class EmulatorWindow : public QMainWindow { + Q_OBJECT + public: - virtual ~EmulatorWindow(); + EmulatorWindow(); - static std::unique_ptr Create(Emulator* emulator); + bool Setup(); + bool InitializeVulkan(); - Emulator* emulator() const { return emulator_; } - ui::Loop* loop() const { return loop_.get(); } - ui::Window* window() const { return window_.get(); } + protected: + // Events - void UpdateTitle(); - void ToggleFullscreen(); + private slots: private: - explicit EmulatorWindow(Emulator* emulator); + void CreateMenuBar(); - bool Initialize(); + std::unique_ptr emulator_; - void FileDrop(wchar_t* filename); - void FileOpen(); - void FileClose(); - void CheckHideCursor(); - void CpuTimeScalarReset(); - void CpuTimeScalarSetHalf(); - void CpuTimeScalarSetDouble(); - void CpuBreakIntoDebugger(); - void GpuTraceFrame(); - void GpuClearCaches(); - void ShowHelpWebsite(); + std::unique_ptr graphics_window_; + std::unique_ptr graphics_provider_; - Emulator* emulator_; - std::unique_ptr loop_; - std::unique_ptr window_; - std::wstring base_title_; - uint64_t cursor_hide_time_ = 0; + std::unique_ptr vulkan_instance_; }; } // namespace app } // namespace xe -#endif // XENIA_APP_EMULATOR_WINDOW_H_ +#endif // XENIA_UI_QT_MAIN_WINDOW_H_ \ No newline at end of file diff --git a/src/xenia/app/premake5.lua b/src/xenia/app/premake5.lua index 3b4b4b9c6..7b61e10d3 100644 --- a/src/xenia/app/premake5.lua +++ b/src/xenia/app/premake5.lua @@ -1,5 +1,6 @@ project_root = "../../.." include(project_root.."/tools/build") +local qt = premake.extensions.qt group("src") project("xenia-app") @@ -32,11 +33,22 @@ project("xenia-app") "xenia-hid-nop", "xenia-kernel", "xenia-ui", + "xenia-ui-qt", "xenia-ui-spirv", "xenia-ui-vulkan", "xenia-vfs", "xxhash", }) + + -- Setup Qt libraries + qt.enable() + qtmodules{"core", "gui", "widgets"} + qtprefix "Qt5" + + configuration {"Debug"} + qtsuffix "d" + configuration {} + flags({ "WinMain", -- Use WinMain instead of main. }) @@ -84,4 +96,7 @@ project("xenia-app") "2>&1", "1>scratch/stdout.txt", }) + debugenvs({ + "PATH=" .. qt.defaultpath .. "/bin", + }) end diff --git a/src/xenia/app/xenia.qrc b/src/xenia/app/xenia.qrc new file mode 100644 index 000000000..858cb94f0 --- /dev/null +++ b/src/xenia/app/xenia.qrc @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/xenia/app/xenia_main.cc b/src/xenia/app/xenia_main.cc index def29b7c5..1604d8e87 100644 --- a/src/xenia/app/xenia_main.cc +++ b/src/xenia/app/xenia_main.cc @@ -9,40 +9,16 @@ #include -#include "xenia/app/emulator_window.h" #include "xenia/base/debugging.h" #include "xenia/base/logging.h" #include "xenia/base/main.h" #include "xenia/base/profiling.h" #include "xenia/base/threading.h" -#include "xenia/debug/ui/debug_window.h" -#include "xenia/emulator.h" -#include "xenia/ui/file_picker.h" #include "xenia/vfs/devices/host_path_device.h" -// Available audio systems: -#include "xenia/apu/nop/nop_audio_system.h" -#if XE_PLATFORM_WIN32 -#include "xenia/apu/xaudio2/xaudio2_audio_system.h" -#endif // XE_PLATFORM_WIN32 +#include "xenia/app/emulator_window.h" -// Available graphics systems: -#include "xenia/gpu/null/null_graphics_system.h" -#include "xenia/gpu/vulkan/vulkan_graphics_system.h" - -// Available input drivers: -#include "xenia/hid/nop/nop_hid.h" -#if XE_PLATFORM_WIN32 -#include "xenia/hid/winkey/winkey_hid.h" -#include "xenia/hid/xinput/xinput_hid.h" -#endif // XE_PLATFORM_WIN32 - -DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]"); -DEFINE_string(gpu, "any", "Graphics system. Use: [any, vulkan, null]"); -DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]"); - -DEFINE_string(target, "", "Specifies the target .xex or .iso to execute."); -DEFINE_bool(fullscreen, false, "Toggles fullscreen"); +#include DEFINE_bool(mount_scratch, false, "Enable scratch mount"); DEFINE_bool(mount_cache, false, "Enable cache mount"); @@ -50,101 +26,19 @@ DEFINE_bool(mount_cache, false, "Enable cache mount"); namespace xe { namespace app { -std::unique_ptr CreateAudioSystem(cpu::Processor* processor) { - if (FLAGS_apu.compare("nop") == 0) { - return apu::nop::NopAudioSystem::Create(processor); -#if XE_PLATFORM_WIN32 - } else if (FLAGS_apu.compare("xaudio2") == 0) { - return apu::xaudio2::XAudio2AudioSystem::Create(processor); -#endif // XE_PLATFORM_WIN32 - } else { - // Create best available. - std::unique_ptr best; - -#if XE_PLATFORM_WIN32 - best = apu::xaudio2::XAudio2AudioSystem::Create(processor); - if (best) { - return best; - } -#endif // XE_PLATFORM_WIN32 - - // Fallback to nop. - return apu::nop::NopAudioSystem::Create(processor); - } -} - -std::unique_ptr CreateGraphicsSystem() { - if (FLAGS_gpu.compare("vulkan") == 0) { - return std::unique_ptr( - new xe::gpu::vulkan::VulkanGraphicsSystem()); - } else if (FLAGS_gpu.compare("null") == 0) { - return std::unique_ptr( - new xe::gpu::null::NullGraphicsSystem()); - } else { - // Create best available. - std::unique_ptr best; - - best = std::unique_ptr( - new xe::gpu::vulkan::VulkanGraphicsSystem()); - if (best) { - return best; - } - - // Nothing! - return nullptr; - } -} - -std::vector> CreateInputDrivers( - ui::Window* window) { - std::vector> drivers; - if (FLAGS_hid.compare("nop") == 0) { - drivers.emplace_back(xe::hid::nop::Create(window)); -#if XE_PLATFORM_WIN32 - } else if (FLAGS_hid.compare("winkey") == 0) { - drivers.emplace_back(xe::hid::winkey::Create(window)); - } else if (FLAGS_hid.compare("xinput") == 0) { - drivers.emplace_back(xe::hid::xinput::Create(window)); -#endif // XE_PLATFORM_WIN32 - } else { -#if XE_PLATFORM_WIN32 - auto xinput_driver = xe::hid::xinput::Create(window); - if (xinput_driver) { - drivers.emplace_back(std::move(xinput_driver)); - } - auto winkey_driver = xe::hid::winkey::Create(window); - if (winkey_driver) { - drivers.emplace_back(std::move(winkey_driver)); - } -#endif // XE_PLATFORM_WIN32 - if (drivers.empty()) { - // Fallback to nop if none created. - drivers.emplace_back(xe::hid::nop::Create(window)); - } - } - return drivers; -} - int xenia_main(const std::vector& args) { Profiler::Initialize(); Profiler::ThreadEnter("main"); - // Create the emulator but don't initialize so we can setup the window. - auto emulator = std::make_unique(L""); - - // Main emulator display window. - auto emulator_window = EmulatorWindow::Create(emulator.get()); - - // Setup and initialize all subsystems. If we can't do something - // (unsupported system, memory issues, etc) this will fail early. - X_STATUS result = - emulator->Setup(emulator_window->window(), CreateAudioSystem, - CreateGraphicsSystem, CreateInputDrivers); - if (XFAILED(result)) { - XELOGE("Failed to setup emulator: %.8X", result); + int argc = 1; + char* argv[] = {"xenia", nullptr}; + QApplication app(argc, argv); + EmulatorWindow main_wnd; + if (!main_wnd.Setup()) { return 1; } + /* if (FLAGS_mount_scratch) { auto scratch_device = std::make_unique( "\\SCRATCH", L"scratch", false); @@ -207,82 +101,14 @@ int xenia_main(const std::vector& args) { return debug_window.get(); }); } + */ - auto evt = xe::threading::Event::CreateAutoResetEvent(false); - emulator->on_launch.AddListener([&]() { - emulator_window->UpdateTitle(); - evt->Set(); - }); - - emulator_window->window()->on_closing.AddListener([&](ui::UIEvent* e) { - // This needs to shut down before the graphics context. - Profiler::Shutdown(); - }); - - bool exiting = false; - emulator_window->loop()->on_quit.AddListener([&](ui::UIEvent* e) { - exiting = true; - evt->Set(); - - // TODO(DrChat): Remove this code and do a proper exit. - XELOGI("Cheap-skate exit!"); - exit(0); - }); - - // Enable the main menu now that the emulator is properly loaded - emulator_window->window()->EnableMainMenu(); - - // Grab path from the flag or unnamed argument. - std::wstring path; - if (!FLAGS_target.empty() || args.size() >= 2) { - if (!FLAGS_target.empty()) { - // Passed as a named argument. - // TODO(benvanik): find something better than gflags that supports - // unicode. - path = xe::to_wstring(FLAGS_target); - } else { - // Passed as an unnamed argument. - path = args[1]; - } - } - - // Toggles fullscreen - if (FLAGS_fullscreen) emulator_window->ToggleFullscreen(); - - if (!path.empty()) { - // Normalize the path and make absolute. - std::wstring abs_path = xe::to_absolute_path(path); - result = emulator->LaunchPath(abs_path); - if (XFAILED(result)) { - xe::FatalError("Failed to launch target: %.8X", result); - emulator.reset(); - emulator_window.reset(); - return 1; - } - } - - // Now, we're going to use the main thread to drive events related to - // emulation. - while (!exiting) { - xe::threading::Wait(evt.get(), false); - - while (true) { - emulator->WaitUntilExit(); - if (emulator->TitleRequested()) { - emulator->LaunchNextTitle(); - } else { - break; - } - } - } - - debug_window.reset(); - emulator.reset(); + main_wnd.show(); + int rc = app.exec(); Profiler::Dump(); Profiler::Shutdown(); - emulator_window.reset(); - return 0; + return rc; } } // namespace app diff --git a/src/xenia/ui/qt/premake5.lua b/src/xenia/ui/qt/premake5.lua index b5e865924..975dfbeaf 100644 --- a/src/xenia/ui/qt/premake5.lua +++ b/src/xenia/ui/qt/premake5.lua @@ -19,6 +19,7 @@ project("xenia-ui-qt") links({ "xenia-base", + "xenia-core", }) defines({ })