From 7938e301e732f09dadd9de3df99a6bc70a0e30be Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 1 Sep 2017 14:13:43 -0700 Subject: [PATCH] full scene traversal and json filters --- .../src/entities/EntityTreeSendThread.cpp | 53 ++++++++++++++----- .../src/entities/EntityTreeSendThread.h | 4 +- .../src/octree/OctreeSendThread.cpp | 4 +- .../src/octree/OctreeSendThread.h | 2 +- libraries/entities/src/DiffTraversal.cpp | 39 ++++++++++++-- libraries/entities/src/DiffTraversal.h | 5 +- 6 files changed, 82 insertions(+), 25 deletions(-) diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index e34dfd97e7..024855235a 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -98,7 +98,7 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O nodeData->copyCurrentViewFrustum(viewFrustum); EntityTreeElementPointer root = std::dynamic_pointer_cast(_myServer->getOctree()->getRoot()); int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - startNewTraversal(viewFrustum, root, lodLevelOffset); + startNewTraversal(viewFrustum, root, lodLevelOffset, true); // When the viewFrustum changed the sort order may be incorrect, so we re-sort // and also use the opportunity to cull anything no longer in view @@ -138,6 +138,11 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O } } } + } else if (_traversal.finished()) { + ViewFrustum viewFrustum; + EntityTreeElementPointer root = std::dynamic_pointer_cast(_myServer->getOctree()->getRoot()); + int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + NO_BOUNDARY_ADJUST; + startNewTraversal(viewFrustum, root, lodLevelOffset, false); } if (!_traversal.finished()) { @@ -165,7 +170,7 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O EntityItemPointer entity = entry.getEntity(); if (entity) { std::cout << "adebug send '" << entity->getName().toStdString() << "'" << " : " << entry.getPriority() << std::endl; // adebug - _knownState[entity] = sendTime; + _knownState[entity.get()] = sendTime; } _sendQueue.pop(); _entitiesInQueue.erase(entry.getRawEntityPointer()); @@ -225,13 +230,14 @@ bool EntityTreeSendThread::addDescendantsToExtraFlaggedEntities(const QUuid& fil return hasNewChild || hasNewDescendants; } -void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset) { - DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, lodLevelOffset); - // there are three types of traversal: +void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesFrustum) { + DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, lodLevelOffset, usesFrustum); + // there are four types of traversal: // // (1) FirstTime = at login --> find everything in view // (2) Repeat = view hasn't changed --> find what has changed since last complete traversal // (3) Differential = view has changed --> find what has changed or in new view but not old + // (4) FullScene = no view frustum -> send everything // // The "scanCallback" we provide to the traversal depends on the type: // @@ -371,10 +377,26 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree } }); break; + case DiffTraversal::FullScene: + _traversal.setScanCallback([&](DiffTraversal::VisibleElement& next) { + next.element->forEachEntity([&](EntityItemPointer entity) { + // Bail early if we've already checked this entity this frame + if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) { + return; + } + if (_knownState.find(entity.get()) == _knownState.end() || + (_knownState.find(entity.get()) != _knownState.end() && entity->getLastEdited() > _knownState[entity.get()])) { + // We don't have a view frustum from which to compute priority + _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); + _entitiesInQueue.insert(entity.get()); + } + }); + }); + break; } } -bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params) { +bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) { #ifdef SEND_SORTED_ENTITIES //auto entityTree = std::static_pointer_cast(_myServer->getOctree()); if (_sendQueue.empty()) { @@ -418,17 +440,20 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream PrioritizedEntity queuedItem = _sendQueue.top(); EntityItemPointer entity = queuedItem.getEntity(); if (entity) { - OctreeElement::AppendState appendEntityState = entity->appendEntityData(&_packetData, params, _extraEncodeData); - _knownState[entity.get()] = sendTime; + // Only send entities that match the jsonFilters, but keep track of everything we've tried to send so we don't try to send it again + if (entity->matchesJSONFilters(jsonFilters)) { + OctreeElement::AppendState appendEntityState = entity->appendEntityData(&_packetData, params, _extraEncodeData); - if (appendEntityState != OctreeElement::COMPLETED) { - if (appendEntityState == OctreeElement::PARTIAL) { - ++_numEntities; + if (appendEntityState != OctreeElement::COMPLETED) { + if (appendEntityState == OctreeElement::PARTIAL) { + ++_numEntities; + } + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + break; } - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - break; + ++_numEntities; } - ++_numEntities; + _knownState[entity.get()] = sendTime; } _sendQueue.pop(); _entitiesInQueue.erase(entity.get()); diff --git a/assignment-client/src/entities/EntityTreeSendThread.h b/assignment-client/src/entities/EntityTreeSendThread.h index 8b763a1c94..bdda159ed5 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.h +++ b/assignment-client/src/entities/EntityTreeSendThread.h @@ -39,8 +39,8 @@ private: bool addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData); bool addDescendantsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData); - void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset); - bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params) override; + void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesFrustum); + bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) override; DiffTraversal _traversal; EntityPriorityQueue _sendQueue; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index b6d9d323c1..5a563037bc 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -458,7 +458,7 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* return _truePacketsSent; } -bool OctreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params) { +bool OctreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) { bool somethingToSend = false; OctreeQueryNode* nodeData = static_cast(params.nodeData); if (!nodeData->elementBag.isEmpty()) { @@ -523,7 +523,7 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre bool lastNodeDidntFit = false; // assume each node fits params.stopReason = EncodeBitstreamParams::UNKNOWN; // reset params.stopReason before traversal - somethingToSend = traverseTreeAndBuildNextPacketPayload(params); + somethingToSend = traverseTreeAndBuildNextPacketPayload(params, nodeData->getJSONParameters()); if (params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { lastNodeDidntFit = true; diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index bcfede262c..a6ceba0e95 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -55,7 +55,7 @@ protected: virtual void preDistributionProcessing() {}; virtual void traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene); - virtual bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params); + virtual bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters); OctreePacketData _packetData; QWeakPointer _node; diff --git a/libraries/entities/src/DiffTraversal.cpp b/libraries/entities/src/DiffTraversal.cpp index e8e300081a..2cbe3f1064 100644 --- a/libraries/entities/src/DiffTraversal.cpp +++ b/libraries/entities/src/DiffTraversal.cpp @@ -142,19 +142,45 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V next.intersection = ViewFrustum::OUTSIDE; } +void DiffTraversal::Waypoint::getNextVisibleElementFullScene(DiffTraversal::VisibleElement& next, uint64_t lastTime) { + // NOTE: no need to set next.intersection or check LOD truncation in the "FullScene" context + if (_nextIndex == -1) { + ++_nextIndex; + EntityTreeElementPointer element = _weakElement.lock(); + if (element->getLastChangedContent() > lastTime) { + next.element = element; + return; + } + } + if (_nextIndex < NUMBER_OF_CHILDREN) { + EntityTreeElementPointer element = _weakElement.lock(); + if (element) { + while (_nextIndex < NUMBER_OF_CHILDREN) { + EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex); + ++_nextIndex; + if (nextElement && nextElement->getLastChanged() > lastTime) { + next.element = nextElement; + return; + } + } + } + } + next.element.reset(); +} + DiffTraversal::DiffTraversal() { const int32_t MIN_PATH_DEPTH = 16; _path.reserve(MIN_PATH_DEPTH); } -DiffTraversal::Type DiffTraversal::prepareNewTraversal( - const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset) { +DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesFrustum) { assert(root); - // there are three types of traversal: + // there are four types of traversal: // // (1) First = fresh view --> find all elements in view // (2) Repeat = view hasn't changed --> find elements changed since last complete traversal // (3) Differential = view has changed --> find elements changed or in new view but not old + // (4) FullScene = no view frustum -> send everything // // for each traversal type we assign the appropriate _getNextVisibleElementCallback // @@ -166,7 +192,12 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal( // Type type; - if (_completedView.startTime == 0) { + if (!usesFrustum) { + type = Type::FullScene; + _getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) { + _path.back().getNextVisibleElementFullScene(next, _completedView.startTime); + }; + } else if (_completedView.startTime == 0) { type = Type::First; _currentView.viewFrustum = viewFrustum; _currentView.lodLevelOffset = root->getLevel() + lodLevelOffset - 1; // -1 because true root has level=1 diff --git a/libraries/entities/src/DiffTraversal.h b/libraries/entities/src/DiffTraversal.h index e849b4fef3..83b2c99bb9 100644 --- a/libraries/entities/src/DiffTraversal.h +++ b/libraries/entities/src/DiffTraversal.h @@ -46,6 +46,7 @@ public: void getNextVisibleElementFirstTime(VisibleElement& next, const View& view); void getNextVisibleElementRepeat(VisibleElement& next, const View& view, uint64_t lastTime); void getNextVisibleElementDifferential(VisibleElement& next, const View& view, const View& lastView); + void getNextVisibleElementFullScene(VisibleElement& next, uint64_t lastTime); int8_t getNextIndex() const { return _nextIndex; } void initRootNextIndex() { _nextIndex = -1; } @@ -55,11 +56,11 @@ public: int8_t _nextIndex; }; - typedef enum { First, Repeat, Differential } Type; + typedef enum { First, Repeat, Differential, FullScene } Type; DiffTraversal(); - Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset); + Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool isFullScene); const ViewFrustum& getCurrentView() const { return _currentView.viewFrustum; } const ViewFrustum& getCompletedView() const { return _completedView.viewFrustum; }