Showing the changes to assignment-client/src/entities/EntityTreeSendThread.cpp (1 of 3 files). Show all
Unified · Split
| @@ -10,12 +10,214 @@ · 9 unmodified lines | ||
| 10 | 10 | // |
| 11 | 11 | |
| 12 | 12 | #include "EntityTreeSendThread.h" |
| 13 | +#include <iostream> // adebug | |
| 13 | 14 | |
| 14 | 15 | #include <EntityNodeData.h> |
| 15 | 16 | #include <EntityTypes.h> |
| 16 | 17 | |
| 17 | 18 | #include "EntityServer.h" |
| 18 | 19 | |
| 20 | +const float INVALID_ENTITY_SEND_PRIORITY = -1.0e-6f; | |
| 21 | + | |
| 22 | +void PrioritizedEntity::updatePriority(const ViewFrustum& view) { | |
| 23 | + EntityItemPointer entity = _weakEntity.lock(); | |
| 24 | + if (entity) { | |
| 25 | + bool success; | |
| 26 | + AACube cube = entity->getQueryAACube(success); | |
| 27 | + if (success) { | |
| 28 | + glm::vec3 center = cube.calcCenter() - view.getPosition(); | |
| 29 | + const float MIN_DISTANCE = 0.001f; | |
| 30 | + float distanceToCenter = glm::length(center) + MIN_DISTANCE; | |
| 31 | + float distance = distanceToCenter; //- 0.5f * cube.getScale(); | |
| 32 | + if (distance < MIN_DISTANCE) { | |
| 33 | + // this object's bounding box overlaps the camera --> give it a big priority | |
| 34 | + _priority = cube.getScale(); | |
| 35 | + } else { | |
| 36 | + // NOTE: we assume view.aspectRatio < 1.0 (view width greater than height) | |
| 37 | + // so we only check against the larger (horizontal) view angle | |
| 38 | + float front = glm::dot(center, view.getDirection()) / distanceToCenter; | |
| 39 | + if (front > cosf(view.getFieldOfView()) || distance < view.getCenterRadius()) { | |
| 40 | + _priority = cube.getScale() / distance; // + front; | |
| 41 | + } else { | |
| 42 | + _priority = INVALID_ENTITY_SEND_PRIORITY; | |
| 43 | + } | |
| 44 | + } | |
| 45 | + } else { | |
| 46 | + // when in doubt just it something positive | |
| 47 | + _priority = 1.0f; | |
| 48 | + } | |
| 49 | + } else { | |
| 50 | + _priority = INVALID_ENTITY_SEND_PRIORITY; | |
| 51 | + } | |
| 52 | +} | |
| 53 | + | |
| 54 | +TreeTraversalPath::Fork::Fork(EntityTreeElementPointer& element) : _nextIndex(0) { | |
| 55 | + assert(element); | |
| 56 | + _weakElement = element; | |
| 57 | +} | |
| 58 | + | |
| 59 | +EntityTreeElementPointer TreeTraversalPath::Fork::getNextElement(const ViewFrustum& view) { | |
| 60 | + if (_nextIndex == -1) { | |
| 61 | + // only get here for the TreeTraversalPath's root Fork at the very beginning of traversal | |
| 62 | + // safe to assume this element is in view | |
| 63 | + ++_nextIndex; | |
| 64 | + return _weakElement.lock(); | |
| 65 | + } else if (_nextIndex < NUMBER_OF_CHILDREN) { | |
| 66 | + EntityTreeElementPointer element = _weakElement.lock(); | |
| 67 | + if (element) { | |
| 68 | + while (_nextIndex < NUMBER_OF_CHILDREN) { | |
| 69 | + EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex); | |
| 70 | + ++_nextIndex; | |
| 71 | + if (nextElement && ViewFrustum::OUTSIDE != nextElement->computeViewIntersection(view)) { | |
| 72 | + return nextElement; | |
| 73 | + } | |
| 74 | + } | |
| 75 | + } | |
| 76 | + } | |
| 77 | + return EntityTreeElementPointer(); | |
| 78 | +} | |
| 79 | + | |
| 80 | +EntityTreeElementPointer TreeTraversalPath::Fork::getNextElementAgain(const ViewFrustum& view, uint64_t oldTime) { | |
| 81 | + if (_nextIndex == -1) { | |
| 82 | + // only get here for the TreeTraversalPath's root Fork at the very beginning of traversal | |
| 83 | + // safe to assume this element is in view | |
| 84 | + ++_nextIndex; | |
| 85 | + EntityTreeElementPointer element = _weakElement.lock(); | |
| 86 | + assert(element); // should never lose root element | |
| 87 | + if (element->getLastChanged() < oldTime) { | |
| 88 | + _nextIndex = NUMBER_OF_CHILDREN; | |
| 89 | + return EntityTreeElementPointer(); | |
| 90 | + } | |
| 91 | + if (element->getLastChanged() > oldTime) { | |
| 92 | + return element; | |
| 93 | + } | |
| 94 | + } | |
| 95 | + if (_nextIndex < NUMBER_OF_CHILDREN) { | |
| 96 | + EntityTreeElementPointer element = _weakElement.lock(); | |
| 97 | + if (element) { | |
| 98 | + while (_nextIndex < NUMBER_OF_CHILDREN) { | |
| 99 | + EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex); | |
| 100 | + ++_nextIndex; | |
| 101 | + if (nextElement && nextElement->getLastChanged() > oldTime && | |
| 102 | + ViewFrustum::OUTSIDE != nextElement->computeViewIntersection(view)) { | |
| 103 | + return nextElement; | |
| 104 | + } | |
| 105 | + } | |
| 106 | + } | |
| 107 | + } | |
| 108 | + return EntityTreeElementPointer(); | |
| 109 | +} | |
| 110 | + | |
| 111 | +EntityTreeElementPointer TreeTraversalPath::Fork::getNextElementDelta(const ViewFrustum& newView, const ViewFrustum& oldView, uint64_t oldTime) { | |
| 112 | + if (_nextIndex == -1) { | |
| 113 | + // only get here for the TreeTraversalPath's root Fork at the very beginning of traversal | |
| 114 | + // safe to assume this element is in newView | |
| 115 | + ++_nextIndex; | |
| 116 | + EntityTreeElementPointer element = _weakElement.lock(); | |
| 117 | + assert(element); // should never lose root element | |
| 118 | + if (element->getLastChanged() < oldTime) { | |
| 119 | + _nextIndex = NUMBER_OF_CHILDREN; | |
| 120 | + return EntityTreeElementPointer(); | |
| 121 | + } | |
| 122 | + return element; | |
| 123 | + } else if (_nextIndex < NUMBER_OF_CHILDREN) { | |
| 124 | + EntityTreeElementPointer element = _weakElement.lock(); | |
| 125 | + if (element) { | |
| 126 | + while (_nextIndex < NUMBER_OF_CHILDREN) { | |
| 127 | + EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex); | |
| 128 | + ++_nextIndex; | |
| 129 | + if (nextElement && | |
| 130 | + !(nextElement->getLastChanged() < oldTime && | |
| 131 | + ViewFrustum::INSIDE == nextElement->computeViewIntersection(oldView)) && | |
| 132 | + ViewFrustum::OUTSIDE != nextElement->computeViewIntersection(newView)) { | |
| 133 | + return nextElement; | |
| 134 | + } | |
| 135 | + } | |
| 136 | + } | |
| 137 | + } | |
| 138 | + return EntityTreeElementPointer(); | |
| 139 | +} | |
| 140 | + | |
| 141 | +TreeTraversalPath::TreeTraversalPath() { | |
| 142 | + const int32_t MIN_PATH_DEPTH = 16; | |
| 143 | + _forks.reserve(MIN_PATH_DEPTH); | |
| 144 | + _traversalCallback = std::bind(&TreeTraversalPath::traverseFirstTime, this); | |
| 145 | +} | |
| 146 | + | |
| 147 | +void TreeTraversalPath::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root) { | |
| 148 | + if (_startOfLastCompletedTraversal == 0) { | |
| 149 | + _traversalCallback = std::bind(&TreeTraversalPath::traverseFirstTime, this); | |
| 150 | + _currentView = view; | |
| 151 | + } else if (_currentView.isVerySimilar(view)) { | |
| 152 | + _traversalCallback = std::bind(&TreeTraversalPath::traverseAgain, this); | |
| 153 | + } else { | |
| 154 | + _currentView = view; | |
| 155 | + _traversalCallback = std::bind(&TreeTraversalPath::traverseDelta, this); | |
| 156 | + } | |
| 157 | + _forks.clear(); | |
| 158 | + if (root) { | |
| 159 | + _forks.push_back(Fork(root)); | |
| 160 | + // set root fork's index such that root element returned at getNextElement() | |
| 161 | + _forks.back().initRootNextIndex(); | |
| 162 | + } | |
| 163 | + _startOfCurrentTraversal = usecTimestampNow(); | |
| 164 | +} | |
| 165 | + | |
| 166 | +EntityTreeElementPointer TreeTraversalPath::traverseFirstTime() { | |
| 167 | + return _forks.back().getNextElement(_currentView); | |
| 168 | +} | |
| 169 | + | |
| 170 | +EntityTreeElementPointer TreeTraversalPath::traverseAgain() { | |
| 171 | + return _forks.back().getNextElementAgain(_currentView, _startOfLastCompletedTraversal); | |
| 172 | +} | |
| 173 | + | |
| 174 | +EntityTreeElementPointer TreeTraversalPath::traverseDelta() { | |
| 175 | + return _forks.back().getNextElementDelta(_currentView, _lastCompletedView, _startOfLastCompletedTraversal); | |
| 176 | +} | |
| 177 | + | |
| 178 | +EntityTreeElementPointer TreeTraversalPath::getNextElement() { | |
| 179 | + if (_forks.empty() || !_traversalCallback) { | |
| 180 | + return EntityTreeElementPointer(); | |
| 181 | + } | |
| 182 | + EntityTreeElementPointer nextElement = _traversalCallback(); | |
| 183 | + if (nextElement) { | |
| 184 | + int8_t nextIndex = _forks.back().getNextIndex(); | |
| 185 | + if (nextIndex > 0) { | |
| 186 | + // nextElement needs to be added to the path | |
| 187 | + _forks.push_back(Fork(nextElement)); | |
| 188 | + } | |
| 189 | + } else { | |
| 190 | + // we're done at this level | |
| 191 | + while (!nextElement) { | |
| 192 | + // pop one level | |
| 193 | + _forks.pop_back(); | |
| 194 | + if (_forks.empty()) { | |
| 195 | + // we've traversed the entire tree | |
| 196 | + onCompleteTraversal(); | |
| 197 | + return nextElement; | |
| 198 | + } | |
| 199 | + // keep looking for nextElement | |
| 200 | + nextElement = _traversalCallback(); | |
| 201 | + if (nextElement) { | |
| 202 | + // we've descended one level so add it to the path | |
| 203 | + _forks.push_back(Fork(nextElement)); | |
| 204 | + } | |
| 205 | + } | |
| 206 | + } | |
| 207 | + return nextElement; | |
| 208 | +} | |
| 209 | + | |
| 210 | +void TreeTraversalPath::dump() const { | |
| 211 | + for (size_t i = 0; i < _forks.size(); ++i) { | |
| 212 | + std::cout << (int)(_forks[i].getNextIndex()) << "-->"; | |
| 213 | + } | |
| 214 | +} | |
| 215 | + | |
| 216 | +void TreeTraversalPath::onCompleteTraversal() { | |
| 217 | + _lastCompletedView = _currentView; | |
| 218 | + _startOfLastCompletedTraversal = _startOfCurrentTraversal; | |
| 219 | +} | |
| 220 | + | |
| 19 | 221 | void EntityTreeSendThread::preDistributionProcessing() { |
| 20 | 222 | auto node = _node.toStrongRef(); |
| 21 | 223 | auto nodeData = static_cast<EntityNodeData*>(node->getLinkedData()); |
| @@ -80,8 +282,67 @@ void EntityTreeSendThread::preDistributionProcessing() { · 58 unmodified lines | ||
| 80 | 282 | } |
| 81 | 283 | } |
| 82 | 284 | |
| 285 | +static size_t adebug = 0; | |
| 286 | + | |
| 83 | 287 | void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, |
| 84 | 288 | bool viewFrustumChanged, bool isFullScene) { |
| 289 | + if (viewFrustumChanged) { | |
| 290 | + ViewFrustum view; | |
| 291 | + nodeData->copyCurrentViewFrustum(view); | |
| 292 | + EntityTreeElementPointer root = std::dynamic_pointer_cast<EntityTreeElement>(_myServer->getOctree()->getRoot()); | |
| 293 | + _path.startNewTraversal(view, root); | |
| 294 | + | |
| 295 | + std::cout << "adebug reset view" << std::endl; // adebug | |
| 296 | + adebug = 0; | |
| 297 | + } | |
| 298 | + if (!_path.empty()) { | |
| 299 | + int32_t numElements = 0; | |
| 300 | + uint64_t t0 = usecTimestampNow(); | |
| 301 | + uint64_t now = t0; | |
| 302 | + | |
| 303 | + QVector<EntityItemPointer> entities; | |
| 304 | + EntityTreeElementPointer nextElement = _path.getNextElement(); | |
| 305 | + while (nextElement) { | |
| 306 | + nextElement->getEntities(_path.getView(), entities); | |
| 307 | + ++numElements; | |
| 308 | + | |
| 309 | + now = usecTimestampNow(); | |
| 310 | + const uint64_t PARTIAL_TRAVERSAL_TIME_BUDGET = 80; | |
| 311 | + if (now - t0 > PARTIAL_TRAVERSAL_TIME_BUDGET) { | |
| 312 | + break; | |
| 313 | + } | |
| 314 | + nextElement = _path.getNextElement(); | |
| 315 | + } | |
| 316 | + uint64_t dt1 = now - t0; | |
| 317 | + for (EntityItemPointer& entity : entities) { | |
| 318 | + PrioritizedEntity entry(entity); | |
| 319 | + entry.updatePriority(_path.getView()); | |
| 320 | + if (entry.getPriority() > INVALID_ENTITY_SEND_PRIORITY) { | |
| 321 | + _sendQueue.push(entry); | |
| 322 | + } | |
| 323 | + } | |
| 324 | + adebug += entities.size(); | |
| 325 | + std::cout << "adebug traverseTreeAndSendContents totalEntities = " << adebug | |
| 326 | + << " numElements = " << numElements | |
| 327 | + << " numEntities = " << entities.size() | |
| 328 | + << " dt = " << dt1 << std::endl; // adebug | |
| 329 | + } else if (!_sendQueue.empty()) { | |
| 330 | + | |
| 331 | + while (!_sendQueue.empty()) { | |
| 332 | + PrioritizedEntity entry = _sendQueue.top(); | |
| 333 | + EntityItemPointer entity = entry.getEntity(); | |
| 334 | + if (entity) { | |
| 335 | + std::cout << "adebug traverseTreeAndSendContents() " << entry.getPriority() | |
| 336 | + << " '" << entity->getName().toStdString() << "'" | |
| 337 | + << std::endl; // adebug | |
| 338 | + } | |
| 339 | + _sendQueue.pop(); | |
| 340 | + } | |
| 341 | + // std::priority_queue doesn't have a clear method, | |
| 342 | + // so we "clear" _sendQueue by setting it equal to an empty queue | |
| 343 | + _sendQueue = EntityPriorityQueue(); | |
| 344 | + } | |
| 345 | + | |
| 85 | 346 | OctreeSendThread::traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene); |
| 86 | 347 | } |
| 87 | 348 | |