Revision control
Copy as Markdown
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include <QtQuick3D/qquick3dobject.h>
#include <QtQuick3D/private/qquick3ditem2d_p.h>
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrenderitem2d_p.h>
#include "qquick3dnode_p_p.h"
#include <QtGui/rhi/qrhi.h>
QT_BEGIN_NAMESPACE
/*
internal
*/
QQuick3DItem2D::QQuick3DItem2D(QQuickItem *item, QQuick3DNode *parent)
: QQuick3DNode(*(new QQuick3DNodePrivate(QQuick3DNodePrivate::Type::Item2D)), parent)
{
m_contentItem = new QQuickItem();
m_contentItem->setObjectName(QLatin1String("parent of ") + item->objectName()); // for debugging
// No size is set for m_contentItem. This is intentional, otherwise item2d anchoring breaks.
QQuickItemPrivate::get(m_contentItem)->ensureSubsceneDeliveryAgent();
QQmlEngine::setObjectOwnership(m_contentItem, QQmlEngine::CppOwnership);
connect(m_contentItem, &QQuickItem::childrenChanged, this, &QQuick3DObject::update);
addChildItem(item);
}
QQuick3DItem2D::~QQuick3DItem2D()
{
delete m_contentItem;
}
void QQuick3DItem2D::addChildItem(QQuickItem *item)
{
item->setParent(m_contentItem);
item->setParentItem(m_contentItem);
QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::ChangeType::Destroyed);
connect(item, &QQuickItem::enabledChanged, this, &QQuick3DItem2D::updatePicking);
connect(item, &QQuickItem::visibleChanged, this, &QQuick3DItem2D::updatePicking);
m_sourceItems.append(item);
update();
}
void QQuick3DItem2D::removeChildItem(QQuickItem *item)
{
m_sourceItems.removeOne(item);
if (item)
QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::ChangeType::Destroyed);
if (m_sourceItems.isEmpty())
emit allChildrenRemoved();
else
update();
}
QQuickItem *QQuick3DItem2D::contentItem() const
{
return m_contentItem;
}
void QQuick3DItem2D::itemDestroyed(QQuickItem *item)
{
removeChildItem(item);
}
void QQuick3DItem2D::updatePicking()
{
m_pickingDirty = true;
update();
}
QSSGRenderGraphObject *QQuick3DItem2D::updateSpatialNode(QSSGRenderGraphObject *node)
{
auto *sourceItemPrivate = QQuickItemPrivate::get(m_contentItem);
QQuickWindow *window = m_contentItem->window();
if (!window) {
const auto &manager = QQuick3DObjectPrivate::get(this)->sceneManager;
window = manager->window();
}
if (!node) {
markAllDirty();
auto *backEndNode = new QSSGRenderItem2D();
backEndNode->m_frontEndObject = this;
node = backEndNode;
}
QQuick3DNode::updateSpatialNode(node);
auto itemNode = static_cast<QSSGRenderItem2D *>(node);
itemNode->m_rootNode = sourceItemPrivate->rootNode();
if (!itemNode->m_rootNode) {
QQuickWindowPrivate::get(window)->updateDirtyNode(m_contentItem);
itemNode->m_rootNode = sourceItemPrivate->rootNode();
if (!itemNode->m_rootNode) {
qWarning() << "Item2D is not initialized. It will not be shown.";
return nullptr;
}
}
if (m_pickingDirty) {
m_pickingDirty = false;
bool isPickable = false;
for (const auto &item : std::as_const(m_sourceItems)) {
// Enable picking for Item2D if any of its child is visible and enabled.
if (item->isVisible() && item->isEnabled()) {
isPickable = true;
break;
}
}
itemNode->setState(QSSGRenderNode::LocalState::Pickable, isPickable);
}
return node;
}
void QQuick3DItem2D::markAllDirty()
{
m_pickingDirty = true;
QQuick3DNode::markAllDirty();
}
void QQuick3DItem2D::preSync()
{
const auto &manager = QQuick3DObjectPrivate::get(this)->sceneManager;
auto *sourcePrivate = QQuickItemPrivate::get(m_contentItem);
auto *window = manager->window();
if (m_window != window) {
update(); // Just schedule an upate immediately.
if (m_window) {
disconnect(m_window, SIGNAL(destroyed(QObject*)), this, SLOT(derefWindow(QObject*)));
sourcePrivate->derefWindow();
}
m_window = window;
sourcePrivate->refWindow(window);
connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(derefWindow(QObject*)));
sourcePrivate->refFromEffectItem(true);
}
}
static void detachWindow(QQuickItem *item, QObject *win)
{
auto *itemPriv = QQuickItemPrivate::get(item);
if (win == itemPriv->window) {
itemPriv->window = nullptr;
itemPriv->windowRefCount = 0;
itemPriv->prevDirtyItem = nullptr;
itemPriv->nextDirtyItem = nullptr;
}
for (auto *child : std::as_const(itemPriv->childItems))
detachWindow(child, win);
}
void QQuick3DItem2D::derefWindow(QObject *win)
{
detachWindow(m_contentItem, win);
}
QT_END_NAMESPACE