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 | #include "EntityTreeSendThread.h" | 12 | #include "EntityTreeSendThread.h" |
| 13 | #include <iostream> // adebug | ||
| 13 | 14 | ||
| 14 | #include <EntityNodeData.h> | 15 | #include <EntityNodeData.h> |
| 15 | #include <EntityTypes.h> | 16 | #include <EntityTypes.h> |
| 16 | 17 | ||
| 17 | #include "EntityServer.h" | 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 | void EntityTreeSendThread::preDistributionProcessing() { | 221 | void EntityTreeSendThread::preDistributionProcessing() { |
| 20 | auto node = _node.toStrongRef(); | 222 | auto node = _node.toStrongRef(); |
| 21 | auto nodeData = static_cast<EntityNodeData*>(node->getLinkedData()); | 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 | void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, | 287 | void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, |
| 84 | bool viewFrustumChanged, bool isFullScene) { | 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 | OctreeSendThread::traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene); | 346 | OctreeSendThread::traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene); |
| 86 | } | 347 | } |
| 87 | 348 | ||