RenderWidget: Hook up to ImGui
This commit is contained in:
parent
63dd91628d
commit
36ce47635b
|
@ -143,6 +143,7 @@ PRIVATE
|
||||||
core
|
core
|
||||||
Qt5::Widgets
|
Qt5::Widgets
|
||||||
uicommon
|
uicommon
|
||||||
|
imgui
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|
|
@ -463,6 +463,9 @@
|
||||||
<ProjectReference Include="$(CoreDir)VideoBackends\Vulkan\Vulkan.vcxproj">
|
<ProjectReference Include="$(CoreDir)VideoBackends\Vulkan\Vulkan.vcxproj">
|
||||||
<Project>{29f29a19-f141-45ad-9679-5a2923b49da3}</Project>
|
<Project>{29f29a19-f141-45ad-9679-5a2923b49da3}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\Externals\imgui\imgui.vcxproj">
|
||||||
|
<Project>{4c3b2264-ea73-4a7b-9cfe-65b0fd635ebb}</Project>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/State.h"
|
#include "Core/State.h"
|
||||||
|
@ -26,6 +28,7 @@
|
||||||
#include "DolphinQt/Resources.h"
|
#include "DolphinQt/Resources.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/RenderBase.h"
|
||||||
#include "VideoCommon/VertexShaderManager.h"
|
#include "VideoCommon/VertexShaderManager.h"
|
||||||
#include "VideoCommon/VideoConfig.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) {
|
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
|
||||||
SetFillBackground(SConfig::GetInstance().bRenderToMain && state == Core::State::Uninitialized);
|
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
|
// 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)
|
bool RenderWidget::event(QEvent* event)
|
||||||
{
|
{
|
||||||
|
PassEventToImGui(event);
|
||||||
|
|
||||||
switch (event->type())
|
switch (event->type())
|
||||||
{
|
{
|
||||||
case QEvent::Paint:
|
case QEvent::Paint:
|
||||||
|
@ -244,3 +251,83 @@ void RenderWidget::OnFreeLookMouseMove(QMouseEvent* event)
|
||||||
m_last_mouse[0] = event->x();
|
m_last_mouse[0] = event->x();
|
||||||
m_last_mouse[1] = event->y();
|
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<const QKeyEvent*>(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<const QMouseEvent*>(event)->x();
|
||||||
|
ImGui::GetIO().MousePos.y = static_cast<const QMouseEvent*>(event)->y();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QEvent::MouseButtonPress:
|
||||||
|
case QEvent::MouseButtonRelease:
|
||||||
|
{
|
||||||
|
auto lock = g_renderer->GetImGuiLock();
|
||||||
|
const u32 button_mask = static_cast<u32>(static_cast<const QMouseEvent*>(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);
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,8 @@ private:
|
||||||
void OnKeepOnTopChanged(bool top);
|
void OnKeepOnTopChanged(bool top);
|
||||||
void SetFillBackground(bool fill);
|
void SetFillBackground(bool fill);
|
||||||
void OnFreeLookMouseMove(QMouseEvent* event);
|
void OnFreeLookMouseMove(QMouseEvent* event);
|
||||||
|
void PassEventToImGui(const QEvent* event);
|
||||||
|
void SetImGuiKeyMap();
|
||||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||||
void dropEvent(QDropEvent* event) override;
|
void dropEvent(QDropEvent* event) override;
|
||||||
|
|
||||||
|
|
|
@ -812,9 +812,18 @@ void Renderer::DrawImGui()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> Renderer::GetImGuiLock()
|
||||||
|
{
|
||||||
|
return std::unique_lock<std::mutex>(m_imgui_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,
|
void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,
|
||||||
u64 ticks)
|
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<std::mutex> imgui_lock(m_imgui_mutex);
|
||||||
|
|
||||||
const AspectMode suggested = g_ActiveConfig.suggested_aspect_mode;
|
const AspectMode suggested = g_ActiveConfig.suggested_aspect_mode;
|
||||||
if (suggested == AspectMode::Analog || suggested == AspectMode::AnalogWide)
|
if (suggested == AspectMode::Analog || suggested == AspectMode::AnalogWide)
|
||||||
{
|
{
|
||||||
|
|
|
@ -188,6 +188,11 @@ public:
|
||||||
|
|
||||||
virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler();
|
virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> 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<std::mutex> GetImGuiLock();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
|
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
|
||||||
bool CalculateTargetSize();
|
bool CalculateTargetSize();
|
||||||
|
@ -243,6 +248,7 @@ protected:
|
||||||
std::unique_ptr<NativeVertexFormat> m_imgui_vertex_format;
|
std::unique_ptr<NativeVertexFormat> m_imgui_vertex_format;
|
||||||
std::vector<std::unique_ptr<AbstractTexture>> m_imgui_textures;
|
std::vector<std::unique_ptr<AbstractTexture>> m_imgui_textures;
|
||||||
std::unique_ptr<AbstractPipeline> m_imgui_pipeline;
|
std::unique_ptr<AbstractPipeline> m_imgui_pipeline;
|
||||||
|
std::mutex m_imgui_mutex;
|
||||||
u64 m_imgui_last_frame_time;
|
u64 m_imgui_last_frame_time;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in New Issue