QmlPuppet: Hide 3D edit view render window

Rendering is now done using QRhi private API and QQuickRenderControl.

In addition, input event handling was changed to use sendEvent instead
of postEvent for our fake mouse events, as mouse event position
gets corrupted somehow if event is handled asynchronously when the
window is hidden.

Change-Id: Ia2466622cd4b60e3f73e0ad3e7e4da7c7c335451
Fixes: QDS-3125
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Miikka Heikkinen
2020-11-17 17:56:45 +02:00
parent a0dd5d2b4f
commit ae15780f84
5 changed files with 492 additions and 201 deletions

View File

@@ -50,11 +50,8 @@ Item {
view.destroy();
}
function createViewForObject(obj, w, h)
function createViewForObject(obj)
{
width = w;
height = h;
if (obj instanceof Material)
createViewForMaterial(obj);
else if (obj instanceof Model)

View File

@@ -45,6 +45,12 @@
#include <QtQuick3D/private/qquick3dviewport_p.h>
#endif
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtGui/private/qrhi_p.h>
#include <QtQuick/private/qquickrendercontrol_p.h>
#include <QtQuick/private/qquickrendertarget_p.h>
#endif
#include <private/qquickdesignersupportitems_p.h>
IconRenderer::IconRenderer(int size, const QString &filePath, const QString &source)
@@ -62,23 +68,26 @@ void IconRenderer::setupRender()
DesignerSupport::activateDesignerWindowManager();
#endif
m_quickView = new QQuickView;
QQmlEngine *engine = nullptr;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QSurfaceFormat surfaceFormat = m_quickView->requestedFormat();
auto view = new QQuickView;
engine = view->engine();
m_window = view;
QSurfaceFormat surfaceFormat = view->requestedFormat();
surfaceFormat.setVersion(4, 1);
surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
m_quickView->setFormat(surfaceFormat);
DesignerSupport::createOpenGLContext(m_quickView);
view->setFormat(surfaceFormat);
DesignerSupport::createOpenGLContext(view);
#else
m_quickView->setDefaultAlphaBuffer(true);
m_quickView->setColor(Qt::transparent);
m_ratio = m_quickView->devicePixelRatio();
m_quickView->installEventFilter(this);
engine = new QQmlEngine;
m_renderControl = new QQuickRenderControl;
m_window = new QQuickWindow(m_renderControl);
m_window->setDefaultAlphaBuffer(true);
m_window->setColor(Qt::transparent);
m_renderControl->initialize();
#endif
QQmlComponent component(m_quickView->engine());
QQmlComponent component(engine);
component.loadUrl(QUrl::fromLocalFile(m_source));
QObject *iconItem = component.create();
@@ -86,13 +95,19 @@ void IconRenderer::setupRender()
#ifdef QUICK3D_MODULE
if (auto scene = qobject_cast<QQuick3DNode *>(iconItem)) {
qmlRegisterType<QmlDesigner::Internal::SelectionBoxGeometry>("SelectionBoxGeometry", 1, 0, "SelectionBoxGeometry");
QQmlComponent component(m_quickView->engine());
QQmlComponent component(engine);
component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/IconRenderer3D.qml"));
m_containerItem = qobject_cast<QQuickItem *>(component.create());
DesignerSupport::setRootItem(m_quickView, m_containerItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
DesignerSupport::setRootItem(view, m_containerItem);
#else
m_window->contentItem()->setSize(m_containerItem->size());
m_window->setGeometry(0, 0, m_containerItem->width(), m_containerItem->height());
m_containerItem->setParentItem(m_window->contentItem());
#endif
auto helper = new QmlDesigner::Internal::GeneralHelper();
m_quickView->engine()->rootContext()->setContextProperty("_generalHelper", helper);
engine->rootContext()->setContextProperty("_generalHelper", helper);
m_contentItem = QQmlProperty::read(m_containerItem, "view3D").value<QQuickItem *>();
auto view3D = qobject_cast<QQuick3DViewport *>(m_contentItem);
@@ -104,21 +119,21 @@ void IconRenderer::setupRender()
m_contentItem = scene;
m_containerItem = new QQuickItem();
m_containerItem->setSize(QSizeF(1024, 1024));
DesignerSupport::setRootItem(m_quickView, m_containerItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
DesignerSupport::setRootItem(view, m_containerItem);
#else
m_window->contentItem()->setSize(m_containerItem->size());
m_window->setGeometry(0, 0, m_containerItem->width(), m_containerItem->height());
m_containerItem->setParentItem(m_window->contentItem());
#endif
m_contentItem->setParentItem(m_containerItem);
}
if (m_containerItem && m_contentItem) {
resizeContent(m_size);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (!initRhi())
QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit);
QTimer::singleShot(0, this, &IconRenderer::createIcon);
#else
m_quickView->show();
m_quickView->lower();
// Failsafe to exit eventually if window fails to expose
QTimer::singleShot(10000, qGuiApp, &QGuiApplication::quit);
#endif
} else {
QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit);
}
@@ -127,25 +142,12 @@ void IconRenderer::setupRender()
}
}
bool IconRenderer::eventFilter(QObject *watched, QEvent *event)
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (watched == m_quickView && event->type() == QEvent::Expose)
QTimer::singleShot(0, this, &IconRenderer::createIcon);
#else
Q_UNUSED(watched)
Q_UNUSED(event)
#endif
return false;
}
void IconRenderer::createIcon()
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
m_designerSupport.refFromEffectItem(m_quickView->rootObject(), false);
m_designerSupport.refFromEffectItem(m_containerItem, false);
#endif
QQuickDesignerSupportItems::disableNativeTextRendering(m_quickView->rootObject());
QQuickDesignerSupportItems::disableNativeTextRendering(m_containerItem);
#ifdef QUICK3D_MODULE
if (m_is3D) {
// Render once to make sure scene is up to date before we set up the selection box
@@ -166,6 +168,8 @@ void IconRenderer::createIcon()
// Render @2x image
resizeContent(m_size * 2);
if (!initRhi())
QTimer::singleShot(1000, qGuiApp, &QGuiApplication::quit);
QString saveFile;
saveFile = fi.absolutePath() + '/' + fi.completeBaseName() + "@2x";
@@ -194,23 +198,39 @@ void IconRenderer::render(const QString &fileName)
item->update();
#endif
};
updateNodesRecursive(m_quickView->rootObject());
updateNodesRecursive(m_containerItem);
QRect rect(QPoint(), m_contentItem->size().toSize());
QImage renderImage;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QImage renderImage = m_designerSupport.renderImageForItem(m_quickView->rootObject(),
rect, rect.size());
renderImage = m_designerSupport.renderImageForItem(m_containerItem, rect, rect.size());
#else
QImage renderImage = m_quickView->grabWindow();
m_renderControl->polishItems();
m_renderControl->beginFrame();
m_renderControl->sync();
m_renderControl->render();
bool readCompleted = false;
QRhiReadbackResult readResult;
readResult.completed = [&] {
readCompleted = true;
QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
readResult.pixelSize.width(), readResult.pixelSize.height(),
QImage::Format_RGBA8888_Premultiplied);
if (m_rhi->isYUpInFramebuffer())
renderImage = wrapperImage.mirrored().copy(0, 0, rect.width(), rect.height());
else
renderImage = wrapperImage.copy(0, 0, rect.width(), rect.height());
};
QRhiResourceUpdateBatch *readbackBatch = m_rhi->nextResourceUpdateBatch();
readbackBatch->readBackTexture(m_texture, &readResult);
QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(m_renderControl);
rd->cb->resourceUpdate(readbackBatch);
m_renderControl->endFrame();
#endif
if (!fileName.isEmpty()) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (m_ratio != 1.) {
rect.setWidth(qRound(rect.size().width() * m_ratio));
rect.setHeight(qRound(rect.size().height() * m_ratio));
}
renderImage = renderImage.copy(rect);
#endif
QFileInfo fi(fileName);
if (fi.suffix().isEmpty())
renderImage.save(fileName, "PNG");
@@ -219,16 +239,60 @@ void IconRenderer::render(const QString &fileName)
}
}
void IconRenderer::resizeContent(int size)
void IconRenderer::resizeContent(int dimensions)
{
int theSize = size;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (m_ratio != 1.)
theSize = qRound(qreal(size) / m_quickView->devicePixelRatio());
#endif
m_contentItem->setSize(QSizeF(theSize, theSize));
QSizeF size(dimensions, dimensions);
m_contentItem->setSize(size);
if (m_contentItem->width() > m_containerItem->width())
m_containerItem->setWidth(m_contentItem->width());
if (m_contentItem->height() > m_containerItem->height())
m_containerItem->setHeight(m_contentItem->height());
}
bool IconRenderer::initRhi()
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (!m_rhi) {
QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(m_renderControl);
m_rhi = rd->rhi;
if (!m_rhi) {
qWarning() << __FUNCTION__ << "Rhi is null";
return false;
}
}
// Don't bother deleting old ones as iconrender is a single shot executable
m_texTarget = nullptr;
m_rpDesc = nullptr;
m_buffer = nullptr;
m_texture = nullptr;
const QSize size = m_containerItem->size().toSize();
m_texture = m_rhi->newTexture(QRhiTexture::RGBA8, size, 1,
QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
if (!m_texture->create()) {
qWarning() << __FUNCTION__ << "QRhiTexture creation failed";
return false;
}
m_buffer = m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size, 1);
if (!m_buffer->create()) {
qWarning() << __FUNCTION__ << "Depth/stencil buffer creation failed";
return false;
}
QRhiTextureRenderTargetDescription rtDesc {QRhiColorAttachment(m_texture)};
rtDesc.setDepthStencilBuffer(m_buffer);
m_texTarget = m_rhi->newTextureRenderTarget(rtDesc);
m_rpDesc = m_texTarget->newCompatibleRenderPassDescriptor();
m_texTarget->setRenderPassDescriptor(m_rpDesc);
if (!m_texTarget->create()) {
qWarning() << __FUNCTION__ << "Texture render target creation failed";
return false;
}
// redirect Qt Quick rendering into our texture
m_window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(m_texTarget));
#endif
return true;
}

View File

@@ -31,8 +31,16 @@
#include <designersupportdelegate.h>
QT_BEGIN_NAMESPACE
class QQuickView;
class QQuickWindow;
class QQuickItem;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
class QQuickRenderControl;
class QRhi;
class QRhiTexture;
class QRhiRenderBuffer;
class QRhiTextureRenderTarget;
class QRhiRenderPassDescriptor;
#endif
QT_END_NAMESPACE
class IconRenderer : public QObject
@@ -44,21 +52,26 @@ public:
void setupRender();
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
private:
void createIcon();
void render(const QString &fileName);
void resizeContent(int size);
void resizeContent(int dimensions);
bool initRhi();
int m_size = 16;
double m_ratio = 1.;
QString m_filePath;
QString m_source;
QQuickView *m_quickView = nullptr;
QQuickWindow *m_window = nullptr;
QQuickItem *m_contentItem = nullptr;
QQuickItem *m_containerItem = nullptr;
DesignerSupport m_designerSupport;
bool m_is3D = false;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QQuickRenderControl *m_renderControl = nullptr;
QRhi *m_rhi = nullptr;
QRhiTexture *m_texture = nullptr;
QRhiRenderBuffer *m_buffer = nullptr;
QRhiTextureRenderTarget *m_texTarget = nullptr;
QRhiRenderPassDescriptor *m_rpDesc = nullptr;
#endif
};

View File

@@ -87,6 +87,14 @@
#include <QtGui/qevent.h>
#include <QtGui/qguiapplication.h>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtGui/private/qrhi_p.h>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qquickrendercontrol_p.h>
#include <QtQuick/private/qquickrendertarget_p.h>
#endif
#ifdef QUICK3D_MODULE
#include <QtQuick3D/private/qquick3dnode_p.h>
#include <QtQuick3D/private/qquick3dcamera_p.h>
@@ -135,29 +143,34 @@ static bool isQuick3DMode()
return mode3D;
}
QQuickView *Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url,
QQuickItem *&rootItem)
void Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url,
RenderViewData &viewData)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
auto view = new QQuickView(quickView()->engine(), quickView());
view->setFormat(quickView()->format());
DesignerSupport::createOpenGLContext(view);
viewData.window = new QQuickView(quickView()->engine(), quickView());
viewData.window->setFormat(quickView()->format());
DesignerSupport::createOpenGLContext(static_cast<QQuickView *>(viewData.window));
#else
auto view = new QQuickView(quickView()->engine(), nullptr);
view->setFormat(quickView()->format());
viewData.renderControl = new QQuickRenderControl;
viewData.window = new QQuickWindow(viewData.renderControl);
viewData.renderControl->initialize();
#endif
QQmlComponent component(engine());
component.loadUrl(url);
rootItem = qobject_cast<QQuickItem *>(component.create());
viewData.rootItem = qobject_cast<QQuickItem *>(component.create());
if (!rootItem) {
if (!viewData.rootItem) {
qWarning() << "Could not create view for: " << url.toString() << component.errors();
return nullptr;
return;
}
DesignerSupport::setRootItem(view, rootItem);
return view;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
DesignerSupport::setRootItem(static_cast<QQuickView *>(viewData.window), viewData.rootItem);
#else
viewData.window->contentItem()->setSize(viewData.rootItem->size());
viewData.window->setGeometry(0, 0, viewData.rootItem->width(), viewData.rootItem->height());
viewData.rootItem->setParentItem(viewData.window->contentItem());
#endif
}
void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances)
@@ -177,6 +190,179 @@ void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<Se
}
}
void Qt5InformationNodeInstanceServer::handleInputEvents()
{
if (m_editView3DData.window) {
int angleDelta = 0;
for (int i = 0; i < m_pendingInputEventCommands.size(); ++i) {
const InputEventCommand &command = m_pendingInputEventCommands[i];
if (command.type() == QEvent::Wheel) {
if (i < m_pendingInputEventCommands.size() - 1) {
// Peek at next command. If that is also a wheel with same button/modifiers
// state, skip this event and add the angle delta to the next one.
auto nextCommand = m_pendingInputEventCommands[i + 1];
if (nextCommand.type() == QEvent::MouseMove
&& nextCommand.button() == command.button()
&& nextCommand.buttons() == command.buttons()
&& nextCommand.modifiers() == command.modifiers()) {
angleDelta += command.angleDelta();
continue;
}
}
QWheelEvent *we
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
= new QWheelEvent(command.pos(), command.pos(), {0, 0},
{0, angleDelta + command.angleDelta()},
command.buttons(), command.modifiers(), Qt::NoScrollPhase,
false);
#else
= new QWheelEvent(command.pos(), command.pos(), {0, 0}, {0, command.angleDelta()},
0, Qt::Horizontal, command.buttons(), command.modifiers(),
Qt::NoScrollPhase, Qt::MouseEventNotSynthesized);
#endif
angleDelta = 0;
QGuiApplication::sendEvent(m_editView3DData.window, we);
} else {
if (command.type() == QEvent::MouseMove && i < m_pendingInputEventCommands.size() - 1) {
// Peek at next command. If that is also a move with only difference being
// the position, skip this event as it is pointless
auto nextCommand = m_pendingInputEventCommands[i + 1];
if (nextCommand.type() == QEvent::MouseMove
&& nextCommand.button() == command.button()
&& nextCommand.buttons() == command.buttons()
&& nextCommand.modifiers() == command.modifiers()) {
continue;
}
}
auto me = new QMouseEvent(command.type(), command.pos(), command.button(),
command.buttons(), command.modifiers());
// We must use sendEvent in Qt 6, as using postEvent allows the associated position
// data stored internally in QMutableEventPoint to potentially be updated by system
// before the event is delivered.
QGuiApplication::sendEvent(m_editView3DData.window, me);
}
}
m_pendingInputEventCommands.clear();
render3DEditView();
}
}
bool Qt5InformationNodeInstanceServer::initRhi(RenderViewData &viewData)
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (!viewData.renderControl) {
qWarning() << __FUNCTION__ << "Render control not created";
return false;
}
if (!viewData.rhi) {
QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(viewData.renderControl);
viewData.rhi = rd->rhi;
if (!viewData.rhi) {
qWarning() << __FUNCTION__ << "Rhi is null";
return false;
}
}
auto cleanRhiResources = [&viewData]() {
// Releasing cached resources is a workaround for bug QTBUG-88761
auto renderer = QQuickWindowPrivate::get(viewData.window)->renderer;
if (renderer)
renderer->releaseCachedResources();
if (viewData.rpDesc) {
viewData.rpDesc->deleteLater();
viewData.rpDesc = nullptr;
}
if (viewData.texTarget) {
viewData.texTarget->deleteLater();
viewData.texTarget = nullptr;
}
if (viewData.buffer) {
viewData.buffer->deleteLater();
viewData.buffer = nullptr;
}
if (viewData.texture) {
viewData.texture->deleteLater();
viewData.texture = nullptr;
}
};
if (viewData.bufferDirty) {
cleanRhiResources();
viewData.bufferDirty = false;
}
const QSize size = viewData.rootItem->size().toSize();
viewData.texture = viewData.rhi->newTexture(QRhiTexture::RGBA8, size, 1,
QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
if (!viewData.texture->create()) {
qWarning() << __FUNCTION__ << "QRhiTexture creation failed";
cleanRhiResources();
return false;
}
viewData.buffer = viewData.rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size, 1);
if (!viewData.buffer->create()) {
qWarning() << __FUNCTION__ << "Depth/stencil buffer creation failed";
cleanRhiResources();
return false;
}
QRhiTextureRenderTargetDescription rtDesc(QRhiColorAttachment(viewData.texture));
rtDesc.setDepthStencilBuffer(viewData.buffer);
viewData.texTarget = viewData.rhi->newTextureRenderTarget(rtDesc);
viewData.rpDesc = viewData.texTarget->newCompatibleRenderPassDescriptor();
viewData.texTarget->setRenderPassDescriptor(viewData.rpDesc);
if (!viewData.texTarget->create()) {
qWarning() << __FUNCTION__ << "Texture render target creation failed";
cleanRhiResources();
return false;
}
// redirect Qt Quick rendering into our texture
viewData.window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(viewData.texTarget));
#endif
return true;
}
QImage Qt5InformationNodeInstanceServer::grabRenderControl(RenderViewData &viewData)
{
QImage renderImage;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (viewData.bufferDirty && !initRhi(viewData))
return renderImage;
viewData.renderControl->polishItems();
viewData.renderControl->beginFrame();
viewData.renderControl->sync();
viewData.renderControl->render();
bool readCompleted = false;
QRhiReadbackResult readResult;
readResult.completed = [&] {
readCompleted = true;
QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
readResult.pixelSize.width(), readResult.pixelSize.height(),
QImage::Format_RGBA8888_Premultiplied);
if (viewData.rhi->isYUpInFramebuffer())
renderImage = wrapperImage.mirrored();
else
renderImage = wrapperImage.copy();
};
QRhiResourceUpdateBatch *readbackBatch = viewData.rhi->nextResourceUpdateBatch();
readbackBatch->readBackTexture(viewData.texture, &readResult);
QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(viewData.renderControl);
rd->cb->resourceUpdate(readbackBatch);
viewData.renderControl->endFrame();
#endif
return renderImage;
}
void Qt5InformationNodeInstanceServer::createEditView3D()
{
#ifdef QUICK3D_MODULE
@@ -199,10 +385,10 @@ void Qt5InformationNodeInstanceServer::createEditView3D()
new QmlDesigner::Internal::IconGizmoImageProvider);
m_3dHelper = helper;
m_editView3D = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml"), m_editView3DRootItem);
createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml"), m_editView3DData);
if (m_editView3DRootItem)
helper->setParent(m_editView3DRootItem);
if (m_editView3DData.rootItem)
helper->setParent(m_editView3DData.rootItem);
#endif
}
@@ -373,10 +559,10 @@ void Qt5InformationNodeInstanceServer::handleNode3DDestroyed(QObject *obj)
{
#ifdef QUICK3D_MODULE
if (qobject_cast<QQuick3DCamera *>(obj)) {
QMetaObject::invokeMethod(m_editView3DRootItem, "releaseCameraGizmo",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseCameraGizmo",
Q_ARG(QVariant, objectToVariant(obj)));
} else if (qobject_cast<QQuick3DAbstractLight *>(obj)) {
QMetaObject::invokeMethod(m_editView3DRootItem, "releaseLightGizmo",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseLightGizmo",
Q_ARG(QVariant, objectToVariant(obj)));
}
removeNode3D(obj);
@@ -392,7 +578,7 @@ void Qt5InformationNodeInstanceServer::updateView3DRect(QObject *view3D)
viewPortrect = QRectF(0., 0., view3D->property("width").toDouble(),
view3D->property("height").toDouble());
}
QQmlProperty viewPortProperty(m_editView3DRootItem, "viewPortRect", context());
QQmlProperty viewPortProperty(m_editView3DData.rootItem, "viewPortRect", context());
viewPortProperty.write(viewPortrect);
}
@@ -405,7 +591,7 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D()
// Active scene change handling on qml side is async, so a deleted importScene would crash
// editView when it updates next. Disable/enable edit view update synchronously to avoid this.
QVariant activeSceneVar = objectToVariant(m_active3DScene);
QMetaObject::invokeMethod(m_editView3DRootItem, "enableEditViewUpdate",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "enableEditViewUpdate",
Q_ARG(QVariant, activeSceneVar));
ServerNodeInstance sceneInstance = active3DSceneInstance();
@@ -419,7 +605,7 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D()
m_active3DSceneUpdatePending = false;
}
QMetaObject::invokeMethod(m_editView3DRootItem, "setActiveScene", Qt::QueuedConnection,
QMetaObject::invokeMethod(m_editView3DData.rootItem, "setActiveScene", Qt::QueuedConnection,
Q_ARG(QVariant, activeSceneVar),
Q_ARG(QVariant, QVariant::fromValue(sceneId)));
@@ -472,11 +658,11 @@ void Qt5InformationNodeInstanceServer::resolveSceneRoots()
if (newRoot != oldRoot) {
if (qobject_cast<QQuick3DCamera *>(node)) {
QMetaObject::invokeMethod(m_editView3DRootItem, "updateCameraGizmoScene",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateCameraGizmoScene",
Q_ARG(QVariant, objectToVariant(newRoot)),
Q_ARG(QVariant, objectToVariant(node)));
} else if (qobject_cast<QQuick3DAbstractLight *>(node)) {
QMetaObject::invokeMethod(m_editView3DRootItem, "updateLightGizmoScene",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateLightGizmoScene",
Q_ARG(QVariant, objectToVariant(newRoot)),
Q_ARG(QVariant, objectToVariant(node)));
}
@@ -535,30 +721,30 @@ void Qt5InformationNodeInstanceServer::render3DEditView(int count)
void Qt5InformationNodeInstanceServer::doRender3DEditView()
{
if (m_editView3DSetupDone) {
if (!m_editView3DContentItem)
m_editView3DContentItem = getContentItemForRendering(m_editView3DRootItem);
if (!m_editView3DData.contentItem)
m_editView3DData.contentItem = getContentItemForRendering(m_editView3DData.rootItem);
QImage renderImage;
updateNodesRecursive(m_editView3DContentItem);
updateNodesRecursive(m_editView3DData.contentItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
renderImage = m_editView3D->grabWindow();
renderImage = m_editView3DData.window->grabWindow();
} else {
// Fake render loop signaling to update things like QML items as 3D textures
m_editView3D->beforeSynchronizing();
m_editView3D->beforeRendering();
m_editView3DData.window->beforeSynchronizing();
m_editView3DData.window->beforeRendering();
QSizeF size = qobject_cast<QQuickItem *>(m_editView3DContentItem)->size();
QSizeF size = qobject_cast<QQuickItem *>(m_editView3DData.contentItem)->size();
QRectF renderRect(QPointF(0., 0.), size);
renderImage = designerSupport()->renderImageForItem(m_editView3DContentItem,
renderImage = designerSupport()->renderImageForItem(m_editView3DData.contentItem,
renderRect, size.toSize());
m_editView3D->afterRendering();
m_editView3DData.window->afterRendering();
}
#else
renderImage = m_editView3D->grabWindow();
renderImage = grabRenderControl(m_editView3DData);
#endif
// There's no instance related to image, so instance id is -1.
@@ -601,9 +787,9 @@ void Qt5InformationNodeInstanceServer::doRenderModelNodeImageView()
void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView()
{
#ifdef QUICK3D_MODULE
if (m_ModelNode3DImageViewRootItem) {
if (!m_ModelNode3DImageViewContentItem)
m_ModelNode3DImageViewContentItem = getContentItemForRendering(m_ModelNode3DImageViewRootItem);
if (m_modelNode3DImageViewData.rootItem) {
if (!m_modelNode3DImageViewData.contentItem)
m_modelNode3DImageViewData.contentItem = getContentItemForRendering(m_modelNode3DImageViewData.rootItem);
// Key number is selected so that it is unlikely to conflict other ImageContainer use.
auto imgContainer = ImageContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001);
@@ -628,43 +814,48 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView()
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
// Requested size is already adjusted for target pixel ratio, so we have to adjust
// back if ratio is not default for our window.
double ratio = m_ModelNode3DImageView->devicePixelRatio();
double ratio = m_modelNode3DImageViewData.window->devicePixelRatio();
renderSize.setWidth(qRound(qreal(renderSize.width()) / ratio));
renderSize.setHeight(qRound(qreal(renderSize.height()) / ratio));
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_modelNode3DImageViewData.bufferDirty = m_modelNode3DImageViewData.bufferDirty
|| m_modelNode3DImageViewData.rootItem->width() != renderSize.width()
|| m_modelNode3DImageViewData.rootItem->height() != renderSize.height();
#endif
QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "createViewForObject",
Q_ARG(QVariant, objectToVariant(instanceObj)),
Q_ARG(QVariant, QVariant::fromValue(renderSize.width())),
Q_ARG(QVariant, QVariant::fromValue(renderSize.height())));
m_modelNode3DImageViewData.window->resize(renderSize);
m_modelNode3DImageViewData.rootItem->setSize(renderSize);
QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "createViewForObject",
Q_ARG(QVariant, objectToVariant(instanceObj)));
bool ready = false;
int count = 0; // Ensure we don't ever get stuck in an infinite loop
while (!ready && ++count < 10) {
updateNodesRecursive(m_ModelNode3DImageViewContentItem);
updateNodesRecursive(m_modelNode3DImageViewData.contentItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
renderImage = m_ModelNode3DImageView->grabWindow();
renderImage = m_modelNode3DImageViewData.window->grabWindow();
} else {
// Fake render loop signaling to update things like QML items as 3D textures
m_ModelNode3DImageView->beforeSynchronizing();
m_ModelNode3DImageView->beforeRendering();
m_modelNode3DImageViewData.window->beforeSynchronizing();
m_modelNode3DImageViewData.window->beforeRendering();
QSizeF size = qobject_cast<QQuickItem *>(m_ModelNode3DImageViewContentItem)->size();
QSizeF size = qobject_cast<QQuickItem *>(m_modelNode3DImageViewData.contentItem)->size();
QRectF renderRect(QPointF(0., 0.), size);
renderImage = designerSupport()->renderImageForItem(m_ModelNode3DImageViewContentItem,
renderImage = designerSupport()->renderImageForItem(m_modelNode3DImageViewData.contentItem,
renderRect, size.toSize());
m_ModelNode3DImageView->afterRendering();
m_modelNode3DImageViewData.window->afterRendering();
}
#else
renderImage = m_ModelNode3DImageView->grabWindow();
renderImage = grabRenderControl(m_modelNode3DImageViewData);
#endif
QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "afterRender");
ready = QQmlProperty::read(m_ModelNode3DImageViewRootItem, "ready").value<bool>();
QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "afterRender");
ready = QQmlProperty::read(m_modelNode3DImageViewData.rootItem, "ready").value<bool>();
}
QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "destroyView");
QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView");
if (!m_modelNodePreviewImageCommand.componentPath().isEmpty()) {
// If component changes, puppet will need a reset anyway, so we can cache the image
m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(), renderImage);
@@ -705,9 +896,9 @@ static QRectF itemBoundingRect(QQuickItem *item)
void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView()
{
if (m_ModelNode2DImageViewRootItem) {
if (!m_ModelNode2DImageViewContentItem)
m_ModelNode2DImageViewContentItem = getContentItemForRendering(m_ModelNode2DImageViewRootItem);
if (m_modelNode2DImageViewData.rootItem) {
if (!m_modelNode2DImageViewData.contentItem)
m_modelNode2DImageViewData.contentItem = getContentItemForRendering(m_modelNode2DImageViewData.rootItem);
// Key number is the same as in 3D case as they produce image for same purpose
auto imgContainer = ImageContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001);
@@ -730,7 +921,7 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView()
return;
}
instanceItem->setParentItem(m_ModelNode2DImageViewContentItem);
instanceItem->setParentItem(m_modelNode2DImageViewData.contentItem);
// Some component may expect to always be shown at certain size, so their layouts may
// not support scaling, so let's always render at the default size if item has one and
@@ -742,21 +933,28 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView()
renderSize = finalSize;
renderRect = QRectF(QPointF(0., 0.), QSizeF(renderSize));
}
m_ModelNode2DImageView->resize(renderSize);
m_ModelNode2DImageViewRootItem->setSize(renderSize);
m_ModelNode2DImageViewContentItem->setPosition(QPointF(-renderRect.x(), -renderRect.y()));
updateNodesRecursive(m_ModelNode2DImageViewContentItem);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_modelNode2DImageViewData.bufferDirty = m_modelNode2DImageViewData.bufferDirty
|| m_modelNode2DImageViewData.rootItem->width() != renderSize.width()
|| m_modelNode2DImageViewData.rootItem->height() != renderSize.height();
#endif
m_modelNode2DImageViewData.window->resize(renderSize);
m_modelNode2DImageViewData.rootItem->setSize(renderSize);
m_modelNode2DImageViewData.contentItem->setPosition(QPointF(-renderRect.x(), -renderRect.y()));
updateNodesRecursive(m_modelNode2DImageViewData.contentItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
renderImage = m_ModelNode2DImageView->grabWindow();
renderImage = m_modelNode2DImageViewData.window->grabWindow();
} else {
renderImage = designerSupport()->renderImageForItem(m_ModelNode2DImageViewContentItem,
renderImage = designerSupport()->renderImageForItem(m_modelNode2DImageViewData.contentItem,
renderRect, renderSize);
}
#else
renderImage = m_ModelNode2DImageView->grabWindow();
renderImage = grabRenderControl(m_modelNode2DImageViewData);
#endif
if (!imageHasContent(renderImage))
@@ -788,13 +986,31 @@ Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceC
m_propertyChangeTimer.setSingleShot(true);
m_selectionChangeTimer.setSingleShot(true);
m_render3DEditViewTimer.setSingleShot(true);
m_inputEventTimer.setSingleShot(true);
m_renderModelNodeImageViewTimer.setSingleShot(true);
}
Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer()
{
m_editView3DSetupDone = false;
m_propertyChangeTimer.stop();
m_propertyChangeTimer.stop();
m_selectionChangeTimer.stop();
m_render3DEditViewTimer.stop();
m_inputEventTimer.stop();
delete m_editView3DData.rootItem;
delete m_editView3DData.window;
delete m_modelNode3DImageViewData.rootItem;
delete m_modelNode3DImageViewData.window;
delete m_modelNode2DImageViewData.rootItem;
delete m_modelNode2DImageViewData.window;
for (auto view : qAsConst(m_view3Ds))
QObject::disconnect(view, nullptr, this, nullptr);
view->disconnect();
for (auto scene : qAsConst(m_3DSceneMap))
scene->disconnect();
}
void Qt5InformationNodeInstanceServer::sendTokenBack()
@@ -887,29 +1103,14 @@ void Qt5InformationNodeInstanceServer::initializeAuxiliaryViews()
#ifdef QUICK3D_MODULE
if (isQuick3DMode())
createEditView3D();
m_ModelNode3DImageView = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode3DImageView.qml"),
m_ModelNode3DImageViewRootItem);
createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode3DImageView.qml"),
m_modelNode3DImageViewData);
#endif
m_ModelNode2DImageView = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode2DImageView.qml"),
m_ModelNode2DImageViewRootItem);
m_ModelNode2DImageView->setDefaultAlphaBuffer(true);
m_ModelNode2DImageView->setColor(Qt::transparent);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (!m_editView3D.isNull()) {
m_editView3D->show();
m_editView3D->lower();
}
if (!m_ModelNode3DImageView.isNull()) {
m_ModelNode3DImageView->show();
m_ModelNode3DImageView->lower();
}
if (!m_ModelNode2DImageView.isNull()) {
m_ModelNode2DImageView->show();
m_ModelNode2DImageView->lower();
}
#endif
createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode2DImageView.qml"),
m_modelNode2DImageViewData);
m_modelNode2DImageViewData.window->setDefaultAlphaBuffer(true);
m_modelNode2DImageViewData.window->setColor(Qt::transparent);
}
void Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout()
@@ -940,7 +1141,7 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
while (cameraIt != cameras.constEnd()) {
const auto cameraObjs = cameraIt.value();
for (auto &obj : cameraObjs) {
QMetaObject::invokeMethod(m_editView3DRootItem, "addCameraGizmo",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "addCameraGizmo",
Q_ARG(QVariant, objectToVariant(cameraIt.key())),
Q_ARG(QVariant, objectToVariant(obj)));
}
@@ -950,7 +1151,7 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
while (lightIt != lights.constEnd()) {
const auto lightObjs = lightIt.value();
for (auto &obj : lightObjs) {
QMetaObject::invokeMethod(m_editView3DRootItem, "addLightGizmo",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "addLightGizmo",
Q_ARG(QVariant, objectToVariant(lightIt.key())),
Q_ARG(QVariant, objectToVariant(obj)));
}
@@ -1134,7 +1335,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
const QHash<QString, QVariantMap> &toolStates)
{
#ifdef QUICK3D_MODULE
if (!m_editView3DRootItem)
if (!m_editView3DData.rootItem)
return;
ServerNodeInstance root = rootNodeInstance();
@@ -1142,13 +1343,13 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
add3DViewPorts(instanceList);
add3DScenes(instanceList);
QObject::connect(m_editView3DRootItem, SIGNAL(selectionChanged(QVariant)),
QObject::connect(m_editView3DData.rootItem, SIGNAL(selectionChanged(QVariant)),
this, SLOT(handleSelectionChanged(QVariant)));
QObject::connect(m_editView3DRootItem, SIGNAL(commitObjectProperty(QVariant, QVariant)),
QObject::connect(m_editView3DData.rootItem, SIGNAL(commitObjectProperty(QVariant, QVariant)),
this, SLOT(handleObjectPropertyCommit(QVariant, QVariant)));
QObject::connect(m_editView3DRootItem, SIGNAL(changeObjectProperty(QVariant, QVariant)),
QObject::connect(m_editView3DData.rootItem, SIGNAL(changeObjectProperty(QVariant, QVariant)),
this, SLOT(handleObjectPropertyChange(QVariant, QVariant)));
QObject::connect(m_editView3DRootItem, SIGNAL(notifyActiveSceneChange()),
QObject::connect(m_editView3DData.rootItem, SIGNAL(notifyActiveSceneChange()),
this, SLOT(handleActiveSceneChange()));
QObject::connect(&m_propertyChangeTimer, &QTimer::timeout,
this, &Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout);
@@ -1156,6 +1357,8 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
this, &Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout);
QObject::connect(&m_render3DEditViewTimer, &QTimer::timeout,
this, &Qt5InformationNodeInstanceServer::doRender3DEditView);
QObject::connect(&m_inputEventTimer, &QTimer::timeout,
this, &Qt5InformationNodeInstanceServer::handleInputEvents);
QString lastSceneId;
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
@@ -1167,7 +1370,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
}
if (toolStates.contains(helper->globalStateId())) {
if (toolStates[helper->globalStateId()].contains(helper->rootSizeKey()))
m_editView3DRootItem->setSize(toolStates[helper->globalStateId()][helper->rootSizeKey()].value<QSize>());
m_editView3DData.rootItem->setSize(toolStates[helper->globalStateId()][helper->rootSizeKey()].value<QSize>());
if (toolStates[helper->globalStateId()].contains(helper->lastSceneIdKey()))
lastSceneId = toolStates[helper->globalStateId()][helper->lastSceneIdKey()].toString();
}
@@ -1198,7 +1401,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
if (toolStates.contains({})) {
// Update tool state to an existing no-scene state before updating the active scene to
// ensure the previous state is inherited properly in all cases.
QMetaObject::invokeMethod(m_editView3DRootItem, "updateToolStates", Qt::QueuedConnection,
QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateToolStates", Qt::QueuedConnection,
Q_ARG(QVariant, toolStates[{}]),
Q_ARG(QVariant, QVariant::fromValue(false)));
}
@@ -1456,13 +1659,13 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
// Ensure the UI has enough selection box items. If it doesn't yet have them, which can be the
// case when the first selection processed is a multiselection, we wait a bit as
// using the new boxes immediately leads to visual glitches.
int boxCount = m_editView3DRootItem->property("selectionBoxes").value<QVariantList>().size();
int boxCount = m_editView3DData.rootItem->property("selectionBoxes").value<QVariantList>().size();
if (boxCount < selectedObjs.size()) {
QMetaObject::invokeMethod(m_editView3DRootItem, "ensureSelectionBoxes",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "ensureSelectionBoxes",
Q_ARG(QVariant, QVariant::fromValue(selectedObjs.size())));
m_selectionChangeTimer.start(0);
} else {
QMetaObject::invokeMethod(m_editView3DRootItem, "selectObjects",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "selectObjects",
Q_ARG(QVariant, QVariant::fromValue(selectedObjs)));
}
@@ -1511,27 +1714,10 @@ void Qt5InformationNodeInstanceServer::removeInstances(const RemoveInstancesComm
void Qt5InformationNodeInstanceServer::inputEvent(const InputEventCommand &command)
{
if (m_editView3D) {
if (command.type() == QEvent::Wheel) {
QWheelEvent *we
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
= new QWheelEvent(command.pos(), command.pos(), {0, 0}, {0, command.angleDelta()},
command.buttons(), command.modifiers(), Qt::NoScrollPhase,
false);
#else
= new QWheelEvent(command.pos(), command.pos(), {0, 0}, {0, command.angleDelta()},
0, Qt::Horizontal, command.buttons(), command.modifiers(),
Qt::NoScrollPhase, Qt::MouseEventNotSynthesized);
#endif
QGuiApplication::postEvent(m_editView3D, we);
} else {
auto me = new QMouseEvent(command.type(), command.pos(), command.button(),
command.buttons(), command.modifiers());
QGuiApplication::postEvent(m_editView3D, me);
}
render3DEditView();
if (m_editView3DData.window) {
m_pendingInputEventCommands.append(command);
if (!m_inputEventTimer.isActive())
m_inputEventTimer.start(0);
}
}
@@ -1554,7 +1740,7 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
updatedState.insert("transformMode", 2);
break;
case View3DActionCommand::FitToView:
QMetaObject::invokeMethod(m_editView3DRootItem, "fitToView");
QMetaObject::invokeMethod(m_editView3DData.rootItem, "fitToView");
break;
case View3DActionCommand::SelectionModeToggle:
updatedState.insert("selectionMode", command.isEnabled() ? 1 : 0);
@@ -1578,7 +1764,7 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
}
if (!updatedState.isEmpty()) {
QMetaObject::invokeMethod(m_editView3DRootItem, "updateToolStates",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateToolStates",
Q_ARG(QVariant, updatedState),
Q_ARG(QVariant, QVariant::fromValue(false)));
}
@@ -1619,7 +1805,7 @@ void Qt5InformationNodeInstanceServer::changeIds(const ChangeIdsCommand &command
qint32 sceneInstanceId = sceneInstance.instanceId();
for (const auto &id : command.ids) {
if (sceneInstanceId == id.instanceId()) {
QMetaObject::invokeMethod(m_editView3DRootItem, "handleActiveSceneIdChange",
QMetaObject::invokeMethod(m_editView3DData.rootItem, "handleActiveSceneIdChange",
Qt::QueuedConnection,
Q_ARG(QVariant, QVariant(sceneInstance.id())));
render3DEditView();
@@ -1763,12 +1949,18 @@ void Qt5InformationNodeInstanceServer::update3DViewState(const Update3dViewState
#ifdef QUICK3D_MODULE
if (command.type() == Update3dViewStateCommand::SizeChange) {
if (m_editView3DSetupDone) {
m_editView3DRootItem->setSize(command.size());
m_editView3DData.rootItem->setSize(command.size());
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_editView3DData.window->contentItem()->setSize(m_editView3DData.rootItem->size());
m_editView3DData.window->setGeometry(0, 0, m_editView3DData.rootItem->width(),
m_editView3DData.rootItem->height());
m_editView3DData.bufferDirty = true;
#endif
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
if (helper)
helper->storeToolState(helper->globalStateId(), helper->rootSizeKey(), QVariant(command.size()), 0);
// Queue two renders to make sure icon gizmos update properly
render3DEditView(2);
// Queue three renders to make sure icon gizmos update properly
render3DEditView(3);
}
}
#else

View File

@@ -39,6 +39,15 @@
QT_BEGIN_NAMESPACE
class QDragMoveEvent;
class QQuickWindow;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
class QQuickRenderControl;
class QRhi;
class QRhiTexture;
class QRhiRenderBuffer;
class QRhiTextureRenderTarget;
class QRhiRenderPassDescriptor;
#endif
QT_END_NAMESPACE
namespace QmlDesigner {
@@ -129,19 +138,33 @@ private:
void doRenderModelNodeImageView();
void doRenderModelNode3DImageView();
void doRenderModelNode2DImageView();
QQuickView *createAuxiliaryQuickView(const QUrl &url, QQuickItem *&rootItem);
void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances);
void handleInputEvents();
struct RenderViewData {
QQuickWindow *window = nullptr;
QQuickItem *rootItem = nullptr;
QQuickItem *contentItem = nullptr;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool bufferDirty = true;
QQuickRenderControl *renderControl = nullptr;
QRhi *rhi = nullptr;
QRhiTexture *texture = nullptr;
QRhiRenderBuffer *buffer = nullptr;
QRhiTextureRenderTarget *texTarget = nullptr;
QRhiRenderPassDescriptor *rpDesc = nullptr;
#endif
};
bool initRhi(RenderViewData &viewData);
QImage grabRenderControl(RenderViewData &viewData);
void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData);
RenderViewData m_editView3DData;
RenderViewData m_modelNode3DImageViewData;
RenderViewData m_modelNode2DImageViewData;
QPointer<QQuickView> m_editView3D;
QQuickItem *m_editView3DRootItem = nullptr;
QQuickItem *m_editView3DContentItem = nullptr;
bool m_editView3DSetupDone = false;
QPointer<QQuickView> m_ModelNode3DImageView;
QQuickItem *m_ModelNode3DImageViewRootItem = nullptr;
QQuickItem *m_ModelNode3DImageViewContentItem = nullptr;
QPointer<QQuickView> m_ModelNode2DImageView;
QQuickItem *m_ModelNode2DImageViewRootItem = nullptr;
QQuickItem *m_ModelNode2DImageViewContentItem = nullptr;
RequestModelNodePreviewImageCommand m_modelNodePreviewImageCommand;
QHash<QString, QImage> m_modelNodePreviewImageCache;
QSet<QObject *> m_view3Ds;
@@ -156,9 +179,11 @@ private:
QTimer m_selectionChangeTimer;
QTimer m_render3DEditViewTimer;
QTimer m_renderModelNodeImageViewTimer;
QTimer m_inputEventTimer;
QVariant m_changedNode;
PropertyName m_changedProperty;
ChangeSelectionCommand m_lastSelectionChangeCommand;
QList<InputEventCommand> m_pendingInputEventCommands;
QObject *m_3dHelper = nullptr;
int m_need3DEditViewRender = 0;
};