summaryrefslogtreecommitdiffstats
path: root/tests/manual/rhi/shared/imgui/qrhiimgui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual/rhi/shared/imgui/qrhiimgui.cpp')
-rw-r--r--tests/manual/rhi/shared/imgui/qrhiimgui.cpp612
1 files changed, 612 insertions, 0 deletions
diff --git a/tests/manual/rhi/shared/imgui/qrhiimgui.cpp b/tests/manual/rhi/shared/imgui/qrhiimgui.cpp
new file mode 100644
index 0000000000..88b0a5d897
--- /dev/null
+++ b/tests/manual/rhi/shared/imgui/qrhiimgui.cpp
@@ -0,0 +1,612 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qrhiimgui_p.h"
+#include <QtCore/qfile.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qclipboard.h>
+#include <QtGui/qimage.h>
+
+#include "imgui.h"
+
+// the imgui default
+static_assert(sizeof(ImDrawVert) == 20);
+// switched to uint in imconfig.h to avoid trouble with 4 byte offset alignment reqs
+static_assert(sizeof(ImDrawIdx) == 4);
+
+QT_BEGIN_NAMESPACE
+
+static QShader getShader(const QString &name)
+{
+ QFile f(name);
+ if (f.open(QIODevice::ReadOnly))
+ return QShader::fromSerialized(f.readAll());
+
+ return QShader();
+}
+
+QRhiImguiRenderer::~QRhiImguiRenderer()
+{
+ releaseResources();
+}
+
+void QRhiImguiRenderer::releaseResources()
+{
+ for (Texture &t : m_textures) {
+ delete t.tex;
+ delete t.srb;
+ }
+ m_textures.clear();
+
+ m_vbuf.reset();
+ m_ibuf.reset();
+ m_ubuf.reset();
+ m_ps.reset();
+ m_sampler.reset();
+
+ m_rhi = nullptr;
+}
+
+void QRhiImguiRenderer::prepare(QRhi *rhi,
+ QRhiRenderTarget *rt,
+ QRhiCommandBuffer *cb,
+ const QMatrix4x4 &mvp,
+ float opacity,
+ float hdrWhiteLevelMultiplierOrZeroForSDRsRGB)
+{
+ if (!m_rhi) {
+ m_rhi = rhi;
+ } else if (m_rhi != rhi) {
+ releaseResources();
+ m_rhi = rhi;
+ }
+
+ if (!m_rhi || f.draw.isEmpty())
+ return;
+
+ m_rt = rt;
+ m_cb = cb;
+
+ if (!m_vbuf) {
+ m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::VertexBuffer, f.totalVbufSize));
+ m_vbuf->setName(QByteArrayLiteral("imgui vertex buffer"));
+ if (!m_vbuf->create())
+ return;
+ } else {
+ if (f.totalVbufSize > m_vbuf->size()) {
+ m_vbuf->setSize(f.totalVbufSize);
+ if (!m_vbuf->create())
+ return;
+ }
+ }
+ if (!m_ibuf) {
+ m_ibuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::IndexBuffer, f.totalIbufSize));
+ m_ibuf->setName(QByteArrayLiteral("imgui index buffer"));
+ if (!m_ibuf->create())
+ return;
+ } else {
+ if (f.totalIbufSize > m_ibuf->size()) {
+ m_ibuf->setSize(f.totalIbufSize);
+ if (!m_ibuf->create())
+ return;
+ }
+ }
+
+ if (!m_ubuf) {
+ m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 + 4 + 4));
+ m_ubuf->setName(QByteArrayLiteral("imgui uniform buffer"));
+ if (!m_ubuf->create())
+ return;
+ }
+
+ if (!m_sampler) {
+ m_sampler.reset(m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
+ QRhiSampler::Repeat, QRhiSampler::Repeat));
+ m_sampler->setName(QByteArrayLiteral("imgui sampler"));
+ if (!m_sampler->create())
+ return;
+ }
+
+ if (m_textures.isEmpty()) {
+ Texture fontTex;
+ fontTex.image = sf.fontTextureData;
+ m_textures.append(fontTex);
+ } else if (!sf.fontTextureData.isNull()) {
+ Texture fontTex;
+ fontTex.image = sf.fontTextureData;
+ delete m_textures[0].tex;
+ delete m_textures[0].srb;
+ m_textures[0] = fontTex;
+ }
+
+ QVarLengthArray<int, 8> texturesNeedUpdate;
+ for (int i = 0; i < m_textures.count(); ++i) {
+ Texture &t(m_textures[i]);
+ if (!t.tex) {
+ t.tex = m_rhi->newTexture(QRhiTexture::RGBA8, t.image.size());
+ t.tex->setName(QByteArrayLiteral("imgui texture ") + QByteArray::number(i));
+ if (!t.tex->create())
+ return;
+ texturesNeedUpdate.append(i);
+ }
+ if (!t.srb) {
+ t.srb = m_rhi->newShaderResourceBindings();
+ t.srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf.get()),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, t.tex, m_sampler.get())
+ });
+ if (!t.srb->create())
+ return;
+ }
+ }
+
+ // If layer.enabled is toggled on the item or an ancestor, the render
+ // target is then suddenly different and may not be compatible.
+ if (m_ps && m_rt->renderPassDescriptor()->serializedFormat() != m_renderPassFormat)
+ m_ps.reset();
+
+ if (!m_ps) {
+ QShader vs = getShader(QLatin1String(":/imgui.vert.qsb"));
+ QShader fs = getShader(QLatin1String(":/imgui.frag.qsb"));
+ if (!vs.isValid() || !fs.isValid()) {
+ qWarning("Failed to load imgui shaders");
+ return;
+ }
+
+ m_ps.reset(m_rhi->newGraphicsPipeline());
+ QRhiGraphicsPipeline::TargetBlend blend;
+ blend.enable = true;
+ // Premultiplied alpha (matches imgui.frag). Would not be needed if we
+ // only cared about outputting to the window (the common case), but
+ // once going through a texture (Item layer, ShaderEffect) which is
+ // then sampled by Quick, the result wouldn't be correct otherwise.
+ blend.srcColor = QRhiGraphicsPipeline::One;
+ blend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
+ blend.srcAlpha = QRhiGraphicsPipeline::One;
+ blend.dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
+ m_ps->setTargetBlends({ blend });
+ m_ps->setCullMode(QRhiGraphicsPipeline::None);
+ m_ps->setDepthTest(true);
+ m_ps->setDepthOp(QRhiGraphicsPipeline::LessOrEqual);
+ m_ps->setDepthWrite(false);
+ m_ps->setFlags(QRhiGraphicsPipeline::UsesScissor);
+
+ m_ps->setShaderStages({
+ { QRhiShaderStage::Vertex, vs },
+ { QRhiShaderStage::Fragment, fs }
+ });
+
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 4 * sizeof(float) + sizeof(quint32) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) },
+ { 0, 2, QRhiVertexInputAttribute::UNormByte4, 4 * sizeof(float) }
+ });
+
+ m_ps->setVertexInputLayout(inputLayout);
+ m_ps->setShaderResourceBindings(m_textures[0].srb);
+ m_ps->setRenderPassDescriptor(m_rt->renderPassDescriptor());
+ m_renderPassFormat = m_rt->renderPassDescriptor()->serializedFormat();
+
+ if (!m_ps->create())
+ return;
+ }
+
+ QRhiResourceUpdateBatch *u = m_rhi->nextResourceUpdateBatch();
+
+ for (const CmdListBuffer &b : f.vbuf)
+ u->updateDynamicBuffer(m_vbuf.get(), b.offset, b.data.size(), b.data.constData());
+
+ for (const CmdListBuffer &b : f.ibuf)
+ u->updateDynamicBuffer(m_ibuf.get(), b.offset, b.data.size(), b.data.constData());
+
+ u->updateDynamicBuffer(m_ubuf.get(), 0, 64, mvp.constData());
+ u->updateDynamicBuffer(m_ubuf.get(), 64, 4, &opacity);
+ u->updateDynamicBuffer(m_ubuf.get(), 68, 4, &hdrWhiteLevelMultiplierOrZeroForSDRsRGB);
+
+ for (int i = 0; i < texturesNeedUpdate.count(); ++i) {
+ Texture &t(m_textures[texturesNeedUpdate[i]]);
+ u->uploadTexture(t.tex, t.image);
+ t.image = QImage();
+ }
+
+ m_cb->resourceUpdate(u);
+}
+
+void QRhiImguiRenderer::render()
+{
+ if (!m_rhi || f.draw.isEmpty() || !m_ps)
+ return;
+
+ m_cb->setGraphicsPipeline(m_ps.get());
+
+ const QSize viewportSize = m_rt->pixelSize();
+ bool needsViewport = true;
+
+ for (const DrawCmd &c : f.draw) {
+ QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), f.vbuf[c.cmdListBufferIdx].offset);
+ if (needsViewport) {
+ needsViewport = false;
+ m_cb->setViewport({ 0, 0, float(viewportSize.width()), float(viewportSize.height()) });
+ }
+ const float sx1 = c.clipRect.x() + c.itemPixelOffset.x();
+ const float sy1 = c.clipRect.y() + c.itemPixelOffset.y();
+ const float sx2 = c.clipRect.z() + c.itemPixelOffset.x();
+ const float sy2 = c.clipRect.w() + c.itemPixelOffset.y();
+ QPoint scissorPos = QPointF(sx1, viewportSize.height() - sy2).toPoint();
+ QSize scissorSize = QSizeF(sx2 - sx1, sy2 - sy1).toSize();
+ scissorPos.setX(qMax(0, scissorPos.x()));
+ scissorPos.setY(qMax(0, scissorPos.y()));
+ scissorSize.setWidth(qMin(viewportSize.width(), scissorSize.width()));
+ scissorSize.setHeight(qMin(viewportSize.height(), scissorSize.height()));
+ m_cb->setScissor({ scissorPos.x(), scissorPos.y(), scissorSize.width(), scissorSize.height() });
+ m_cb->setShaderResources(m_textures[c.textureIndex].srb);
+ m_cb->setVertexInput(0, 1, &vbufBinding, m_ibuf.get(), c.indexOffset, QRhiCommandBuffer::IndexUInt32);
+ m_cb->drawIndexed(c.elemCount);
+ }
+}
+
+static const char *getClipboardText(void *)
+{
+ static QByteArray contents;
+ contents = QGuiApplication::clipboard()->text().toUtf8();
+ return contents.constData();
+}
+
+static void setClipboardText(void *, const char *text)
+{
+ QGuiApplication::clipboard()->setText(QString::fromUtf8(text));
+}
+
+QRhiImgui::QRhiImgui()
+{
+ ImGui::CreateContext();
+ rebuildFontAtlas();
+ ImGuiIO &io(ImGui::GetIO());
+ io.GetClipboardTextFn = getClipboardText;
+ io.SetClipboardTextFn = setClipboardText;
+}
+
+QRhiImgui::~QRhiImgui()
+{
+ ImGui::DestroyContext();
+}
+
+void QRhiImgui::rebuildFontAtlas()
+{
+ unsigned char *pixels;
+ int w, h;
+ ImGuiIO &io(ImGui::GetIO());
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &w, &h);
+ const QImage wrapperImg(const_cast<const uchar *>(pixels), w, h, QImage::Format_RGBA8888);
+ sf.fontTextureData = wrapperImg.copy();
+ io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(quintptr(0)));
+}
+
+void QRhiImgui::nextFrame(const QSizeF &logicalOutputSize, float dpr, const QPointF &logicalOffset, FrameFunc frameFunc)
+{
+ ImGuiIO &io(ImGui::GetIO());
+
+ const QPointF itemPixelOffset = logicalOffset * dpr;
+ f.outputPixelSize = (logicalOutputSize * dpr).toSize();
+ io.DisplaySize.x = logicalOutputSize.width();
+ io.DisplaySize.y = logicalOutputSize.height();
+ io.DisplayFramebufferScale = ImVec2(dpr, dpr);
+
+ ImGui::NewFrame();
+ if (frameFunc)
+ frameFunc();
+ ImGui::Render();
+
+ ImDrawData *draw = ImGui::GetDrawData();
+ draw->ScaleClipRects(ImVec2(dpr, dpr));
+
+ f.vbuf.resize(draw->CmdListsCount);
+ f.ibuf.resize(draw->CmdListsCount);
+ f.totalVbufSize = 0;
+ f.totalIbufSize = 0;
+ for (int n = 0; n < draw->CmdListsCount; ++n) {
+ const ImDrawList *cmdList = draw->CmdLists[n];
+ const int vbufSize = cmdList->VtxBuffer.Size * sizeof(ImDrawVert);
+ f.vbuf[n].offset = f.totalVbufSize;
+ f.totalVbufSize += vbufSize;
+ const int ibufSize = cmdList->IdxBuffer.Size * sizeof(ImDrawIdx);
+ f.ibuf[n].offset = f.totalIbufSize;
+ f.totalIbufSize += ibufSize;
+ }
+ f.draw.clear();
+ for (int n = 0; n < draw->CmdListsCount; ++n) {
+ const ImDrawList *cmdList = draw->CmdLists[n];
+ f.vbuf[n].data = QByteArray(reinterpret_cast<const char *>(cmdList->VtxBuffer.Data),
+ cmdList->VtxBuffer.Size * sizeof(ImDrawVert));
+ f.ibuf[n].data = QByteArray(reinterpret_cast<const char *>(cmdList->IdxBuffer.Data),
+ cmdList->IdxBuffer.Size * sizeof(ImDrawIdx));
+ const ImDrawIdx *indexBufOffset = nullptr;
+ for (int i = 0; i < cmdList->CmdBuffer.Size; ++i) {
+ const ImDrawCmd *cmd = &cmdList->CmdBuffer[i];
+ const quint32 indexOffset = f.ibuf[n].offset + quintptr(indexBufOffset);
+ if (!cmd->UserCallback) {
+ QRhiImguiRenderer::DrawCmd dc;
+ dc.cmdListBufferIdx = n;
+ dc.textureIndex = int(reinterpret_cast<qintptr>(cmd->TextureId));
+ dc.indexOffset = indexOffset;
+ dc.elemCount = cmd->ElemCount;
+ dc.itemPixelOffset = itemPixelOffset;
+ dc.clipRect = QVector4D(cmd->ClipRect.x, cmd->ClipRect.y, cmd->ClipRect.z, cmd->ClipRect.w);
+ f.draw.append(dc);
+ } else {
+ cmd->UserCallback(cmdList, cmd);
+ }
+ indexBufOffset += cmd->ElemCount;
+ }
+ }
+}
+
+void QRhiImgui::syncRenderer(QRhiImguiRenderer *renderer)
+{
+ renderer->sf = sf;
+ sf.fontTextureData = QImage();
+ renderer->f = std::move(f);
+}
+
+static void updateKeyboardModifiers(Qt::KeyboardModifiers modifiers)
+{
+ ImGuiIO &io(ImGui::GetIO());
+ io.AddKeyEvent(ImGuiKey_ModCtrl, modifiers.testFlag(Qt::ControlModifier));
+ io.AddKeyEvent(ImGuiKey_ModShift, modifiers.testFlag(Qt::ShiftModifier));
+ io.AddKeyEvent(ImGuiKey_ModAlt, modifiers.testFlag(Qt::AltModifier));
+ io.AddKeyEvent(ImGuiKey_ModSuper, modifiers.testFlag(Qt::MetaModifier));
+}
+
+static ImGuiKey mapKey(int k)
+{
+ switch (k) {
+ case Qt::Key_Space:
+ return ImGuiKey_Space;
+ case Qt::Key_Apostrophe:
+ return ImGuiKey_Apostrophe;
+ case Qt::Key_Comma:
+ return ImGuiKey_Comma;
+ case Qt::Key_Minus:
+ return ImGuiKey_Minus;
+ case Qt::Key_Period:
+ return ImGuiKey_Period;
+ case Qt::Key_Slash:
+ return ImGuiKey_Slash;
+ case Qt::Key_0:
+ return ImGuiKey_0;
+ case Qt::Key_1:
+ return ImGuiKey_1;
+ case Qt::Key_2:
+ return ImGuiKey_2;
+ case Qt::Key_3:
+ return ImGuiKey_3;
+ case Qt::Key_4:
+ return ImGuiKey_4;
+ case Qt::Key_5:
+ return ImGuiKey_5;
+ case Qt::Key_6:
+ return ImGuiKey_6;
+ case Qt::Key_7:
+ return ImGuiKey_8;
+ case Qt::Key_8:
+ return ImGuiKey_8;
+ case Qt::Key_9:
+ return ImGuiKey_9;
+ case Qt::Key_Semicolon:
+ return ImGuiKey_Semicolon;
+ case Qt::Key_Equal:
+ return ImGuiKey_Equal;
+ case Qt::Key_A:
+ return ImGuiKey_A;
+ case Qt::Key_B:
+ return ImGuiKey_B;
+ case Qt::Key_C:
+ return ImGuiKey_C;
+ case Qt::Key_D:
+ return ImGuiKey_D;
+ case Qt::Key_E:
+ return ImGuiKey_E;
+ case Qt::Key_F:
+ return ImGuiKey_F;
+ case Qt::Key_G:
+ return ImGuiKey_G;
+ case Qt::Key_H:
+ return ImGuiKey_H;
+ case Qt::Key_I:
+ return ImGuiKey_I;
+ case Qt::Key_J:
+ return ImGuiKey_J;
+ case Qt::Key_K:
+ return ImGuiKey_K;
+ case Qt::Key_L:
+ return ImGuiKey_L;
+ case Qt::Key_M:
+ return ImGuiKey_M;
+ case Qt::Key_N:
+ return ImGuiKey_N;
+ case Qt::Key_O:
+ return ImGuiKey_O;
+ case Qt::Key_P:
+ return ImGuiKey_P;
+ case Qt::Key_Q:
+ return ImGuiKey_Q;
+ case Qt::Key_R:
+ return ImGuiKey_R;
+ case Qt::Key_S:
+ return ImGuiKey_S;
+ case Qt::Key_T:
+ return ImGuiKey_T;
+ case Qt::Key_U:
+ return ImGuiKey_U;
+ case Qt::Key_V:
+ return ImGuiKey_V;
+ case Qt::Key_W:
+ return ImGuiKey_W;
+ case Qt::Key_X:
+ return ImGuiKey_X;
+ case Qt::Key_Y:
+ return ImGuiKey_Y;
+ case Qt::Key_Z:
+ return ImGuiKey_Z;
+ case Qt::Key_BracketLeft:
+ return ImGuiKey_LeftBracket;
+ case Qt::Key_Backslash:
+ return ImGuiKey_Backslash;
+ case Qt::Key_BracketRight:
+ return ImGuiKey_RightBracket;
+ case Qt::Key_QuoteLeft:
+ return ImGuiKey_GraveAccent;
+ case Qt::Key_Escape:
+ return ImGuiKey_Escape;
+ case Qt::Key_Tab:
+ return ImGuiKey_Tab;
+ case Qt::Key_Backspace:
+ return ImGuiKey_Backspace;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ return ImGuiKey_Enter;
+ case Qt::Key_Insert:
+ return ImGuiKey_Insert;
+ case Qt::Key_Delete:
+ return ImGuiKey_Delete;
+ case Qt::Key_Pause:
+ return ImGuiKey_Pause;
+ case Qt::Key_Print:
+ return ImGuiKey_PrintScreen;
+ case Qt::Key_Home:
+ return ImGuiKey_Home;
+ case Qt::Key_End:
+ return ImGuiKey_End;
+ case Qt::Key_Left:
+ return ImGuiKey_LeftArrow;
+ case Qt::Key_Up:
+ return ImGuiKey_UpArrow;
+ case Qt::Key_Right:
+ return ImGuiKey_RightArrow;
+ case Qt::Key_Down:
+ return ImGuiKey_DownArrow;
+ case Qt::Key_PageUp:
+ return ImGuiKey_PageUp;
+ case Qt::Key_PageDown:
+ return ImGuiKey_PageDown;
+ case Qt::Key_Shift:
+ return ImGuiKey_LeftShift;
+ case Qt::Key_Control:
+ return ImGuiKey_LeftCtrl;
+ case Qt::Key_Meta:
+ return ImGuiKey_LeftSuper;
+ case Qt::Key_Alt:
+ return ImGuiKey_LeftAlt;
+ case Qt::Key_CapsLock:
+ return ImGuiKey_CapsLock;
+ case Qt::Key_NumLock:
+ return ImGuiKey_NumLock;
+ case Qt::Key_ScrollLock:
+ return ImGuiKey_ScrollLock;
+ case Qt::Key_F1:
+ return ImGuiKey_F1;
+ case Qt::Key_F2:
+ return ImGuiKey_F2;
+ case Qt::Key_F3:
+ return ImGuiKey_F3;
+ case Qt::Key_F4:
+ return ImGuiKey_F4;
+ case Qt::Key_F5:
+ return ImGuiKey_F5;
+ case Qt::Key_F6:
+ return ImGuiKey_F6;
+ case Qt::Key_F7:
+ return ImGuiKey_F7;
+ case Qt::Key_F8:
+ return ImGuiKey_F8;
+ case Qt::Key_F9:
+ return ImGuiKey_F9;
+ case Qt::Key_F10:
+ return ImGuiKey_F10;
+ case Qt::Key_F11:
+ return ImGuiKey_F11;
+ case Qt::Key_F12:
+ return ImGuiKey_F12;
+ default:
+ break;
+ }
+ return ImGuiKey_None;
+}
+
+bool QRhiImgui::processEvent(QEvent *event)
+{
+ ImGuiIO &io(ImGui::GetIO());
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ {
+ QMouseEvent *me = static_cast<QMouseEvent *>(event);
+ updateKeyboardModifiers(me->modifiers());
+ Qt::MouseButtons buttons = me->buttons();
+ if (buttons.testFlag(Qt::LeftButton) && !pressedMouseButtons.testFlag(Qt::LeftButton))
+ io.AddMouseButtonEvent(0, true);
+ if (buttons.testFlag(Qt::RightButton) && !pressedMouseButtons.testFlag(Qt::RightButton))
+ io.AddMouseButtonEvent(1, true);
+ if (buttons.testFlag(Qt::MiddleButton) && !pressedMouseButtons.testFlag(Qt::MiddleButton))
+ io.AddMouseButtonEvent(2, true);
+ pressedMouseButtons = buttons;
+ }
+ return true;
+
+ case QEvent::MouseButtonRelease:
+ {
+ QMouseEvent *me = static_cast<QMouseEvent *>(event);
+ Qt::MouseButtons buttons = me->buttons();
+ if (!buttons.testFlag(Qt::LeftButton) && pressedMouseButtons.testFlag(Qt::LeftButton))
+ io.AddMouseButtonEvent(0, false);
+ if (!buttons.testFlag(Qt::RightButton) && pressedMouseButtons.testFlag(Qt::RightButton))
+ io.AddMouseButtonEvent(1, false);
+ if (!buttons.testFlag(Qt::MiddleButton) && pressedMouseButtons.testFlag(Qt::MiddleButton))
+ io.AddMouseButtonEvent(2, false);
+ pressedMouseButtons = buttons;
+ }
+ return true;
+
+ case QEvent::MouseMove:
+ {
+ QMouseEvent *me = static_cast<QMouseEvent *>(event);
+ const QPointF pos = me->position();
+ io.AddMousePosEvent(pos.x(), pos.y());
+ }
+ return true;
+
+ case QEvent::Wheel:
+ {
+ QWheelEvent *we = static_cast<QWheelEvent *>(event);
+ QPointF wheel(we->angleDelta().x() / 120.0f, we->angleDelta().y() / 120.0f);
+ io.AddMouseWheelEvent(wheel.x(), wheel.y());
+ }
+ return true;
+
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(event);
+ const bool down = event->type() == QEvent::KeyPress;
+ updateKeyboardModifiers(ke->modifiers());
+ io.AddKeyEvent(mapKey(ke->key()), down);
+ if (down && !ke->text().isEmpty()) {
+ const QByteArray text = ke->text().toUtf8();
+ io.AddInputCharactersUTF8(text.constData());
+ }
+ }
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+QT_END_NAMESPACE