From 27350bd7deb3334420aa8ff17ce87544c18aeeef Mon Sep 17 00:00:00 2001 From: Brad Davis <bdavis@saintandreas.org> Date: Wed, 20 Sep 2017 15:39:42 -0700 Subject: [PATCH] Don't add items to the scene graph until they have a valid parent chain --- .../src/EntityTreeRenderer.cpp | 118 ++++++++++++------ .../src/EntityTreeRenderer.h | 5 +- .../src/RenderableEntityItem.cpp | 4 +- .../src/RenderableEntityItem.h | 2 +- libraries/render/src/render/Forward.h | 1 + libraries/shared/src/SpatiallyNestable.cpp | 16 +++ libraries/shared/src/SpatiallyNestable.h | 4 + 7 files changed, 107 insertions(+), 43 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index e8ad163964..a79e29f003 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -159,6 +159,78 @@ void EntityTreeRenderer::shutdown() { clear(); // always clear() on shutdown } +void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction) { + // Clear any expired entities + // FIXME should be able to use std::remove_if, but it fails due to some + // weird compilation error related to EntityItemID assignment operators + for (auto itr = _entitiesToAdd.begin(); _entitiesToAdd.end() != itr; ) { + if (itr->second.expired()) { + _entitiesToAdd.erase(itr++); + } else { + ++itr; + } + } + + if (!_entitiesToAdd.empty()) { + std::unordered_set<EntityItemID> processedIds; + for (const auto& entry : _entitiesToAdd) { + auto entity = entry.second.lock(); + if (!entity) { + continue; + } + + // Path to the parent transforms is not valid, + // don't add to the scene graph yet + if (!entity->isParentPathComplete()) { + continue; + } + + auto entityID = entity->getEntityItemID(); + processedIds.insert(entityID); + auto renderable = EntityRenderer::addToScene(*this, entity, scene, transaction); + if (renderable) { + _entitiesInScene.insert({ entityID, renderable }); + } + } + + + if (!processedIds.empty()) { + for (const auto& processedId : processedIds) { + _entitiesToAdd.erase(processedId); + } + } + } +} + +void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene, render::Transaction& transaction) { + std::unordered_set<EntityItemID> changedEntities; + _changedEntitiesGuard.withWriteLock([&] { +#if 0 + // FIXME Weird build failure in latest VC update that fails to compile when using std::swap + changedEntities.swap(_changedEntities); +#else + changedEntities.insert(_changedEntities.begin(), _changedEntities.end()); + _changedEntities.clear(); +#endif + }); + + for (const auto& entityId : changedEntities) { + auto renderable = renderableForEntityId(entityId); + if (!renderable) { + continue; + } + _renderablesToUpdate.insert({ entityId, renderable }); + } + + if (!_renderablesToUpdate.empty()) { + for (const auto& entry : _renderablesToUpdate) { + const auto& renderable = entry.second; + renderable->updateInScene(scene, transaction); + } + _renderablesToUpdate.clear(); + } +} + void EntityTreeRenderer::update(bool simulate) { PerformanceTimer perfTimer("ETRupdate"); if (_tree && !_shuttingDown) { @@ -178,30 +250,11 @@ void EntityTreeRenderer::update(bool simulate) { } } - std::unordered_set<EntityItemID> changedEntities; - // FIXME Weird build failure in latest VC update that fails to compile when using std::swap - _changedEntitiesGuard.withWriteLock([&] { - changedEntities.insert(_changedEntities.begin(), _changedEntities.end()); - _changedEntities.clear(); - }); - - for (const auto& entityId : changedEntities) { - auto renderable = renderableForEntityId(entityId); - if (!renderable) { - continue; - } - - _renderablesToUpdate.insert({ entityId, renderable }); - } - auto scene = _viewState->getMain3DScene(); - if (scene && !_renderablesToUpdate.empty()) { + if (scene) { render::Transaction transaction; - for (const auto& entry : _renderablesToUpdate) { - const auto& renderable = entry.second; - renderable->updateInScene(scene, transaction); - } - _renderablesToUpdate.clear(); + addPendingEntities(scene, transaction); + updateChangedEntities(scene, transaction); scene->enqueueTransaction(transaction); } } @@ -689,8 +742,12 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) { } void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { + // If it's in the pending queue, remove it + _entitiesToAdd.erase(entityID); + auto itr = _entitiesInScene.find(entityID); if (_entitiesInScene.end() == itr) { + // Not in the scene, and no longer potentially in the pending queue, we're done return; } @@ -725,25 +782,10 @@ void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) { checkAndCallPreload(entityID); auto entity = std::static_pointer_cast<EntityTree>(_tree)->findEntityByID(entityID); if (entity) { - addEntityToScene(entity); + _entitiesToAdd.insert({ entity->getEntityItemID(), entity }); } } -void EntityTreeRenderer::addEntityToScene(const EntityItemPointer& entity) { - // here's where we add the entity payload to the scene - auto scene = _viewState->getMain3DScene(); - if (!scene) { - qCWarning(entitiesrenderer) << "EntityTreeRenderer::addEntityToScene(), Unexpected null scene, possibly during application shutdown"; - return; - } - - auto renderable = EntityRenderer::addToScene(*this, entity, scene); - if (renderable) { - _entitiesInScene[entity->getEntityItemID()] = renderable; - } -} - - void EntityTreeRenderer::entityScriptChanging(const EntityItemID& entityID, bool reload) { checkAndCallPreload(entityID, reload, true); } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 05ddaa6b0a..1b1d46d50c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -36,6 +36,7 @@ namespace render { namespace entities { class EntityRenderer; using EntityRendererPointer = std::shared_ptr<EntityRenderer>; using EntityRendererWeakPointer = std::weak_ptr<EntityRenderer>; + } } // Allow the use of std::unordered_map with QUuid keys @@ -157,12 +158,13 @@ protected: } private: + void addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction); + void updateChangedEntities(const render::ScenePointer& scene, render::Transaction& transaction); EntityRendererPointer renderableForEntity(const EntityItemPointer& entity) const { return renderableForEntityId(entity->getID()); } render::ItemID renderableIdForEntity(const EntityItemPointer& entity) const { return renderableIdForEntityId(entity->getID()); } void resetEntitiesScriptEngine(); - void addEntityToScene(const EntityItemPointer& entity); bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr); bool applyLayeredZones(); @@ -260,6 +262,7 @@ private: std::unordered_map<EntityItemID, EntityRendererPointer> _renderablesToUpdate; std::unordered_map<EntityItemID, EntityRendererPointer> _entitiesInScene; + std::unordered_map<EntityItemID, EntityItemWeakPointer> _entitiesToAdd; // For Scene.shouldRenderEntities QList<EntityItemID> _entityIDsLastInScene; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index ceaf073e08..3f1e89b86c 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -187,7 +187,7 @@ void EntityRenderer::render(RenderArgs* args) { // Methods called by the EntityTreeRenderer // -EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, const EntityItemPointer& entity, const ScenePointer& scene) { +EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, const EntityItemPointer& entity, const ScenePointer& scene, Transaction& transaction) { EntityRenderer::Pointer result; if (!entity) { return result; @@ -245,9 +245,7 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, } if (result) { - Transaction transaction; result->addToScene(scene, transaction); - scene->enqueueTransaction(transaction); } return result; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 629841d76e..6b47ff8b1d 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -30,7 +30,7 @@ class EntityRenderer : public QObject, public std::enable_shared_from_this<Entit public: static void initEntityRenderers(); - static Pointer addToScene(EntityTreeRenderer& renderer, const EntityItemPointer& entity, const ScenePointer& scene); + static Pointer addToScene(EntityTreeRenderer& renderer, const EntityItemPointer& entity, const ScenePointer& scene, Transaction& transaction); // Allow classes to override this to interact with the user virtual bool wantsHandControllerPointerEvents() const { return false; } diff --git a/libraries/render/src/render/Forward.h b/libraries/render/src/render/Forward.h index 1f297d39e1..4fb9251247 100644 --- a/libraries/render/src/render/Forward.h +++ b/libraries/render/src/render/Forward.h @@ -28,6 +28,7 @@ namespace render { class Scene; using ScenePointer = std::shared_ptr<Scene>; class ShapePipeline; + class Transaction; } using RenderArgs = render::Args; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index db78144100..8ea38f5f13 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -1182,3 +1182,19 @@ void SpatiallyNestable::dump(const QString& prefix) const { parent->dump(prefix + " "); } } + +bool SpatiallyNestable::isParentPathComplete() const { + static const QUuid IDENTITY; + QUuid parentID = getParentID(); + if (parentID.isNull() || parentID == IDENTITY) { + return true; + } + + bool success = false; + SpatiallyNestablePointer parent = getParentPointer(success); + if (!success || !parent) { + return false; + } + + return parent->isParentPathComplete(); +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 90d2e33016..b6be4dc056 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -66,6 +66,10 @@ public: static QString nestableTypeToString(NestableType nestableType); + + virtual bool isParentPathComplete() const; + + // world frame virtual const Transform getTransform(bool& success, int depth = 0) const; virtual const Transform getTransform() const;