From 6389fea320cea95b1a2b3d3ccb4ae443a759887f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 10 Jun 2014 16:51:49 -0700 Subject: [PATCH] first cut at really using partial appendElementData to make models span packets. still needs work --- libraries/models/src/ModelItem.h | 4 ++ libraries/models/src/ModelTreeElement.cpp | 51 ++++++++++++++++++++--- libraries/models/src/ModelTreeElement.h | 5 +++ libraries/octree/src/Octree.cpp | 36 ++++++++++++++-- libraries/octree/src/OctreeElementBag.h | 2 +- 5 files changed, 88 insertions(+), 10 deletions(-) diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 662c89c558..3fa8a0659f 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -188,6 +188,10 @@ public: bool isKnownID; }; +inline bool operator<(const ModelItemID& a, const ModelItemID& b) { + return (a.id == b.id) ? (a.creatorTokenID < b.creatorTokenID) : (a.id < b.id); +} + Q_DECLARE_METATYPE(ModelItemID); Q_DECLARE_METATYPE(QVector); QScriptValue ModelItemIDtoScriptValue(QScriptEngine* engine, const ModelItemID& properties); diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index a5c1c373ab..eac174e3b4 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -58,6 +58,13 @@ OctreeElement::AppendState ModelTreeElement::appendElementData(OctreePacketData* EncodeBitstreamParams& params) const { OctreeElement::AppendState appendElementState = OctreeElement::COMPLETED; // assume the best... + + // first, check the params.extraEncodeData to see if there's any partial re-encode data for this element + OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData; + ModelTreeElementExtraEncodeData* elementExtraEncodeData = NULL; + if (extraEncodeData && extraEncodeData->contains(this)) { + elementExtraEncodeData = static_cast(extraEncodeData->value(this)); + } LevelDetails elementLevel = packetData->startLevel(); @@ -67,15 +74,25 @@ OctreeElement::AppendState ModelTreeElement::appendElementData(OctreePacketData* QVector indexesOfModelsToInclude; for (uint16_t i = 0; i < _modelItems->size(); i++) { - if (params.viewFrustum) { - const ModelItem& model = (*_modelItems)[i]; + const ModelItem& model = (*_modelItems)[i]; + bool includeThisModel = true; + + if (elementExtraEncodeData) { + includeThisModel = elementExtraEncodeData->includedItems.contains(model.getModelItemID()); + if (includeThisModel) { + elementExtraEncodeData->includedItems.remove(model.getModelItemID()); // remove it + } + } + + if (includeThisModel && params.viewFrustum) { AACube modelCube = model.getAACube(); modelCube.scale(TREE_SCALE); - if (params.viewFrustum->cubeInFrustum(modelCube) != ViewFrustum::OUTSIDE) { - indexesOfModelsToInclude << i; - numberOfModels++; + if (params.viewFrustum->cubeInFrustum(modelCube) == ViewFrustum::OUTSIDE) { + includeThisModel = false; // out of view, don't include it } - } else { + } + + if (includeThisModel) { indexesOfModelsToInclude << i; numberOfModels++; } @@ -106,10 +123,32 @@ OctreeElement::AppendState ModelTreeElement::appendElementData(OctreePacketData* // If any part of the model items didn't fit, then the element is considered partial if (appendModelState != OctreeElement::COMPLETED) { appendElementState = OctreeElement::PARTIAL; + + // add this item into our list for the next appendElementData() pass + if (extraEncodeData) { + if (!elementExtraEncodeData) { + elementExtraEncodeData = new ModelTreeElementExtraEncodeData(); + } + elementExtraEncodeData->includedItems.insert(model.getModelItemID(), true); + } } } } + // If we were provided with extraEncodeData, and we allocated and/or got elementExtraEncodeData + // then we need to do some additional processing + if (extraEncodeData && elementExtraEncodeData) { + + // If after processing we have some includedItems left in it, then make sure we re-add it back to our map + if (elementExtraEncodeData->includedItems.size()) { + extraEncodeData->insert(this, elementExtraEncodeData); + } else { + // otherwise, clean things up... + extraEncodeData->remove(this); + delete elementExtraEncodeData; + } + } + // If we wrote fewer models than we expected, update the number of models in our packet bool successUpdateModelCount = true; if (numberOfModels != actualNumberOfModels) { diff --git a/libraries/models/src/ModelTreeElement.h b/libraries/models/src/ModelTreeElement.h index a8c8b38572..63db7ac4e3 100644 --- a/libraries/models/src/ModelTreeElement.h +++ b/libraries/models/src/ModelTreeElement.h @@ -45,6 +45,11 @@ public: }; +class ModelTreeElementExtraEncodeData { +public: + QMap includedItems; // for now, bool, soon ModelPropertyFlags +}; + class ModelTreeElement : public OctreeElement { friend class ModelTree; // to allow createElement to new us... diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 27835a7bf4..a066447073 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -988,6 +988,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, OctreePacketData* packetData, OctreeElementBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel, const ViewFrustum::location& parentLocationThisView) const { + + // 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; @@ -1350,8 +1354,23 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // 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. In the case that an element was partially written, we need to - OctreeElement::AppendState appendState = childElement->appendElementData(packetData, params); - continueThisLevel = (appendState == OctreeElement::COMPLETED); + + + OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); + + // Continue this level so long as some part of this child element was appended. + // TODO: consider if we want to also keep going in the child append state was NONE... to do this + // we'd need to make sure the appendElementData didn't accidentally add bad partial data, we'd + // also want to remove the child exists bit flag from the packet. I tried this quickly with voxels + // and got some bad data including bad colors and some errors in recursing the tree, so clearly there's + // more to it than that. This current implementation is slightly less efficient, because it could + // be that one child element didn't fit but theoretically others could. + continueThisLevel = (childAppendState != OctreeElement::NONE); + + // If this child was partially appended, then consider this element to be partially appended + if (childAppendState == OctreeElement::PARTIAL) { + elementAppendState = OctreeElement::PARTIAL; + } int bytesAfterChild = packetData->getUncompressedSize(); @@ -1362,7 +1381,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, 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 (params.stats) { + if (params.stats && (childAppendState != OctreeElement::NONE)) { params.stats->colorSent(childElement); } } @@ -1571,6 +1590,17 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* 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) { + qDebug() << "elementAppendState == OctreeElement::PARTIAL... bag.insert(element)....."; + bag.insert(element); + } } return bytesAtThisLevel; diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index 9020b0e6c6..1b74f507c6 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -41,6 +41,6 @@ private: bool _hooked; }; -typedef QMap OctreeElementExtraEncodeData; +typedef QMap OctreeElementExtraEncodeData; #endif // hifi_OctreeElementBag_h