DRY traversal scan callbacks

This commit is contained in:
Clement 2018-04-16 18:30:51 -07:00
parent 7f67547fae
commit 3862a02cee
3 changed files with 115 additions and 136 deletions

View file

@ -62,6 +62,10 @@ void ConicalView::set(const DiffTraversal::View& view) {
} }
float ConicalView::computePriority(const AACube& cube) const { float ConicalView::computePriority(const AACube& cube) const {
if (_conicalViewFrustums.empty()) {
return PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
}
float priority = PrioritizedEntity::DO_NOT_SEND; float priority = PrioritizedEntity::DO_NOT_SEND;
for (const auto& view : _conicalViewFrustums) { for (const auto& view : _conicalViewFrustums) {

View file

@ -135,25 +135,27 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
bool forceRemove = prevSendQueue.top().shouldForceRemove(); bool forceRemove = prevSendQueue.top().shouldForceRemove();
prevSendQueue.pop(); prevSendQueue.pop();
if (entity) { if (entity) {
if (!forceRemove) { float priority = PrioritizedEntity::DO_NOT_SEND;
if (forceRemove) {
priority = PrioritizedEntity::FORCE_REMOVE;
} else {
bool success = false; bool success = false;
AACube cube = entity->getQueryAACube(success); AACube cube = entity->getQueryAACube(success);
if (success) { if (success) {
if (_traversal.getCurrentView().intersects(cube)) { const auto& view = _traversal.getCurrentView();
float priority = _conicalView.computePriority(cube); if (view.intersects(cube) && view.isBigEnough(cube)) {
if (priority != PrioritizedEntity::DO_NOT_SEND) { priority = _conicalView.computePriority(cube);
if (_traversal.getCurrentView().isBigEnough(cube)) {
_sendQueue.push(PrioritizedEntity(entity, priority));
_entitiesInQueue.insert(entity.get());
}
}
} }
} else { } else {
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
_entitiesInQueue.insert(entity.get());
} }
} else { }
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::FORCE_REMOVE, true));
if (priority != PrioritizedEntity::DO_NOT_SEND) {
_sendQueue.emplace(entity, priority, forceRemove);
_entitiesInQueue.insert(entity.get()); _entitiesInQueue.insert(entity.get());
} }
} }
@ -245,104 +247,79 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En
case DiffTraversal::First: case DiffTraversal::First:
// When we get to a First traversal, clear the _knownState // When we get to a First traversal, clear the _knownState
_knownState.clear(); _knownState.clear();
if (view.usesViewFrustums()) { _traversal.setScanCallback([this](DiffTraversal::VisibleElement& next) {
_traversal.setScanCallback([this](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;
}
float priority = PrioritizedEntity::DO_NOT_SEND;
bool success = false;
AACube cube = entity->getQueryAACube(success);
if (success) {
const auto& view = _traversal.getCurrentView();
// Check the size of the entity, it's possible that a "too small to see" entity is included in a
// larger octree cell because of its position (for example if it crosses the boundary of a cell it
// pops to the next higher cell. So we want to check to see that the entity is large enough to be seen
// before we consider including it.
if ((next.intersection == ViewFrustum::INSIDE || view.intersects(cube)) &&
view.isBigEnough(cube)) {
priority = _conicalView.computePriority(cube);
}
} else {
priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
}
if (priority != PrioritizedEntity::DO_NOT_SEND) {
_sendQueue.emplace(entity, priority);
_entitiesInQueue.insert(entity.get());
}
});
});
break;
case DiffTraversal::Repeat:
_traversal.setScanCallback([this](DiffTraversal::VisibleElement& next) {
uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal();
if (next.element->getLastChangedContent() > startOfCompletedTraversal) {
next.element->forEachEntity([&](EntityItemPointer entity) { next.element->forEachEntity([&](EntityItemPointer entity) {
// Bail early if we've already checked this entity this frame // Bail early if we've already checked this entity this frame
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) { if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
return; return;
} }
bool success = false; float priority = PrioritizedEntity::DO_NOT_SEND;
AACube cube = entity->getQueryAACube(success);
if (success) {
if (_traversal.getCurrentView().intersects(cube)) { auto knownTimestamp = _knownState.find(entity.get());
// Check the size of the entity, it's possible that a "too small to see" entity is included in a if (knownTimestamp == _knownState.end()) {
// larger octree cell because of its position (for example if it crosses the boundary of a cell it bool success = false;
// pops to the next higher cell. So we want to check to see that the entity is large enough to be seen AACube cube = entity->getQueryAACube(success);
// before we consider including it. if (success) {
if (_traversal.getCurrentView().isBigEnough(cube)) { const auto& view = _traversal.getCurrentView();
float priority = _conicalView.computePriority(cube); // See the DiffTraversal::First case for an explanation of the "entity is too small" check
_sendQueue.push(PrioritizedEntity(entity, priority)); if ((next.intersection == ViewFrustum::INSIDE || view.intersects(cube)) &&
_entitiesInQueue.insert(entity.get()); view.isBigEnough(cube)) {
priority = _conicalView.computePriority(cube);
} }
} else {
priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
} }
} else { } else if (entity->getLastEdited() > knownTimestamp->second) {
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); // it is known and it changed --> put it on the queue with any priority
// TODO: sort these correctly
priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
}
if (priority != PrioritizedEntity::DO_NOT_SEND) {
_sendQueue.emplace(entity, priority);
_entitiesInQueue.insert(entity.get()); _entitiesInQueue.insert(entity.get());
} }
}); });
}); }
} else { });
_traversal.setScanCallback([this](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;
}
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
_entitiesInQueue.insert(entity.get());
});
});
}
break;
case DiffTraversal::Repeat:
if (view.usesViewFrustums()) {
_traversal.setScanCallback([this](DiffTraversal::VisibleElement& next) {
uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal();
if (next.element->getLastChangedContent() > startOfCompletedTraversal) {
next.element->forEachEntity([&](EntityItemPointer entity) {
// Bail early if we've already checked this entity this frame
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
return;
}
auto knownTimestamp = _knownState.find(entity.get());
if (knownTimestamp == _knownState.end()) {
bool success = false;
AACube cube = entity->getQueryAACube(success);
if (success) {
if (next.intersection == ViewFrustum::INSIDE ||
_traversal.getCurrentView().intersects(cube)) {
// See the DiffTraversal::First case for an explanation of the "entity is too small" check
if (_traversal.getCurrentView().isBigEnough(cube)) {
float priority = _conicalView.computePriority(cube);
_sendQueue.push(PrioritizedEntity(entity, priority));
_entitiesInQueue.insert(entity.get());
}
}
} else {
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
_entitiesInQueue.insert(entity.get());
}
} else if (entity->getLastEdited() > knownTimestamp->second
|| entity->getLastChangedOnServer() > knownTimestamp->second) {
// it is known and it changed --> put it on the queue with any priority
// TODO: sort these correctly
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
_entitiesInQueue.insert(entity.get());
}
});
}
});
} else {
_traversal.setScanCallback([this](DiffTraversal::VisibleElement& next) {
uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal();
if (next.element->getLastChangedContent() > startOfCompletedTraversal) {
next.element->forEachEntity([&](EntityItemPointer entity) {
// Bail early if we've already checked this entity this frame
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
return;
}
auto knownTimestamp = _knownState.find(entity.get());
if (knownTimestamp == _knownState.end()
|| entity->getLastEdited() > knownTimestamp->second
|| entity->getLastChangedOnServer() > knownTimestamp->second) {
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
_entitiesInQueue.insert(entity.get());
}
});
}
});
}
break; break;
case DiffTraversal::Differential: case DiffTraversal::Differential:
assert(view.usesViewFrustums()); assert(view.usesViewFrustums());
@ -352,36 +329,35 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) { if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
return; return;
} }
float priority = PrioritizedEntity::DO_NOT_SEND;
auto knownTimestamp = _knownState.find(entity.get()); auto knownTimestamp = _knownState.find(entity.get());
if (knownTimestamp == _knownState.end()) { if (knownTimestamp == _knownState.end()) {
bool success = false; bool success = false;
AACube cube = entity->getQueryAACube(success); AACube cube = entity->getQueryAACube(success);
if (success) { if (success) {
if (_traversal.getCurrentView().intersects(cube)) { const auto& view = _traversal.getCurrentView();
// See the DiffTraversal::First case for an explanation of the "entity is too small" check // See the DiffTraversal::First case for an explanation of the "entity is too small" check
if (_traversal.getCurrentView().isBigEnough(cube)) { if ((next.intersection == ViewFrustum::INSIDE || view.intersects(cube)) &&
if (!_traversal.getCompletedView().intersects(cube)) { view.isBigEnough(cube)) {
float priority = _conicalView.computePriority(cube); // If this entity wasn't in the last view or
_sendQueue.push(PrioritizedEntity(entity, priority)); // If this entity was skipped last time because it was too small, we still need to send it
_entitiesInQueue.insert(entity.get()); priority = _conicalView.computePriority(cube);
} else if (!_traversal.getCompletedView().isBigEnough(cube)) {
// If this entity was skipped last time because it was too small, we still need to send it
// this object was skipped in last completed traversal
float priority = _conicalView.computePriority(cube);
_sendQueue.push(PrioritizedEntity(entity, priority));
_entitiesInQueue.insert(entity.get());
}
}
} }
} else { } else {
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
_entitiesInQueue.insert(entity.get());
} }
} else if (entity->getLastEdited() > knownTimestamp->second } else if (entity->getLastEdited() > knownTimestamp->second
|| entity->getLastChangedOnServer() > knownTimestamp->second) { || entity->getLastChangedOnServer() > knownTimestamp->second) {
// it is known and it changed --> put it on the queue with any priority // it is known and it changed --> put it on the queue with any priority
// TODO: sort these correctly // TODO: sort these correctly
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
}
if (priority != PrioritizedEntity::DO_NOT_SEND) {
_sendQueue.emplace(entity, priority);
_entitiesInQueue.insert(entity.get()); _entitiesInQueue.insert(entity.get());
} }
}); });
@ -499,11 +475,11 @@ void EntityTreeSendThread::editingEntityPointer(const EntityItemPointer& entity)
if (success) { if (success) {
// We can force a removal from _knownState if the current view is used and entity is out of view // We can force a removal from _knownState if the current view is used and entity is out of view
if (_traversal.doesCurrentUseViewFrustum() && !_traversal.getCurrentView().intersects(cube)) { if (_traversal.doesCurrentUseViewFrustum() && !_traversal.getCurrentView().intersects(cube)) {
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::FORCE_REMOVE, true)); _sendQueue.emplace(entity, PrioritizedEntity::FORCE_REMOVE, true);
_entitiesInQueue.insert(entity.get()); _entitiesInQueue.insert(entity.get());
} }
} else { } else {
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY, true)); _sendQueue.emplace(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY, true);
_entitiesInQueue.insert(entity.get()); _entitiesInQueue.insert(entity.get());
} }
} }

View file

@ -13,7 +13,6 @@
#include <OctreeUtils.h> #include <OctreeUtils.h>
DiffTraversal::Waypoint::Waypoint(EntityTreeElementPointer& element) : _nextIndex(0) { DiffTraversal::Waypoint::Waypoint(EntityTreeElementPointer& element) : _nextIndex(0) {
assert(element); assert(element);
_weakElement = element; _weakElement = element;
@ -140,12 +139,12 @@ bool DiffTraversal::View::isBigEnough(const AACube& cube, float minDiameter) con
return true; return true;
} }
for (const auto& viewFrustum : viewFrustums) { bool isBigEnough = std::any_of(std::begin(viewFrustums), std::end(viewFrustums),
if (isAngularSizeBigEnough(viewFrustum.getPosition(), cube, lodScaleFactor, minDiameter)) { [&](const ViewFrustum& viewFrustum) {
return true; return isAngularSizeBigEnough(viewFrustum.getPosition(), cube, lodScaleFactor, minDiameter);
} });
}
return false; return isBigEnough;
} }
bool DiffTraversal::View::intersects(const AACube& cube) const { bool DiffTraversal::View::intersects(const AACube& cube) const {
@ -154,12 +153,12 @@ bool DiffTraversal::View::intersects(const AACube& cube) const {
return true; return true;
} }
for (const auto& viewFrustum : viewFrustums) { bool intersects = std::any_of(std::begin(viewFrustums), std::end(viewFrustums),
if (viewFrustum.cubeIntersectsKeyhole(cube)) { [&](const ViewFrustum& viewFrustum) {
return true; return viewFrustum.cubeIntersectsKeyhole(cube);
} });
}
return false; return intersects;
} }
ViewFrustum::intersection DiffTraversal::View::calculateIntersection(const AACube& cube) const { ViewFrustum::intersection DiffTraversal::View::calculateIntersection(const AACube& cube) const {
@ -231,7 +230,7 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal(const DiffTraversal::View
// If usesViewFrustum changes, treat it as a First traversal // If usesViewFrustum changes, treat it as a First traversal
if (_completedView.startTime == 0 || _currentView.usesViewFrustums() != _completedView.usesViewFrustums()) { if (_completedView.startTime == 0 || _currentView.usesViewFrustums() != _completedView.usesViewFrustums()) {
type = Type::First; type = Type::First;
_currentView.viewFrustums = std::move(view.viewFrustums); _currentView.viewFrustums = view.viewFrustums;
_currentView.lodScaleFactor = view.lodScaleFactor; _currentView.lodScaleFactor = view.lodScaleFactor;
_getNextVisibleElementCallback = [this](DiffTraversal::VisibleElement& next) { _getNextVisibleElementCallback = [this](DiffTraversal::VisibleElement& next) {
_path.back().getNextVisibleElementFirstTime(next, _currentView); _path.back().getNextVisibleElementFirstTime(next, _currentView);
@ -243,7 +242,7 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal(const DiffTraversal::View
}; };
} else { } else {
type = Type::Differential; type = Type::Differential;
_currentView.viewFrustums = std::move(view.viewFrustums); _currentView.viewFrustums = view.viewFrustums;
_currentView.lodScaleFactor = view.lodScaleFactor; _currentView.lodScaleFactor = view.lodScaleFactor;
_getNextVisibleElementCallback = [this](DiffTraversal::VisibleElement& next) { _getNextVisibleElementCallback = [this](DiffTraversal::VisibleElement& next) {
_path.back().getNextVisibleElementDifferential(next, _currentView, _completedView); _path.back().getNextVisibleElementDifferential(next, _currentView, _completedView);