rhi manual tests: allow having some gui controls
Having a simple Dear ImGui bridge is not just useful for the manual tests, which do not have any other means to displays GUIs, but is in itself an important exercise for the QRhi machinery. Have a new manual test that exercises the built-in ImGui demo window. Then use it in the displacement test for real, to replace the myriads of key presses with on-screen sliders and checkboxes (with less code). Change-Id: I296bafae2a5cce6fc7a447d97e68e5bcec15f451 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
parent
401edea982
commit
fbb26c2b88
@ -31,6 +31,7 @@ add_subdirectory(stenciloutline)
|
||||
add_subdirectory(stereo)
|
||||
add_subdirectory(tex1d)
|
||||
add_subdirectory(displacement)
|
||||
add_subdirectory(imguirenderer)
|
||||
if(QT_FEATURE_widgets)
|
||||
add_subdirectory(rhiwidget)
|
||||
endif()
|
||||
|
@ -20,3 +20,7 @@ qt_internal_add_resource(displacement "displacement"
|
||||
"material.frag.qsb"
|
||||
"heightmap.png"
|
||||
)
|
||||
|
||||
set(imgui_base ../shared/imgui)
|
||||
set(imgui_target displacement)
|
||||
include(${imgui_base}/imgui.cmakeinc)
|
||||
|
@ -1,18 +1,17 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#define EXAMPLEFW_KEYPRESS_EVENTS
|
||||
#define EXAMPLEFW_IMGUI
|
||||
#include "../shared/examplefw.h"
|
||||
#include "../shared/cube.h"
|
||||
|
||||
// Another tessellation test. Use the keys (info printed on debug output) to
|
||||
// change the tessellation and displacement factors. Compatible with Direct 3D
|
||||
// via hand-written hull and domain shaders, but this already pushes the limits
|
||||
// of what is sensible when it comes to injecting hand-written HLSL code to get
|
||||
// tessellation functional (cbuffer layout, resource registers all need to be
|
||||
// figured out manually and works only as long as the GLSL source is not
|
||||
// changing, etc.). Note that the domain shader must use SampleLevel
|
||||
// (textureLod), it won't compile for ds_5_0 otherwise.
|
||||
// Another tessellation test. Compatible with Direct 3D via hand-written hull
|
||||
// and domain shaders, but this already pushes the limits of what is sensible
|
||||
// when it comes to injecting hand-written HLSL code to get tessellation
|
||||
// functional (cbuffer layout, resource registers all need to be figured out
|
||||
// manually and works only as long as the GLSL source is not changing, etc.).
|
||||
// Note that the domain shader must use SampleLevel (textureLod), it won't
|
||||
// compile for ds_5_0 otherwise.
|
||||
|
||||
static const quint32 UBUF_SIZE = 80;
|
||||
|
||||
@ -30,8 +29,8 @@ struct {
|
||||
float rotation = 0.0f;
|
||||
float viewZ = 0.0f;
|
||||
float displacementAmount = 0.0f;
|
||||
float tessInner = 4;
|
||||
float tessOuter = 4;
|
||||
int tessInner = 4;
|
||||
int tessOuter = 4;
|
||||
bool useTex = false;
|
||||
bool wireframe = true;
|
||||
|
||||
@ -43,18 +42,6 @@ void Window::customInit()
|
||||
if (!m_r->isFeatureSupported(QRhi::Tessellation))
|
||||
qFatal("Tessellation is not supported");
|
||||
|
||||
qDebug("Left: decrease inner tessellation factor (default is 4)\n"
|
||||
"Right: increase inner tessellation factor\n"
|
||||
"Up: decrease outer tessellation factor (default is 4)\n"
|
||||
"Down: increase outer tessellation factor\n"
|
||||
"W: move camera forward\n"
|
||||
"S: move camera backwards\n"
|
||||
"[: decrease displacement amount (default is 0)\n"
|
||||
"]: increase displacement amount\n"
|
||||
"Tab: toggle displacement texture usage (off by default)\n"
|
||||
"Backspace: toggle wireframe (on by default)\n"
|
||||
);
|
||||
|
||||
d.initialUpdates = m_r->nextResourceUpdateBatch();
|
||||
|
||||
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube));
|
||||
@ -165,8 +152,10 @@ void Window::customRender()
|
||||
|
||||
memcpy(p, mvp.constData(), 64);
|
||||
memcpy(p + 64, &d.displacementAmount, sizeof(float));
|
||||
memcpy(p + 68, &d.tessInner, sizeof(float));
|
||||
memcpy(p + 72, &d.tessOuter, sizeof(float));
|
||||
float tessInnerFloat = d.tessInner;
|
||||
memcpy(p + 68, &tessInnerFloat, sizeof(float));
|
||||
float tessOuterFloat = d.tessOuter;
|
||||
memcpy(p + 72, &tessOuterFloat, sizeof(float));
|
||||
qint32 useTex = d.useTex ? 1 : 0;
|
||||
memcpy(p + 76, &useTex, sizeof(qint32));
|
||||
|
||||
@ -186,37 +175,25 @@ void Window::customRender()
|
||||
cb->setVertexInput(0, 3, vbufBinding);
|
||||
cb->draw(36);
|
||||
|
||||
m_imguiRenderer->render();
|
||||
|
||||
cb->endPass();
|
||||
|
||||
if (d.rotate)
|
||||
d.rotation += 1;
|
||||
}
|
||||
|
||||
void Window::keyPressEvent(QKeyEvent *e)
|
||||
void Window::customGui()
|
||||
{
|
||||
if (e->key() == Qt::Key_Right)
|
||||
d.tessInner += 1.0f;
|
||||
else if (e->key() == Qt::Key_Left)
|
||||
d.tessInner -= 1.0f;
|
||||
else if (e->key() == Qt::Key_Down)
|
||||
d.tessOuter += 1.0f;
|
||||
else if (e->key() == Qt::Key_Up)
|
||||
d.tessOuter -= 1.0f;
|
||||
else if (e->key() == Qt::Key_W)
|
||||
d.viewZ += 0.1f;
|
||||
else if (e->key() == Qt::Key_S)
|
||||
d.viewZ -= 0.1f;
|
||||
else if (e->key() == Qt::Key_Space)
|
||||
d.rotate = !d.rotate;
|
||||
else if (e->key() == Qt::Key_BracketLeft)
|
||||
d.displacementAmount -= 0.1f;
|
||||
else if (e->key() == Qt::Key_BracketRight)
|
||||
d.displacementAmount += 0.1f;
|
||||
else if (e->key() == Qt::Key_Tab)
|
||||
d.useTex = !d.useTex;
|
||||
else if (e->key() == Qt::Key_Backspace)
|
||||
d.wireframe = !d.wireframe;
|
||||
|
||||
qDebug("Inner: %f Outer: %f Displacement amount: %f Use displacement map: %d",
|
||||
d.tessInner, d.tessOuter, d.displacementAmount, d.useTex);
|
||||
ImGui::SetNextWindowPos(ImVec2(10, 10), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(500, 250), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Test");
|
||||
ImGui::SliderInt("Inner", &d.tessInner, 0, 20);
|
||||
ImGui::SliderInt("Outer", &d.tessOuter, 0, 20);
|
||||
ImGui::SliderFloat("Displacement", &d.displacementAmount, 0.0f, 4.0f);
|
||||
ImGui::Checkbox("Use displacement texture", &d.useTex);
|
||||
ImGui::SliderFloat("Z", &d.viewZ, -16.0f, 4.0f);
|
||||
ImGui::Checkbox("Rotate", &d.rotate);
|
||||
ImGui::Checkbox("Wireframe", &d.wireframe);
|
||||
ImGui::End();
|
||||
}
|
||||
|
30
tests/manual/rhi/imguirenderer/CMakeLists.txt
Normal file
30
tests/manual/rhi/imguirenderer/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
||||
qt_internal_add_manual_test(imguirenderer
|
||||
GUI
|
||||
SOURCES
|
||||
imguirenderer.cpp
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
|
||||
set_source_files_properties("../shared/texture.vert.qsb"
|
||||
PROPERTIES QT_RESOURCE_ALIAS "texture.vert.qsb"
|
||||
)
|
||||
set_source_files_properties("../shared/texture.frag.qsb"
|
||||
PROPERTIES QT_RESOURCE_ALIAS "texture.frag.qsb"
|
||||
)
|
||||
set_source_files_properties("../shared/qt256.png"
|
||||
PROPERTIES QT_RESOURCE_ALIAS "qt256.png"
|
||||
)
|
||||
qt_internal_add_resource(imguirenderer "imguirenderer"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
"../shared/texture.vert.qsb"
|
||||
"../shared/texture.frag.qsb"
|
||||
"../shared/qt256.png"
|
||||
)
|
||||
|
||||
set(imgui_base ../shared/imgui)
|
||||
set(imgui_target imguirenderer)
|
||||
include(${imgui_base}/imgui.cmakeinc)
|
128
tests/manual/rhi/imguirenderer/imguirenderer.cpp
Normal file
128
tests/manual/rhi/imguirenderer/imguirenderer.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#define EXAMPLEFW_IMGUI
|
||||
#include "../shared/examplefw.h"
|
||||
|
||||
#include "../shared/cube.h"
|
||||
|
||||
struct {
|
||||
QMatrix4x4 winProj;
|
||||
QList<QRhiResource *> releasePool;
|
||||
QRhiResourceUpdateBatch *initialUpdates = nullptr;
|
||||
QRhiBuffer *vbuf = nullptr;
|
||||
QRhiBuffer *ubuf = nullptr;
|
||||
QRhiTexture *tex = nullptr;
|
||||
QRhiSampler *sampler = nullptr;
|
||||
QRhiShaderResourceBindings *srb = nullptr;
|
||||
QRhiGraphicsPipeline *ps = nullptr;
|
||||
bool showDemoWindow = true;
|
||||
float rotation = 0.0f;
|
||||
} d;
|
||||
|
||||
void Window::customInit()
|
||||
{
|
||||
d.initialUpdates = m_r->nextResourceUpdateBatch();
|
||||
|
||||
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube));
|
||||
d.vbuf->create();
|
||||
d.releasePool << d.vbuf;
|
||||
|
||||
d.initialUpdates->uploadStaticBuffer(d.vbuf, cube);
|
||||
|
||||
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
|
||||
d.ubuf->create();
|
||||
d.releasePool << d.ubuf;
|
||||
float opacity = 1.0f;
|
||||
d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &opacity);
|
||||
|
||||
QImage image = QImage(QLatin1String(":/qt256.png")).convertToFormat(QImage::Format_RGBA8888).mirrored();
|
||||
d.tex = m_r->newTexture(QRhiTexture::RGBA8, QSize(image.width(), image.height()), 1, {});
|
||||
d.releasePool << d.tex;
|
||||
d.tex->create();
|
||||
d.initialUpdates->uploadTexture(d.tex, image);
|
||||
|
||||
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
|
||||
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
|
||||
d.releasePool << d.sampler;
|
||||
d.sampler->create();
|
||||
|
||||
d.srb = m_r->newShaderResourceBindings();
|
||||
d.releasePool << d.srb;
|
||||
d.srb->setBindings({
|
||||
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
|
||||
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler)
|
||||
});
|
||||
d.srb->create();
|
||||
|
||||
d.ps = m_r->newGraphicsPipeline();
|
||||
d.releasePool << d.ps;
|
||||
d.ps->setCullMode(QRhiGraphicsPipeline::Back);
|
||||
const QRhiShaderStage stages[] = {
|
||||
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
||||
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
||||
};
|
||||
d.ps->setShaderStages(stages, stages + 2);
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({
|
||||
{ 3 * sizeof(float) },
|
||||
{ 2 * sizeof(float) }
|
||||
});
|
||||
inputLayout.setAttributes({
|
||||
{ 0, 0, QRhiVertexInputAttribute::Float3, 0 },
|
||||
{ 1, 1, QRhiVertexInputAttribute::Float2, 0 }
|
||||
});
|
||||
d.ps->setVertexInputLayout(inputLayout);
|
||||
d.ps->setShaderResourceBindings(d.srb);
|
||||
d.ps->setRenderPassDescriptor(m_rp);
|
||||
d.ps->create();
|
||||
}
|
||||
|
||||
void Window::customRelease()
|
||||
{
|
||||
qDeleteAll(d.releasePool);
|
||||
d.releasePool.clear();
|
||||
}
|
||||
|
||||
void Window::customRender()
|
||||
{
|
||||
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
|
||||
QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
|
||||
if (d.initialUpdates) {
|
||||
u->merge(d.initialUpdates);
|
||||
d.initialUpdates->release();
|
||||
d.initialUpdates = nullptr;
|
||||
}
|
||||
|
||||
QMatrix4x4 mvp = m_proj;
|
||||
mvp.rotate(d.rotation, 0, 1, 0);
|
||||
u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData());
|
||||
|
||||
const QSize outputSizeInPixels = m_sc->currentPixelSize();
|
||||
cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u);
|
||||
|
||||
cb->setGraphicsPipeline(d.ps);
|
||||
cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
|
||||
cb->setShaderResources();
|
||||
const QRhiCommandBuffer::VertexInput vbufBindings[] = {
|
||||
{ d.vbuf, 0 },
|
||||
{ d.vbuf, quint32(36 * 3 * sizeof(float)) }
|
||||
};
|
||||
cb->setVertexInput(0, 2, vbufBindings);
|
||||
cb->draw(36);
|
||||
|
||||
m_imguiRenderer->render();
|
||||
|
||||
cb->endPass();
|
||||
}
|
||||
|
||||
void Window::customGui()
|
||||
{
|
||||
ImGui::ShowDemoWindow(&d.showDemoWindow);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(50, 120), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(400, 100), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Test");
|
||||
ImGui::SliderFloat("Rotation", &d.rotation, 0.0f, 360.0f);
|
||||
ImGui::End();
|
||||
}
|
@ -36,6 +36,11 @@
|
||||
#include <QtGui/private/qrhimetal_p.h>
|
||||
#endif
|
||||
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
#include "qrhiimgui_p.h"
|
||||
#include "imgui.h"
|
||||
#endif
|
||||
|
||||
QShader getShader(const QString &name)
|
||||
{
|
||||
QFile f(name);
|
||||
@ -45,6 +50,15 @@ QShader getShader(const QString &name)
|
||||
return QShader();
|
||||
}
|
||||
|
||||
QByteArray getResource(const QString &name)
|
||||
{
|
||||
QFile f(name);
|
||||
if (f.open(QIODevice::ReadOnly))
|
||||
return f.readAll();
|
||||
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
enum GraphicsApi
|
||||
{
|
||||
Null,
|
||||
@ -102,6 +116,9 @@ protected:
|
||||
void customInit();
|
||||
void customRelease();
|
||||
void customRender();
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
void customGui();
|
||||
#endif
|
||||
|
||||
void exposeEvent(QExposeEvent *) override;
|
||||
bool event(QEvent *) override;
|
||||
@ -130,6 +147,11 @@ protected:
|
||||
|
||||
QColor m_clearColor;
|
||||
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
QRhiImguiRenderer *m_imguiRenderer;
|
||||
QRhiImgui m_imgui;
|
||||
#endif
|
||||
|
||||
friend int main(int, char**);
|
||||
};
|
||||
|
||||
@ -204,6 +226,10 @@ bool Window::event(QEvent *e)
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
if (m_imgui.processEvent(e))
|
||||
return true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@ -276,6 +302,21 @@ void Window::init()
|
||||
m_rp = m_sc->newCompatibleRenderPassDescriptor();
|
||||
m_sc->setRenderPassDescriptor(m_rp);
|
||||
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
ImGuiIO &io(ImGui::GetIO());
|
||||
io.FontAllowUserScaling = true; // enable ctrl+wheel on windows
|
||||
io.IniFilename = nullptr; // no imgui.ini
|
||||
|
||||
QByteArray font = getResource(QLatin1String(":/fonts/RobotoMono-Medium.ttf"));
|
||||
ImFontConfig fontCfg;
|
||||
fontCfg.FontDataOwnedByAtlas = false;
|
||||
io.Fonts->Clear();
|
||||
io.Fonts->AddFontFromMemoryTTF(font.data(), font.size(), 20.0f, &fontCfg);
|
||||
m_imgui.rebuildFontAtlas();
|
||||
|
||||
m_imguiRenderer = new QRhiImguiRenderer;
|
||||
#endif
|
||||
|
||||
customInit();
|
||||
}
|
||||
|
||||
@ -292,6 +333,11 @@ void Window::releaseResources()
|
||||
delete m_sc;
|
||||
m_sc = nullptr;
|
||||
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
delete m_imguiRenderer;
|
||||
m_imguiRenderer = nullptr;
|
||||
#endif
|
||||
|
||||
delete m_r;
|
||||
m_r = nullptr;
|
||||
|
||||
@ -360,6 +406,20 @@ void Window::render()
|
||||
m_frameCount = 0;
|
||||
}
|
||||
|
||||
#ifdef EXAMPLEFW_IMGUI
|
||||
m_imgui.nextFrame(size(), devicePixelRatio(), QPointF(0, 0), std::bind(&Window::customGui, this));
|
||||
m_imgui.syncRenderer(m_imguiRenderer);
|
||||
|
||||
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
|
||||
QRhiRenderTarget *rt = m_sc->currentFrameRenderTarget();
|
||||
const QSize outputSizeInPixels = m_sc->currentPixelSize();
|
||||
const float dpr = devicePixelRatio();
|
||||
|
||||
QMatrix4x4 guiMvp = m_r->clipSpaceCorrMatrix();
|
||||
guiMvp.ortho(0, outputSizeInPixels.width() / dpr, outputSizeInPixels.height() / dpr, 0, 1, -1);
|
||||
m_imguiRenderer->prepare(m_r, rt, cb, guiMvp, 1.0f);
|
||||
#endif
|
||||
|
||||
customRender();
|
||||
|
||||
m_r->endFrame(m_sc, endFrameFlags);
|
||||
|
2
tests/manual/rhi/shared/imgui/buildshaders.bat
Normal file
2
tests/manual/rhi/shared/imgui/buildshaders.bat
Normal file
@ -0,0 +1,2 @@
|
||||
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -c imgui.vert -o imgui.vert.qsb
|
||||
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -c imgui.frag -o imgui.frag.qsb
|
202
tests/manual/rhi/shared/imgui/fonts/LICENSE.txt
Normal file
202
tests/manual/rhi/shared/imgui/fonts/LICENSE.txt
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
BIN
tests/manual/rhi/shared/imgui/fonts/RobotoMono-Medium.ttf
Normal file
BIN
tests/manual/rhi/shared/imgui/fonts/RobotoMono-Medium.ttf
Normal file
Binary file not shown.
29
tests/manual/rhi/shared/imgui/imgui.cmakeinc
Normal file
29
tests/manual/rhi/shared/imgui/imgui.cmakeinc
Normal file
@ -0,0 +1,29 @@
|
||||
set(imgui_sources
|
||||
${imgui_base}/imgui/imgui.cpp
|
||||
${imgui_base}/imgui/imgui_draw.cpp
|
||||
${imgui_base}/imgui/imgui_tables.cpp
|
||||
${imgui_base}/imgui/imgui_widgets.cpp
|
||||
${imgui_base}/imgui/imgui_demo.cpp
|
||||
${imgui_base}/qrhiimgui.cpp
|
||||
${imgui_base}/qrhiimgui_p.h
|
||||
)
|
||||
|
||||
target_sources(${imgui_target} PRIVATE
|
||||
${imgui_sources}
|
||||
)
|
||||
|
||||
target_include_directories(${imgui_target} PRIVATE
|
||||
${imgui_base}
|
||||
${imgui_base}/imgui
|
||||
)
|
||||
|
||||
qt6_add_resources(${imgui_target} "imgui_resources"
|
||||
PREFIX
|
||||
"/"
|
||||
BASE
|
||||
${imgui_base}
|
||||
FILES
|
||||
${imgui_base}/imgui.vert.qsb
|
||||
${imgui_base}/imgui.frag.qsb
|
||||
${imgui_base}/fonts/RobotoMono-Medium.ttf
|
||||
)
|
21
tests/manual/rhi/shared/imgui/imgui.frag
Normal file
21
tests/manual/rhi/shared/imgui/imgui.frag
Normal file
@ -0,0 +1,21 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec2 v_texcoord;
|
||||
layout(location = 1) in vec4 v_color;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
float opacity;
|
||||
};
|
||||
|
||||
layout(binding = 1) uniform sampler2D tex;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 c = v_color * texture(tex, v_texcoord);
|
||||
c.a *= opacity;
|
||||
c.rgb *= c.a;
|
||||
fragColor = c;
|
||||
}
|
BIN
tests/manual/rhi/shared/imgui/imgui.frag.qsb
Normal file
BIN
tests/manual/rhi/shared/imgui/imgui.frag.qsb
Normal file
Binary file not shown.
20
tests/manual/rhi/shared/imgui/imgui.vert
Normal file
20
tests/manual/rhi/shared/imgui/imgui.vert
Normal file
@ -0,0 +1,20 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
layout(location = 1) in vec2 texcoord;
|
||||
layout(location = 2) in vec4 color;
|
||||
|
||||
layout(location = 0) out vec2 v_texcoord;
|
||||
layout(location = 1) out vec4 v_color;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
mat4 mvp;
|
||||
float opacity;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
v_texcoord = texcoord;
|
||||
v_color = color;
|
||||
gl_Position = mvp * vec4(position.xy, 0.0, 1.0);
|
||||
}
|
BIN
tests/manual/rhi/shared/imgui/imgui.vert.qsb
Normal file
BIN
tests/manual/rhi/shared/imgui/imgui.vert.qsb
Normal file
Binary file not shown.
21
tests/manual/rhi/shared/imgui/imgui/LICENSE.txt
Normal file
21
tests/manual/rhi/shared/imgui/imgui/LICENSE.txt
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2022 Omar Cornut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
125
tests/manual/rhi/shared/imgui/imgui/imconfig.h
Normal file
125
tests/manual/rhi/shared/imgui/imgui/imconfig.h
Normal file
@ -0,0 +1,125 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||
//-----------------------------------------------------------------------------
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//#define IMGUI_USE_WCHAR32
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
|
||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||
//#define IMGUI_USE_STB_SPRINTF
|
||||
|
||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
//struct ImDrawCmd;
|
||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||
//#define ImDrawCallback MyImDrawCallback
|
||||
|
||||
//---- Debug Tools: Macro to break in Debugger
|
||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
//#define IM_DEBUG_BREAK __debugbreak()
|
||||
|
||||
//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
|
||||
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
|
||||
// This adds a small runtime cost which is why it is not enabled by default.
|
||||
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, const MyMatrix44& v);
|
||||
}
|
||||
*/
|
13444
tests/manual/rhi/shared/imgui/imgui/imgui.cpp
Normal file
13444
tests/manual/rhi/shared/imgui/imgui/imgui.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3065
tests/manual/rhi/shared/imgui/imgui/imgui.h
Normal file
3065
tests/manual/rhi/shared/imgui/imgui/imgui.h
Normal file
File diff suppressed because it is too large
Load Diff
7969
tests/manual/rhi/shared/imgui/imgui/imgui_demo.cpp
Normal file
7969
tests/manual/rhi/shared/imgui/imgui/imgui_demo.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4162
tests/manual/rhi/shared/imgui/imgui/imgui_draw.cpp
Normal file
4162
tests/manual/rhi/shared/imgui/imgui/imgui_draw.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2975
tests/manual/rhi/shared/imgui/imgui/imgui_internal.h
Normal file
2975
tests/manual/rhi/shared/imgui/imgui/imgui_internal.h
Normal file
File diff suppressed because it is too large
Load Diff
4068
tests/manual/rhi/shared/imgui/imgui/imgui_tables.cpp
Normal file
4068
tests/manual/rhi/shared/imgui/imgui/imgui_tables.cpp
Normal file
File diff suppressed because it is too large
Load Diff
8394
tests/manual/rhi/shared/imgui/imgui/imgui_widgets.cpp
Normal file
8394
tests/manual/rhi/shared/imgui/imgui/imgui_widgets.cpp
Normal file
File diff suppressed because it is too large
Load Diff
627
tests/manual/rhi/shared/imgui/imgui/imstb_rectpack.h
Normal file
627
tests/manual/rhi/shared/imgui/imgui/imstb_rectpack.h
Normal file
@ -0,0 +1,627 @@
|
||||
// [DEAR IMGUI]
|
||||
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
//
|
||||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Before #including,
|
||||
//
|
||||
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||
//
|
||||
// in the file that you want to have the implementation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Credits
|
||||
//
|
||||
// Library
|
||||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||
// 0.99 (2019-02-07) warning fixes
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
// 0.09 (2016-08-27) fix compiler warnings
|
||||
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
typedef int stbrp_coord;
|
||||
|
||||
#define STBRP__MAXVAL 0x7fffffff
|
||||
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
//
|
||||
// The function returns 1 if all of the rectangles were successfully
|
||||
// packed and 0 otherwise.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#ifndef STBRP_SORT
|
||||
#include <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
context->extra[1].y = (1<<30);
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
|
||||
STBRP__NOTUSED(c);
|
||||
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
// if it can't possibly fit, bail immediately
|
||||
if (width > c->width || height > c->height) {
|
||||
fr.prev_link = NULL;
|
||||
fr.x = fr.y = 0;
|
||||
return fr;
|
||||
}
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height <= c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags and all_rects_packed status
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
if (!rects[i].was_packed)
|
||||
all_rects_packed = 0;
|
||||
}
|
||||
|
||||
// return the all_rects_packed status
|
||||
return all_rects_packed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
1447
tests/manual/rhi/shared/imgui/imgui/imstb_textedit.h
Normal file
1447
tests/manual/rhi/shared/imgui/imgui/imstb_textedit.h
Normal file
File diff suppressed because it is too large
Load Diff
5085
tests/manual/rhi/shared/imgui/imgui/imstb_truetype.h
Normal file
5085
tests/manual/rhi/shared/imgui/imgui/imstb_truetype.h
Normal file
File diff suppressed because it is too large
Load Diff
606
tests/manual/rhi/shared/imgui/qrhiimgui.cpp
Normal file
606
tests/manual/rhi/shared/imgui/qrhiimgui.cpp
Normal file
@ -0,0 +1,606 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#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)
|
||||
{
|
||||
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));
|
||||
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);
|
||||
|
||||
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
|
93
tests/manual/rhi/shared/imgui/qrhiimgui_p.h
Normal file
93
tests/manual/rhi/shared/imgui/qrhiimgui_p.h
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef QRHIIMGUI_P_H
|
||||
#define QRHIIMGUI_P_H
|
||||
|
||||
#include <QtGui/private/qrhi_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QEvent;
|
||||
|
||||
class QRhiImguiRenderer
|
||||
{
|
||||
public:
|
||||
~QRhiImguiRenderer();
|
||||
|
||||
struct CmdListBuffer {
|
||||
quint32 offset;
|
||||
QByteArray data;
|
||||
};
|
||||
|
||||
struct DrawCmd {
|
||||
int cmdListBufferIdx;
|
||||
int textureIndex;
|
||||
quint32 indexOffset;
|
||||
quint32 elemCount;
|
||||
QPointF itemPixelOffset;
|
||||
QVector4D clipRect;
|
||||
};
|
||||
|
||||
struct StaticRenderData {
|
||||
QImage fontTextureData;
|
||||
};
|
||||
|
||||
struct FrameRenderData {
|
||||
quint32 totalVbufSize = 0;
|
||||
quint32 totalIbufSize = 0;
|
||||
QVarLengthArray<CmdListBuffer, 4> vbuf;
|
||||
QVarLengthArray<CmdListBuffer, 4> ibuf;
|
||||
QVarLengthArray<DrawCmd, 4> draw;
|
||||
QSize outputPixelSize;
|
||||
};
|
||||
|
||||
StaticRenderData sf;
|
||||
FrameRenderData f;
|
||||
|
||||
void prepare(QRhi *rhi, QRhiRenderTarget *rt, QRhiCommandBuffer *cb, const QMatrix4x4 &mvp, float opacity);
|
||||
void render();
|
||||
void releaseResources();
|
||||
|
||||
private:
|
||||
QRhi *m_rhi = nullptr;
|
||||
QRhiRenderTarget *m_rt = nullptr;
|
||||
QRhiCommandBuffer *m_cb = nullptr;
|
||||
|
||||
std::unique_ptr<QRhiBuffer> m_vbuf;
|
||||
std::unique_ptr<QRhiBuffer> m_ibuf;
|
||||
std::unique_ptr<QRhiBuffer> m_ubuf;
|
||||
std::unique_ptr<QRhiGraphicsPipeline> m_ps;
|
||||
QVector<quint32> m_renderPassFormat;
|
||||
std::unique_ptr<QRhiSampler> m_sampler;
|
||||
|
||||
struct Texture {
|
||||
QImage image;
|
||||
QRhiTexture *tex = nullptr;
|
||||
QRhiShaderResourceBindings *srb = nullptr;
|
||||
};
|
||||
QVector<Texture> m_textures;
|
||||
};
|
||||
|
||||
class QRhiImgui
|
||||
{
|
||||
public:
|
||||
QRhiImgui();
|
||||
~QRhiImgui();
|
||||
|
||||
using FrameFunc = std::function<void()>;
|
||||
void nextFrame(const QSizeF &logicalOutputSize, float dpr, const QPointF &logicalOffset, FrameFunc frameFunc);
|
||||
void syncRenderer(QRhiImguiRenderer *renderer);
|
||||
bool processEvent(QEvent *e);
|
||||
|
||||
void rebuildFontAtlas();
|
||||
|
||||
private:
|
||||
QRhiImguiRenderer::StaticRenderData sf;
|
||||
QRhiImguiRenderer::FrameRenderData f;
|
||||
Qt::MouseButtons pressedMouseButtons;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user