From 2e5e6e3f618a8a9fcfa5c34811188c9309627dce Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 12 Jun 2014 13:03:37 -0700 Subject: [PATCH] get model props spanning multiple packets --- libraries/models/src/ModelItem.cpp | 284 +++++++++++++++------- libraries/models/src/ModelItem.h | 10 +- libraries/models/src/ModelTree.h | 3 +- libraries/models/src/ModelTreeElement.cpp | 76 ++++-- libraries/models/src/ModelTreeElement.h | 2 +- tests/octree/src/OctreeTests.cpp | 14 +- 6 files changed, 268 insertions(+), 121 deletions(-) diff --git a/libraries/models/src/ModelItem.cpp b/libraries/models/src/ModelItem.cpp index ca93803899..6a924d2b5c 100644 --- a/libraries/models/src/ModelItem.cpp +++ b/libraries/models/src/ModelItem.cpp @@ -132,7 +132,7 @@ void ModelItem::init(glm::vec3 position, float radius, rgbColor color, uint32_t _lastAnimated = now; } -OctreeElement::AppendState ModelItem::appendModelData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { +OctreeElement::AppendState ModelItem::oldVersionAppendModelData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { bool success = packetData->appendValue(getID()); @@ -196,7 +196,8 @@ OctreeElement::AppendState ModelItem::appendModelData(OctreePacketData* packetDa return success ? OctreeElement::COMPLETED : OctreeElement::NONE; } -OctreeElement::AppendState ModelItem::new___appendModelData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { +OctreeElement::AppendState ModelItem::appendModelData(OctreePacketData* packetData, EncodeBitstreamParams& params, + ModelTreeElementExtraEncodeData* modelTreeElementExtraEncodeData) const { // ALL this fits... // object ID [16 bytes] @@ -212,6 +213,29 @@ OctreeElement::AppendState ModelItem::new___appendModelData(OctreePacketData* pa ByteCountCoded updateDeltaCoder = updateDelta; QByteArray encodedUpdateDelta = updateDeltaCoder; ModelPropertyFlags propertyFlags(PROP_LAST_ITEM); + ModelPropertyFlags requestedProperties; + + requestedProperties += PROP_POSITION; + requestedProperties += PROP_RADIUS; + requestedProperties += PROP_MODEL_URL; + requestedProperties += PROP_ROTATION; + requestedProperties += PROP_COLOR; + requestedProperties += PROP_ANIMATION_URL; + requestedProperties += PROP_ANIMATION_FPS; + requestedProperties += PROP_ANIMATION_FRAME_INDEX; + requestedProperties += PROP_ANIMATION_PLAYING; + requestedProperties += PROP_SHOULD_BE_DELETED; + + ModelPropertyFlags propertiesDidntFit = requestedProperties; + + // If we are being called for a subsequent pass at appendModelData() that failed to completely encode this item, + // then our modelTreeElementExtraEncodeData should include data about which properties we need to append. + if (modelTreeElementExtraEncodeData && modelTreeElementExtraEncodeData->includedItems.contains(getModelItemID())) { + requestedProperties = modelTreeElementExtraEncodeData->includedItems.value(getModelItemID()); + } + + //qDebug() << "requestedProperties="; + //requestedProperties.debugDumpBits(); LevelDetails modelLevel = packetData->startLevel(); @@ -242,126 +266,206 @@ OctreeElement::AppendState ModelItem::new___appendModelData(OctreePacketData* pa // PROP_VISIBLE, // PROP_POSITION - LevelDetails propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendPosition(getPosition()); - if (successPropertyFits) { - propertyFlags |= PROP_POSITION; - propertyCount++; - packetData->endLevel(propertyLevel); + if (requestedProperties.getHasProperty(PROP_POSITION)) { + //qDebug() << "PROP_POSITION requested..."; + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = packetData->appendPosition(getPosition()); + if (successPropertyFits) { + propertyFlags |= PROP_POSITION; + propertiesDidntFit -= PROP_POSITION; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + //qDebug() << "PROP_POSITION didn't fit..."; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; + //qDebug() << "PROP_POSITION NOT requested..."; + propertiesDidntFit -= PROP_POSITION; } // PROP_RADIUS - propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendValue(getRadius()); - if (successPropertyFits) { - propertyFlags |= PROP_RADIUS; - propertyCount++; - packetData->endLevel(propertyLevel); + if (requestedProperties.getHasProperty(PROP_RADIUS)) { + //qDebug() << "PROP_RADIUS requested..."; + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = packetData->appendValue(getRadius()); + if (successPropertyFits) { + propertyFlags |= PROP_RADIUS; + propertiesDidntFit -= PROP_RADIUS; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + //qDebug() << "PROP_RADIUS didn't fit..."; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; + //qDebug() << "PROP_RADIUS NOT requested..."; + propertiesDidntFit -= PROP_RADIUS; } // PROP_MODEL_URL - propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendValue(getModelURL()); - if (successPropertyFits) { - propertyFlags |= PROP_MODEL_URL; - propertyCount++; - packetData->endLevel(propertyLevel); + if (requestedProperties.getHasProperty(PROP_MODEL_URL)) { + //qDebug() << "PROP_MODEL_URL requested..."; + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = packetData->appendValue(getModelURL()); + if (successPropertyFits) { + propertyFlags |= PROP_MODEL_URL; + propertiesDidntFit -= PROP_MODEL_URL; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + //qDebug() << "PROP_MODEL_URL didn't fit..."; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; + //qDebug() << "PROP_MODEL_URL NOT requested..."; + propertiesDidntFit -= PROP_MODEL_URL; } // PROP_ROTATION - propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendValue(getModelRotation()); - if (successPropertyFits) { - propertyFlags |= PROP_ROTATION; - propertyCount++; - packetData->endLevel(propertyLevel); + if (requestedProperties.getHasProperty(PROP_ROTATION)) { + //qDebug() << "PROP_ROTATION requested..."; + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = packetData->appendValue(getModelRotation()); + if (successPropertyFits) { + propertyFlags |= PROP_ROTATION; + propertiesDidntFit -= PROP_ROTATION; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + //qDebug() << "PROP_ROTATION didn't fit..."; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; + //qDebug() << "PROP_ROTATION NOT requested..."; + propertiesDidntFit -= PROP_ROTATION; } // PROP_COLOR - propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendColor(getColor()); - if (successPropertyFits) { - propertyFlags |= PROP_COLOR; - propertyCount++; - packetData->endLevel(propertyLevel); + if (requestedProperties.getHasProperty(PROP_COLOR)) { + //qDebug() << "PROP_COLOR requested..."; + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = packetData->appendColor(getColor()); + if (successPropertyFits) { + propertyFlags |= PROP_COLOR; + propertiesDidntFit -= PROP_COLOR; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + //qDebug() << "PROP_COLOR didn't fit..."; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; + //qDebug() << "PROP_COLOR NOT requested..."; + propertiesDidntFit -= PROP_COLOR; } // PROP_SCRIPT // script would go here... // PROP_ANIMATION_URL - propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendValue(getAnimationURL()); - if (successPropertyFits) { - propertyFlags |= PROP_ANIMATION_URL; - propertyCount++; - packetData->endLevel(propertyLevel); + if (requestedProperties.getHasProperty(PROP_ANIMATION_URL)) { + //qDebug() << "PROP_ANIMATION_URL requested..."; + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = packetData->appendValue(getAnimationURL()); + if (successPropertyFits) { + propertyFlags |= PROP_ANIMATION_URL; + propertiesDidntFit -= PROP_ANIMATION_URL; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + //qDebug() << "PROP_ANIMATION_URL didn't fit..."; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; + //qDebug() << "PROP_ANIMATION_URL NOT requested..."; + propertiesDidntFit -= PROP_ANIMATION_URL; } // PROP_ANIMATION_FPS - propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendValue(getAnimationFPS()); - if (successPropertyFits) { - propertyFlags |= PROP_ANIMATION_FPS; - propertyCount++; - packetData->endLevel(propertyLevel); + if (requestedProperties.getHasProperty(PROP_ANIMATION_FPS)) { + //qDebug() << "PROP_ANIMATION_FPS requested..."; + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = packetData->appendValue(getAnimationFPS()); + if (successPropertyFits) { + propertyFlags |= PROP_ANIMATION_FPS; + propertiesDidntFit -= PROP_ANIMATION_FPS; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + //qDebug() << "PROP_ANIMATION_FPS didn't fit..."; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; + //qDebug() << "PROP_ANIMATION_FPS NOT requested..."; + propertiesDidntFit -= PROP_ANIMATION_FPS; } // PROP_ANIMATION_FRAME_INDEX - propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendValue(getAnimationFrameIndex()); - if (successPropertyFits) { - propertyFlags |= PROP_ANIMATION_FRAME_INDEX; - propertyCount++; - packetData->endLevel(propertyLevel); + if (requestedProperties.getHasProperty(PROP_ANIMATION_FRAME_INDEX)) { + //qDebug() << "PROP_ANIMATION_FRAME_INDEX requested..."; + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = packetData->appendValue(getAnimationFrameIndex()); + if (successPropertyFits) { + propertyFlags |= PROP_ANIMATION_FRAME_INDEX; + propertiesDidntFit -= PROP_ANIMATION_FRAME_INDEX; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + //qDebug() << "PROP_ANIMATION_FRAME_INDEX didn't fit..."; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; + //qDebug() << "PROP_ANIMATION_FRAME_INDEX NOT requested..."; + propertiesDidntFit -= PROP_ANIMATION_FRAME_INDEX; } // PROP_ANIMATION_PLAYING - propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendValue(getAnimationIsPlaying()); - if (successPropertyFits) { - propertyFlags |= PROP_ANIMATION_PLAYING; - propertyCount++; - packetData->endLevel(propertyLevel); + if (requestedProperties.getHasProperty(PROP_ANIMATION_PLAYING)) { + //qDebug() << "PROP_ANIMATION_PLAYING requested..."; + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = packetData->appendValue(getAnimationIsPlaying()); + if (successPropertyFits) { + propertyFlags |= PROP_ANIMATION_PLAYING; + propertiesDidntFit -= PROP_ANIMATION_PLAYING; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + //qDebug() << "PROP_ANIMATION_PLAYING didn't fit..."; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; + //qDebug() << "PROP_ANIMATION_PLAYING NOT requested..."; + propertiesDidntFit -= PROP_ANIMATION_PLAYING; } // PROP_SHOULD_BE_DELETED - propertyLevel = packetData->startLevel(); - successPropertyFits = packetData->appendValue(getShouldDie()); - if (successPropertyFits) { - propertyFlags |= PROP_SHOULD_BE_DELETED; - propertyCount++; - packetData->endLevel(propertyLevel); + if (requestedProperties.getHasProperty(PROP_SHOULD_BE_DELETED)) { + //qDebug() << "PROP_SHOULD_BE_DELETED requested..."; + LevelDetails propertyLevel = packetData->startLevel(); + successPropertyFits = packetData->appendValue(getShouldDie()); + if (successPropertyFits) { + propertyFlags |= PROP_SHOULD_BE_DELETED; + propertiesDidntFit -= PROP_SHOULD_BE_DELETED; + propertyCount++; + packetData->endLevel(propertyLevel); + } else { + //qDebug() << "PROP_SHOULD_BE_DELETED didn't fit..."; + packetData->discardLevel(propertyLevel); + appendState = OctreeElement::PARTIAL; + } } else { - packetData->discardLevel(propertyLevel); - appendState = OctreeElement::PARTIAL; + //qDebug() << "PROP_SHOULD_BE_DELETED NOT requested..."; + propertiesDidntFit -= PROP_SHOULD_BE_DELETED; } } if (propertyCount > 0) { @@ -393,6 +497,18 @@ OctreeElement::AppendState ModelItem::new___appendModelData(OctreePacketData* pa packetData->discardLevel(modelLevel); appendState = OctreeElement::NONE; // if we got here, then we didn't include the item } + + //qDebug() << "propertyFlags="; + //propertyFlags.debugDumpBits(); + + //qDebug() << "propertiesDidntFit="; + //propertiesDidntFit.debugDumpBits(); + + // If any part of the model items didn't fit, then the element is considered partial + if (appendState != OctreeElement::COMPLETED) { + // add this item into our list for the next appendElementData() pass + modelTreeElementExtraEncodeData->includedItems.insert(getModelItemID(), propertiesDidntFit); + } return appendState; } @@ -409,7 +525,7 @@ int ModelItem::expectedBytes() { return expectedBytes; } -int ModelItem::readModelDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { +int ModelItem::oldVersionReadModelDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { int bytesRead = 0; if (bytesLeftToRead >= expectedBytes()) { @@ -499,7 +615,7 @@ int ModelItem::readModelDataFromBuffer(const unsigned char* data, int bytesLeftT return bytesRead; } -int ModelItem::new___readModelDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { +int ModelItem::readModelDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { // TODO: handle old format?? //if (args.bitstreamVersion >= VERSION_MODELS_HAVE_ANIMATION) { diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 3fa8a0659f..c25d1c1aa2 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -29,6 +29,7 @@ class ModelEditPacketSender; class ModelItemProperties; class ModelsScriptingInterface; class ModelTree; +class ModelTreeElementExtraEncodeData; class ScriptEngine; class VoxelEditPacketSender; class VoxelsScriptingInterface; @@ -286,11 +287,12 @@ public: void setProperties(const ModelItemProperties& properties); - OctreeElement::AppendState new___appendModelData(OctreePacketData* packetData, EncodeBitstreamParams& params) const; - int new___readModelDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); - - OctreeElement::AppendState appendModelData(OctreePacketData* packetData, EncodeBitstreamParams& params) const; + OctreeElement::AppendState appendModelData(OctreePacketData* packetData, EncodeBitstreamParams& params, + ModelTreeElementExtraEncodeData* modelTreeElementExtraEncodeData) const; int readModelDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); + + OctreeElement::AppendState oldVersionAppendModelData(OctreePacketData* packetData, EncodeBitstreamParams& params) const; + int oldVersionReadModelDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); static int expectedBytes(); static bool encodeModelEditMessageDetails(PacketType command, ModelItemID id, const ModelItemProperties& details, diff --git a/libraries/models/src/ModelTree.h b/libraries/models/src/ModelTree.h index a2a3c9cd28..f8b982ab0d 100644 --- a/libraries/models/src/ModelTree.h +++ b/libraries/models/src/ModelTree.h @@ -74,7 +74,8 @@ public: bool hasAnyDeletedModels() const { return _recentlyDeletedModelItemIDs.size() > 0; } bool hasModelsDeletedSince(quint64 sinceTime); - bool encodeModelsDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime, unsigned char* packetData, size_t maxLength, size_t& outputLength); + bool encodeModelsDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime, + unsigned char* packetData, size_t maxLength, size_t& outputLength); void forgetModelsDeletedBefore(quint64 sinceTime); void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index bcfd101dd1..12eeccfb12 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -56,14 +56,19 @@ ModelTreeElement* ModelTreeElement::addChildAtIndex(int index) { // contents across multiple packets. OctreeElement::AppendState ModelTreeElement::appendElementData(OctreePacketData* packetData, 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; + ModelTreeElementExtraEncodeData* modelTreeElementExtraEncodeData = NULL; + bool hadElementExtraData = false; if (extraEncodeData && extraEncodeData->contains(this)) { - elementExtraEncodeData = static_cast(extraEncodeData->value(this)); + modelTreeElementExtraEncodeData = static_cast(extraEncodeData->value(this)); + hadElementExtraData = true; + } else { + // if there wasn't one already, then create one + modelTreeElementExtraEncodeData = new ModelTreeElementExtraEncodeData(); } LevelDetails elementLevel = packetData->startLevel(); @@ -77,11 +82,8 @@ OctreeElement::AppendState ModelTreeElement::appendElementData(OctreePacketData* 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 (hadElementExtraData) { + includeThisModel = modelTreeElementExtraEncodeData->includedItems.contains(model.getModelItemID()); } if (includeThisModel && params.viewFrustum) { @@ -107,7 +109,7 @@ OctreeElement::AppendState ModelTreeElement::appendElementData(OctreePacketData* LevelDetails modelLevel = packetData->startLevel(); - OctreeElement::AppendState appendModelState = model.appendModelData(packetData, params); + OctreeElement::AppendState appendModelState = model.appendModelData(packetData, params, modelTreeElementExtraEncodeData); // If none of this model data was able to be appended, then discard it // and don't include it in our model count @@ -119,33 +121,33 @@ OctreeElement::AppendState ModelTreeElement::appendElementData(OctreePacketData* packetData->endLevel(modelLevel); actualNumberOfModels++; } + + // If the model item got completely appended, then we can remove it from the extra encode data + if (appendModelState == OctreeElement::COMPLETED) { + modelTreeElementExtraEncodeData->includedItems.remove(model.getModelItemID()); + } // If any part of the model items didn't fit, then the element is considered partial + // NOTE: if the model item didn't fit or only partially fit, then the model item should have + // added itself to the extra encode data. 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 we were provided with extraEncodeData, and we allocated and/or got modelTreeElementExtraEncodeData + // then we need to do some additional processing, namely make sure our extraEncodeData is up to date for + // this octree element. + if (extraEncodeData && modelTreeElementExtraEncodeData) { // 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); + if (modelTreeElementExtraEncodeData->includedItems.size()) { + extraEncodeData->insert(this, modelTreeElementExtraEncodeData); } else { // otherwise, clean things up... extraEncodeData->remove(this); - delete elementExtraEncodeData; + delete modelTreeElementExtraEncodeData; } } @@ -343,16 +345,22 @@ bool ModelTreeElement::findSpherePenetration(const glm::vec3& center, float radi } bool ModelTreeElement::updateModel(const ModelItem& model) { + const bool wantDebug = false; + if (wantDebug) { + ModelItemID modelItemID = model.getModelItemID(); + qDebug() << "ModelTreeElement::updateModel(model) modelID.id=" + << modelItemID.id << "creatorTokenID=" << modelItemID.creatorTokenID; + } + // NOTE: this method must first lookup the model by ID, hence it is O(N) // and "model is not found" is worst-case (full N) but maybe we don't care? // (guaranteed that num models per elemen is small?) - const bool wantDebug = false; uint16_t numberOfModels = _modelItems->size(); for (uint16_t i = 0; i < numberOfModels; i++) { ModelItem& thisModel = (*_modelItems)[i]; if (thisModel.getID() == model.getID()) { int difference = thisModel.getLastUpdated() - model.getLastUpdated(); - bool changedOnServer = thisModel.getLastEdited() < model.getLastEdited(); + bool changedOnServer = thisModel.getLastEdited() <= model.getLastEdited(); bool localOlder = thisModel.getLastUpdated() < model.getLastUpdated(); if (changedOnServer || localOlder) { if (wantDebug) { @@ -506,6 +514,8 @@ bool ModelTreeElement::removeModelWithID(uint32_t id) { int ModelTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { + + const bool wantDebugging = false; // If we're the root, but this bitstream doesn't support root elements with data, then // return without reading any bytes @@ -532,6 +542,22 @@ int ModelTreeElement::readElementDataFromBuffer(const unsigned char* data, int b for (uint16_t i = 0; i < numberOfModels; i++) { ModelItem tempModel; int bytesForThisModel = tempModel.readModelDataFromBuffer(dataAt, bytesLeftToRead, args); + + if (wantDebugging) { + ModelItemID modelItemID = tempModel.getModelItemID(); + qDebug() << "ModelTreeElement::readElementDataFromBuffer()... tempModel.modelItemID.id=" + << modelItemID.id << "creatorTokenID=" << modelItemID.creatorTokenID; + } + + const ModelItem* existingModelItem = _myTree->findModelByID(modelItemID.id, true); + if (existingModelItem) { + //qDebug() << "ModelTreeElement::readElementDataFromBuffer()... model item already exists..."; + tempModel.copyChangedProperties(*existingModelItem); // copy original properties... + bytesForThisModel = tempModel.readModelDataFromBuffer(dataAt, bytesLeftToRead, args); // reread only the changed properties + } + + //qDebug() << "ModelTreeElement::readElementDataFromBuffer()... _myTree->storeModel(tempModel)"; + _myTree->storeModel(tempModel); dataAt += bytesForThisModel; bytesLeftToRead -= bytesForThisModel; diff --git a/libraries/models/src/ModelTreeElement.h b/libraries/models/src/ModelTreeElement.h index 63db7ac4e3..86e000efb3 100644 --- a/libraries/models/src/ModelTreeElement.h +++ b/libraries/models/src/ModelTreeElement.h @@ -47,7 +47,7 @@ public: class ModelTreeElementExtraEncodeData { public: - QMap includedItems; // for now, bool, soon ModelPropertyFlags + QMap includedItems; // for now, bool, soon ModelPropertyFlags }; diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index 96df55ad5c..4f829ddb70 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -16,6 +16,8 @@ #include #include +#include +#include #include #include #include @@ -1270,7 +1272,7 @@ void OctreeTests::byteCountCodingTests(bool verbose) { void OctreeTests::modelItemTests(bool verbose) { //verbose = true; - + ModelTreeElementExtraEncodeData modelTreeElementExtraEncodeData; int testsTaken = 0; int testsPassed = 0; int testsFailed = 0; @@ -1288,7 +1290,7 @@ void OctreeTests::modelItemTests(bool verbose) { modelItem.setID(1042); modelItem.setModelURL("http://foo.com/foo.fbx"); - bool appendResult = modelItem.new___appendModelData(&packetData, params); + bool appendResult = modelItem.appendModelData(&packetData, params, &modelTreeElementExtraEncodeData); int bytesWritten = packetData.getUncompressedSize(); if (verbose) { qDebug() << "Test 1: bytesRead == bytesWritten ..."; @@ -1302,7 +1304,7 @@ void OctreeTests::modelItemTests(bool verbose) { const unsigned char* data = packetData.getUncompressedData(); int bytesLeftToRead = packetData.getUncompressedSize(); - int bytesRead = modelItemFromBuffer.new___readModelDataFromBuffer(data, bytesLeftToRead, args); + int bytesRead = modelItemFromBuffer.readModelDataFromBuffer(data, bytesLeftToRead, args); if (verbose) { qDebug() << "bytesRead=" << bytesRead; qDebug() << "modelItemFromBuffer.getID()=" << modelItemFromBuffer.getID(); @@ -1343,7 +1345,7 @@ void OctreeTests::modelItemTests(bool verbose) { QByteArray garbageData(almostFullOfData, 0); packetData.appendValue(garbageData); - appendResult = modelItem.new___appendModelData(&packetData, params); + appendResult = modelItem.appendModelData(&packetData, params, &modelTreeElementExtraEncodeData); bytesWritten = packetData.getUncompressedSize() - almostFullOfData; if (verbose) { qDebug() << "Test 3: attempt to appendModelData in nearly full packetData ..."; @@ -1370,7 +1372,7 @@ void OctreeTests::modelItemTests(bool verbose) { QByteArray garbageData(almostFullOfData, 0); packetData.appendValue(garbageData); - appendResult = modelItem.new___appendModelData(&packetData, params); + appendResult = modelItem.appendModelData(&packetData, params, &modelTreeElementExtraEncodeData); bytesWritten = packetData.getUncompressedSize() - almostFullOfData; if (verbose) { qDebug() << "Test 4: attempt to appendModelData in nearly full packetData which some should fit ..."; @@ -1392,7 +1394,7 @@ void OctreeTests::modelItemTests(bool verbose) { const unsigned char* data = packetData.getUncompressedData() + almostFullOfData; int bytesLeftToRead = packetData.getUncompressedSize() - almostFullOfData; - int bytesRead = modelItemFromBuffer.new___readModelDataFromBuffer(data, bytesLeftToRead, args); + int bytesRead = modelItemFromBuffer.readModelDataFromBuffer(data, bytesLeftToRead, args); if (verbose) { qDebug() << "Test 5: partial ModelItem written ... bytesRead == bytesWritten..."; qDebug() << "bytesRead=" << bytesRead;