diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index fbc7f0d110..afdc0c923f 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -1274,25 +1274,37 @@ void SpannerSetAttribute::writeMetavoxelRoot(const MetavoxelNode& root, Metavoxe void SpannerSetAttribute::readMetavoxelDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) { - forever { - SharedObjectPointer object; - state.base.stream >> object; - if (!object) { - break; + readMetavoxelSubdivision(data, state); +} + +static void writeDeltaSubdivision(SharedObjectSet& oldSet, SharedObjectSet& newSet, Bitstream& stream) { + for (SharedObjectSet::iterator newIt = newSet.begin(); newIt != newSet.end(); ) { + SharedObjectSet::iterator oldIt = oldSet.find(*newIt); + if (oldIt == oldSet.end()) { + stream << *newIt; // added + newIt = newSet.erase(newIt); + + } else { + oldSet.erase(oldIt); + newIt++; } - data.toggle(state.base.attribute, object); } - // even if the root is empty, it should still exist - if (!data.getRoot(state.base.attribute)) { - data.createRoot(state.base.attribute); + foreach (const SharedObjectPointer& object, oldSet) { + stream << object; // removed } + stream << SharedObjectPointer(); + foreach (const SharedObjectPointer& object, newSet) { + object->maybeWriteSubdivision(stream); + } + stream << SharedObjectPointer(); } void SpannerSetAttribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) { - state.base.visit = Spanner::getAndIncrementNextVisit(); - root.writeSpannerDelta(reference, state); - state.base.stream << SharedObjectPointer(); + SharedObjectSet oldSet, newSet; + reference.getSpanners(this, state.minimum, state.size, state.base.referenceLOD, oldSet); + root.getSpanners(this, state.minimum, state.size, state.base.lod, newSet); + writeDeltaSubdivision(oldSet, newSet, state.base.stream); } void SpannerSetAttribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { @@ -1302,14 +1314,31 @@ void SpannerSetAttribute::readMetavoxelSubdivision(MetavoxelData& data, Metavoxe if (!object) { break; } - data.insert(state.base.attribute, object); + data.toggle(state.base.attribute, object); + } + forever { + SharedObjectPointer object; + state.base.stream >> object; + if (!object) { + break; + } + SharedObjectPointer newObject = object->readSubdivision(state.base.stream); + if (newObject != object) { + data.replace(state.base.attribute, object, newObject); + state.base.stream.addSubdividedObject(newObject); + } + } + // even if the root is empty, it should still exist + if (!data.getRoot(state.base.attribute)) { + data.createRoot(state.base.attribute); } } void SpannerSetAttribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { - state.base.visit = Spanner::getAndIncrementNextVisit(); - root.writeSpannerSubdivision(state); - state.base.stream << SharedObjectPointer(); + SharedObjectSet oldSet, newSet; + root.getSpanners(this, state.minimum, state.size, state.base.referenceLOD, oldSet); + root.getSpanners(this, state.minimum, state.size, state.base.lod, newSet); + writeDeltaSubdivision(oldSet, newSet, state.base.stream); } bool SpannerSetAttribute::metavoxelRootsEqual(const MetavoxelNode& firstRoot, const MetavoxelNode& secondRoot, diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index e4af43feee..c3bd05d3c7 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -267,7 +267,9 @@ Bitstream::ReadMappings Bitstream::getAndResetReadMappings() { _typeStreamerStreamer.getAndResetTransientValues(), _attributeStreamer.getAndResetTransientValues(), _scriptStringStreamer.getAndResetTransientValues(), - _sharedObjectStreamer.getAndResetTransientValues() }; + _sharedObjectStreamer.getAndResetTransientValues(), + _subdividedObjects }; + _subdividedObjects.clear(); return mappings; } @@ -291,6 +293,16 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) { reference = it.value(); _weakSharedObjectHash.remove(it.value()->getRemoteID()); } + foreach (const SharedObjectPointer& object, mappings.subdividedObjects) { + QPointer& reference = _sharedObjectReferences[object->getRemoteOriginID()]; + if (reference && reference != object) { + int id = _sharedObjectStreamer.removePersistentValue(reference.data()); + if (id != 0) { + _sharedObjectStreamer.insertPersistentValue(id, object); + } + } + reference = object; + } } void Bitstream::persistAndResetReadMappings() { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index e5aa30fac5..121aa6c672 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -99,10 +99,12 @@ public: int takePersistentID(P value) { return _persistentIDs.take(value); } - void removePersistentValue(V value) { int id = _valueIDs.take(value); _persistentValues.remove(id); } + int removePersistentValue(V value) { int id = _valueIDs.take(value); _persistentValues.remove(id); return id; } V takePersistentValue(int id) { V value = _persistentValues.take(id); _valueIDs.remove(value); return value; } + void insertPersistentValue(int id, V value) { _valueIDs.insert(value, id); _persistentValues.insert(id, value); } + void copyPersistentMappings(const RepeatedValueStreamer& other); void clearPersistentMappings(); @@ -289,6 +291,7 @@ public: QHash attributeValues; QHash scriptStringValues; QHash sharedObjectValues; + QVector subdividedObjects; }; /// Performs all of the various lazily initializations (of object streamers, etc.) If multiple threads need to use @@ -374,6 +377,9 @@ public: /// Resets to the initial state. void reset(); + /// Adds a subdivided object, which will be added to the read mappings and used as a reference if persisted. + void addSubdividedObject(const SharedObjectPointer& object) { _subdividedObjects.append(object); } + /// Returns the set of transient mappings gathered during writing and resets them. WriteMappings getAndResetWriteMappings(); @@ -576,6 +582,8 @@ private: RepeatedValueStreamer _scriptStringStreamer; RepeatedValueStreamer _sharedObjectStreamer; + QVector _subdividedObjects; + WeakSharedObjectHash _sharedObjectReferences; WeakSharedObjectHash _weakSharedObjectHash; diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index 95dc75fec0..dcfa9732b3 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -147,11 +147,11 @@ void SharedObject::readExtraDelta(Bitstream& in, const SharedObject* reference) // nothing by default } -void SharedObject::writeExtraSubdivision(Bitstream& out) { +void SharedObject::maybeWriteSubdivision(Bitstream& out) { // nothing by default } -SharedObject* SharedObject::readExtraSubdivision(Bitstream& in) { +SharedObject* SharedObject::readSubdivision(Bitstream& in) { return this; } diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index cf9bf4e645..ebea322bf1 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -92,12 +92,13 @@ public: /// Reads the delta-encoded non-property contents of this object from the specified stream. virtual void readExtraDelta(Bitstream& in, const SharedObject* reference); - /// Writes the subdivision of the non-property contents of this object to the specified stream. - virtual void writeExtraSubdivision(Bitstream& out); + /// Writes the subdivision of the contents of this object (preceeded by a + /// reference to the object itself) to the specified stream if necessary. + virtual void maybeWriteSubdivision(Bitstream& out); - /// Reads the subdivision of the non-property contents of this object from the specified stream. + /// Reads the subdivision of this object from the specified stream. /// \return the modified object, or this if no modification was performed - virtual SharedObject* readExtraSubdivision(Bitstream& in); + virtual SharedObject* readSubdivision(Bitstream& in); private: diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index f2a1ebb27f..1dc55a7904 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -3016,7 +3016,7 @@ void Heightfield::readExtraDelta(Bitstream& in, const SharedObject* reference) { } } -void Heightfield::writeExtraSubdivision(Bitstream& out) { +void Heightfield::maybeWriteSubdivision(Bitstream& out) { MetavoxelLOD lod, referenceLOD; if (out.getContext()) { MetavoxelStreamBase* base = static_cast(out.getContext()); @@ -3026,13 +3026,13 @@ void Heightfield::writeExtraSubdivision(Bitstream& out) { HeightfieldStreamBase base = { out, lod, referenceLOD }; HeightfieldStreamState state = { base, glm::vec2(), 1.0f }; - if (state.becameSubdivided()) { + if (state.becameSubdividedOrCollapsed()) { out << SharedObjectPointer(this); _root->writeSubdivision(state); } } -SharedObject* Heightfield::readExtraSubdivision(Bitstream& in) { +SharedObject* Heightfield::readSubdivision(Bitstream& in) { MetavoxelLOD lod, referenceLOD; if (in.getContext()) { MetavoxelStreamBase* base = static_cast(in.getContext()); @@ -3046,6 +3046,8 @@ SharedObject* Heightfield::readExtraSubdivision(Bitstream& in) { HeightfieldNodePointer root(_root->readSubdivision(state)); if (_root != root) { Heightfield* newHeightfield = static_cast(clone(true)); + newHeightfield->setRemoteID(getRemoteID()); + newHeightfield->setRemoteOriginID(getRemoteOriginID()); newHeightfield->setRoot(root); return newHeightfield; } diff --git a/libraries/metavoxels/src/Spanner.h b/libraries/metavoxels/src/Spanner.h index bbfcbff1ff..bec1355b48 100644 --- a/libraries/metavoxels/src/Spanner.h +++ b/libraries/metavoxels/src/Spanner.h @@ -642,8 +642,8 @@ public: virtual void readExtra(Bitstream& in); virtual void writeExtraDelta(Bitstream& out, const SharedObject* reference) const; virtual void readExtraDelta(Bitstream& in, const SharedObject* reference); - virtual void writeExtraSubdivision(Bitstream& out); - virtual SharedObject* readExtraSubdivision(Bitstream& in); + virtual void maybeWriteSubdivision(Bitstream& out); + virtual SharedObject* readSubdivision(Bitstream& in); signals: