diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 4b643ba847..b90aa668f5 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -165,6 +165,14 @@ void Attribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& refer root.writeDelta(reference, state); } +void Attribute::readSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { + data.getRoot(state.attribute)->readSubdivision(state); +} + +void Attribute::writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { + root.writeSubdivision(state); +} + QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) : InlineAttribute(name, defaultValue) { } @@ -313,3 +321,21 @@ void SpannerSetAttribute::writeDelta(const MetavoxelNode& root, const MetavoxelN root.writeSpannerDelta(reference, state); state.stream << SharedObjectPointer(); } + +void SpannerSetAttribute::readSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { + forever { + SharedObjectPointer object; + state.stream >> object; + if (!object) { + break; + } + data.insert(state.attribute, object); + } +} + +void SpannerSetAttribute::writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { + Spanner::incrementVisit(); + root.writeSpannerSubdivision(state); + state.stream << SharedObjectPointer(); +} + diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index dae0e87f37..8678e62b41 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -178,6 +178,9 @@ public: virtual void readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state); virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state); + + virtual void readSubdivision(MetavoxelData& data, MetavoxelStreamState& state); + virtual void writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state); virtual bool equal(void* first, void* second) const = 0; @@ -332,6 +335,9 @@ public: virtual void readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state); virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state); + + virtual void readSubdivision(MetavoxelData& data, MetavoxelStreamState& state); + virtual void writeSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state); }; #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 970b2a7d87..f3cce11e75 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -31,6 +31,10 @@ bool MetavoxelLOD::shouldSubdivide(const glm::vec3& minimum, float size) const { return size >= glm::distance(position, minimum + glm::vec3(size, size, size) * 0.5f) * threshold; } +bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference) const { + return shouldSubdivide(minimum, size) && !reference.shouldSubdivide(minimum, size); +} + MetavoxelData::MetavoxelData() : _size(1.0f) { } @@ -295,10 +299,15 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, referenceLOD }; MetavoxelNode* oldRoot = _roots.value(attribute); if (oldRoot) { - oldRoot->incrementReferenceCount(); - attribute->readDelta(*this, *oldRoot, state); - oldRoot->decrementReferenceCount(attribute); - + bool changed; + in >> changed; + if (changed) { + oldRoot->incrementReferenceCount(); + attribute->readDelta(*this, *oldRoot, state); + oldRoot->decrementReferenceCount(attribute); + } else { + attribute->readSubdivision(*this, state); + } } else { attribute->read(*this, state); } @@ -317,7 +326,9 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD void MetavoxelData::writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, Bitstream& out, const MetavoxelLOD& lod) const { // first things first: there might be no change whatsoever - if (_size == reference._size && _roots == reference._roots) { + glm::vec3 minimum = getMinimum(); + bool becameSubdivided = lod.becameSubdivided(minimum, _size, referenceLOD); + if (_size == reference._size && _roots == reference._roots && !becameSubdivided) { out << false; return; } @@ -338,14 +349,20 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, const MetavoxelLO expandedReference = expanded; } - // write the added/changed roots + // write the added/changed/subdivided roots for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key()); - if (it.value() != referenceRoot) { - out << it.key(); - MetavoxelStreamState state = { getMinimum(), _size, it.key(), out, lod, referenceLOD }; + MetavoxelStreamState state = { minimum, _size, it.key(), out, lod, referenceLOD }; + if (it.value() != referenceRoot || becameSubdivided) { + out << it.key(); if (referenceRoot) { - it.key()->writeDelta(*it.value(), *referenceRoot, state); + if (it.value() == referenceRoot) { + out << false; + it.key()->writeSubdivision(*it.value(), state); + } else { + out << true; + it.key()->writeDelta(*it.value(), *referenceRoot, state); + } } else { it.key()->write(*it.value(), state); } @@ -506,15 +523,18 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta } } else { for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); bool changed; state.stream >> changed; - if (changed) { - nextState.setMinimum(state.minimum, i); + if (changed) { _children[i] = new MetavoxelNode(state.attribute); _children[i]->readDelta(*reference._children[i], nextState); } else { _children[i] = reference._children[i]; _children[i]->incrementReferenceCount(); + if (nextState.becameSubdivided()) { + _children[i]->readSubdivision(nextState); + } } } } @@ -539,10 +559,13 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt } } else { for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); if (_children[i] == reference._children[i]) { state.stream << false; - } else { - nextState.setMinimum(state.minimum, i); + if (nextState.becameSubdivided()) { + _children[i]->writeSubdivision(nextState); + } + } else { state.stream << true; _children[i]->writeDelta(*reference._children[i], nextState); } @@ -551,6 +574,63 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt } } +void MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { + bool leaf; + bool subdivideReference = state.shouldSubdivideReference(); + if (!subdivideReference) { + state.stream >> leaf; + } else { + leaf = isLeaf(); + } + if (leaf) { + clearChildren(state.attribute); + + } else { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + if (!subdivideReference) { + clearChildren(state.attribute); + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + _children[i] = new MetavoxelNode(state.attribute); + _children[i]->read(nextState); + } + } else { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + if (nextState.becameSubdivided()) { + _children[i]->readSubdivision(nextState); + } + } + } + } +} + +void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const { + bool leaf = isLeaf(); + bool subdivideReference = state.shouldSubdivideReference(); + if (!subdivideReference) { + state.stream << leaf; + } + if (!leaf) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + if (!subdivideReference) { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + _children[i]->write(nextState); + } + } else { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + if (nextState.becameSubdivided()) { + _children[i]->writeSubdivision(nextState); + } + } + } + } +} + void MetavoxelNode::writeSpanners(MetavoxelStreamState& state) const { foreach (const SharedObjectPointer& object, decodeInline(_attributeValue)) { if (static_cast(object.data())->testAndSetVisited()) { @@ -602,9 +682,32 @@ void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelS return; } for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); if (_children[i] != reference._children[i]) { - nextState.setMinimum(state.minimum, i); _children[i]->writeSpannerDelta(*reference._children[i], nextState); + + } else if (nextState.becameSubdivided()) { + _children[i]->writeSpannerSubdivision(nextState); + } + } +} + +void MetavoxelNode::writeSpannerSubdivision(MetavoxelStreamState& state) const { + if (!isLeaf()) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + if (!state.shouldSubdivideReference()) { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + _children[i]->writeSpanners(nextState); + } + } else { + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + if (nextState.becameSubdivided()) { + _children[i]->writeSpannerSubdivision(nextState); + } + } } } } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index aa2615e574..0c11055b0f 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -44,6 +44,9 @@ public: bool isValid() const { return threshold > 0.0f; } bool shouldSubdivide(const glm::vec3& minimum, float size) const; + + /// Checks whether the node or any of the nodes underneath it have had subdivision enabled as compared to the reference. + bool becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference) const; }; DECLARE_STREAMABLE_METATYPE(MetavoxelLOD) @@ -88,6 +91,7 @@ public: void writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, Bitstream& out, const MetavoxelLOD& lod) const; + MetavoxelNode* getRoot(const AttributePointer& attribute) const { return _roots.value(attribute); } MetavoxelNode* createRoot(const AttributePointer& attribute); private: @@ -113,6 +117,7 @@ public: bool shouldSubdivide() const { return lod.shouldSubdivide(minimum, size); } bool shouldSubdivideReference() const { return referenceLOD.shouldSubdivide(minimum, size); } + bool becameSubdivided() const { return lod.becameSubdivided(minimum, size, referenceLOD); } void setMinimum(const glm::vec3& lastMinimum, int index); }; @@ -144,8 +149,12 @@ public: void readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state); void writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const; + void readSubdivision(MetavoxelStreamState& state); + void writeSubdivision(MetavoxelStreamState& state) const; + void writeSpanners(MetavoxelStreamState& state) const; void writeSpannerDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const; + void writeSpannerSubdivision(MetavoxelStreamState& state) const; /// Increments the node's reference count. void incrementReferenceCount() { _referenceCount++; }