summaryrefslogtreecommitdiffstats
path: root/tests/auto/render/entity/tst_entity.cpp
diff options
context:
space:
mode:
authorJim Albamont <jim.albamont@kdab.com>2019-03-13 13:23:21 -0500
committerJames Turner <james.turner@kdab.com>2019-04-04 09:15:50 +0000
commitbf2c2e9bb2dd0b13cb2cb6728de0c2421fbafbb7 (patch)
tree27ac13c4706c134ae476071a6b8b9646ac97ee35 /tests/auto/render/entity/tst_entity.cpp
parentf0f5a2de1da2e05e3587d2a6486687ebbe649339 (diff)
Fix Entity parenting hierarchy
When the initial Entity backend node hierarchy is created it skips over any non-entity nodes to ensure that Entities are only parented to other Entities. Calling QNode::setParent breaks this when reparenting Entities to non-entity nodes. Fix by sending a new "parentEntityUpdated" property update that backend Entity nodes listen for. They keep the id of their new parent and flag the need to rebuild the entity hierarchy. This triggers a new job to clear the children and parents of every backend Entity, then rebuilds the hierarchy using the stored parent ID in each Entity. This is much more forgiving of creation/parenting ordering issues and shouldn't be less performant because any Entity reparent was previously marking everything dirty anyway. Add a new test from QTBUG-73905 that creates 4 cylinders and manipulates the parents in different ways. Add a new test to tst_nodes to reparent a QEntity to a QNode and ensure the entity finds it's correct QEntity parent. Add a new test to tst_entity to ensure backend nodes correctly handle the new parenting events. Task-number: QTBUG-73905 Change-Id: Iab0203947d89bbed2868b3629fbde879675fe568 Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'tests/auto/render/entity/tst_entity.cpp')
-rw-r--r--tests/auto/render/entity/tst_entity.cpp119
1 files changed, 118 insertions, 1 deletions
diff --git a/tests/auto/render/entity/tst_entity.cpp b/tests/auto/render/entity/tst_entity.cpp
index 6ad958451..123a648d6 100644
--- a/tests/auto/render/entity/tst_entity.cpp
+++ b/tests/auto/render/entity/tst_entity.cpp
@@ -151,7 +151,7 @@ private slots:
QVERIFY(!entity.componentsUuid<EnvironmentLight>().isEmpty());
QVERIFY(!entity.componentUuid<Armature>().isNull());
QVERIFY(entity.isBoundingVolumeDirty());
- QVERIFY(!entity.childrenHandles().isEmpty());
+ QVERIFY(entity.childrenHandles().isEmpty());
QVERIFY(!entity.layerIds().isEmpty());
QVERIFY(renderer.dirtyBits() != 0);
bool containsAll = entity.containsComponentsOfType<Transform,
@@ -162,6 +162,7 @@ private slots:
entity.cleanup();
// THEN
+ QVERIFY(entity.parentEntityId().isNull());
QVERIFY(entity.componentUuid<Transform>().isNull());
QVERIFY(entity.componentUuid<CameraLens>().isNull());
QVERIFY(entity.componentUuid<Material>().isNull());
@@ -180,6 +181,122 @@ private slots:
QVERIFY(!containsAll);
}
+ void checkRebuildingEntityHierarchy()
+ {
+ // GIVEN
+ TestRenderer renderer;
+ NodeManagers nodeManagers;
+ Qt3DCore::QEntity frontendEntityA, frontendEntityB, frontendEntityC;
+
+ auto entityCreator = [&nodeManagers, &renderer](const Qt3DCore::QEntity &frontEndEntity) {
+ Entity *entity = nodeManagers.renderNodesManager()->getOrCreateResource(frontEndEntity.id());
+ entity->setNodeManagers(&nodeManagers);
+ entity->setRenderer(&renderer);
+ return entity;
+ };
+
+ auto backendA = entityCreator(frontendEntityA);
+ auto backendB = entityCreator(frontendEntityB);
+ auto backendC = entityCreator(frontendEntityC);
+
+ // THEN
+ QVERIFY(backendA->parentEntityId().isNull());
+ QVERIFY(backendB->parentEntityId().isNull());
+ QVERIFY(backendC->parentEntityId().isNull());
+
+ QVERIFY(backendA->parent() == nullptr);
+ QVERIFY(backendB->parent() == nullptr);
+ QVERIFY(backendC->parent() == nullptr);
+
+ QVERIFY(backendA->childrenHandles().isEmpty());
+ QVERIFY(backendB->childrenHandles().isEmpty());
+ QVERIFY(backendC->childrenHandles().isEmpty());
+
+ // WHEN
+ renderer.clearDirtyBits(0);
+ QVERIFY(renderer.dirtyBits() == 0);
+
+ auto sendParentChange = [&nodeManagers](const Qt3DCore::QEntity &entity) {
+ const auto parentChange = QPropertyUpdatedChangePtr::create(entity.id());
+ parentChange->setPropertyName("parentEntityUpdated");
+ auto parent = entity.parentEntity();
+ parentChange->setValue(QVariant::fromValue(parent ? parent->id() : Qt3DCore::QNodeId()));
+
+ Entity *backendEntity = nodeManagers.renderNodesManager()->getOrCreateResource(entity.id());
+ backendEntity->sceneChangeEvent(parentChange);
+ };
+
+ // reparent B to A and C to B.
+ frontendEntityB.setParent(&frontendEntityA);
+ sendParentChange(frontendEntityB);
+ frontendEntityC.setParent(&frontendEntityB);
+ sendParentChange(frontendEntityC);
+
+ // THEN
+ QVERIFY(renderer.dirtyBits() & AbstractRenderer::EntityHierarchyDirty);
+
+ QVERIFY(backendA->parentEntityId().isNull());
+ QVERIFY(backendB->parentEntityId() == frontendEntityA.id());
+ QVERIFY(backendC->parentEntityId() == frontendEntityB.id());
+
+ QVERIFY(backendA->parent() == nullptr);
+ QVERIFY(backendB->parent() == nullptr);
+ QVERIFY(backendC->parent() == nullptr);
+
+ QVERIFY(backendA->childrenHandles().isEmpty());
+ QVERIFY(backendB->childrenHandles().isEmpty());
+ QVERIFY(backendC->childrenHandles().isEmpty());
+
+ // WHEN
+ auto rebuildHierarchy = [](Entity *backend) {
+ backend->clearEntityHierarchy();
+ backend->rebuildEntityHierarchy();
+ };
+ rebuildHierarchy(backendA);
+ rebuildHierarchy(backendB);
+ rebuildHierarchy(backendC);
+
+ // THEN
+ QVERIFY(backendA->parent() == nullptr);
+ QVERIFY(backendB->parent() == backendA);
+ QVERIFY(backendC->parent() == backendB);
+
+ QVERIFY(!backendA->childrenHandles().isEmpty());
+ QVERIFY(!backendB->childrenHandles().isEmpty());
+ QVERIFY(backendC->childrenHandles().isEmpty());
+
+ // WHEN - reparent B to null.
+ frontendEntityB.setParent(static_cast<Qt3DCore::QNode *>(nullptr));
+ sendParentChange(frontendEntityB);
+ rebuildHierarchy(backendA);
+ rebuildHierarchy(backendB);
+ rebuildHierarchy(backendC);
+
+ QVERIFY(backendA->parentEntityId().isNull());
+ QVERIFY(backendB->parentEntityId().isNull());
+ QVERIFY(backendC->parentEntityId() == frontendEntityB.id());
+
+ QVERIFY(backendA->parent() == nullptr);
+ QVERIFY(backendB->parent() == nullptr);
+ QVERIFY(backendC->parent() == backendB);
+
+ QVERIFY(backendA->childrenHandles().isEmpty());
+ QVERIFY(!backendB->childrenHandles().isEmpty());
+ QVERIFY(backendC->childrenHandles().isEmpty());
+
+ // WHEN - cleanup
+ backendA->cleanup();
+ backendB->cleanup();
+ backendC->cleanup();
+
+ // THEN
+ QVERIFY(backendA->parentEntityId().isNull());
+ QVERIFY(backendB->parentEntityId().isNull());
+ QVERIFY(backendC->parentEntityId().isNull());
+
+ QVERIFY(renderer.dirtyBits() != 0);
+ }
+
void shouldHandleSingleComponentEvents_data()
{
QTest::addColumn<QComponent*>("component");