diff --git a/assignment-client/src/entities/EntityTreeSendThread.h b/assignment-client/src/entities/EntityTreeSendThread.h index 594f423838..1e2bd15429 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.h +++ b/assignment-client/src/entities/EntityTreeSendThread.h @@ -48,8 +48,6 @@ private: void preDistributionProcessing() override; bool hasSomethingToSend(OctreeQueryNode* nodeData) override { return !_sendQueue.empty(); } bool shouldStartNewTraversal(OctreeQueryNode* nodeData, bool viewFrustumChanged) override { return viewFrustumChanged || _traversal.finished(); } - void preStartNewScene(OctreeQueryNode* nodeData, bool isFullScene) override {}; - bool shouldTraverseAndSend(OctreeQueryNode* nodeData) override { return true; } DiffTraversal _traversal; EntityPriorityQueue _sendQueue; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 715e83f403..f8d566862e 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -304,23 +304,6 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* return numPackets; } -void OctreeSendThread::preStartNewScene(OctreeQueryNode* nodeData, bool isFullScene) { - // If we're starting a full scene, then definitely we want to empty the elementBag - if (isFullScene) { - nodeData->elementBag.deleteAll(); - } - - // This is the start of "resending" the scene. - bool dontRestartSceneOnMove = false; // this is experimental - if (dontRestartSceneOnMove) { - if (nodeData->elementBag.isEmpty()) { - nodeData->elementBag.insert(_myServer->getOctree()->getRoot()); - } - } else { - nodeData->elementBag.insert(_myServer->getOctree()->getRoot()); - } -} - /// Version of octree element distributor that sends the deepest LOD level at once int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged) { OctreeServer::didPacketDistributor(this); @@ -366,16 +349,8 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* // the current view frustum for things to send. if (shouldStartNewTraversal(nodeData, viewFrustumChanged)) { - // if our view has changed, we need to reset these things... - if (viewFrustumChanged) { - if (nodeData->moveShouldDump() || nodeData->hasLodChanged()) { - nodeData->dumpOutOfView(); - } - } - // track completed scenes and send out the stats packet accordingly nodeData->stats.sceneCompleted(); - nodeData->setLastRootTimestamp(_myServer->getOctree()->getRoot()->getLastChanged()); _myServer->getOctree()->releaseSceneEncodeData(&nodeData->extraEncodeData); // TODO: add these to stats page @@ -389,111 +364,74 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* // TODO: add these to stats page //::startSceneSleepTime = _usleepTime; - nodeData->sceneStart(usecTimestampNow() - CHANGE_FUDGE); // start tracking our stats nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getOctree()->getRoot()); - - preStartNewScene(nodeData, isFullScene); } - // If we have something in our elementBag, then turn them into packets and send them out... - if (shouldTraverseAndSend(nodeData)) { - quint64 start = usecTimestampNow(); + quint64 start = usecTimestampNow(); - _myServer->getOctree()->withReadLock([&]{ - traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene); - }); + _myServer->getOctree()->withReadLock([&]{ + traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene); + }); - // Here's where we can/should allow the server to send other data... - // send the environment packet - // TODO: should we turn this into a while loop to better handle sending multiple special packets - if (_myServer->hasSpecialPacketsToSend(node) && !nodeData->isShuttingDown()) { - int specialPacketsSent = 0; - int specialBytesSent = _myServer->sendSpecialPackets(node, nodeData, specialPacketsSent); - nodeData->resetOctreePacket(); // because nodeData's _sequenceNumber has changed - _truePacketsSent += specialPacketsSent; - _trueBytesSent += specialBytesSent; - _packetsSentThisInterval += specialPacketsSent; + // Here's where we can/should allow the server to send other data... + // send the environment packet + // TODO: should we turn this into a while loop to better handle sending multiple special packets + if (_myServer->hasSpecialPacketsToSend(node) && !nodeData->isShuttingDown()) { + int specialPacketsSent = 0; + int specialBytesSent = _myServer->sendSpecialPackets(node, nodeData, specialPacketsSent); + nodeData->resetOctreePacket(); // because nodeData's _sequenceNumber has changed + _truePacketsSent += specialPacketsSent; + _trueBytesSent += specialBytesSent; + _packetsSentThisInterval += specialPacketsSent; - _totalPackets += specialPacketsSent; - _totalBytes += specialBytesSent; + _totalPackets += specialPacketsSent; + _totalBytes += specialBytesSent; - _totalSpecialPackets += specialPacketsSent; - _totalSpecialBytes += specialBytesSent; + _totalSpecialPackets += specialPacketsSent; + _totalSpecialBytes += specialBytesSent; + } + + // calculate max number of packets that can be sent during this interval + int clientMaxPacketsPerInterval = std::max(1, (nodeData->getMaxQueryPacketsPerSecond() / INTERVALS_PER_SECOND)); + int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); + + // Re-send packets that were nacked by the client + while (nodeData->hasNextNackedPacket() && _packetsSentThisInterval < maxPacketsPerInterval) { + const NLPacket* packet = nodeData->getNextNackedPacket(); + if (packet) { + DependencyManager::get()->sendUnreliablePacket(*packet, *node); + int numBytes = packet->getDataSize(); + _truePacketsSent++; + _trueBytesSent += numBytes; + _packetsSentThisInterval++; + + _totalPackets++; + _totalBytes += numBytes; + _totalWastedBytes += udt::MAX_PACKET_SIZE - packet->getDataSize(); } + } - // calculate max number of packets that can be sent during this interval - int clientMaxPacketsPerInterval = std::max(1, (nodeData->getMaxQueryPacketsPerSecond() / INTERVALS_PER_SECOND)); - int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); + quint64 end = usecTimestampNow(); + int elapsedmsec = (end - start) / USECS_PER_MSEC; + OctreeServer::trackLoopTime(elapsedmsec); - // Re-send packets that were nacked by the client - while (nodeData->hasNextNackedPacket() && _packetsSentThisInterval < maxPacketsPerInterval) { - const NLPacket* packet = nodeData->getNextNackedPacket(); - if (packet) { - DependencyManager::get()->sendUnreliablePacket(*packet, *node); - int numBytes = packet->getDataSize(); - _truePacketsSent++; - _trueBytesSent += numBytes; - _packetsSentThisInterval++; + // if after sending packets we've emptied our bag, then we want to remember that we've sent all + // the octree elements from the current view frustum + if (!hasSomethingToSend(nodeData)) { + nodeData->setViewSent(true); - _totalPackets++; - _totalBytes += numBytes; - _totalWastedBytes += udt::MAX_PACKET_SIZE - packet->getDataSize(); - } + // If this was a full scene then make sure we really send out a stats packet at this point so that + // the clients will know the scene is stable + if (isFullScene) { + nodeData->stats.sceneCompleted(); + handlePacketSend(node, nodeData, true); } - - quint64 end = usecTimestampNow(); - int elapsedmsec = (end - start) / USECS_PER_MSEC; - OctreeServer::trackLoopTime(elapsedmsec); - - // if after sending packets we've emptied our bag, then we want to remember that we've sent all - // the octree elements from the current view frustum - if (!hasSomethingToSend(nodeData)) { - nodeData->updateLastKnownViewFrustum(); - nodeData->setViewSent(true); - - // If this was a full scene then make sure we really send out a stats packet at this point so that - // the clients will know the scene is stable - if (isFullScene) { - nodeData->stats.sceneCompleted(); - handlePacketSend(node, nodeData, true); - } - } - - } // end if bag wasn't empty, and so we sent stuff... + } return _truePacketsSent; } -bool OctreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) { - bool somethingToSend = false; - OctreeQueryNode* nodeData = static_cast(params.nodeData); - if (!nodeData->elementBag.isEmpty()) { - quint64 encodeStart = usecTimestampNow(); - quint64 lockWaitStart = encodeStart; - - _myServer->getOctree()->withReadLock([&]{ - OctreeServer::trackTreeWaitTime((float)(usecTimestampNow() - lockWaitStart)); - - OctreeElementPointer subTree = nodeData->elementBag.extract(); - if (subTree) { - // NOTE: this is where the tree "contents" are actually packed - nodeData->stats.encodeStarted(); - _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->elementBag, params); - nodeData->stats.encodeStopped(); - - somethingToSend = true; - } - }); - - OctreeServer::trackEncodeTime((float)(usecTimestampNow() - encodeStart)); - } else { - OctreeServer::trackTreeWaitTime(OctreeServer::SKIP_TIME); - OctreeServer::trackEncodeTime(OctreeServer::SKIP_TIME); - } - return somethingToSend; -} - void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) { // calculate max number of packets that can be sent during this interval int clientMaxPacketsPerInterval = std::max(1, (nodeData->getMaxQueryPacketsPerSecond() / INTERVALS_PER_SECOND)); @@ -502,21 +440,12 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre int extraPackingAttempts = 0; // init params once outside the while loop - int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); - int boundaryLevelAdjust = boundaryLevelAdjustClient + - (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - float octreeSizeScale = nodeData->getOctreeSizeScale(); - EncodeBitstreamParams params(INT_MAX, WANT_EXISTS_BITS, DONT_CHOP, - viewFrustumChanged, boundaryLevelAdjust, octreeSizeScale, - isFullScene, nodeData); + EncodeBitstreamParams params(WANT_EXISTS_BITS, nodeData); // Our trackSend() function is implemented by the server subclass, and will be called back as new entities/data elements are sent params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) { _myServer->trackSend(dataID, dataEdited, _nodeUuid); }; nodeData->copyCurrentViewFrustum(params.viewFrustum); - if (viewFrustumChanged) { - nodeData->copyLastKnownViewFrustum(params.lastViewFrustum); - } bool somethingToSend = true; // assume we have something bool hadSomething = hasSomethingToSend(nodeData); @@ -537,7 +466,7 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre } // If the bag had contents but is now empty then we know we've sent the entire scene. - bool completedScene = hadSomething && nodeData->elementBag.isEmpty(); + bool completedScene = hadSomething; if (completedScene || lastNodeDidntFit) { // we probably want to flush what has accumulated in nodeData but: // do we have more data to send? and is there room? diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 220952e209..91c0ec7adc 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -54,7 +54,7 @@ protected: virtual void traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene); - virtual bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters); + virtual bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) = 0; OctreePacketData _packetData; QWeakPointer _node; @@ -63,14 +63,12 @@ protected: private: /// Called before a packetDistributor pass to allow for pre-distribution processing - virtual void preDistributionProcessing() {}; + virtual void preDistributionProcessing() = 0; int handlePacketSend(SharedNodePointer node, OctreeQueryNode* nodeData, bool dontSuppressDuplicate = false); int packetDistributor(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged); - virtual bool hasSomethingToSend(OctreeQueryNode* nodeData) { return !nodeData->elementBag.isEmpty(); } - virtual bool shouldStartNewTraversal(OctreeQueryNode* nodeData, bool viewFrustumChanged) { return viewFrustumChanged || !hasSomethingToSend(nodeData); } - virtual void preStartNewScene(OctreeQueryNode* nodeData, bool isFullScene); - virtual bool shouldTraverseAndSend(OctreeQueryNode* nodeData) { return hasSomethingToSend(nodeData); } + virtual bool hasSomethingToSend(OctreeQueryNode* nodeData) = 0; + virtual bool shouldStartNewTraversal(OctreeQueryNode* nodeData, bool viewFrustumChanged) = 0; int _truePacketsSent { 0 }; // available for debug stats int _trueBytesSent { 0 }; // available for debug stats diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 0dbd24fe9c..fad2c1f026 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -876,10 +876,6 @@ void OctreeServer::parsePayload() { } } -OctreeServer::UniqueSendThread OctreeServer::newSendThread(const SharedNodePointer& node) { - return std::unique_ptr(new OctreeSendThread(this, node)); -} - OctreeServer::UniqueSendThread OctreeServer::createSendThread(const SharedNodePointer& node) { auto sendThread = newSendThread(node); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index e7efc731f2..b25e537d70 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -174,7 +174,7 @@ protected: void beginRunning(QByteArray replaceData); UniqueSendThread createSendThread(const SharedNodePointer& node); - virtual UniqueSendThread newSendThread(const SharedNodePointer& node); + virtual UniqueSendThread newSendThread(const SharedNodePointer& node) = 0; int _argc; const char** _argv; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index de98c1a47a..0557bbe5ad 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -120,7 +120,6 @@ public: void markAsChangedOnServer(); quint64 getLastChangedOnServer() const; - // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; virtual OctreeElement::AppendState appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 791c030fc8..a080801a0e 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -88,7 +88,6 @@ public: // These methods will allow the OctreeServer to send your tree inbound edit packets of your // own definition. Implement these to allow your octree based server to support editing - virtual bool getWantSVOfileVersions() const override { return true; } virtual PacketType expectedDataPacketType() const override { return PacketType::EntityData; } virtual bool handlesEditPacketType(PacketType packetType) const override; void fixupTerseEditLogging(EntityItemProperties& properties, QList& changedProperties); @@ -107,11 +106,7 @@ public: virtual bool rootElementHasData() const override { return true; } - // the root at least needs to store the number of entities in the packet/buffer - virtual int minimumRequiredRootDataBytes() const override { return sizeof(uint16_t); } - virtual bool suppressEmptySubtrees() const override { return false; } virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const override; - virtual bool mustIncludeAllChildData() const override { return false; } virtual void update() override { update(true); } diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 1ae55bc333..cbcddfc57b 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -67,455 +67,6 @@ void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) cons } } -void EntityTreeElement::initializeExtraEncodeData(EncodeBitstreamParams& params) { - - auto entityNodeData = static_cast(params.nodeData); - assert(entityNodeData); - - OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; - - assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes - // Check to see if this element yet has encode data... if it doesn't create it - if (!extraEncodeData->contains(this)) { - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData { new EntityTreeElementExtraEncodeData() }; - entityTreeElementExtraEncodeData->elementCompleted = (_entityItems.size() == 0); - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - EntityTreeElementPointer child = getChildAtIndex(i); - if (!child) { - entityTreeElementExtraEncodeData->childCompleted[i] = true; // if no child exists, it is completed - } else { - if (child->hasEntities()) { - entityTreeElementExtraEncodeData->childCompleted[i] = false; // HAS ENTITIES NEEDS ENCODING - } else { - entityTreeElementExtraEncodeData->childCompleted[i] = true; // child doesn't have enities, it is completed - } - } - } - forEachEntity([&](EntityItemPointer entity) { - entityTreeElementExtraEncodeData->entities.insert(entity->getEntityItemID(), entity->getEntityProperties(params)); - }); - - // TODO: some of these inserts might be redundant!!! - extraEncodeData->insert(this, entityTreeElementExtraEncodeData); - } -} - -bool EntityTreeElement::shouldIncludeChildData(int childIndex, EncodeBitstreamParams& params) const { - - auto entityNodeData = static_cast(params.nodeData); - assert(entityNodeData); - - OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; - assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes - - if (extraEncodeData->contains(this)) { - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData - = std::static_pointer_cast((*extraEncodeData)[this]); - - bool childCompleted = entityTreeElementExtraEncodeData->childCompleted[childIndex]; - - // If we haven't completely sent the child yet, then we should include it - return !childCompleted; - } - - // I'm not sure this should ever happen, since we should have the extra encode data if we're considering - // the child data for this element - assert(false); - return false; -} - -bool EntityTreeElement::shouldRecurseChildTree(int childIndex, EncodeBitstreamParams& params) const { - EntityTreeElementPointer childElement = getChildAtIndex(childIndex); - if (childElement->alreadyFullyEncoded(params)) { - return false; - } - - return true; // if we don't know otherwise than recurse! -} - -bool EntityTreeElement::alreadyFullyEncoded(EncodeBitstreamParams& params) const { - auto entityNodeData = static_cast(params.nodeData); - assert(entityNodeData); - - OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; - assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes - - if (extraEncodeData->contains(this)) { - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData - = std::static_pointer_cast((*extraEncodeData)[this]); - - // If we know that ALL subtrees below us have already been recursed, then we don't - // need to recurse this child. - return entityTreeElementExtraEncodeData->subtreeCompleted; - } - return false; -} - -void EntityTreeElement::updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const { - auto entityNodeData = static_cast(params.nodeData); - assert(entityNodeData); - - OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; - assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes - - if (extraEncodeData->contains(this)) { - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData - = std::static_pointer_cast((*extraEncodeData)[this]); - - if (childAppendState == OctreeElement::COMPLETED) { - entityTreeElementExtraEncodeData->childCompleted[childIndex] = true; - } - } else { - assert(false); // this shouldn't happen! - } -} - - - - -void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params) const { - const bool wantDebug = false; - - if (wantDebug) { - qCDebug(entities) << "EntityTreeElement::elementEncodeComplete() element:" << _cube; - } - - auto entityNodeData = static_cast(params.nodeData); - assert(entityNodeData); - - OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; - assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes - assert(extraEncodeData->contains(this)); - - EntityTreeElementExtraEncodeDataPointer thisExtraEncodeData - = std::static_pointer_cast((*extraEncodeData)[this]); - - // Note: this will be called when OUR element has finished running through encodeTreeBitstreamRecursion() - // which means, it's possible that our parent element hasn't finished encoding OUR data... so - // in this case, our children may be complete, and we should clean up their encode data... - // but not necessarily cleanup our own encode data... - // - // If we're really complete here's what must be true... - // 1) our own data must be complete - // 2) the data for all our immediate children must be complete. - // However, the following might also be the case... - // 1) it's ok for our child trees to not yet be fully encoded/complete... - // SO LONG AS... the our child's node is in the bag ready for encoding - - bool someChildTreeNotComplete = false; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - EntityTreeElementPointer childElement = getChildAtIndex(i); - if (childElement) { - - // why would this ever fail??? - // If we've encoding this element before... but we're coming back a second time in an attempt to - // encode our parent... this might happen. - if (extraEncodeData->contains(childElement.get())) { - EntityTreeElementExtraEncodeDataPointer childExtraEncodeData - = std::static_pointer_cast((*extraEncodeData)[childElement.get()]); - - if (wantDebug) { - qCDebug(entities) << "checking child: " << childElement->_cube; - qCDebug(entities) << " childElement->isLeaf():" << childElement->isLeaf(); - qCDebug(entities) << " childExtraEncodeData->elementCompleted:" << childExtraEncodeData->elementCompleted; - qCDebug(entities) << " childExtraEncodeData->subtreeCompleted:" << childExtraEncodeData->subtreeCompleted; - } - - if (childElement->isLeaf() && childExtraEncodeData->elementCompleted) { - if (wantDebug) { - qCDebug(entities) << " CHILD IS LEAF -- AND CHILD ELEMENT DATA COMPLETED!!!"; - } - childExtraEncodeData->subtreeCompleted = true; - } - - if (!childExtraEncodeData->elementCompleted || !childExtraEncodeData->subtreeCompleted) { - someChildTreeNotComplete = true; - } - } - } - } - - if (wantDebug) { - qCDebug(entities) << "for this element: " << _cube; - qCDebug(entities) << " WAS elementCompleted:" << thisExtraEncodeData->elementCompleted; - qCDebug(entities) << " WAS subtreeCompleted:" << thisExtraEncodeData->subtreeCompleted; - } - - thisExtraEncodeData->subtreeCompleted = !someChildTreeNotComplete; - - if (wantDebug) { - qCDebug(entities) << " NOW elementCompleted:" << thisExtraEncodeData->elementCompleted; - qCDebug(entities) << " NOW subtreeCompleted:" << thisExtraEncodeData->subtreeCompleted; - - if (thisExtraEncodeData->subtreeCompleted) { - qCDebug(entities) << " YEAH!!!!! >>>>>>>>>>>>>> NOW subtreeCompleted:" << thisExtraEncodeData->subtreeCompleted; - } - } -} - -OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData* packetData, - EncodeBitstreamParams& params) const { - - OctreeElement::AppendState appendElementState = OctreeElement::COMPLETED; // assume the best... - - auto entityNodeData = static_cast(params.nodeData); - Q_ASSERT_X(entityNodeData, "EntityTreeElement::appendElementData", "expected params.nodeData not to be null"); - - // first, check the params.extraEncodeData to see if there's any partial re-encode data for this element - OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; - - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData = NULL; - bool hadElementExtraData = false; - if (extraEncodeData && extraEncodeData->contains(this)) { - entityTreeElementExtraEncodeData = - std::static_pointer_cast((*extraEncodeData)[this]); - hadElementExtraData = true; - } else { - // if there wasn't one already, then create one - entityTreeElementExtraEncodeData.reset(new EntityTreeElementExtraEncodeData()); - entityTreeElementExtraEncodeData->elementCompleted = !hasContent(); - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - EntityTreeElementPointer child = getChildAtIndex(i); - if (!child) { - entityTreeElementExtraEncodeData->childCompleted[i] = true; // if no child exists, it is completed - } else { - if (child->hasEntities()) { - entityTreeElementExtraEncodeData->childCompleted[i] = false; - } else { - // if the child doesn't have enities, it is completed - entityTreeElementExtraEncodeData->childCompleted[i] = true; - } - } - } - forEachEntity([&](EntityItemPointer entity) { - entityTreeElementExtraEncodeData->entities.insert(entity->getEntityItemID(), entity->getEntityProperties(params)); - }); - } - - //assert(extraEncodeData); - //assert(extraEncodeData->contains(this)); - //entityTreeElementExtraEncodeData = std::static_pointer_cast((*extraEncodeData)[this]); - - LevelDetails elementLevel = packetData->startLevel(); - - // write our entities out... first determine which of the entities are in view based on our params - uint16_t numberOfEntities = 0; - uint16_t actualNumberOfEntities = 0; - int numberOfEntitiesOffset = 0; - withReadLock([&] { - QVector indexesOfEntitiesToInclude; - - // It's possible that our element has been previous completed. In this case we'll simply not include any of our - // entities for encoding. This is needed because we encode the element data at the "parent" level, and so we - // need to handle the case where our sibling elements need encoding but we don't. - if (!entityTreeElementExtraEncodeData->elementCompleted) { - - - // we have an EntityNodeData instance - // so we should assume that means we might have JSON filters to check - auto jsonFilters = entityNodeData->getJSONParameters(); - - - for (uint16_t i = 0; i < _entityItems.size(); i++) { - EntityItemPointer entity = _entityItems[i]; - bool includeThisEntity = true; - - if (!params.forceSendScene && entity->getLastChangedOnServer() < entityNodeData->getLastTimeBagEmpty()) { - includeThisEntity = false; - } - - // if this entity has been updated since our last full send and there are json filters, check them - if (includeThisEntity && !jsonFilters.isEmpty()) { - - // if params include JSON filters, check if this entity matches - bool entityMatchesFilters = entity->matchesJSONFilters(jsonFilters); - - if (entityMatchesFilters) { - // make sure this entity is in the set of entities sent last frame - entityNodeData->insertSentFilteredEntity(entity->getID()); - } else if (entityNodeData->sentFilteredEntity(entity->getID())) { - // this entity matched in the previous frame - we send it still so the client realizes it just - // fell outside of their filter - entityNodeData->removeSentFilteredEntity(entity->getID()); - } else if (!entityNodeData->isEntityFlaggedAsExtra(entity->getID())) { - // we don't send this entity because - // (1) it didn't match our filter - // (2) it didn't match our filter last frame - // (3) it isn't one the JSON query flags told us we should still include - includeThisEntity = false; - } - } - - if (includeThisEntity && hadElementExtraData) { - includeThisEntity = entityTreeElementExtraEncodeData->entities.contains(entity->getEntityItemID()); - } - - // we only check the bounds against our frustum and LOD if the query has asked us to check against the frustum - // which can sometimes not be the case when JSON filters are sent - if (entityNodeData->getUsesFrustum() && (includeThisEntity || params.recurseEverything)) { - - // we want to use the maximum possible box for this, so that we don't have to worry about the nuance of - // simulation changing what's visible. consider the case where the entity contains an angular velocity - // the entity may not be in view and then in view a frame later, let the client side handle it's view - // frustum culling on rendering. - bool success; - AACube entityCube = entity->getQueryAACube(success); - if (!success || !params.viewFrustum.cubeIntersectsKeyhole(entityCube)) { - includeThisEntity = false; // out of view, don't include it - } else { - // 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. - success = true; - // we can't cull a parent-entity by its dimensions because the child may be larger. we need to - // avoid sending details about a child but not the parent. the parent's queryAACube should have - // been adjusted to encompass the queryAACube of the child. - AABox entityBounds = entity->hasChildren() ? AABox(entityCube) : entity->getAABox(success); - if (!success) { - // if this entity is a child of an avatar, the entity-server wont be able to determine its - // AABox. If this happens, fall back to the queryAACube. - entityBounds = AABox(entityCube); - } - auto renderAccuracy = calculateRenderAccuracy(params.viewFrustum.getPosition(), - entityBounds, - params.octreeElementSizeScale, - params.boundaryLevelAdjust); - if (renderAccuracy <= 0.0f) { - includeThisEntity = false; // too small, don't include it - - #ifdef WANT_LOD_DEBUGGING - qCDebug(entities) << "skipping entity - TOO SMALL - \n" - << "......id:" << entity->getID() << "\n" - << "....name:" << entity->getName() << "\n" - << "..bounds:" << entityBounds << "\n" - << "....cell:" << getAACube(); - #endif - } - } - } - - if (includeThisEntity) { - #ifdef WANT_LOD_DEBUGGING - qCDebug(entities) << "including entity - \n" - << "......id:" << entity->getID() << "\n" - << "....name:" << entity->getName() << "\n" - << "....cell:" << getAACube(); - #endif - indexesOfEntitiesToInclude << i; - numberOfEntities++; - } else { - // if the extra data included this entity, and we've decided to not include the entity, then - // we can treat it as if it was completed. - entityTreeElementExtraEncodeData->entities.remove(entity->getEntityItemID()); - } - } - } - - numberOfEntitiesOffset = packetData->getUncompressedByteOffset(); - bool successAppendEntityCount = packetData->appendValue(numberOfEntities); - - if (successAppendEntityCount) { - foreach(uint16_t i, indexesOfEntitiesToInclude) { - EntityItemPointer entity = _entityItems[i]; - LevelDetails entityLevel = packetData->startLevel(); - OctreeElement::AppendState appendEntityState = entity->appendEntityData(packetData, - params, entityTreeElementExtraEncodeData); - - // If none of this entity data was able to be appended, then discard it - // and don't include it in our entity count - if (appendEntityState == OctreeElement::NONE) { - packetData->discardLevel(entityLevel); - } else { - // If either ALL or some of it got appended, then end the level (commit it) - // and include the entity in our final count of entities - packetData->endLevel(entityLevel); - actualNumberOfEntities++; - - // If the entity item got completely appended, then we can remove it from the extra encode data - if (appendEntityState == OctreeElement::COMPLETED) { - entityTreeElementExtraEncodeData->entities.remove(entity->getEntityItemID()); - } - } - - // If any part of the entity items didn't fit, then the element is considered partial - // NOTE: if the entity item didn't fit or only partially fit, then the entity item should have - // added itself to the extra encode data. - if (appendEntityState != OctreeElement::COMPLETED) { - appendElementState = OctreeElement::PARTIAL; - } - } - } else { - // we we couldn't add the entity count, then we couldn't add anything for this element and we're in a NONE state - appendElementState = OctreeElement::NONE; - } - }); - - // If we were provided with extraEncodeData, and we allocated and/or got entityTreeElementExtraEncodeData - // then we need to do some additional processing, namely make sure our extraEncodeData is up to date for - // this octree element. - if (extraEncodeData && entityTreeElementExtraEncodeData) { - - // After processing, if we are PARTIAL or COMPLETED then we need to re-include our extra data. - // Only our parent can remove our extra data in these cases and only after it knows that all of its - // children have been encoded. - // - // FIXME -- this comment seems wrong.... - // - // If we weren't able to encode ANY data about ourselves, then we go ahead and remove our element data - // since that will signal that the entire element needs to be encoded on the next attempt - if (appendElementState == OctreeElement::NONE) { - - if (!entityTreeElementExtraEncodeData->elementCompleted && entityTreeElementExtraEncodeData->entities.size() == 0) { - // TODO: we used to delete the extra encode data here. But changing the logic around - // this is now a dead code branch. Clean this up! - } else { - // TODO: some of these inserts might be redundant!!! - extraEncodeData->insert(this, entityTreeElementExtraEncodeData); - } - } else { - - // If we weren't previously completed, check to see if we are - if (!entityTreeElementExtraEncodeData->elementCompleted) { - // If all of our items have been encoded, then we are complete as an element. - if (entityTreeElementExtraEncodeData->entities.size() == 0) { - entityTreeElementExtraEncodeData->elementCompleted = true; - } - } - - // TODO: some of these inserts might be redundant!!! - extraEncodeData->insert(this, entityTreeElementExtraEncodeData); - } - } - - // Determine if no entities at all were able to fit - bool noEntitiesFit = (numberOfEntities > 0 && actualNumberOfEntities == 0); - - // If we wrote fewer entities than we expected, update the number of entities in our packet - bool successUpdateEntityCount = true; - if (numberOfEntities != actualNumberOfEntities) { - successUpdateEntityCount = packetData->updatePriorBytes(numberOfEntitiesOffset, - (const unsigned char*)&actualNumberOfEntities, sizeof(actualNumberOfEntities)); - } - - // If we weren't able to update our entity count, or we couldn't fit any entities, then - // we should discard our element and return a result of NONE - if (!successUpdateEntityCount) { - packetData->discardLevel(elementLevel); - appendElementState = OctreeElement::NONE; - } else { - if (noEntitiesFit) { - //appendElementState = OctreeElement::PARTIAL; - packetData->discardLevel(elementLevel); - appendElementState = OctreeElement::NONE; - } else { - packetData->endLevel(elementLevel); - } - } - return appendElementState; -} - bool EntityTreeElement::containsEntityBounds(EntityItemPointer entity) const { bool success; auto queryCube = entity->getQueryAACube(success); diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index a56af5d03f..76e1e40812 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -121,17 +121,6 @@ public: virtual bool requiresSplit() const override { return false; } virtual void debugExtraEncodeData(EncodeBitstreamParams& params) const override; - virtual void initializeExtraEncodeData(EncodeBitstreamParams& params) override; - virtual bool shouldIncludeChildData(int childIndex, EncodeBitstreamParams& params) const override; - virtual bool shouldRecurseChildTree(int childIndex, EncodeBitstreamParams& params) const override; - virtual void updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const override; - virtual void elementEncodeComplete(EncodeBitstreamParams& params) const override; - - bool alreadyFullyEncoded(EncodeBitstreamParams& params) const; - - /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. - virtual OctreeElement::AppendState appendElementData(OctreePacketData* packetData, - EncodeBitstreamParams& params) const override; /// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading /// from the network. diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 3f7fc5f799..f0fbb20f98 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -186,7 +186,6 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, } -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags LightEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_IS_SPOTLIGHT; diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index 00196d7b23..92a1c25970 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -128,7 +128,6 @@ int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, } -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags LineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_COLOR; diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index 375453e0e9..84f9acf5f5 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -26,7 +26,6 @@ class LineEntityItem : public EntityItem { virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 6c040296a3..489ba5772c 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -89,8 +89,6 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da return bytesRead; } - -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_MATERIAL_URL; diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index 969eb577ff..30743850dd 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -32,7 +32,6 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index bec7bc1906..be62664ff9 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -144,7 +144,6 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, return bytesRead; } -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); @@ -721,4 +720,4 @@ bool ModelEntityItem::isAnimatingSomething() const { _animationProperties.getRunning() && (_animationProperties.getFPS() != 0.0f); }); -} \ No newline at end of file +} diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index c2109ba51f..327606ae2f 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -30,7 +30,6 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 7d27011c56..d9ef5e2178 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -503,8 +503,6 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch return bytesRead; } - -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 498d13058e..420c570e8d 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -216,8 +216,6 @@ int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da return bytesRead; } - -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags PolyLineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_COLOR; diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 2dc8befe97..871c451c50 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -26,7 +26,6 @@ class PolyLineEntityItem : public EntityItem { virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index 84ce83d3a1..ed3372818a 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -183,8 +183,6 @@ int PolyVoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* dat return bytesRead; } - -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags PolyVoxEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_VOXEL_VOLUME_SIZE; diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 0ddfe3e8cc..4dfe7b9535 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -26,7 +26,6 @@ class PolyVoxEntityItem : public EntityItem { virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 99f18d2dac..520d892682 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -188,8 +188,6 @@ int ShapeEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, return bytesRead; } - -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags ShapeEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_SHAPE; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 7030a95562..97080d3ca2 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -98,8 +98,6 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, return bytesRead; } - -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_TEXT; diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 06b377ee14..efdc84bcd8 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -30,7 +30,6 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 548bca3225..f3159ba3f8 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -83,8 +83,6 @@ int WebEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, i return bytesRead; } - -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags WebEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_SOURCE_URL; diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index dab7cd5e22..1179f22ded 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -29,7 +29,6 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 4ae020f966..b07d0597bc 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -191,8 +191,6 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, return bytesRead; } - -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 2c6b01fc69..3a9c7cb1e6 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -33,7 +33,6 @@ public: virtual bool setProperties(const EntityItemProperties& properties) override; virtual bool setSubClassProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index dafdfd5bf4..43883f68f3 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -45,7 +45,6 @@ #include "Octree.h" #include "OctreeConstants.h" -#include "OctreeElementBag.h" #include "OctreeLogging.h" #include "OctreeQueryNode.h" #include "OctreeUtils.h" @@ -57,7 +56,6 @@ Octree::Octree(bool shouldReaverage) : _rootElement(NULL), _isDirty(true), _shouldReaverage(shouldReaverage), - _stopImport(false), _isViewing(false), _isServer(false) { @@ -490,131 +488,6 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, uint64_t buffe // skip bitstream to new startPoint bitstreamAt += theseBytesRead; bytesRead += theseBytesRead; - - if (args.wantImportProgress) { - emit importProgress((100 * (bitstreamAt - bitstream)) / bufferSizeBytes); - } - } -} - -void Octree::deleteOctreeElementAt(float x, float y, float z, float s) { - unsigned char* octalCode = pointToOctalCode(x,y,z,s); - deleteOctalCodeFromTree(octalCode); - delete[] octalCode; // cleanup memory -} - -class DeleteOctalCodeFromTreeArgs { -public: - bool collapseEmptyTrees; - const unsigned char* codeBuffer; - int lengthOfCode; - bool deleteLastChild; - bool pathChanged; -}; - -// Note: uses the codeColorBuffer format, but the color's are ignored, because -// this only finds and deletes the element from the tree. -void Octree::deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool collapseEmptyTrees) { - // recurse the tree while decoding the codeBuffer, once you find the element in question, recurse - // back and implement color reaveraging, and marking of lastChanged - DeleteOctalCodeFromTreeArgs args; - args.collapseEmptyTrees = collapseEmptyTrees; - args.codeBuffer = codeBuffer; - args.lengthOfCode = numberOfThreeBitSectionsInCode(codeBuffer); - args.deleteLastChild = false; - args.pathChanged = false; - - withWriteLock([&] { - deleteOctalCodeFromTreeRecursion(_rootElement, &args); - }); -} - -void Octree::deleteOctalCodeFromTreeRecursion(const OctreeElementPointer& element, void* extraData) { - DeleteOctalCodeFromTreeArgs* args = (DeleteOctalCodeFromTreeArgs*)extraData; - - int lengthOfElementCode = numberOfThreeBitSectionsInCode(element->getOctalCode()); - - // Since we traverse the tree in code order, we know that if our code - // matches, then we've reached our target element. - if (lengthOfElementCode == args->lengthOfCode) { - // we've reached our target, depending on how we're called we may be able to operate on it - // it here, we need to recurse up, and delete it there. So we handle these cases the same to keep - // the logic consistent. - args->deleteLastChild = true; - return; - } - - // Ok, we know we haven't reached our target element yet, so keep looking - int childIndex = branchIndexWithDescendant(element->getOctalCode(), args->codeBuffer); - OctreeElementPointer childElement = element->getChildAtIndex(childIndex); - - // If there is no child at the target location, and the current parent element is a colored leaf, - // then it means we were asked to delete a child out of a larger leaf voxel. - // We support this by breaking up the parent voxel into smaller pieces. - if (!childElement && element->requiresSplit()) { - // we need to break up ancestors until we get to the right level - OctreeElementPointer ancestorElement = element; - while (true) { - int index = branchIndexWithDescendant(ancestorElement->getOctalCode(), args->codeBuffer); - - // we end up with all the children, even the one we want to delete - ancestorElement->splitChildren(); - - int lengthOfAncestorElement = numberOfThreeBitSectionsInCode(ancestorElement->getOctalCode()); - - // If we've reached the parent of the target, then stop breaking up children - if (lengthOfAncestorElement == (args->lengthOfCode - 1)) { - - // since we created all the children when we split, we need to delete this target one - ancestorElement->deleteChildAtIndex(index); - break; - } - ancestorElement = ancestorElement->getChildAtIndex(index); - } - _isDirty = true; - args->pathChanged = true; - - // ends recursion, unwinds up stack - return; - } - - // if we don't have a child and we reach this point, then we actually know that the parent - // isn't a colored leaf, and the child branch doesn't exist, so there's nothing to do below and - // we can safely return, ending the recursion and unwinding - if (!childElement) { - return; - } - - // If we got this far then we have a child for the branch we're looking for, but we're not there yet - // recurse till we get there - deleteOctalCodeFromTreeRecursion(childElement, args); - - // If the lower level determined it needs to be deleted, then we should delete now. - if (args->deleteLastChild) { - element->deleteChildAtIndex(childIndex); // note: this will track dirtiness and lastChanged for this element - - // track our tree dirtiness - _isDirty = true; - - // track that path has changed - args->pathChanged = true; - - // If we're in collapseEmptyTrees mode, and this was the last child of this element, then we also want - // to delete this element. This will collapse the empty tree above us. - if (args->collapseEmptyTrees && element->getChildCount() == 0) { - // Can't delete the root this way. - if (element == _rootElement) { - args->deleteLastChild = false; // reset so that further up the unwinding chain we don't do anything - } - } else { - args->deleteLastChild = false; // reset so that further up the unwinding chain we don't do anything - } - } - - // If the lower level did some work, then we need to let this element know, so it can - // do any bookkeeping it wants to, like color re-averaging, time stamp marking, etc - if (args->pathChanged) { - element->handleSubtreeChanged(shared_from_this()); } } @@ -883,720 +756,6 @@ OctreeElementPointer Octree::getElementEnclosingPoint(const glm::vec3& point, Oc return args.element; } - - -int Octree::encodeTreeBitstream(const OctreeElementPointer& element, - OctreePacketData* packetData, OctreeElementBag& bag, - EncodeBitstreamParams& params) { - - // How many bytes have we written so far at this level; - int bytesWritten = 0; - - // you can't call this without a valid element - if (!element) { - qCDebug(octree, "WARNING! encodeTreeBitstream() called with element=NULL"); - params.stopReason = EncodeBitstreamParams::NULL_NODE; - return bytesWritten; - } - - // you can't call this without a valid nodeData - auto octreeQueryNode = static_cast(params.nodeData); - if (!octreeQueryNode) { - qCDebug(octree, "WARNING! encodeTreeBitstream() called with nodeData=NULL"); - params.stopReason = EncodeBitstreamParams::NULL_NODE_DATA; - return bytesWritten; - } - - // If we're at a element that is out of view, then we can return, because no nodes below us will be in view! - if (octreeQueryNode->getUsesFrustum() && !params.recurseEverything && !element->isInView(params.viewFrustum)) { - params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW; - return bytesWritten; - } - - // write the octal code - bool roomForOctalCode = false; // assume the worst - int codeLength = 1; // assume root - if (params.chopLevels) { - unsigned char* newCode = chopOctalCode(element->getOctalCode(), params.chopLevels); - roomForOctalCode = packetData->startSubTree(newCode); - - if (newCode) { - codeLength = numberOfThreeBitSectionsInCode(newCode); - delete[] newCode; - } else { - codeLength = 1; - } - } else { - roomForOctalCode = packetData->startSubTree(element->getOctalCode()); - codeLength = (int)bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(element->getOctalCode())); - } - - // If the octalcode couldn't fit, then we can return, because no nodes below us will fit... - if (!roomForOctalCode) { - bag.insert(element); - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - return bytesWritten; - } - - bytesWritten += codeLength; // keep track of byte count - - int currentEncodeLevel = 0; - - // record some stats, this is the one element that we won't record below in the recursion function, so we need to - // track it here - octreeQueryNode->stats.traversed(element); - - ViewFrustum::intersection parentLocationThisView = ViewFrustum::INTERSECT; // assume parent is in view, but not fully - - int childBytesWritten = encodeTreeBitstreamRecursion(element, packetData, bag, params, - currentEncodeLevel, parentLocationThisView); - - // if childBytesWritten == 1 then something went wrong... that's not possible - assert(childBytesWritten != 1); - - // if childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some - // reason couldn't be written... so reset them here... This isn't true for the non-color included case - if (suppressEmptySubtrees() && childBytesWritten == 2) { - childBytesWritten = 0; - //params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT... - } - - // if we wrote child bytes, then return our result of all bytes written - if (childBytesWritten) { - bytesWritten += childBytesWritten; - } else { - // otherwise... if we didn't write any child bytes, then pretend like we also didn't write our octal code - bytesWritten = 0; - //params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } - - if (bytesWritten == 0) { - packetData->discardSubTree(); - } else { - packetData->endSubTree(); - } - - return bytesWritten; -} - -int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element, - OctreePacketData* packetData, OctreeElementBag& bag, - EncodeBitstreamParams& params, int& currentEncodeLevel, - const ViewFrustum::intersection& parentLocationThisView) const { - - - const bool wantDebug = false; - - // The append state of this level/element. - OctreeElement::AppendState elementAppendState = OctreeElement::COMPLETED; // assume the best - - // How many bytes have we written so far at this level; - int bytesAtThisLevel = 0; - - // you can't call this without a valid element - if (!element) { - qCDebug(octree, "WARNING! encodeTreeBitstreamRecursion() called with element=NULL"); - params.stopReason = EncodeBitstreamParams::NULL_NODE; - return bytesAtThisLevel; - } - - // you can't call this without a valid nodeData - auto octreeQueryNode = static_cast(params.nodeData); - if (!octreeQueryNode) { - qCDebug(octree, "WARNING! encodeTreeBitstream() called with nodeData=NULL"); - params.stopReason = EncodeBitstreamParams::NULL_NODE_DATA; - return bytesAtThisLevel; - } - - - // Keep track of how deep we've encoded. - currentEncodeLevel++; - - params.maxLevelReached = std::max(currentEncodeLevel, params.maxLevelReached); - - // If we've reached our max Search Level, then stop searching. - if (currentEncodeLevel >= params.maxEncodeLevel) { - params.stopReason = EncodeBitstreamParams::TOO_DEEP; - return bytesAtThisLevel; - } - - ViewFrustum::intersection nodeLocationThisView = ViewFrustum::INSIDE; // assume we're inside - if (octreeQueryNode->getUsesFrustum() && !params.recurseEverything) { - float boundaryDistance = boundaryDistanceForRenderLevel(element->getLevel() + params.boundaryLevelAdjust, - params.octreeElementSizeScale); - - // If we're too far away for our render level, then just return - if (element->distanceToCamera(params.viewFrustum) >= boundaryDistance) { - octreeQueryNode->stats.skippedDistance(element); - params.stopReason = EncodeBitstreamParams::LOD_SKIP; - return bytesAtThisLevel; - } - - // if the parent isn't known to be INSIDE, then it must be INTERSECT, and we should double check to see - // if we are INSIDE, INTERSECT, or OUTSIDE - if (parentLocationThisView != ViewFrustum::INSIDE) { - assert(parentLocationThisView != ViewFrustum::OUTSIDE); // we shouldn't be here if our parent was OUTSIDE! - nodeLocationThisView = element->computeViewIntersection(params.viewFrustum); - } - - // If we're at a element that is out of view, then we can return, because no nodes below us will be in view! - // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if - // we're out of view - if (nodeLocationThisView == ViewFrustum::OUTSIDE) { - octreeQueryNode->stats.skippedOutOfView(element); - params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW; - return bytesAtThisLevel; - } - - // Ok, we are in view, but if we're in delta mode, then we also want to make sure we weren't already in view - // because we don't send nodes from the previously know in view frustum. - bool wasInView = false; - - if (params.deltaView) { - ViewFrustum::intersection location = element->computeViewIntersection(params.lastViewFrustum); - - // If we're a leaf, then either intersect or inside is considered "formerly in view" - if (element->isLeaf()) { - wasInView = location != ViewFrustum::OUTSIDE; - } else { - wasInView = location == ViewFrustum::INSIDE; - } - - // If we were in view, double check that we didn't switch LOD visibility... namely, the was in view doesn't - // tell us if it was so small we wouldn't have rendered it. Which may be the case. And we may have moved closer - // to it, and so therefore it may now be visible from an LOD perspective, in which case we don't consider it - // as "was in view"... - if (wasInView) { - float boundaryDistance = boundaryDistanceForRenderLevel(element->getLevel() + params.boundaryLevelAdjust, - params.octreeElementSizeScale); - if (element->distanceToCamera(params.lastViewFrustum) >= boundaryDistance) { - // This would have been invisible... but now should be visible (we wouldn't be here otherwise)... - wasInView = false; - } - } - } - - // If we were previously in the view, then we normally will return out of here and stop recursing. But - // if we're in deltaView mode, and this element has changed since it was last sent, then we do - // need to send it. - if (wasInView && !(params.deltaView && element->hasChangedSince(octreeQueryNode->getLastTimeBagEmpty() - CHANGE_FUDGE))) { - octreeQueryNode->stats.skippedWasInView(element); - params.stopReason = EncodeBitstreamParams::WAS_IN_VIEW; - return bytesAtThisLevel; - } - } - - // If we're not in delta sending mode, and we weren't asked to do a force send, and the voxel hasn't changed, - // then we can also bail early and save bits - if (!params.forceSendScene && !params.deltaView && - !element->hasChangedSince(octreeQueryNode->getLastTimeBagEmpty() - CHANGE_FUDGE)) { - - octreeQueryNode->stats.skippedNoChange(element); - - params.stopReason = EncodeBitstreamParams::NO_CHANGE; - return bytesAtThisLevel; - } - - bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! - - // At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level - // is 1 byte for child colors + 3*NUMBER_OF_CHILDREN bytes for the actual colors + 1 byte for child trees. - // There could be sub trees below this point, which might take many more bytes, but that's ok, because we can - // always mark our subtrees as not existing and stop the packet at this point, then start up with a new packet - // for the remaining sub trees. - unsigned char childrenExistInTreeBits = 0; - unsigned char childrenExistInPacketBits = 0; - unsigned char childrenDataBits = 0; - - // Make our local buffer large enough to handle writing at this level in case we need to. - LevelDetails thisLevelKey = packetData->startLevel(); - int requiredBytes = sizeof(childrenDataBits) + sizeof(childrenExistInPacketBits); - if (params.includeExistsBits) { - requiredBytes += sizeof(childrenExistInTreeBits); - } - - // If this datatype allows root elements to include data, and this is the root, then ask the tree for the - // minimum bytes needed for root data and reserve those also - if (element == _rootElement && rootElementHasData()) { - requiredBytes += minimumRequiredRootDataBytes(); - } - - bool continueThisLevel = packetData->reserveBytes(requiredBytes); - - // If we can't reserve our minimum bytes then we can discard this level and return as if none of this level fits - if (!continueThisLevel) { - packetData->discardLevel(thisLevelKey); - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - bag.insert(element); - return bytesAtThisLevel; - } - - int inViewCount = 0; - int inViewNotLeafCount = 0; - int inViewWithColorCount = 0; - - OctreeElementPointer sortedChildren[NUMBER_OF_CHILDREN] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; - float distancesToChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - int indexOfChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElementPointer childElement = element->getChildAtIndex(i); - - // if the caller wants to include childExistsBits, then include them - if (params.includeExistsBits && childElement) { - childrenExistInTreeBits += (1 << (7 - i)); - } - - sortedChildren[i] = childElement; - indexOfChildren[i] = i; - distancesToChildren[i] = 0.0f; - - // track stats - // must check childElement here, because it could be we got here with no childElement - if (childElement) { - octreeQueryNode->stats.traversed(childElement); - } - } - - // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so - // add them to our distance ordered array of children - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElementPointer childElement = sortedChildren[i]; - int originalIndex = indexOfChildren[i]; - - bool childIsInView = (childElement && - (params.recurseEverything || !octreeQueryNode->getUsesFrustum() || - (nodeLocationThisView == ViewFrustum::INSIDE) || // parent was fully in view, we can assume ALL children are - (nodeLocationThisView == ViewFrustum::INTERSECT && - childElement->isInView(params.viewFrustum)) // the parent intersects and the child is in view - )); - - if (!childIsInView) { - // must check childElement here, because it could be we got here because there was no childElement - if (childElement) { - octreeQueryNode->stats.skippedOutOfView(childElement); - } - } else { - // Before we consider this further, let's see if it's in our LOD scope... - float boundaryDistance = params.recurseEverything || !octreeQueryNode->getUsesFrustum() ? 1 : - boundaryDistanceForRenderLevel(childElement->getLevel() + params.boundaryLevelAdjust, - params.octreeElementSizeScale); - - if (!(distancesToChildren[i] < boundaryDistance)) { - // don't need to check childElement here, because we can't get here with no childElement - octreeQueryNode->stats.skippedDistance(childElement); - } else { - inViewCount++; - - // track children in view as existing and not a leaf, if they're a leaf, - // we don't care about recursing deeper on them, and we don't consider their - // subtree to exist - if (!(childElement && childElement->isLeaf())) { - childrenExistInPacketBits += (1 << (7 - originalIndex)); - inViewNotLeafCount++; - } - - bool childIsOccluded = false; // assume it's not occluded - - bool shouldRender = params.recurseEverything || !octreeQueryNode->getUsesFrustum() || - childElement->calculateShouldRender(params.viewFrustum, - params.octreeElementSizeScale, params.boundaryLevelAdjust); - - // track some stats - // don't need to check childElement here, because we can't get here with no childElement - if (!shouldRender && childElement->isLeaf()) { - octreeQueryNode->stats.skippedDistance(childElement); - } - // don't need to check childElement here, because we can't get here with no childElement - if (childIsOccluded) { - octreeQueryNode->stats.skippedOccluded(childElement); - } - - // track children with actual color, only if the child wasn't previously in view! - if (shouldRender && !childIsOccluded) { - bool childWasInView = false; - - if (childElement && params.deltaView) { - ViewFrustum::intersection location = childElement->computeViewIntersection(params.lastViewFrustum); - - // If we're a leaf, then either intersect or inside is considered "formerly in view" - if (childElement->isLeaf()) { - childWasInView = location != ViewFrustum::OUTSIDE; - } else { - childWasInView = location == ViewFrustum::INSIDE; - } - } - - // If our child wasn't in view (or we're ignoring wasInView) then we add it to our sending items. - // Or if we were previously in the view, but this element has changed since it was last sent, then we do - // need to send it. - if (!childWasInView || - (params.deltaView && - childElement->hasChangedSince(octreeQueryNode->getLastTimeBagEmpty() - CHANGE_FUDGE))){ - - childrenDataBits += (1 << (7 - originalIndex)); - inViewWithColorCount++; - } else { - // otherwise just track stats of the items we discarded - // don't need to check childElement here, because we can't get here with no childElement - if (childWasInView) { - octreeQueryNode->stats.skippedWasInView(childElement); - } else { - octreeQueryNode->stats.skippedNoChange(childElement); - } - } - } - } - } - } - - // NOTE: the childrenDataBits indicates that there is an array of child element data included in this packet. - // We will write this bit mask but we may come back later and update the bits that are actually included - packetData->releaseReservedBytes(sizeof(childrenDataBits)); - continueThisLevel = packetData->appendBitMask(childrenDataBits); - - int childDataBitsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenDataBits)); - unsigned char actualChildrenDataBits = 0; - - assert(continueThisLevel); // since we used reserved bits, this really shouldn't fail - bytesAtThisLevel += sizeof(childrenDataBits); // keep track of byte count - - octreeQueryNode->stats.colorBitsWritten(); // really data bits not just color bits - - // NOW might be a good time to give our tree subclass and this element a chance to set up and check any extra encode data - element->initializeExtraEncodeData(params); - - // write the child element data... - // NOTE: the format of the bitstream is generally this: - // [octalcode] - // [bitmask for existence of child data] - // N x [child data] - // [bitmask for existence of child elements in tree] - // [bitmask for existence of child elements in buffer] - // N x [ ... tree for children ...] - // - // This section of the code, is writing the "N x [child data]" portion of this bitstream - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (oneAtBit(childrenDataBits, i)) { - OctreeElementPointer childElement = element->getChildAtIndex(i); - - // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already - // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the - // data for this child at this point - if (childElement && element->shouldIncludeChildData(i, params)) { - - int bytesBeforeChild = packetData->getUncompressedSize(); - - // a childElement may "partially" write it's data. for example, the model server where the entire - // contents of the element may be larger than can fit in a single MTU/packetData. In this case, - // we want to allow the appendElementData() to respond that it produced partial data, which should be - // written, but that the childElement needs to be reprocessed in an additional pass or passes - // to be completed. - LevelDetails childDataLevelKey = packetData->startLevel(); - - OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); - - // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state - element->updateEncodedData(i, childAppendState, params); - - // Continue this level so long as some part of this child element was appended. - bool childFit = (childAppendState != OctreeElement::NONE); - - // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit - // the data type wants to bail on this element level completely - if (!childFit && mustIncludeAllChildData()) { - continueThisLevel = false; - break; - } - - // If the child was partially or fully appended, then mark the actualChildrenDataBits as including - // this child data - if (childFit) { - actualChildrenDataBits += (1 << (7 - i)); - continueThisLevel = packetData->endLevel(childDataLevelKey); - } else { - packetData->discardLevel(childDataLevelKey); - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } - - // If this child was partially appended, then consider this element to be partially appended - if (childAppendState == OctreeElement::PARTIAL) { - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } - - int bytesAfterChild = packetData->getUncompressedSize(); - - bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child - - // don't need to check childElement here, because we can't get here with no childElement - if (childAppendState != OctreeElement::NONE) { - octreeQueryNode->stats.colorSent(childElement); - } - } - } - } - - if (!mustIncludeAllChildData() && !continueThisLevel) { - qCDebug(octree) << "WARNING UNEXPECTED CASE: reached end of child element data loop with continueThisLevel=FALSE"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - - if (continueThisLevel && actualChildrenDataBits != childrenDataBits) { - // repair the child data mask - continueThisLevel = packetData->updatePriorBitMask(childDataBitsPlaceHolder, actualChildrenDataBits); - if (!continueThisLevel) { - qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to update childDataBitsPlaceHolder"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - } - - // if the caller wants to include childExistsBits, then include them even if not in view, put them before the - // childrenExistInPacketBits, so that the lower code can properly repair the packet exists bits - if (continueThisLevel && params.includeExistsBits) { - packetData->releaseReservedBytes(sizeof(childrenExistInTreeBits)); - continueThisLevel = packetData->appendBitMask(childrenExistInTreeBits); - if (continueThisLevel) { - bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count - - octreeQueryNode->stats.existsBitsWritten(); - } else { - qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to append childrenExistInTreeBits"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - } - - // write the child exist bits - if (continueThisLevel) { - packetData->releaseReservedBytes(sizeof(childrenExistInPacketBits)); - continueThisLevel = packetData->appendBitMask(childrenExistInPacketBits); - if (continueThisLevel) { - bytesAtThisLevel += sizeof(childrenExistInPacketBits); // keep track of byte count - - octreeQueryNode->stats.existsInPacketBitsWritten(); - } else { - qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to append childrenExistInPacketBits"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - } - - // We only need to keep digging, if there is at least one child that is inView, and not a leaf. - keepDiggingDeeper = (inViewNotLeafCount > 0); - - // - // NOTE: the format of the bitstream is generally this: - // [octalcode] - // [bitmask for existence of child data] - // N x [child data] - // [bitmask for existence of child elements in tree] - // [bitmask for existence of child elements in buffer] - // N x [ ... tree for children ...] - // - // This section of the code, is writing the "N x [ ... tree for children ...]" portion of this bitstream - // - if (continueThisLevel && keepDiggingDeeper) { - - // at this point, we need to iterate the children who are in view, even if not colored - // and we need to determine if there's a deeper tree below them that we care about. - // - // Since this recursive function assumes we're already writing, we know we've already written our - // childrenExistInPacketBits. But... we don't really know how big the child tree will be. And we don't know if - // we'll have room in our buffer to actually write all these child trees. What we kinda would like to do is - // write our childExistsBits as a place holder. Then let each potential tree have a go at it. If they - // write something, we keep them in the bits, if they don't, we take them out. - // - // we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was! - int childExistsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenExistInPacketBits)); - - // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the - // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, - // and then later reshuffle these sections of our output buffer back into normal order. This allows us to make - // a single recursive pass in distance sorted order, but retain standard order in our encoded packet - - // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so - // add them to our distance ordered array of children - for (int indexByDistance = 0; indexByDistance < NUMBER_OF_CHILDREN; indexByDistance++) { - OctreeElementPointer childElement = sortedChildren[indexByDistance]; - int originalIndex = indexOfChildren[indexByDistance]; - - if (oneAtBit(childrenExistInPacketBits, originalIndex)) { - - int thisLevel = currentEncodeLevel; - - int childTreeBytesOut = 0; - - // NOTE: some octree styles (like models and particles) will store content in parent elements, and child - // elements. In this case, if we stop recursion when we include any data (the colorbits should really be - // called databits), then we wouldn't send the children. So those types of Octree's should tell us to keep - // recursing, by returning TRUE in recurseChildrenWithData(). - - if (params.recurseEverything || !octreeQueryNode->getUsesFrustum() - || recurseChildrenWithData() || !oneAtBit(childrenDataBits, originalIndex)) { - - // Allow the datatype a chance to determine if it really wants to recurse this tree. Usually this - // will be true. But if the tree has already been encoded, we will skip this. - if (element->shouldRecurseChildTree(originalIndex, params)) { - childTreeBytesOut = encodeTreeBitstreamRecursion(childElement, packetData, bag, params, - thisLevel, nodeLocationThisView); - } else { - childTreeBytesOut = 0; - } - } - - // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, - // basically, the children below don't contain any info. - - // if the child tree wrote 1 byte??? something must have gone wrong... because it must have at least the color - // byte and the child exist byte. - // - assert(childTreeBytesOut != 1); - - // if the child tree wrote just 2 bytes, then it means: it had no colors and no child nodes, because... - // if it had colors it would write 1 byte for the color mask, - // and at least a color's worth of bytes for the element of colors. - // if it had child trees (with something in them) then it would have the 1 byte for child mask - // and some number of bytes of lower children... - // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! - // - // we can make this act like no bytes out, by just resetting the bytes out in this case - if (suppressEmptySubtrees() && !params.includeExistsBits && childTreeBytesOut == 2) { - childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees - - } - - bytesAtThisLevel += childTreeBytesOut; - - // If we had previously started writing, and if the child DIDN'T write any bytes, - // then we want to remove their bit from the childExistsPlaceHolder bitmask - if (childTreeBytesOut == 0) { - - // remove this child's bit... - childrenExistInPacketBits -= (1 << (7 - originalIndex)); - - // repair the child exists mask - continueThisLevel = packetData->updatePriorBitMask(childExistsPlaceHolder, childrenExistInPacketBits); - if (!continueThisLevel) { - qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to update childExistsPlaceHolder"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - - // If this is the last of the child exists bits, then we're actually be rolling out the entire tree - if (childrenExistInPacketBits == 0) { - octreeQueryNode->stats.childBitsRemoved(params.includeExistsBits); - } - - if (!continueThisLevel) { - if (wantDebug) { - qCDebug(octree) << " WARNING line:" << __LINE__; - qCDebug(octree) << " breaking the child recursion loop with continueThisLevel=false!!!"; - qCDebug(octree) << " AFTER attempting to updatePriorBitMask() for empty sub tree...."; - qCDebug(octree) << " IS THIS ACCEPTABLE!!!!"; - } - break; // can't continue... - } - - // Note: no need to move the pointer, cause we already stored this - } // end if (childTreeBytesOut == 0) - } // end if (oneAtBit(childrenExistInPacketBits, originalIndex)) - } // end for - } // end keepDiggingDeeper - - // If we made it this far, then we've written all of our child data... if this element is the root - // element, then we also allow the root element to write out it's data... - if (continueThisLevel && element == _rootElement && rootElementHasData()) { - int bytesBeforeChild = packetData->getUncompressedSize(); - - // release the bytes we reserved... - packetData->releaseReservedBytes(minimumRequiredRootDataBytes()); - - LevelDetails rootDataLevelKey = packetData->startLevel(); - OctreeElement::AppendState rootAppendState = element->appendElementData(packetData, params); - - bool partOfRootFit = (rootAppendState != OctreeElement::NONE); - bool allOfRootFit = (rootAppendState == OctreeElement::COMPLETED); - - if (partOfRootFit) { - continueThisLevel = packetData->endLevel(rootDataLevelKey); - if (!continueThisLevel) { - qCDebug(octree) << " UNEXPECTED ROOT ELEMENT -- could not packetData->endLevel(rootDataLevelKey) -- line:" << __LINE__; - } - } else { - packetData->discardLevel(rootDataLevelKey); - } - - if (!allOfRootFit) { - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } - - // do we really ever NOT want to continue this level??? - //continueThisLevel = (rootAppendState == OctreeElement::COMPLETED); - - int bytesAfterChild = packetData->getUncompressedSize(); - - if (continueThisLevel) { - bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child - - octreeQueryNode->stats.colorSent(element); - } - - if (!continueThisLevel) { - qCDebug(octree) << "WARNING UNEXPECTED CASE: Something failed in packing ROOT data"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - } - - // if we were unable to fit this level in our packet, then rewind and add it to the element bag for - // sending later... - if (continueThisLevel) { - continueThisLevel = packetData->endLevel(thisLevelKey); - } else { - packetData->discardLevel(thisLevelKey); - - if (!mustIncludeAllChildData()) { - qCDebug(octree) << "WARNING UNEXPECTED CASE: Something failed in attempting to pack this element"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - } - - // This happens if the element could not be written at all. In the case of Octree's that support partial - // element data, continueThisLevel will be true. So this only happens if the full element needs to be - // added back to the element bag. - if (!continueThisLevel) { - if (!mustIncludeAllChildData()) { - qCDebug(octree) << "WARNING UNEXPECTED CASE - Something failed in attempting to pack this element."; - qCDebug(octree) << " If the datatype requires all child data, then this might happen. Otherwise" ; - qCDebug(octree) << " this is an unexpected case and we should research a potential logic error." ; - } - - bag.insert(element); - - // don't need to check element here, because we can't get here with no element - octreeQueryNode->stats.didntFit(element); - - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - bytesAtThisLevel = 0; // didn't fit - } else { - - // assuming we made it here with continueThisLevel == true, we STILL might want - // to add our element back to the bag for additional encoding, specifically if - // the appendState is PARTIAL, in this case, we re-add our element to the bag - // and assume that the appendElementData() has stored any required state data - // in the params extraEncodeData - if (elementAppendState == OctreeElement::PARTIAL) { - bag.insert(element); - } - } - - // If our element is completed let the element know so it can do any cleanup it of extra wants - if (elementAppendState == OctreeElement::COMPLETED) { - element->elementEncodeComplete(params); - } - - return bytesAtThisLevel; -} - bool Octree::readFromFile(const char* fileName) { QString qFileName = findMostRecentFileExtension(fileName, PERSIST_EXTENSIONS); @@ -1615,14 +774,10 @@ bool Octree::readFromFile(const char* fileName) { QFileInfo fileInfo(qFileName); uint64_t fileLength = fileInfo.size(); - emit importSize(1.0f, 1.0f, 1.0f); - emit importProgress(0); - qCDebug(octree) << "Loading file" << qFileName << "..."; bool success = readFromStream(fileLength, fileInputStream); - emit importProgress(100); file.close(); return success; @@ -1863,7 +1018,3 @@ bool Octree::countOctreeElementsOperation(const OctreeElementPointer& element, v (*(uint64_t*)extraData)++; return true; // keep going } - -void Octree::cancelImport() { - _stopImport = true; -} diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index c4c4508138..a2ad834e18 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -49,126 +49,62 @@ public: // Callback function, for recuseTreeWithOperation using RecurseOctreeOperation = std::function; -typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; typedef QHash CubeList; const bool NO_EXISTS_BITS = false; const bool WANT_EXISTS_BITS = true; -const bool COLLAPSE_EMPTY_TREE = true; -const bool DONT_COLLAPSE = false; -const int DONT_CHOP = 0; const int NO_BOUNDARY_ADJUST = 0; const int LOW_RES_MOVING_ADJUST = 1; -#define IGNORE_COVERAGE_MAP NULL - class EncodeBitstreamParams { public: ViewFrustum viewFrustum; - ViewFrustum lastViewFrustum; - int maxEncodeLevel; - int maxLevelReached; bool includeExistsBits; - int chopLevels; - bool deltaView; - bool recurseEverything { false }; - int boundaryLevelAdjust; - float octreeElementSizeScale; - bool forceSendScene; NodeData* nodeData; // output hints from the encode process typedef enum { UNKNOWN, DIDNT_FIT, - NULL_NODE, - NULL_NODE_DATA, - TOO_DEEP, - LOD_SKIP, - OUT_OF_VIEW, - WAS_IN_VIEW, - NO_CHANGE, - OCCLUDED, FINISHED } reason; reason stopReason; - EncodeBitstreamParams( - int maxEncodeLevel = INT_MAX, - bool includeExistsBits = WANT_EXISTS_BITS, - int chopLevels = 0, - bool useDeltaView = false, - int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, - float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, - bool forceSendScene = true, - NodeData* nodeData = nullptr) : - maxEncodeLevel(maxEncodeLevel), - maxLevelReached(0), + EncodeBitstreamParams(bool includeExistsBits = WANT_EXISTS_BITS, + NodeData* nodeData = nullptr) : includeExistsBits(includeExistsBits), - chopLevels(chopLevels), - deltaView(useDeltaView), - boundaryLevelAdjust(boundaryLevelAdjust), - octreeElementSizeScale(octreeElementSizeScale), - forceSendScene(forceSendScene), nodeData(nodeData), stopReason(UNKNOWN) { - lastViewFrustum.invalidate(); } void displayStopReason() { printf("StopReason: "); switch (stopReason) { - default: case UNKNOWN: qDebug("UNKNOWN"); break; - case DIDNT_FIT: qDebug("DIDNT_FIT"); break; - case NULL_NODE: qDebug("NULL_NODE"); break; - case TOO_DEEP: qDebug("TOO_DEEP"); break; - case LOD_SKIP: qDebug("LOD_SKIP"); break; - case OUT_OF_VIEW: qDebug("OUT_OF_VIEW"); break; - case WAS_IN_VIEW: qDebug("WAS_IN_VIEW"); break; - case NO_CHANGE: qDebug("NO_CHANGE"); break; - case OCCLUDED: qDebug("OCCLUDED"); break; + case FINISHED: qDebug("FINISHED"); break; } } QString getStopReason() { switch (stopReason) { - default: case UNKNOWN: return QString("UNKNOWN"); break; - case DIDNT_FIT: return QString("DIDNT_FIT"); break; - case NULL_NODE: return QString("NULL_NODE"); break; - case TOO_DEEP: return QString("TOO_DEEP"); break; - case LOD_SKIP: return QString("LOD_SKIP"); break; - case OUT_OF_VIEW: return QString("OUT_OF_VIEW"); break; - case WAS_IN_VIEW: return QString("WAS_IN_VIEW"); break; - case NO_CHANGE: return QString("NO_CHANGE"); break; - case OCCLUDED: return QString("OCCLUDED"); break; + case FINISHED: return QString("FINISHED"); break; } } std::function trackSend { [](const QUuid&, quint64){} }; }; -class ReadElementBufferToTreeArgs { -public: - const unsigned char* buffer; - int length; - bool destructive; - bool pathChanged; -}; - class ReadBitstreamToTreeParams { public: bool includeExistsBits; OctreeElementPointer destinationElement; QUuid sourceUUID; SharedNodePointer sourceNode; - bool wantImportProgress; - PacketVersion bitstreamVersion; int elementsPerPacket = 0; int entitiesPerPacket = 0; @@ -176,15 +112,11 @@ public: bool includeExistsBits = WANT_EXISTS_BITS, OctreeElementPointer destinationElement = NULL, QUuid sourceUUID = QUuid(), - SharedNodePointer sourceNode = SharedNodePointer(), - bool wantImportProgress = false, - PacketVersion bitstreamVersion = 0) : + SharedNodePointer sourceNode = SharedNodePointer()) : includeExistsBits(includeExistsBits), destinationElement(destinationElement), sourceUUID(sourceUUID), - sourceNode(sourceNode), - wantImportProgress(wantImportProgress), - bitstreamVersion(bitstreamVersion) + sourceNode(sourceNode) {} }; @@ -199,7 +131,6 @@ public: // These methods will allow the OctreeServer to send your tree inbound edit packets of your // own definition. Implement these to allow your octree based server to support editing - virtual bool getWantSVOfileVersions() const { return false; } virtual PacketType expectedDataPacketType() const { return PacketType::Unknown; } virtual PacketVersion expectedVersion() const { return versionForPacketType(expectedDataPacketType()); } virtual bool handlesEditPacketType(PacketType packetType) const { return false; } @@ -209,12 +140,8 @@ public: virtual void processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; } virtual void processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; } - virtual bool recurseChildrenWithData() const { return true; } virtual bool rootElementHasData() const { return false; } - virtual int minimumRequiredRootDataBytes() const { return 0; } - virtual bool suppressEmptySubtrees() const { return true; } virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const { } - virtual bool mustIncludeAllChildData() const { return true; } virtual void update() { } // nothing to do by default @@ -223,11 +150,8 @@ public: virtual void eraseAllOctreeElements(bool createNewRoot = true); virtual void readBitstreamToTree(const unsigned char* bitstream, uint64_t bufferSizeBytes, ReadBitstreamToTreeParams& args); - void deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool collapseEmptyTrees = DONT_COLLAPSE); void reaverageOctreeElements(OctreeElementPointer startElement = OctreeElementPointer()); - void deleteOctreeElementAt(float x, float y, float z, float s); - /// Find the voxel at position x,y,z,s /// \return pointer to the OctreeElement or NULL if none at x,y,z,s. OctreeElementPointer getOctreeElementAt(float x, float y, float z, float s) const; @@ -250,8 +174,6 @@ public: void recurseTreeWithOperator(RecurseOctreeOperator* operatorObject); - int encodeTreeBitstream(const OctreeElementPointer& element, OctreePacketData* packetData, OctreeElementBag& bag, - EncodeBitstreamParams& params) ; bool isDirty() const { return _isDirty; } void clearDirtyBit() { _isDirty = false; } @@ -344,22 +266,10 @@ public: void incrementPersistDataVersion() { _persistDataVersion++; } -signals: - void importSize(float x, float y, float z); - void importProgress(int progress); - -public slots: - void cancelImport(); - protected: void deleteOctalCodeFromTreeRecursion(const OctreeElementPointer& element, void* extraData); - int encodeTreeBitstreamRecursion(const OctreeElementPointer& element, - OctreePacketData* packetData, OctreeElementBag& bag, - EncodeBitstreamParams& params, int& currentEncodeLevel, - const ViewFrustum::intersection& parentLocationThisView) const; - static bool countOctreeElementsOperation(const OctreeElementPointer& element, void* extraData); OctreeElementPointer nodeForOctalCode(const OctreeElementPointer& ancestorElement, const unsigned char* needleCode, OctreeElementPointer* parentOfFoundElement) const; @@ -374,7 +284,6 @@ protected: bool _isDirty; bool _shouldReaverage; - bool _stopImport; bool _isViewing; bool _isServer; diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 989951b661..6446e3b460 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -461,33 +461,6 @@ ViewFrustum::intersection OctreeElement::computeViewIntersection(const ViewFrust return viewFrustum.calculateCubeKeyholeIntersection(_cube); } -// There are two types of nodes for which we want to "render" -// 1) Leaves that are in the LOD -// 2) Non-leaves are more complicated though... usually you don't want to render them, but if their children -// wouldn't be rendered, then you do want to render them. But sometimes they have some children that ARE -// in the LOD, and others that are not. In this case we want to render the parent, and none of the children. -// -// Since, if we know the camera position and orientation, we can know which of the corners is the "furthest" -// corner. We can use we can use this corner as our "voxel position" to do our distance calculations off of. -// By doing this, we don't need to test each child voxel's position vs the LOD boundary -bool OctreeElement::calculateShouldRender(const ViewFrustum& viewFrustum, float voxelScaleSize, int boundaryLevelAdjust) const { - bool shouldRender = false; - - if (hasContent()) { - float furthestDistance = furthestDistanceToCamera(viewFrustum); - float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize); - bool inChildBoundary = (furthestDistance <= childBoundary); - if (hasDetailedContent() && inChildBoundary) { - shouldRender = true; - } else { - float boundary = childBoundary * 2.0f; // the boundary is always twice the distance of the child boundary - bool inBoundary = (furthestDistance <= boundary); - shouldRender = inBoundary && !inChildBoundary; - } - } - return shouldRender; -} - // Calculates the distance to the furthest point of the voxel to the camera // does as much math as possible in voxel scale and then scales up to TREE_SCALE at end float OctreeElement::furthestDistanceToCamera(const ViewFrustum& viewFrustum) const { diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 514039713b..b7857c3e6c 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -85,16 +85,6 @@ public: typedef enum { COMPLETED, PARTIAL, NONE } AppendState; virtual void debugExtraEncodeData(EncodeBitstreamParams& params) const { } - virtual void initializeExtraEncodeData(EncodeBitstreamParams& params) { } - virtual bool shouldIncludeChildData(int childIndex, EncodeBitstreamParams& params) const { return true; } - virtual bool shouldRecurseChildTree(int childIndex, EncodeBitstreamParams& params) const { return true; } - - virtual void updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const { } - virtual void elementEncodeComplete(EncodeBitstreamParams& params) const { } - - /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. - virtual AppendState appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const - { return COMPLETED; } /// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading /// from the network. @@ -139,9 +129,6 @@ public: float distanceToCamera(const ViewFrustum& viewFrustum) const; float furthestDistanceToCamera(const ViewFrustum& viewFrustum) const; - bool calculateShouldRender(const ViewFrustum& viewFrustum, - float voxelSizeScale = DEFAULT_OCTREE_SIZE_SCALE, int boundaryLevelAdjust = 0) const; - // points are assumed to be in Voxel Coordinates (not TREE_SCALE'd) float distanceSquareToPoint(const glm::vec3& point) const; // when you don't need the actual distance, use this. float distanceToPoint(const glm::vec3& point) const; diff --git a/libraries/octree/src/OctreeElementBag.cpp b/libraries/octree/src/OctreeElementBag.cpp deleted file mode 100644 index afd2d5cdc3..0000000000 --- a/libraries/octree/src/OctreeElementBag.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// OctreeElementBag.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 4/25/2013. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "OctreeElementBag.h" -#include - -void OctreeElementBag::deleteAll() { - _bagElements = Bag(); -} - -/// does the bag contain elements? -/// if all of the contained elements are expired, they will not report as empty, and -/// a single last item will be returned by extract as a null pointer -bool OctreeElementBag::isEmpty() { - return _bagElements.empty(); -} - -void OctreeElementBag::insert(const OctreeElementPointer& element) { - _bagElements[element.get()] = element; -} - -OctreeElementPointer OctreeElementBag::extract() { - OctreeElementPointer result; - - // Find the first element still alive - Bag::iterator it = _bagElements.begin(); - while (it != _bagElements.end() && !result) { - result = it->second.lock(); - it = _bagElements.erase(it); - } - return result; -} diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index 34c49f1e60..a79648f596 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -16,30 +16,8 @@ #ifndef hifi_OctreeElementBag_h #define hifi_OctreeElementBag_h -#include - #include "OctreeElement.h" -class OctreeElementBag { - using Bag = std::unordered_map; - -public: - void insert(const OctreeElementPointer& element); // put a element into the bag - - OctreeElementPointer extract(); /// pull a element out of the bag (could come in any order) and if all of the - /// elements have expired, a single null pointer will be returned - - bool isEmpty(); /// does the bag contain elements, - /// if all of the contained elements are expired, they will not report as empty, and - /// a single last item will be returned by extract as a null pointer - - void deleteAll(); - size_t size() const { return _bagElements.size(); } - -private: - Bag _bagElements; -}; - class OctreeElementExtraEncodeDataBase { public: OctreeElementExtraEncodeDataBase() {} diff --git a/libraries/octree/src/OctreeProcessor.cpp b/libraries/octree/src/OctreeProcessor.cpp index 65b30dd197..0808e817ed 100644 --- a/libraries/octree/src/OctreeProcessor.cpp +++ b/libraries/octree/src/OctreeProcessor.cpp @@ -117,7 +117,7 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe if (sectionLength) { // ask the VoxelTree to read the bitstream into the tree ReadBitstreamToTreeParams args(WANT_EXISTS_BITS, NULL, - sourceUUID, sourceNode, false, message.getVersion()); + sourceUUID, sourceNode); quint64 startUncompress, startLock = usecTimestampNow(); quint64 startReadBitsteam, endReadBitsteam; // FIXME STUTTER - there may be an opportunity to bump this lock outside of the diff --git a/libraries/octree/src/OctreeQueryNode.cpp b/libraries/octree/src/OctreeQueryNode.cpp index f0c9027493..16542b697e 100644 --- a/libraries/octree/src/OctreeQueryNode.cpp +++ b/libraries/octree/src/OctreeQueryNode.cpp @@ -144,11 +144,6 @@ void OctreeQueryNode::copyCurrentViewFrustum(ViewFrustum& viewOut) const { viewOut = _currentViewFrustum; } -void OctreeQueryNode::copyLastKnownViewFrustum(ViewFrustum& viewOut) const { - QMutexLocker viewLocker(&_viewMutex); - viewOut = _lastKnownViewFrustum; -} - bool OctreeQueryNode::updateCurrentViewFrustum() { // if shutting down, return immediately if (_isShuttingDown) { @@ -229,70 +224,6 @@ void OctreeQueryNode::setViewSent(bool viewSent) { } } -void OctreeQueryNode::updateLastKnownViewFrustum() { - // if shutting down, return immediately - if (_isShuttingDown) { - return; - } - - { - QMutexLocker viewLocker(&_viewMutex); - bool frustumChanges = !_lastKnownViewFrustum.isVerySimilar(_currentViewFrustum); - - if (frustumChanges) { - // save our currentViewFrustum into our lastKnownViewFrustum - _lastKnownViewFrustum = _currentViewFrustum; - } - } - - // save that we know the view has been sent. - setLastTimeBagEmpty(); -} - - -bool OctreeQueryNode::moveShouldDump() const { - // if shutting down, return immediately - if (_isShuttingDown) { - return false; - } - - QMutexLocker viewLocker(&_viewMutex); - glm::vec3 oldPosition = _lastKnownViewFrustum.getPosition(); - glm::vec3 newPosition = _currentViewFrustum.getPosition(); - - // theoretically we could make this slightly larger but relative to avatar scale. - const float MAXIMUM_MOVE_WITHOUT_DUMP = 0.0f; - return glm::distance(newPosition, oldPosition) > MAXIMUM_MOVE_WITHOUT_DUMP; -} - -void OctreeQueryNode::dumpOutOfView() { - // if shutting down, return immediately - if (_isShuttingDown) { - return; - } - - int stillInView = 0; - int outOfView = 0; - OctreeElementBag tempBag; - ViewFrustum viewCopy; - copyCurrentViewFrustum(viewCopy); - while (OctreeElementPointer elementToCheck = elementBag.extract()) { - if (elementToCheck->isInView(viewCopy)) { - tempBag.insert(elementToCheck); - stillInView++; - } else { - outOfView++; - } - } - if (stillInView > 0) { - while (OctreeElementPointer elementToKeepInBag = tempBag.extract()) { - if (elementToKeepInBag->isInView(viewCopy)) { - elementBag.insert(elementToKeepInBag); - } - } - } -} - void OctreeQueryNode::packetSent(const NLPacket& packet) { _sentPacketHistory.packetSent(_sequenceNumber, packet); _sequenceNumber++; diff --git a/libraries/octree/src/OctreeQueryNode.h b/libraries/octree/src/OctreeQueryNode.h index fd89a89949..640a7c7ddc 100644 --- a/libraries/octree/src/OctreeQueryNode.h +++ b/libraries/octree/src/OctreeQueryNode.h @@ -46,23 +46,14 @@ public: bool shouldSuppressDuplicatePacket(); unsigned int getAvailable() const { return _octreePacket->bytesAvailableForWrite(); } - int getMaxSearchLevel() const { return _maxSearchLevel; } - void resetMaxSearchLevel() { _maxSearchLevel = 1; } - void incrementMaxSearchLevel() { _maxSearchLevel++; } - int getMaxLevelReached() const { return _maxLevelReachedInLastSearch; } - void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } - - OctreeElementBag elementBag; OctreeElementExtraEncodeData extraEncodeData; void copyCurrentViewFrustum(ViewFrustum& viewOut) const; - void copyLastKnownViewFrustum(ViewFrustum& viewOut) const; // These are not classic setters because they are calculating and maintaining state // which is set asynchronously through the network receive bool updateCurrentViewFrustum(); - void updateLastKnownViewFrustum(); bool getViewSent() const { return _viewSent; } void setViewSent(bool viewSent); @@ -70,24 +61,13 @@ public: bool getViewFrustumChanging() const { return _viewFrustumChanging; } bool getViewFrustumJustStoppedChanging() const { return _viewFrustumJustStoppedChanging; } - bool moveShouldDump() const; - - quint64 getLastTimeBagEmpty() const { return _lastTimeBagEmpty; } - void setLastTimeBagEmpty() { _lastTimeBagEmpty = _sceneSendStartTime; } - bool hasLodChanged() const { return _lodChanged; } OctreeSceneStats stats; - void dumpOutOfView(); - - quint64 getLastRootTimestamp() const { return _lastRootTimestamp; } - void setLastRootTimestamp(quint64 timestamp) { _lastRootTimestamp = timestamp; } unsigned int getlastOctreePacketLength() const { return _lastOctreePacketLength; } int getDuplicatePacketCount() const { return _duplicatePacketCount; } - void sceneStart(quint64 sceneSendStartTime) { _sceneSendStartTime = sceneSendStartTime; } - void nodeKilled(); bool isShuttingDown() const { return _isShuttingDown; } @@ -118,18 +98,11 @@ private: int _duplicatePacketCount { 0 }; quint64 _firstSuppressedPacket { usecTimestampNow() }; - int _maxSearchLevel { 1 }; - int _maxLevelReachedInLastSearch { 1 }; - mutable QMutex _viewMutex { QMutex::Recursive }; ViewFrustum _currentViewFrustum; - ViewFrustum _lastKnownViewFrustum; - quint64 _lastTimeBagEmpty { 0 }; bool _viewFrustumChanging { false }; bool _viewFrustumJustStoppedChanging { true }; - OctreeSendThread* _octreeSendThread { nullptr }; - // watch for LOD changes int _lastClientBoundaryLevelAdjust { 0 }; float _lastClientOctreeSizeScale { DEFAULT_OCTREE_SIZE_SCALE }; @@ -138,16 +111,12 @@ private: OCTREE_PACKET_SEQUENCE _sequenceNumber { 0 }; - quint64 _lastRootTimestamp { 0 }; - PacketType _myPacketType { PacketType::Unknown }; bool _isShuttingDown { false }; SentPacketHistory _sentPacketHistory; QQueue _nackedSequenceNumbers; - quint64 _sceneSendStartTime = 0; - std::array _lastOctreePayload; QJsonObject _lastCheckJSONParameters; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 054603440d..c4d5e4a915 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -284,10 +284,6 @@ void OctreeSceneStats::didntFit(const OctreeElementPointer& element) { } } -void OctreeSceneStats::colorBitsWritten() { - _colorBitsWritten++; -} - void OctreeSceneStats::existsBitsWritten() { _existsBitsWritten++; } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index 78b4dfd26f..e1228609a6 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -79,9 +79,6 @@ public: /// Track that a element was due to be sent, but didn't fit in the packet and was moved to next packet void didntFit(const OctreeElementPointer& element); - /// Track that the color bitmask was was sent as part of computation of a scene - void colorBitsWritten(); - /// Track that the exists in tree bitmask was was sent as part of computation of a scene void existsBitsWritten(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index ae4338be6f..b1ceab4149 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -248,22 +248,6 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio } } -unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels) { - int codeLength = numberOfThreeBitSectionsInCode(originalOctalCode); - unsigned char* newCode = NULL; - if (codeLength > chopLevels) { - int newLength = codeLength - chopLevels; - newCode = new unsigned char[newLength+1]; - *newCode = newLength; // set the length byte - - for (int section = chopLevels; section < codeLength; section++) { - char sectionValue = getOctalCodeSectionValue(originalOctalCode, section); - setOctalCodeSectionValue(newCode, section - chopLevels, sectionValue); - } - } - return newCode; -} - bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) { if (!possibleAncestor || !possibleDescendent) { return false; diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 89c5e6d74e..63cbc58cfa 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -40,8 +40,6 @@ const int UNKNOWN_OCTCODE_LENGTH = -2; /// \param int maxBytes number of bytes that octalCode is expected to be, -1 if unknown int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes = UNKNOWN_OCTCODE_LENGTH); -unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels); - const int CHECK_NODE_ONLY = -1; bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild = CHECK_NODE_ONLY); diff --git a/tests/entities/src/main.cpp b/tests/entities/src/main.cpp index bf79f9d3e9..43a5d2e48d 100644 --- a/tests/entities/src/main.cpp +++ b/tests/entities/src/main.cpp @@ -160,7 +160,6 @@ int main(int argc, char** argv) { QByteArray packet = file.readAll(); EntityItemPointer item = ShapeEntityItem::boxFactory(EntityItemID(), EntityItemProperties()); ReadBitstreamToTreeParams params; - params.bitstreamVersion = 33; auto start = usecTimestampNow(); for (int i = 0; i < 1000; ++i) {