void QCollisionAspect::sceneNodeAdded(QSceneChangePtr &e) { QScenePropertyChangePtr propertyChange = e.staticCast<QScenePropertyChange>(); QNodePtr nodePtr = propertyChange->value().value<QNodePtr>(); QNode *n = nodePtr.data(); QNodeVisitor visitor; visitor.traverse(n, this, &QCollisionAspect::visitNode); }
/*! * \internal * * Called by _q_setParentHelper() or _q_postConstructorInit() * on the main thread. */ void QNodePrivate::_q_addChild(QNode *childNode) { Q_ASSERT(childNode); Q_ASSERT_X(childNode->parent() == q_func(), Q_FUNC_INFO, "not a child of this node"); // Have we already notified the parent about its new child? If so, bail out // early so that we do not send more than one new child event to the backend QNodePrivate *childD = QNodePrivate::get(childNode); if (childD->m_notifiedParent == true) return; // Store our id as the parentId in the child so that even if the child gets // removed from the scene as part of the destruction of the parent, when the // parent's children are deleted in the QObject dtor, we still have access to // the parentId. If we didn't store this, we wouldn't have access at that time // because the parent would then only be a QObject, the QNode part would have // been destroyed already. childD->m_parentId = m_id; if (!m_scene) return; // We need to send a QPropertyNodeAddedChange to the backend // to notify the backend that we have a new child if (m_changeArbiter != nullptr) { // Flag that we have notified the parent. We do this immediately before // creating the change because that recurses back into this function and // we need to catch that to avoid sending more than one new child event // to the backend. childD->m_notifiedParent = true; const auto change = QPropertyNodeAddedChangePtr::create(m_id, childNode); change->setPropertyName("children"); notifyObservers(change); } // Update the scene // TODO: Fold this into the QNodeCreatedChangeGenerator so we don't have to // traverse the sub tree three times! QNodeVisitor visitor; visitor.traverse(childNode, this, &QNodePrivate::addEntityComponentToScene); }
/*! * \internal * * Notify the backend that the parent lost this node as a child and * that this node is being destroyed. We only send the node removed * change for the parent's children property iff we have an id for * a parent node. This is set/unset in the _q_addChild()/_q_removeChild() * functions (and initialized in init() if there is a parent at * construction time). * * Likewise, we only send the node destroyed change, iff we have * previously sent a node created change. This is tracked via the * m_hasBackendNode member. */ void QNodePrivate::notifyDestructionChangesAndRemoveFromScene() { Q_Q(QNode); // We notify the backend that the parent lost us as a child if (m_changeArbiter != nullptr && !m_parentId.isNull()) { const auto change = QPropertyNodeRemovedChangePtr::create(m_parentId, q); change->setPropertyName("children"); notifyObservers(change); } // Tell the backend we are about to be destroyed if (m_hasBackendNode) { const QDestructionIdAndTypeCollector collector(q); const auto destroyedChange = QNodeDestroyedChangePtr::create(q, collector.subtreeIdsAndTypes()); notifyObservers(destroyedChange); } // We unset the scene from the node as its backend node was/is about to be destroyed QNodeVisitor visitor; visitor.traverse(q, this, &QNodePrivate::unsetSceneHelper); }
/*! * \internal * * Reparents the public QNode to \a parent. If the new parent is nullptr then this * QNode is no longer part of the scene and so we notify the backend of its removal * from its parent's list of children, and then send a QNodeDestroyedChange to the * aspects so that the corresponding backend node is destroyed. * * If \a parent is not null, then we must tell its new parent about this QNode now * being a child of it on the backend. If this QNode did not have a parent upon * entry to this function, then we must first send a QNodeCreatedChange to the backend * prior to sending the QPropertyNodeAddedChange to its parent. * * Note: This function should never be called from the ctor directly as the type may * not be fully created yet and creating creation changes involves calling a virtual * function on QNode. The function _q_notifyCreationAndChildChanges() is used * for sending initial notification when a parent is passed to the QNode ctor. * That function does a subset of this function with the assumption that the new object * had no parent before (must be true as it is newly constructed). */ void QNodePrivate::_q_setParentHelper(QNode *parent) { Q_Q(QNode); QNode *oldParentNode = q->parentNode(); // We may get the situation where the QML engine has set the QObject // parent but we have not yet set up the QNode parent requirements. // This check handles this and means we propagate the scene and arbiter // from the parent in the code below. const bool needsSceneInit = !oldParentNode || (oldParentNode && m_parentId != oldParentNode->id()); // If we had a parent, we let him know that we are about to change // parent if (oldParentNode && m_hasBackendNode) { QNodePrivate::get(oldParentNode)->_q_removeChild(q); // If we have an old parent but the new parent is null // the backend node needs to be destroyed if (!parent) notifyDestructionChangesAndRemoveFromScene(); } // Flag that we need to notify any new parent m_notifiedParent = false; // Basically QObject::setParent but for QObjectPrivate QObjectPrivate::setParent_helper(parent); QNode *newParentNode = q->parentNode(); if (newParentNode) { // If we had no parent but are about to set one, // we need to send a QNodeCreatedChange if (needsSceneInit) { QNodePrivate *newParentPrivate = QNodePrivate::get(newParentNode); // Set the scene helper / arbiter if (newParentPrivate->m_scene) { QNodeVisitor visitor; visitor.traverse(q, newParentNode->d_func(), &QNodePrivate::setSceneHelper); } // We want to make sure that subTreeRoot is always created before // child. // Given a case such as below // QEntity *subTreeRoot = new QEntity(someGlobalExisitingRoot) // QEntity *child = new QEntity(); // child->setParent(subTreeRoot) // We need to take into account that subTreeRoot needs to be // created in the backend before the child. // Therefore we only call notifyCreationChanges if the parent // hasn't been created yet as we know that when the parent will be // fully created, it will also send the changes for all of its // children if (QNodePrivate::get(newParentNode)->m_hasBackendNode) notifyCreationChange(); } // If we have a valid new parent, we let him know that we are its child QNodePrivate::get(newParentNode)->_q_addChild(q); } }
void QCollisionAspect::setRootEntity(QEntity *rootObject) { QNodeVisitor visitor; visitor.traverse(rootObject, this, &QCollisionAspect::visitNode); }