diff --git a/src/frontend/EmuThread.hpp b/src/frontend/EmuThread.hpp index 8b0eebfe..c4d1d7a5 100644 --- a/src/frontend/EmuThread.hpp +++ b/src/frontend/EmuThread.hpp @@ -18,7 +18,6 @@ public: void TogglePause() const noexcept; void Reset() const noexcept; void Stop() const noexcept; - void requestInterruption() { interruptionRequested = true; } bool interruptionRequested = false, isRunning = false, parallelRDPInitialized = false; std::shared_ptr core; diff --git a/src/frontend/ImGuiImpl/GUI.hpp b/src/frontend/ImGuiImpl/GUI.hpp index 96571f17..b8d88a72 100644 --- a/src/frontend/ImGuiImpl/GUI.hpp +++ b/src/frontend/ImGuiImpl/GUI.hpp @@ -149,6 +149,9 @@ namespace gui { ImGui::NewFrame(); } - inline void EndFrame() { + inline void Cleanup() { + ImGui_ImplVulkan_Shutdown(); + ImGui_ImplSDL3_Shutdown(); + ImGui::DestroyContext(); } } \ No newline at end of file diff --git a/src/frontend/ImGuiImpl/PopupWindow.hpp b/src/frontend/ImGuiImpl/PopupWindow.hpp index f5bf5a1d..9b4deed2 100644 --- a/src/frontend/ImGuiImpl/PopupWindow.hpp +++ b/src/frontend/ImGuiImpl/PopupWindow.hpp @@ -7,18 +7,26 @@ namespace gui { struct PopupWindow { PopupWindow(const std::string& title, std::function&& func = nullptr, bool opened = false) : title(title), exec(func), opened(opened) {} - void setFunc(std::function&& func) { - exec = func; - } + void setFunc(std::function&& func) { exec = func; } void setOpened(bool v) { opened = v; } + void setOnClose(std::function&& func) { onClose = func; } + void setOnOpen(std::function&& func) { onOpen = func; } bool render() { - if(!opened) - return false; + if(!opened) { + if(onClose) + onClose(); + return false; + } + if (!ImGui::IsPopupOpen(title.c_str())) + { + if(onOpen) + onOpen(); ImGui::OpenPopup(title.c_str()); + } ImVec2 center = ImGui::GetMainViewport()->GetCenter(); ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); @@ -27,6 +35,7 @@ struct PopupWindow { { if(exec) exec(); + ImGui::EndPopup(); return true; @@ -36,6 +45,8 @@ struct PopupWindow { } private: std::function exec; + std::function onClose; + std::function onOpen; std::string title; bool opened = false; }; diff --git a/src/frontend/InputSettings.cpp b/src/frontend/InputSettings.cpp index 3fec129e..3bedf400 100644 --- a/src/frontend/InputSettings.cpp +++ b/src/frontend/InputSettings.cpp @@ -14,10 +14,18 @@ InputSettings::InputSettings(nlohmann::json &settings) : settings(settings) { devices.addItem({"Keyboard/Mouse"}); SDL_InitSubSystem(SDL_INIT_GAMEPAD); +} + +void InputSettings::RegisterEventWatchers() { SDL_AddEventWatch(QueryDevices, this); SDL_AddEventWatch(PollGamepad, this); } +void InputSettings::UnregisterEventWatchers() { + SDL_RemoveEventWatch(QueryDevices, this); + SDL_RemoveEventWatch(PollGamepad, this); +} + bool InputSettings::render() { if(devices.render()) { auto currentlySelectedDevice = devices.getCurrentlySelected(); diff --git a/src/frontend/InputSettings.hpp b/src/frontend/InputSettings.hpp index d5b8d8ee..3bdf42e4 100644 --- a/src/frontend/InputSettings.hpp +++ b/src/frontend/InputSettings.hpp @@ -59,4 +59,6 @@ public: bool getModified() { return modified; } nlohmann::json &settings; std::array GetMappedKeys(); + void RegisterEventWatchers(); + void UnregisterEventWatchers(); }; diff --git a/src/frontend/KaizenGui.cpp b/src/frontend/KaizenGui.cpp index 244bdbee..7097df5d 100644 --- a/src/frontend/KaizenGui.cpp +++ b/src/frontend/KaizenGui.cpp @@ -22,14 +22,6 @@ KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_sha core->Stop(); } }); - - emuExitFunc = [&]() { - quit = true; - if (emuThread.isRunning) { - emuThread.requestInterruption(); - while (emuThread.isRunning) {} - } - }; about.setFunc([&]() { ImGui::Text("Kaizen is a Nintendo 64 emulator that strives"); @@ -63,7 +55,10 @@ KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_sha Util::panic("Error: {}", NFD::GetError()); LoadROM(path.get()); }}, - {"Exit", std::move(emuExitFunc)} + {"Exit", [&]() { + quit = true; + emuThread.Stop(); + }} } }); @@ -85,6 +80,10 @@ KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_sha }}); } +KaizenGui::~KaizenGui() { + gui::Cleanup(); +} + void KaizenGui::RenderUI() { gui::StartFrame(); statusBar.render(); @@ -114,17 +113,22 @@ void KaizenGui::LoadROM(const std::string &path) noexcept { Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB); } -int KaizenGui::run() { +void KaizenGui::run() { while(!quit) { - if(vulkanWidget.wsiPlatform->quitRequested) { - emuExitFunc(); + emuThread.run(); + SDL_Event e; + while (SDL_PollEvent(&e)) { + ImGui_ImplSDL3_ProcessEvent(&e); + switch(e.type) { + case SDL_EVENT_QUIT: + quit = true; + emuThread.Stop(); + break; + } } RenderUI(); - emuThread.run(); } - - return 0; } void KaizenGui::LoadTAS(const std::string &path) const noexcept { diff --git a/src/frontend/KaizenGui.hpp b/src/frontend/KaizenGui.hpp index 8ded172e..4eac0716 100644 --- a/src/frontend/KaizenGui.hpp +++ b/src/frontend/KaizenGui.hpp @@ -11,6 +11,7 @@ class KaizenGui final { gui::NativeWindow window; public: explicit KaizenGui() noexcept; + ~KaizenGui(); double fpsCounter = -1.0; gui::MenuBar menuBar; gui::MenuItem actionPause{"Pause", nullptr, false}, actionStop{"Stop", nullptr, false}, actionReset{"Reset", nullptr, false}; @@ -21,7 +22,7 @@ public: gui::PopupWindow about{"About Kaizen"}; gui::StatusBar statusBar{}; - int run(); + void run(); void LoadTAS(const std::string &path) const noexcept; void LoadROM(const std::string &path) noexcept; private: diff --git a/src/frontend/RenderWidget.cpp b/src/frontend/RenderWidget.cpp index fda8f44b..fb0b80b8 100644 --- a/src/frontend/RenderWidget.cpp +++ b/src/frontend/RenderWidget.cpp @@ -9,80 +9,4 @@ RenderWidget::RenderWidget(const std::shared_ptr &core, SDL_Window* w wsiPlatform = std::make_shared(core, window); windowInfo = std::make_shared(window); core->parallel.Init(wsiPlatform, windowInfo, core->cpu->GetMem().GetRDRAMPtr()); -} - -void SDLWSIPlatform::poll_input() { - SDL_Event e; - while (SDL_PollEvent(&e)) { - ImGui_ImplSDL3_ProcessEvent(&e); - switch (e.type) { - case SDL_EVENT_QUIT: - quitRequested = true; - break; - case SDL_EVENT_GAMEPAD_ADDED: - { - const auto index = e.gdevice.which; - - gamepad = SDL_OpenGamepad(index); - Util::info("Controller found!"); - - const auto serial = SDL_GetGamepadSerial(gamepad); - const auto name = SDL_GetGamepadName(gamepad); - const auto path = SDL_GetGamepadPath(gamepad); - - Util::info("\tName: {}", name ? name : "Not available"); - Util::info("\tSerial: {}", serial ? serial : "Not available"); - Util::info("\tPath: {}", path ? path : "Not available"); - - gamepadConnected = true; - } - break; - case SDL_EVENT_GAMEPAD_REMOVED: - { - gamepadConnected = false; - SDL_CloseGamepad(gamepad); - } - break; - } - } - - if (gamepadConnected) { - n64::PIF &pif = core->cpu->GetMem().mmio.si.pif; - pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH)); - pif.UpdateButton(0, n64::Controller::Key::B, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_WEST)); - pif.UpdateButton(0, n64::Controller::Key::Z, - SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) == SDL_JOYSTICK_AXIS_MAX); - pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_START)); - pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_UP)); - pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_DOWN)); - pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_LEFT)); - pif.UpdateButton(0, n64::Controller::Key::DRight, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_RIGHT)); - pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER)); - pif.UpdateButton(0, n64::Controller::Key::RT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER)); - pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) <= -127); - pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) >= 127); - pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) <= -127); - pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) >= 127); - - float xclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX); - if (xclamped < 0) { - xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MAX)); - } else { - xclamped /= SDL_JOYSTICK_AXIS_MAX; - } - - xclamped *= 86; - - float yclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY); - if (yclamped < 0) { - yclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN)); - } else { - yclamped /= SDL_JOYSTICK_AXIS_MAX; - } - - yclamped *= 86; - - pif.UpdateAxis(0, n64::Controller::Axis::Y, -yclamped); - pif.UpdateAxis(0, n64::Controller::Axis::X, xclamped); - } -} +} \ No newline at end of file diff --git a/src/frontend/RenderWidget.hpp b/src/frontend/RenderWidget.hpp index 6f4b8c7a..e280b6f8 100644 --- a/src/frontend/RenderWidget.hpp +++ b/src/frontend/RenderWidget.hpp @@ -25,6 +25,10 @@ private: class SDLWSIPlatform final : public Vulkan::WSIPlatform { public: explicit SDLWSIPlatform(const std::shared_ptr &core, SDL_Window* window) : window(window), core(core) {} + ~SDLWSIPlatform() { + if(gamepadConnected) + SDL_CloseGamepad(gamepad); + } std::vector get_instance_extensions() override { auto vec = std::vector(); @@ -44,7 +48,9 @@ public: return surface; } - void destroy_surface(VkInstance, VkSurfaceKHR) override {} + void destroy_surface(VkInstance instance, VkSurfaceKHR surface) override { + SDL_Vulkan_DestroySurface(instance, surface, nullptr); + } uint32_t get_surface_width() override { return 640; } @@ -52,7 +58,7 @@ public: bool alive(Vulkan::WSI &) override { return true; } - void poll_input() override; + void poll_input() override {} void poll_input_async(Granite::InputTrackerHandler *handler) override {} void event_frame_tick(double frame, double elapsed) override {} @@ -63,7 +69,6 @@ public: SDL_Window* window{}; VkSurfaceKHR surface; - bool quitRequested = false; private: std::shared_ptr core; SDL_Gamepad *gamepad{}; diff --git a/src/frontend/SettingsWindow.cpp b/src/frontend/SettingsWindow.cpp index 60d0a3ae..5755ba3f 100644 --- a/src/frontend/SettingsWindow.cpp +++ b/src/frontend/SettingsWindow.cpp @@ -52,6 +52,14 @@ SettingsWindow::SettingsWindow() : settings{JSONOpenOrCreate("resources/settings apply.setEnabled(false); + popup.setOnOpen([&]() { + inputSettings.RegisterEventWatchers(); + }); + + popup.setOnClose([&]() { + inputSettings.UnregisterEventWatchers(); + }); + popup.setFunc([&]() { tabs.render(); diff --git a/src/frontend/main.cpp b/src/frontend/main.cpp index 31753596..62428024 100644 --- a/src/frontend/main.cpp +++ b/src/frontend/main.cpp @@ -13,5 +13,7 @@ int main(int argc, char **argv) { return -1; } - return kaizenGui.run(); + kaizenGui.run(); + + return 0; }