qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,68 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(hellovulkancubes LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/vulkan/hellovulkancubes")
find_package(Qt6 REQUIRED COMPONENTS Concurrent Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(hellovulkancubes
camera.cpp camera.h
main.cpp
mainwindow.cpp mainwindow.h
mesh.cpp mesh.h
renderer.cpp renderer.h
shader.cpp shader.h
vulkanwindow.cpp vulkanwindow.h
)
set_target_properties(hellovulkancubes PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(hellovulkancubes PRIVATE
Qt6::Concurrent
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
# Resources:
set_source_files_properties("../shared/block.buf"
PROPERTIES QT_RESOURCE_ALIAS "block.buf"
)
set_source_files_properties("../shared/qt_logo.buf"
PROPERTIES QT_RESOURCE_ALIAS "qt_logo.buf"
)
set(hellovulkancubes_resource_files
"../shared/block.buf"
"../shared/qt_logo.buf"
"color_frag.spv"
"color_phong_frag.spv"
"color_phong_vert.spv"
"color_vert.spv"
)
qt6_add_resources(hellovulkancubes "hellovulkancubes"
PREFIX
"/"
FILES
${hellovulkancubes_resource_files}
)
install(TARGETS hellovulkancubes
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,65 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "camera.h"
Camera::Camera(const QVector3D &pos)
: m_forward(0.0f, 0.0f, -1.0f),
m_right(1.0f, 0.0f, 0.0f),
m_up(0.0f, 1.0f, 0.0f),
m_pos(pos),
m_yaw(0.0f),
m_pitch(0.0f)
{
}
static inline void clamp360(float *v)
{
if (*v > 360.0f)
*v -= 360.0f;
if (*v < -360.0f)
*v += 360.0f;
}
void Camera::yaw(float degrees)
{
m_yaw += degrees;
clamp360(&m_yaw);
m_yawMatrix.setToIdentity();
m_yawMatrix.rotate(m_yaw, 0, 1, 0);
QMatrix4x4 rotMat = m_pitchMatrix * m_yawMatrix;
m_forward = (QVector4D(0.0f, 0.0f, -1.0f, 0.0f) * rotMat).toVector3D();
m_right = (QVector4D(1.0f, 0.0f, 0.0f, 0.0f) * rotMat).toVector3D();
}
void Camera::pitch(float degrees)
{
m_pitch += degrees;
clamp360(&m_pitch);
m_pitchMatrix.setToIdentity();
m_pitchMatrix.rotate(m_pitch, 1, 0, 0);
QMatrix4x4 rotMat = m_pitchMatrix * m_yawMatrix;
m_forward = (QVector4D(0.0f, 0.0f, -1.0f, 0.0f) * rotMat).toVector3D();
m_up = (QVector4D(0.0f, 1.0f, 0.0f, 0.0f) * rotMat).toVector3D();
}
void Camera::walk(float amount)
{
m_pos[0] += amount * m_forward.x();
m_pos[2] += amount * m_forward.z();
}
void Camera::strafe(float amount)
{
m_pos[0] += amount * m_right.x();
m_pos[2] += amount * m_right.z();
}
QMatrix4x4 Camera::viewMatrix() const
{
QMatrix4x4 m = m_pitchMatrix * m_yawMatrix;
m.translate(-m_pos);
return m;
}

View File

@ -0,0 +1,33 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef CAMERA_H
#define CAMERA_H
#include <QVector3D>
#include <QMatrix4x4>
class Camera
{
public:
Camera(const QVector3D &pos);
void yaw(float degrees);
void pitch(float degrees);
void walk(float amount);
void strafe(float amount);
QMatrix4x4 viewMatrix() const;
private:
QVector3D m_forward;
QVector3D m_right;
QVector3D m_up;
QVector3D m_pos;
float m_yaw;
float m_pitch;
QMatrix4x4 m_yawMatrix;
QMatrix4x4 m_pitchMatrix;
};
#endif

View File

@ -0,0 +1,12 @@
#version 440
layout(push_constant) uniform PC {
layout(offset = 64) vec3 color;
} pc;
layout(location = 0) out vec4 fragColor;
void main()
{
fragColor = vec4(pc.color, 1.0);
}

View File

@ -0,0 +1,14 @@
#version 440
layout(location = 0) in vec4 position;
out gl_PerVertex { vec4 gl_Position; };
layout(push_constant) uniform PC {
mat4 mvp;
} pc;
void main()
{
gl_Position = pc.mvp * position;
}

Binary file not shown.

View File

@ -0,0 +1,39 @@
#version 440
layout(location = 0) in vec3 vECVertNormal;
layout(location = 1) in vec3 vECVertPos;
layout(location = 2) flat in vec3 vDiffuseAdjust;
layout(std140, binding = 1) uniform buf {
vec3 ECCameraPosition;
vec3 ka;
vec3 kd;
vec3 ks;
// Have one light only for now.
vec3 ECLightPosition;
vec3 attenuation;
vec3 color;
float intensity;
float specularExp;
} ubuf;
layout(location = 0) out vec4 fragColor;
void main()
{
vec3 unnormL = ubuf.ECLightPosition - vECVertPos;
float dist = length(unnormL);
float att = 1.0 / (ubuf.attenuation.x + ubuf.attenuation.y * dist + ubuf.attenuation.z * dist * dist);
vec3 N = normalize(vECVertNormal);
vec3 L = normalize(unnormL);
float NL = max(0.0, dot(N, L));
vec3 dColor = att * ubuf.intensity * ubuf.color * NL;
vec3 R = reflect(-L, N);
vec3 V = normalize(ubuf.ECCameraPosition - vECVertPos);
float RV = max(0.0, dot(R, V));
vec3 sColor = att * ubuf.intensity * ubuf.color * pow(RV, ubuf.specularExp);
fragColor = vec4(ubuf.ka + (ubuf.kd + vDiffuseAdjust) * dColor + ubuf.ks * sColor, 1.0);
}

View File

@ -0,0 +1,32 @@
#version 440
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 normal;
// Instanced attributes to variate the translation of the model and the diffuse
// color of the material.
layout(location = 2) in vec3 instTranslate;
layout(location = 3) in vec3 instDiffuseAdjust;
out gl_PerVertex { vec4 gl_Position; };
layout(location = 0) out vec3 vECVertNormal;
layout(location = 1) out vec3 vECVertPos;
layout(location = 2) flat out vec3 vDiffuseAdjust;
layout(std140, binding = 0) uniform buf {
mat4 vp;
mat4 model;
mat3 modelNormal;
} ubuf;
void main()
{
vECVertNormal = normalize(ubuf.modelNormal * normal);
mat4 t = mat4(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
instTranslate.x, instTranslate.y, instTranslate.z, 1);
vECVertPos = vec3(t * ubuf.model * position);
vDiffuseAdjust = instDiffuseAdjust;
gl_Position = ubuf.vp * t * ubuf.model * position;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,24 @@
QT += widgets concurrent
HEADERS += \
mainwindow.h \
vulkanwindow.h \
renderer.h \
mesh.h \
shader.h \
camera.h
SOURCES += \
main.cpp \
mainwindow.cpp \
vulkanwindow.cpp \
renderer.cpp \
mesh.cpp \
shader.cpp \
camera.cpp
RESOURCES += hellovulkancubes.qrc
# install
target.path = $$[QT_INSTALL_EXAMPLES]/vulkan/hellovulkancubes
INSTALLS += target

View File

@ -0,0 +1,10 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="block.buf">../shared/block.buf</file>
<file alias="qt_logo.buf">../shared/qt_logo.buf</file>
<file>color_phong_vert.spv</file>
<file>color_phong_frag.spv</file>
<file>color_vert.spv</file>
<file>color_frag.spv</file>
</qresource>
</RCC>

View File

@ -0,0 +1,33 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include <QLoggingCategory>
#include "mainwindow.h"
#include "vulkanwindow.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
const bool dbg = qEnvironmentVariableIntValue("QT_VK_DEBUG");
QVulkanInstance inst;
if (dbg) {
QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true"));
inst.setLayers({ "VK_LAYER_KHRONOS_validation" });
}
if (!inst.create())
qFatal("Failed to create Vulkan instance: %d", inst.errorCode());
VulkanWindow *vulkanWindow = new VulkanWindow(dbg);
vulkanWindow->setVulkanInstance(&inst);
MainWindow mainWindow(vulkanWindow);
mainWindow.resize(1024, 768);
mainWindow.show();
return app.exec();
}

View File

@ -0,0 +1,70 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "mainwindow.h"
#include "vulkanwindow.h"
#include <QApplication>
#include <QLabel>
#include <QPushButton>
#include <QLCDNumber>
#include <QCheckBox>
#include <QGridLayout>
MainWindow::MainWindow(VulkanWindow *vulkanWindow)
{
QWidget *wrapper = QWidget::createWindowContainer(vulkanWindow);
wrapper->setFocusPolicy(Qt::StrongFocus);
wrapper->setFocus();
infoLabel = new QLabel;
infoLabel->setFrameStyle(QFrame::Box | QFrame::Raised);
infoLabel->setAlignment(Qt::AlignCenter);
infoLabel->setText(tr("This example demonstrates instanced drawing\nof a mesh loaded from a file.\n"
"Uses a Phong material with a single light.\n"
"Also demonstrates dynamic uniform buffers\nand a bit of threading with QtConcurrent.\n"
"Uses 4x MSAA when available.\n"
"Comes with an FPS camera.\n"
"Hit [Shift+]WASD to walk and strafe.\nPress and move mouse to look around.\n"
"Click Add New to increase the number of instances."));
meshSwitch = new QCheckBox(tr("&Use Qt logo"));
meshSwitch->setFocusPolicy(Qt::NoFocus); // do not interfere with vulkanWindow's keyboard input
counterLcd = new QLCDNumber(5);
counterLcd->setSegmentStyle(QLCDNumber::Filled);
counterLcd->display(m_count);
newButton = new QPushButton(tr("&Add new"));
newButton->setFocusPolicy(Qt::NoFocus);
quitButton = new QPushButton(tr("&Quit"));
quitButton->setFocusPolicy(Qt::NoFocus);
pauseButton = new QPushButton(tr("&Pause"));
pauseButton->setFocusPolicy(Qt::NoFocus);
connect(quitButton, &QPushButton::clicked, qApp, &QCoreApplication::quit);
connect(newButton, &QPushButton::clicked, vulkanWindow, [=] {
vulkanWindow->addNew();
m_count = vulkanWindow->instanceCount();
counterLcd->display(m_count);
});
connect(pauseButton, &QPushButton::clicked, vulkanWindow, &VulkanWindow::togglePaused);
connect(meshSwitch, &QCheckBox::clicked, vulkanWindow, &VulkanWindow::meshSwitched);
QGridLayout *layout = new QGridLayout;
layout->addWidget(infoLabel, 0, 2);
layout->addWidget(meshSwitch, 1, 2);
layout->addWidget(createLabel(tr("INSTANCES")), 2, 2);
layout->addWidget(counterLcd, 3, 2);
layout->addWidget(newButton, 4, 2);
layout->addWidget(pauseButton, 5, 2);
layout->addWidget(quitButton, 6, 2);
layout->addWidget(wrapper, 0, 0, 7, 2);
setLayout(layout);
}
QLabel *MainWindow::createLabel(const QString &text)
{
QLabel *lbl = new QLabel(text);
lbl->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
return lbl;
}

View File

@ -0,0 +1,36 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
QT_BEGIN_NAMESPACE
class QLCDNumber;
class QLabel;
class QPushButton;
class QCheckBox;
QT_END_NAMESPACE
class VulkanWindow;
class MainWindow : public QWidget
{
public:
MainWindow(VulkanWindow *vulkanWindow);
private:
QLabel *createLabel(const QString &text);
QLabel *infoLabel;
QCheckBox *meshSwitch;
QLCDNumber *counterLcd;
QPushButton *newButton;
QPushButton *quitButton;
QPushButton *pauseButton;
int m_count = 128;
};
#endif

View File

@ -0,0 +1,51 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "mesh.h"
#include <QtConcurrentRun>
#include <QFile>
void Mesh::load(const QString &fn)
{
reset();
m_maybeRunning = true;
m_future = QtConcurrent::run([fn]() {
MeshData md;
QFile f(fn);
if (!f.open(QIODevice::ReadOnly)) {
qWarning("Failed to open %s", qPrintable(fn));
return md;
}
QByteArray buf = f.readAll();
const char *p = buf.constData();
quint32 format;
memcpy(&format, p, 4);
if (format != 1) {
qWarning("Invalid format in %s", qPrintable(fn));
return md;
}
int ofs = 4;
memcpy(&md.vertexCount, p + ofs, 4);
ofs += 4;
memcpy(md.aabb, p + ofs, 6 * 4);
ofs += 6 * 4;
const int byteCount = md.vertexCount * 8 * 4;
md.geom.resize(byteCount);
memcpy(md.geom.data(), p + ofs, byteCount);
return md;
});
}
MeshData *Mesh::data()
{
if (m_maybeRunning && !m_data.isValid())
m_data = m_future.result();
return &m_data;
}
void Mesh::reset()
{
*data() = MeshData();
m_maybeRunning = false;
}

View File

@ -0,0 +1,32 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MESH_H
#define MESH_H
#include <QString>
#include <QFuture>
struct MeshData
{
bool isValid() const { return vertexCount > 0; }
int vertexCount = 0;
float aabb[6];
QByteArray geom; // x, y, z, u, v, nx, ny, nz
};
class Mesh
{
public:
void load(const QString &fn);
MeshData *data();
bool isValid() { return data()->isValid(); }
void reset();
private:
bool m_maybeRunning = false;
QFuture<MeshData> m_future;
MeshData m_data;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,111 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef RENDERER_H
#define RENDERER_H
#include "vulkanwindow.h"
#include "mesh.h"
#include "shader.h"
#include "camera.h"
#include <QFutureWatcher>
#include <QMutex>
class Renderer : public QVulkanWindowRenderer
{
public:
Renderer(VulkanWindow *w, int initialCount);
void preInitResources() override;
void initResources() override;
void initSwapChainResources() override;
void releaseSwapChainResources() override;
void releaseResources() override;
void startNextFrame() override;
bool animating() const { return m_animating; }
void setAnimating(bool a) { m_animating = a; }
int instanceCount() const { return m_instCount; }
void addNew();
void yaw(float degrees);
void pitch(float degrees);
void walk(float amount);
void strafe(float amount);
void setUseLogo(bool b);
private:
void createPipelines();
void createItemPipeline();
void createFloorPipeline();
void ensureBuffers();
void ensureInstanceBuffer();
void getMatrices(QMatrix4x4 *mvp, QMatrix4x4 *model, QMatrix3x3 *modelNormal, QVector3D *eyePos);
void writeFragUni(quint8 *p, const QVector3D &eyePos);
void buildFrame();
void buildDrawCallsForItems();
void buildDrawCallsForFloor();
void markViewProjDirty() { m_vpDirty = m_window->concurrentFrameCount(); }
VulkanWindow *m_window;
QVulkanDeviceFunctions *m_devFuncs;
bool m_useLogo = false;
Mesh m_blockMesh;
Mesh m_logoMesh;
VkBuffer m_blockVertexBuf = VK_NULL_HANDLE;
VkBuffer m_logoVertexBuf = VK_NULL_HANDLE;
struct {
VkDeviceSize vertUniSize;
VkDeviceSize fragUniSize;
VkDeviceSize uniMemStartOffset;
Shader vs;
Shader fs;
VkDescriptorPool descPool = VK_NULL_HANDLE;
VkDescriptorSetLayout descSetLayout = VK_NULL_HANDLE;
VkDescriptorSet descSet;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
VkPipeline pipeline = VK_NULL_HANDLE;
} m_itemMaterial;
VkBuffer m_floorVertexBuf = VK_NULL_HANDLE;
struct {
Shader vs;
Shader fs;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
VkPipeline pipeline = VK_NULL_HANDLE;
} m_floorMaterial;
VkDeviceMemory m_bufMem = VK_NULL_HANDLE;
VkBuffer m_uniBuf = VK_NULL_HANDLE;
VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
QFuture<void> m_pipelinesFuture;
QVector3D m_lightPos;
Camera m_cam;
QMatrix4x4 m_proj;
int m_vpDirty = 0;
QMatrix4x4 m_floorModel;
bool m_animating;
float m_rotation = 0.0f;
int m_instCount;
int m_preparedInstCount = 0;
QByteArray m_instData;
VkBuffer m_instBuf = VK_NULL_HANDLE;
VkDeviceMemory m_instBufMem = VK_NULL_HANDLE;
QFutureWatcher<void> m_frameWatcher;
bool m_framePending;
QMutex m_guiMutex;
};
#endif

View File

@ -0,0 +1,47 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "shader.h"
#include <QtConcurrentRun>
#include <QFile>
#include <QVulkanDeviceFunctions>
void Shader::load(QVulkanInstance *inst, VkDevice dev, const QString &fn)
{
reset();
m_maybeRunning = true;
m_future = QtConcurrent::run([inst, dev, fn]() {
ShaderData sd;
QFile f(fn);
if (!f.open(QIODevice::ReadOnly)) {
qWarning("Failed to open %s", qPrintable(fn));
return sd;
}
QByteArray blob = f.readAll();
VkShaderModuleCreateInfo shaderInfo;
memset(&shaderInfo, 0, sizeof(shaderInfo));
shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shaderInfo.codeSize = blob.size();
shaderInfo.pCode = reinterpret_cast<const uint32_t *>(blob.constData());
VkResult err = inst->deviceFunctions(dev)->vkCreateShaderModule(dev, &shaderInfo, nullptr, &sd.shaderModule);
if (err != VK_SUCCESS) {
qWarning("Failed to create shader module: %d", err);
return sd;
}
return sd;
});
}
ShaderData *Shader::data()
{
if (m_maybeRunning && !m_data.isValid())
m_data = m_future.result();
return &m_data;
}
void Shader::reset()
{
*data() = ShaderData();
m_maybeRunning = false;
}

View File

@ -0,0 +1,30 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef SHADER_H
#define SHADER_H
#include <QVulkanInstance>
#include <QFuture>
struct ShaderData
{
bool isValid() const { return shaderModule != VK_NULL_HANDLE; }
VkShaderModule shaderModule = VK_NULL_HANDLE;
};
class Shader
{
public:
void load(QVulkanInstance *inst, VkDevice dev, const QString &fn);
ShaderData *data();
bool isValid() { return data()->isValid(); }
void reset();
private:
bool m_maybeRunning = false;
QFuture<ShaderData> m_future;
ShaderData m_data;
};
#endif

View File

@ -0,0 +1,87 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "vulkanwindow.h"
#include "renderer.h"
#include <QMouseEvent>
#include <QKeyEvent>
VulkanWindow::VulkanWindow(bool dbg)
: m_debug(dbg)
{
}
QVulkanWindowRenderer *VulkanWindow::createRenderer()
{
m_renderer = new Renderer(this, 128);
return m_renderer;
}
void VulkanWindow::addNew()
{
m_renderer->addNew();
}
void VulkanWindow::togglePaused()
{
m_renderer->setAnimating(!m_renderer->animating());
}
void VulkanWindow::meshSwitched(bool enable)
{
m_renderer->setUseLogo(enable);
}
void VulkanWindow::mousePressEvent(QMouseEvent *e)
{
m_pressed = true;
m_lastPos = e->position().toPoint();
}
void VulkanWindow::mouseReleaseEvent(QMouseEvent *)
{
m_pressed = false;
}
void VulkanWindow::mouseMoveEvent(QMouseEvent *e)
{
if (!m_pressed)
return;
int dx = e->position().toPoint().x() - m_lastPos.x();
int dy = e->position().toPoint().y() - m_lastPos.y();
if (dy)
m_renderer->pitch(dy / 10.0f);
if (dx)
m_renderer->yaw(dx / 10.0f);
m_lastPos = e->position().toPoint();
}
void VulkanWindow::keyPressEvent(QKeyEvent *e)
{
const float amount = e->modifiers().testFlag(Qt::ShiftModifier) ? 1.0f : 0.1f;
switch (e->key()) {
case Qt::Key_W:
m_renderer->walk(amount);
break;
case Qt::Key_S:
m_renderer->walk(-amount);
break;
case Qt::Key_A:
m_renderer->strafe(-amount);
break;
case Qt::Key_D:
m_renderer->strafe(amount);
break;
default:
break;
}
}
int VulkanWindow::instanceCount() const
{
return m_renderer->instanceCount();
}

View File

@ -0,0 +1,38 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef VULKANWINDOW_H
#define VULKANWINDOW_H
#include <QVulkanWindow>
class Renderer;
class VulkanWindow : public QVulkanWindow
{
public:
VulkanWindow(bool dbg);
QVulkanWindowRenderer *createRenderer() override;
bool isDebugEnabled() const { return m_debug; }
int instanceCount() const;
public slots:
void addNew();
void togglePaused();
void meshSwitched(bool enable);
private:
void mousePressEvent(QMouseEvent *) override;
void mouseReleaseEvent(QMouseEvent *) override;
void mouseMoveEvent(QMouseEvent *) override;
void keyPressEvent(QKeyEvent *) override;
bool m_debug;
Renderer *m_renderer;
bool m_pressed = false;
QPoint m_lastPos;
};
#endif