From 36ce47635bd6b7287252fd87847629c853dabb6f Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 10 Oct 2018 21:41:52 +1000 Subject: [PATCH] RenderWidget: Hook up to ImGui --- Source/Core/DolphinQt/CMakeLists.txt | 1 + Source/Core/DolphinQt/DolphinQt.vcxproj | 3 + Source/Core/DolphinQt/RenderWidget.cpp | 87 +++++++++++++++++++++++++ Source/Core/DolphinQt/RenderWidget.h | 2 + Source/Core/VideoCommon/RenderBase.cpp | 9 +++ Source/Core/VideoCommon/RenderBase.h | 6 ++ 6 files changed, 108 insertions(+) diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 8e6deec6f8..3d987cae90 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -143,6 +143,7 @@ PRIVATE core Qt5::Widgets uicommon + imgui ) if(WIN32) diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index bd0346edd7..694f7b9f13 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -463,6 +463,9 @@ {29f29a19-f141-45ad-9679-5a2923b49da3} + + {4c3b2264-ea73-4a7b-9cfe-65b0fd635ebb} + diff --git a/Source/Core/DolphinQt/RenderWidget.cpp b/Source/Core/DolphinQt/RenderWidget.cpp index 4be5f26b1d..6953de0798 100644 --- a/Source/Core/DolphinQt/RenderWidget.cpp +++ b/Source/Core/DolphinQt/RenderWidget.cpp @@ -17,6 +17,8 @@ #include #include +#include "imgui.h" + #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/State.h" @@ -26,6 +28,7 @@ #include "DolphinQt/Resources.h" #include "DolphinQt/Settings.h" +#include "VideoCommon/RenderBase.h" #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoConfig.h" @@ -49,6 +52,8 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent) connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { SetFillBackground(SConfig::GetInstance().bRenderToMain && state == Core::State::Uninitialized); + if (state == Core::State::Running) + SetImGuiKeyMap(); }); // We have to use Qt::DirectConnection here because we don't want those signals to get queued @@ -153,6 +158,8 @@ void RenderWidget::showFullScreen() bool RenderWidget::event(QEvent* event) { + PassEventToImGui(event); + switch (event->type()) { case QEvent::Paint: @@ -244,3 +251,83 @@ void RenderWidget::OnFreeLookMouseMove(QMouseEvent* event) m_last_mouse[0] = event->x(); m_last_mouse[1] = event->y(); } + +void RenderWidget::PassEventToImGui(const QEvent* event) +{ + if (!Core::IsRunningAndStarted()) + return; + + switch (event->type()) + { + case QEvent::KeyPress: + case QEvent::KeyRelease: + { + // As the imgui KeysDown array is only 512 elements wide, and some Qt keys which + // we need to track (e.g. alt) are above this value, we mask the lower 9 bits. + // Even masked, the key codes are still unique, so conflicts aren't an issue. + // The actual text input goes through AddInputCharactersUTF8(). + const QKeyEvent* key_event = static_cast(event); + const bool is_down = event->type() == QEvent::KeyPress; + const int key = (key_event->key() & 0x1FF); + auto lock = g_renderer->GetImGuiLock(); + if (key < ArraySize(ImGui::GetIO().KeysDown)) + ImGui::GetIO().KeysDown[key] = is_down; + + if (is_down) + { + auto utf8 = key_event->text().toUtf8(); + ImGui::GetIO().AddInputCharactersUTF8(utf8.constData()); + } + } + break; + + case QEvent::MouseMove: + { + auto lock = g_renderer->GetImGuiLock(); + ImGui::GetIO().MousePos.x = static_cast(event)->x(); + ImGui::GetIO().MousePos.y = static_cast(event)->y(); + } + break; + + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + { + auto lock = g_renderer->GetImGuiLock(); + const u32 button_mask = static_cast(static_cast(event)->buttons()); + for (size_t i = 0; i < ArraySize(ImGui::GetIO().MouseDown); i++) + ImGui::GetIO().MouseDown[i] = (button_mask & (1u << i)) != 0; + } + break; + + default: + break; + } +} + +void RenderWidget::SetImGuiKeyMap() +{ + static const int key_map[][2] = {{ImGuiKey_Tab, Qt::Key_Tab}, + {ImGuiKey_LeftArrow, Qt::Key_Left}, + {ImGuiKey_RightArrow, Qt::Key_Right}, + {ImGuiKey_UpArrow, Qt::Key_Up}, + {ImGuiKey_DownArrow, Qt::Key_Down}, + {ImGuiKey_PageUp, Qt::Key_PageUp}, + {ImGuiKey_PageDown, Qt::Key_PageDown}, + {ImGuiKey_Home, Qt::Key_Home}, + {ImGuiKey_End, Qt::Key_End}, + {ImGuiKey_Insert, Qt::Key_Insert}, + {ImGuiKey_Delete, Qt::Key_Delete}, + {ImGuiKey_Backspace, Qt::Key_Backspace}, + {ImGuiKey_Space, Qt::Key_Space}, + {ImGuiKey_Enter, Qt::Key_Enter}, + {ImGuiKey_Escape, Qt::Key_Escape}, + {ImGuiKey_A, Qt::Key_A}, + {ImGuiKey_C, Qt::Key_C}, + {ImGuiKey_V, Qt::Key_V}, + {ImGuiKey_X, Qt::Key_X}, + {ImGuiKey_Y, Qt::Key_Y}, + {ImGuiKey_Z, Qt::Key_Z}}; + auto lock = g_renderer->GetImGuiLock(); + for (size_t i = 0; i < ArraySize(key_map); i++) + ImGui::GetIO().KeyMap[key_map[i][0]] = (key_map[i][1] & 0x1FF); +} diff --git a/Source/Core/DolphinQt/RenderWidget.h b/Source/Core/DolphinQt/RenderWidget.h index 4d7e53f24e..a9099fd5a7 100644 --- a/Source/Core/DolphinQt/RenderWidget.h +++ b/Source/Core/DolphinQt/RenderWidget.h @@ -36,6 +36,8 @@ private: void OnKeepOnTopChanged(bool top); void SetFillBackground(bool fill); void OnFreeLookMouseMove(QMouseEvent* event); + void PassEventToImGui(const QEvent* event); + void SetImGuiKeyMap(); void dragEnterEvent(QDragEnterEvent* event) override; void dropEvent(QDropEvent* event) override; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 76f3d29864..dd988b3f5c 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -812,9 +812,18 @@ void Renderer::DrawImGui() } } +std::unique_lock Renderer::GetImGuiLock() +{ + return std::unique_lock(m_imgui_mutex); +} + void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, u64 ticks) { + // Hold the imgui lock while we're presenting. + // It's only to prevent races on inputs anyway, at this point. + std::unique_lock imgui_lock(m_imgui_mutex); + const AspectMode suggested = g_ActiveConfig.suggested_aspect_mode; if (suggested == AspectMode::Analog || suggested == AspectMode::AnalogWide) { diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index bc0145a0d1..df0de0fa48 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -188,6 +188,11 @@ public: virtual std::unique_ptr CreateAsyncShaderCompiler(); + // Returns a lock for the ImGui mutex, enabling data structures to be modified from outside. + // Use with care, only non-drawing functions should be called from outside the video thread, + // as the drawing is tied to a "frame". + std::unique_lock GetImGuiLock(); + protected: std::tuple CalculateTargetScale(int x, int y) const; bool CalculateTargetSize(); @@ -243,6 +248,7 @@ protected: std::unique_ptr m_imgui_vertex_format; std::vector> m_imgui_textures; std::unique_ptr m_imgui_pipeline; + std::mutex m_imgui_mutex; u64 m_imgui_last_frame_time; private: