first cut at really using partial appendElementData to make models span packets. still needs work

This commit is contained in:
ZappoMan 2014-06-10 16:51:49 -07:00
parent 66b0333dc9
commit 6389fea320
5 changed files with 88 additions and 10 deletions

View file

@ -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<ModelItemID>);
QScriptValue ModelItemIDtoScriptValue(QScriptEngine* engine, const ModelItemID& properties);

View file

@ -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<ModelTreeElementExtraEncodeData*>(extraEncodeData->value(this));
}
LevelDetails elementLevel = packetData->startLevel();
@ -67,15 +74,25 @@ OctreeElement::AppendState ModelTreeElement::appendElementData(OctreePacketData*
QVector<uint16_t> 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) {

View file

@ -45,6 +45,11 @@ public:
};
class ModelTreeElementExtraEncodeData {
public:
QMap<ModelItemID, bool> includedItems; // for now, bool, soon ModelPropertyFlags
};
class ModelTreeElement : public OctreeElement {
friend class ModelTree; // to allow createElement to new us...

View file

@ -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;

View file

@ -41,6 +41,6 @@ private:
bool _hooked;
};
typedef QMap<OctreeElement*,void*> OctreeElementExtraEncodeData;
typedef QMap<const OctreeElement*,void*> OctreeElementExtraEncodeData;
#endif // hifi_OctreeElementBag_h