Lots of work on metavoxel LODs and spanners.

This commit is contained in:
Andrzej Kapolka 2014-03-04 21:27:13 -08:00
parent 7a182ed659
commit 63b4a2453b
10 changed files with 355 additions and 171 deletions

View file

@ -111,13 +111,17 @@ int MetavoxelSession::parseData(const QByteArray& packet) {
} }
void MetavoxelSession::sendDelta() { void MetavoxelSession::sendDelta() {
// wait until we have a valid lod
if (!_lod.isValid()) {
return;
}
Bitstream& out = _sequencer.startPacket(); Bitstream& out = _sequencer.startPacket();
out << QVariant::fromValue(MetavoxelDeltaMessage()); out << QVariant::fromValue(MetavoxelDeltaMessage());
_server->getData().writeDelta(_sendRecords.first().data, out); _server->getData().writeDelta(_sendRecords.first().data, _sendRecords.first().lod, out, _lod);
_sequencer.endPacket(); _sequencer.endPacket();
// record the send // record the send
SendRecord record = { _sequencer.getOutgoingPacketNumber(), _server->getData() }; SendRecord record = { _sequencer.getOutgoingPacketNumber(), _server->getData(), _lod };
_sendRecords.append(record); _sendRecords.append(record);
} }
@ -139,7 +143,7 @@ void MetavoxelSession::handleMessage(const QVariant& message) {
int userType = message.userType(); int userType = message.userType();
if (userType == ClientStateMessage::Type) { if (userType == ClientStateMessage::Type) {
ClientStateMessage state = message.value<ClientStateMessage>(); ClientStateMessage state = message.value<ClientStateMessage>();
_position = state.position; _lod = state.lod;
} else if (userType == MetavoxelEditMessage::Type) { } else if (userType == MetavoxelEditMessage::Type) {
_server->applyEdit(message.value<MetavoxelEditMessage>()); _server->applyEdit(message.value<MetavoxelEditMessage>());

View file

@ -78,6 +78,7 @@ private:
public: public:
int packetNumber; int packetNumber;
MetavoxelData data; MetavoxelData data;
MetavoxelLOD lod;
}; };
MetavoxelServer* _server; MetavoxelServer* _server;
@ -86,7 +87,7 @@ private:
SharedNodePointer _node; SharedNodePointer _node;
glm::vec3 _position; MetavoxelLOD _lod;
QList<SendRecord> _sendRecords; QList<SendRecord> _sendRecords;
}; };

View file

@ -182,11 +182,16 @@ MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) :
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&))); connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&)));
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&))); connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int)));
connect(&_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int))); connect(&_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int)));
// insert the baseline send record
SendRecord sendRecord = { 0 };
_sendRecords.append(sendRecord);
// insert the baseline receive record // insert the baseline receive record
ReceiveRecord record = { 0, _data }; ReceiveRecord receiveRecord = { 0, _data };
_receiveRecords.append(record); _receiveRecords.append(receiveRecord);
} }
MetavoxelClient::~MetavoxelClient() { MetavoxelClient::~MetavoxelClient() {
@ -206,9 +211,14 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) {
void MetavoxelClient::simulate(float deltaTime) { void MetavoxelClient::simulate(float deltaTime) {
Bitstream& out = _sequencer.startPacket(); Bitstream& out = _sequencer.startPacket();
ClientStateMessage state = { Application::getInstance()->getCamera()->getPosition() }; const float FIXED_LOD_THRESHOLD = 0.0001f;
ClientStateMessage state = { MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(), FIXED_LOD_THRESHOLD) };
out << QVariant::fromValue(state); out << QVariant::fromValue(state);
_sequencer.endPacket(); _sequencer.endPacket();
// record the send
SendRecord record = { _sequencer.getOutgoingPacketNumber(), state.lod };
_sendRecords.append(record);
} }
int MetavoxelClient::parseData(const QByteArray& packet) { int MetavoxelClient::parseData(const QByteArray& packet) {
@ -227,7 +237,7 @@ void MetavoxelClient::readPacket(Bitstream& in) {
handleMessage(message, in); handleMessage(message, in);
// record the receipt // record the receipt
ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data }; ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data, _sendRecords.first().lod };
_receiveRecords.append(record); _receiveRecords.append(record);
// reapply local edits // reapply local edits
@ -238,6 +248,10 @@ void MetavoxelClient::readPacket(Bitstream& in) {
} }
} }
void MetavoxelClient::clearSendRecordsBefore(int index) {
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
}
void MetavoxelClient::clearReceiveRecordsBefore(int index) { void MetavoxelClient::clearReceiveRecordsBefore(int index) {
_receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1); _receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1);
} }
@ -245,7 +259,7 @@ void MetavoxelClient::clearReceiveRecordsBefore(int index) {
void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
int userType = message.userType(); int userType = message.userType();
if (userType == MetavoxelDeltaMessage::Type) { if (userType == MetavoxelDeltaMessage::Type) {
_data.readDelta(_receiveRecords.first().data, in); _data.readDelta(_receiveRecords.first().data, _receiveRecords.first().lod, in, _sendRecords.first().lod);
} else if (userType == QMetaType::QVariantList) { } else if (userType == QMetaType::QVariantList) {
foreach (const QVariant& element, message.toList()) { foreach (const QVariant& element, message.toList()) {

View file

@ -103,16 +103,25 @@ private slots:
void readPacket(Bitstream& in); void readPacket(Bitstream& in);
void clearSendRecordsBefore(int index);
void clearReceiveRecordsBefore(int index); void clearReceiveRecordsBefore(int index);
private: private:
void handleMessage(const QVariant& message, Bitstream& in); void handleMessage(const QVariant& message, Bitstream& in);
class SendRecord {
public:
int packetNumber;
MetavoxelLOD lod;
};
class ReceiveRecord { class ReceiveRecord {
public: public:
int packetNumber; int packetNumber;
MetavoxelData data; MetavoxelData data;
MetavoxelLOD lod;
}; };
SharedNodePointer _node; SharedNodePointer _node;
@ -121,6 +130,7 @@ private:
MetavoxelData _data; MetavoxelData _data;
QList<SendRecord> _sendRecords;
QList<ReceiveRecord> _receiveRecords; QList<ReceiveRecord> _receiveRecords;
}; };

View file

@ -49,6 +49,9 @@ void AttributeRegistry::configureScriptEngine(QScriptEngine* engine) {
} }
AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) { AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) {
if (!attribute) {
return attribute;
}
AttributePointer& pointer = _attributes[attribute->getName()]; AttributePointer& pointer = _attributes[attribute->getName()];
if (!pointer) { if (!pointer) {
pointer = attribute; pointer = attribute;
@ -146,20 +149,20 @@ Attribute::Attribute(const QString& name) {
Attribute::~Attribute() { Attribute::~Attribute() {
} }
void Attribute::read(MetavoxelNode& root, Bitstream& in) { void Attribute::read(MetavoxelData& data, MetavoxelStreamState& state) {
root.read(this, in); data.createRoot(state.attribute)->read(state);
} }
void Attribute::write(const MetavoxelNode& root, Bitstream& out) { void Attribute::write(const MetavoxelNode& root, MetavoxelStreamState& state) {
root.write(this, out); root.write(state);
} }
void Attribute::readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in) { void Attribute::readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) {
root.readDelta(this, reference, in); data.createRoot(state.attribute)->readDelta(reference, state);
} }
void Attribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out) { void Attribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) {
root.writeDelta(this, reference, out); root.writeDelta(reference, state);
} }
QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) : QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) :
@ -277,18 +280,36 @@ SpannerSetAttribute::SpannerSetAttribute(const QString& name, const QMetaObject*
SharedObjectSetAttribute(name, metaObject) { SharedObjectSetAttribute(name, metaObject) {
} }
void SpannerSetAttribute::read(MetavoxelNode& root, Bitstream& in) { void SpannerSetAttribute::read(MetavoxelData& data, MetavoxelStreamState& state) {
root.read(this, in); forever {
SharedObjectPointer object;
state.stream >> object;
if (!object) {
break;
}
data.insert(state.attribute, object);
}
} }
void SpannerSetAttribute::write(const MetavoxelNode& root, Bitstream& out) { void SpannerSetAttribute::write(const MetavoxelNode& root, MetavoxelStreamState& state) {
root.write(this, out); Spanner::incrementVisit();
root.writeSpanners(state);
state.stream << SharedObjectPointer();
} }
void SpannerSetAttribute::readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in) { void SpannerSetAttribute::readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state) {
root.readDelta(this, reference, in); forever {
SharedObjectPointer object;
state.stream >> object;
if (!object) {
break;
}
data.toggle(state.attribute, object);
}
} }
void SpannerSetAttribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out) { void SpannerSetAttribute::writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state) {
root.writeDelta(this, reference, out); Spanner::incrementVisit();
root.writeSpannerDelta(reference, state);
state.stream << SharedObjectPointer();
} }

View file

@ -23,7 +23,9 @@ class QScriptEngine;
class QScriptValue; class QScriptValue;
class Attribute; class Attribute;
class MetavoxelData;
class MetavoxelNode; class MetavoxelNode;
class MetavoxelStreamState;
typedef SharedObjectPointerTemplate<Attribute> AttributePointer; typedef SharedObjectPointerTemplate<Attribute> AttributePointer;
@ -171,11 +173,11 @@ public:
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { read(in, value, isLeaf); } virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { read(in, value, isLeaf); }
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { write(out, value, isLeaf); } virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { write(out, value, isLeaf); }
virtual void read(MetavoxelNode& root, Bitstream& in); virtual void read(MetavoxelData& data, MetavoxelStreamState& state);
virtual void write(const MetavoxelNode& root, Bitstream& out); virtual void write(const MetavoxelNode& root, MetavoxelStreamState& state);
virtual void readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in); virtual void readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state);
virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out); virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state);
virtual bool equal(void* first, void* second) const = 0; virtual bool equal(void* first, void* second) const = 0;
@ -325,11 +327,11 @@ public:
Q_INVOKABLE SpannerSetAttribute(const QString& name = QString(), Q_INVOKABLE SpannerSetAttribute(const QString& name = QString(),
const QMetaObject* metaObject = &SharedObject::staticMetaObject); const QMetaObject* metaObject = &SharedObject::staticMetaObject);
virtual void read(MetavoxelNode& root, Bitstream& in); virtual void read(MetavoxelData& data, MetavoxelStreamState& state);
virtual void write(const MetavoxelNode& root, Bitstream& out); virtual void write(const MetavoxelNode& root, MetavoxelStreamState& state);
virtual void readDelta(MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& in); virtual void readDelta(MetavoxelData& data, const MetavoxelNode& reference, MetavoxelStreamState& state);
virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, Bitstream& out); virtual void writeDelta(const MetavoxelNode& root, const MetavoxelNode& reference, MetavoxelStreamState& state);
}; };
#endif /* defined(__interface__AttributeRegistry__) */ #endif /* defined(__interface__AttributeRegistry__) */

View file

@ -27,6 +27,10 @@ MetavoxelLOD::MetavoxelLOD(const glm::vec3& position, float threshold) :
threshold(threshold) { threshold(threshold) {
} }
bool MetavoxelLOD::shouldSubdivide(const glm::vec3& minimum, float size) const {
return size >= glm::distance(position, minimum + glm::vec3(size, size, size) * 0.5f) * threshold;
}
MetavoxelData::MetavoxelData() : _size(1.0f) { MetavoxelData::MetavoxelData() : _size(1.0f) {
} }
@ -62,7 +66,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) {
const QVector<AttributePointer>& inputs = visitor.getInputs(); const QVector<AttributePointer>& inputs = visitor.getInputs();
const QVector<AttributePointer>& outputs = visitor.getOutputs(); const QVector<AttributePointer>& outputs = visitor.getOutputs();
MetavoxelVisitation firstVisitation = { NULL, visitor, QVector<MetavoxelNode*>(inputs.size() + 1), MetavoxelVisitation firstVisitation = { NULL, visitor, QVector<MetavoxelNode*>(inputs.size() + 1),
QVector<MetavoxelNode*>(outputs.size()), { glm::vec3(_size, _size, _size) * -0.5f, _size, QVector<MetavoxelNode*>(outputs.size()), { getMinimum(), _size,
QVector<AttributeValue>(inputs.size() + 1), QVector<OwnedAttributeValue>(outputs.size()) } }; QVector<AttributeValue>(inputs.size() + 1), QVector<OwnedAttributeValue>(outputs.size()) } };
for (int i = 0; i < inputs.size(); i++) { for (int i = 0; i < inputs.size(); i++) {
MetavoxelNode* node = _roots.value(inputs.at(i)); MetavoxelNode* node = _roots.value(inputs.at(i));
@ -98,10 +102,27 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) {
} }
} }
class InsertVisitor : public MetavoxelVisitor { typedef void (*SpannerUpdateFunction)(SharedObjectSet& set, const SharedObjectPointer& object);
void insertSpanner(SharedObjectSet& set, const SharedObjectPointer& object) {
set.insert(object);
}
void removeSpanner(SharedObjectSet& set, const SharedObjectPointer& object) {
set.remove(object);
}
void toggleSpanner(SharedObjectSet& set, const SharedObjectPointer& object) {
if (!set.remove(object)) {
set.insert(object);
}
}
template<SpannerUpdateFunction F> class SpannerUpdateVisitor : public MetavoxelVisitor {
public: public:
InsertVisitor(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); SpannerUpdateVisitor(const AttributePointer& attribute, const Box& bounds,
float granularity, const SharedObjectPointer& object);
virtual bool visit(MetavoxelInfo& info); virtual bool visit(MetavoxelInfo& info);
@ -113,8 +134,8 @@ private:
const SharedObjectPointer& _object; const SharedObjectPointer& _object;
}; };
InsertVisitor::InsertVisitor(const AttributePointer& attribute, const Box& bounds, template<SpannerUpdateFunction F> SpannerUpdateVisitor<F>::SpannerUpdateVisitor(const AttributePointer& attribute,
float granularity, const SharedObjectPointer& object) : const Box& bounds, float granularity, const SharedObjectPointer& object) :
MetavoxelVisitor(QVector<AttributePointer>() << attribute, QVector<AttributePointer>() << attribute), MetavoxelVisitor(QVector<AttributePointer>() << attribute, QVector<AttributePointer>() << attribute),
_attribute(attribute), _attribute(attribute),
_bounds(bounds), _bounds(bounds),
@ -122,7 +143,7 @@ InsertVisitor::InsertVisitor(const AttributePointer& attribute, const Box& bound
_object(object) { _object(object) {
} }
bool InsertVisitor::visit(MetavoxelInfo& info) { template<SpannerUpdateFunction F> bool SpannerUpdateVisitor<F>::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_bounds)) { if (!info.getBounds().intersects(_bounds)) {
return false; return false;
} }
@ -130,61 +151,45 @@ bool InsertVisitor::visit(MetavoxelInfo& info) {
return true; return true;
} }
SharedObjectSet set = info.inputValues.at(0).getInlineValue<SharedObjectSet>(); SharedObjectSet set = info.inputValues.at(0).getInlineValue<SharedObjectSet>();
set.insert(_object); F(set, _object);
info.outputValues[0] = AttributeValue(_attribute, encodeInline(set)); info.outputValues[0] = AttributeValue(_attribute, encodeInline(set));
return false; return false;
} }
void MetavoxelData::insert(const AttributePointer& attribute, const SharedObjectPointer& object) {
Spanner* spanner = static_cast<Spanner*>(object.data());
insert(attribute, spanner->getBounds(), spanner->getGranularity(), object);
}
void MetavoxelData::insert(const AttributePointer& attribute, const Box& bounds, void MetavoxelData::insert(const AttributePointer& attribute, const Box& bounds,
float granularity, const SharedObjectPointer& object) { float granularity, const SharedObjectPointer& object) {
// expand to fit the entire bounds // expand to fit the entire bounds
while (!getBounds().contains(bounds)) { while (!getBounds().contains(bounds)) {
expand(); expand();
} }
InsertVisitor visitor(attribute, bounds, granularity, object); SpannerUpdateVisitor<insertSpanner> visitor(attribute, bounds, granularity, object);
guide(visitor); guide(visitor);
} }
class RemoveVisitor : public MetavoxelVisitor { void MetavoxelData::remove(const AttributePointer& attribute, const SharedObjectPointer& object) {
public: Spanner* spanner = static_cast<Spanner*>(object.data());
remove(attribute, spanner->getBounds(), spanner->getGranularity(), object);
RemoveVisitor(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object);
virtual bool visit(MetavoxelInfo& info);
private:
const AttributePointer& _attribute;
const Box& _bounds;
float _longestSide;
const SharedObjectPointer& _object;
};
RemoveVisitor::RemoveVisitor(const AttributePointer& attribute, const Box& bounds,
float granularity, const SharedObjectPointer& object) :
MetavoxelVisitor(QVector<AttributePointer>() << attribute, QVector<AttributePointer>() << attribute),
_attribute(attribute),
_bounds(bounds),
_longestSide(qMax(bounds.getLongestSide(), granularity)),
_object(object) {
}
bool RemoveVisitor::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_bounds)) {
return false;
}
if (info.size > _longestSide) {
return true;
}
SharedObjectSet set = info.inputValues.at(0).getInlineValue<SharedObjectSet>();
set.remove(_object);
info.outputValues[0] = AttributeValue(_attribute, encodeInline(set));
return false;
} }
void MetavoxelData::remove(const AttributePointer& attribute, const Box& bounds, void MetavoxelData::remove(const AttributePointer& attribute, const Box& bounds,
float granularity, const SharedObjectPointer& object) { float granularity, const SharedObjectPointer& object) {
RemoveVisitor visitor(attribute, bounds, granularity, object); SpannerUpdateVisitor<removeSpanner> visitor(attribute, bounds, granularity, object);
guide(visitor);
}
void MetavoxelData::toggle(const AttributePointer& attribute, const SharedObjectPointer& object) {
Spanner* spanner = static_cast<Spanner*>(object.data());
toggle(attribute, spanner->getBounds(), spanner->getGranularity(), object);
}
void MetavoxelData::toggle(const AttributePointer& attribute, const Box& bounds,
float granularity, const SharedObjectPointer& object) {
SpannerUpdateVisitor<toggleSpanner> visitor(attribute, bounds, granularity, object);
guide(visitor); guide(visitor);
} }
@ -231,7 +236,7 @@ void MetavoxelData::expand() {
_size *= 2.0f; _size *= 2.0f;
} }
void MetavoxelData::read(Bitstream& in) { void MetavoxelData::read(Bitstream& in, const MetavoxelLOD& lod) {
// clear out any existing roots // clear out any existing roots
decrementRootReferenceCounts(); decrementRootReferenceCounts();
_roots.clear(); _roots.clear();
@ -239,27 +244,29 @@ void MetavoxelData::read(Bitstream& in) {
in >> _size; in >> _size;
// read in the new roots // read in the new roots
int rootCount; forever {
in >> rootCount;
for (int i = 0; i < rootCount; i++) {
AttributePointer attribute; AttributePointer attribute;
in >> attribute; in >> attribute;
MetavoxelNode*& root = _roots[attribute]; if (!attribute) {
root = new MetavoxelNode(attribute); break;
attribute->read(*root, in); }
MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, lod };
attribute->read(*this, state);
} }
} }
void MetavoxelData::write(Bitstream& out) const { void MetavoxelData::write(Bitstream& out, const MetavoxelLOD& lod) const {
out << _size; out << _size;
out << _roots.size();
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
out << it.key(); out << it.key();
it.key()->write(*it.value(), out); MetavoxelStreamState state = { getMinimum(), _size, it.key(), out, lod, lod };
it.key()->write(*it.value(), state);
} }
out << AttributePointer();
} }
void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) { void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD,
Bitstream& in, const MetavoxelLOD& lod) {
// shallow copy the reference // shallow copy the reference
*this = reference; *this = reference;
@ -279,34 +286,36 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) {
} }
} }
int changedCount; forever {
in >> changedCount;
for (int i = 0; i < changedCount; i++) {
AttributePointer attribute; AttributePointer attribute;
in >> attribute; in >> attribute;
MetavoxelNode*& root = _roots[attribute]; if (!attribute) {
if (root) { break;
MetavoxelNode* oldRoot = root; }
root = new MetavoxelNode(attribute); MetavoxelStreamState state = { getMinimum(), _size, attribute, in, lod, referenceLOD };
attribute->readDelta(*root, *oldRoot, in); MetavoxelNode* oldRoot = _roots.value(attribute);
if (oldRoot) {
oldRoot->incrementReferenceCount();
attribute->readDelta(*this, *oldRoot, state);
oldRoot->decrementReferenceCount(attribute); oldRoot->decrementReferenceCount(attribute);
} else { } else {
root = new MetavoxelNode(attribute); attribute->read(*this, state);
attribute->read(*root, in);
} }
} }
int removedCount; forever {
in >> removedCount;
for (int i = 0; i < removedCount; i++) {
AttributePointer attribute; AttributePointer attribute;
in >> attribute; in >> attribute;
if (!attribute) {
break;
}
_roots.take(attribute)->decrementReferenceCount(attribute); _roots.take(attribute)->decrementReferenceCount(attribute);
} }
} }
void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) const { void MetavoxelData::writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD,
Bitstream& out, const MetavoxelLOD& lod) const {
// first things first: there might be no change whatsoever // first things first: there might be no change whatsoever
if (_size == reference._size && _roots == reference._roots) { if (_size == reference._size && _roots == reference._roots) {
out << false; out << false;
@ -329,42 +338,29 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) c
expandedReference = expanded; expandedReference = expanded;
} }
// count the number of roots added/changed, then write // write the added/changed roots
int changedCount = 0;
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key());
if (it.value() != referenceRoot) {
changedCount++;
}
}
out << changedCount;
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key()); MetavoxelNode* referenceRoot = expandedReference->_roots.value(it.key());
if (it.value() != referenceRoot) { if (it.value() != referenceRoot) {
out << it.key(); out << it.key();
MetavoxelStreamState state = { getMinimum(), _size, it.key(), out, lod, referenceLOD };
if (referenceRoot) { if (referenceRoot) {
it.key()->writeDelta(*it.value(), *referenceRoot, out); it.key()->writeDelta(*it.value(), *referenceRoot, state);
} else { } else {
it.key()->write(*it.value(), out); it.key()->write(*it.value(), state);
} }
} }
} }
out << AttributePointer();
// same with nodes removed // same with nodes removed
int removedCount = 0;
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = expandedReference->_roots.constBegin();
it != expandedReference->_roots.constEnd(); it++) {
if (!_roots.contains(it.key())) {
removedCount++;
}
}
out << removedCount;
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = expandedReference->_roots.constBegin(); for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = expandedReference->_roots.constBegin();
it != expandedReference->_roots.constEnd(); it++) { it != expandedReference->_roots.constEnd(); it++) {
if (!_roots.contains(it.key())) { if (!_roots.contains(it.key())) {
out << it.key(); out << it.key();
} }
} }
out << AttributePointer();
// delete the expanded reference if we had to expand // delete the expanded reference if we had to expand
if (expandedReference != &reference) { if (expandedReference != &reference) {
@ -372,6 +368,14 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) c
} }
} }
MetavoxelNode* MetavoxelData::createRoot(const AttributePointer& attribute) {
MetavoxelNode*& root = _roots[attribute];
if (root) {
root->decrementReferenceCount(attribute);
}
return root = new MetavoxelNode(attribute);
}
void MetavoxelData::incrementRootReferenceCounts() { void MetavoxelData::incrementRootReferenceCounts() {
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
it.value()->incrementReferenceCount(); it.value()->incrementReferenceCount();
@ -384,6 +388,17 @@ void MetavoxelData::decrementRootReferenceCounts() {
} }
} }
static glm::vec3 getNextMinimum(const glm::vec3& minimum, float nextSize, int index) {
return minimum + glm::vec3(
(index & X_MAXIMUM_FLAG) ? nextSize : 0.0f,
(index & Y_MAXIMUM_FLAG) ? nextSize : 0.0f,
(index & Z_MAXIMUM_FLAG) ? nextSize : 0.0f);
}
void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) {
minimum = getNextMinimum(lastMinimum, size, index);
}
MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) : _referenceCount(1) { MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue) : _referenceCount(1) {
_attributeValue = attributeValue.copy(); _attributeValue = attributeValue.copy();
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
@ -431,50 +446,72 @@ bool MetavoxelNode::isLeaf() const {
return true; return true;
} }
void MetavoxelNode::read(const AttributePointer& attribute, Bitstream& in) { void MetavoxelNode::read(MetavoxelStreamState& state) {
clearChildren(attribute); clearChildren(state.attribute);
if (!state.shouldSubdivide()) {
state.attribute->read(state.stream, _attributeValue, true);
return;
}
bool leaf; bool leaf;
in >> leaf; state.stream >> leaf;
attribute->read(in, _attributeValue, leaf); state.attribute->read(state.stream, _attributeValue, leaf);
if (!leaf) { if (!leaf) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
_children[i] = new MetavoxelNode(attribute); nextState.setMinimum(state.minimum, i);
_children[i]->read(attribute, in); _children[i] = new MetavoxelNode(state.attribute);
_children[i]->read(nextState);
} }
} }
} }
void MetavoxelNode::write(const AttributePointer& attribute, Bitstream& out) const { void MetavoxelNode::write(MetavoxelStreamState& state) const {
if (!state.shouldSubdivide()) {
state.attribute->write(state.stream, _attributeValue, true);
return;
}
bool leaf = isLeaf(); bool leaf = isLeaf();
out << leaf; state.stream << leaf;
attribute->write(out, _attributeValue, leaf); state.attribute->write(state.stream, _attributeValue, leaf);
if (!leaf) { if (!leaf) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
_children[i]->write(attribute, out); nextState.setMinimum(state.minimum, i);
_children[i]->write(nextState);
} }
} }
} }
void MetavoxelNode::readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in) { void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) {
clearChildren(attribute); clearChildren(state.attribute);
if (!state.shouldSubdivide()) {
state.attribute->readDelta(state.stream, _attributeValue, reference._attributeValue, true);
return;
}
bool leaf; bool leaf;
in >> leaf; state.stream >> leaf;
attribute->readDelta(in, _attributeValue, reference._attributeValue, leaf); state.attribute->readDelta(state.stream, _attributeValue, reference._attributeValue, leaf);
if (!leaf) { if (!leaf) {
if (reference.isLeaf()) { MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
if (reference.isLeaf() || !state.shouldSubdivideReference()) {
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
_children[i] = new MetavoxelNode(attribute); nextState.setMinimum(state.minimum, i);
_children[i]->read(attribute, in); _children[i] = new MetavoxelNode(state.attribute);
_children[i]->read(nextState);
} }
} else { } else {
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
bool changed; bool changed;
in >> changed; state.stream >> changed;
if (changed) { if (changed) {
_children[i] = new MetavoxelNode(attribute); nextState.setMinimum(state.minimum, i);
_children[i]->readDelta(attribute, *reference._children[i], in); _children[i] = new MetavoxelNode(state.attribute);
_children[i]->readDelta(*reference._children[i], nextState);
} else { } else {
_children[i] = reference._children[i]; _children[i] = reference._children[i];
_children[i]->incrementReferenceCount(); _children[i]->incrementReferenceCount();
@ -484,28 +521,94 @@ void MetavoxelNode::readDelta(const AttributePointer& attribute, const Metavoxel
} }
} }
void MetavoxelNode::writeDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& out) const { void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const {
if (!state.shouldSubdivide()) {
state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, true);
return;
}
bool leaf = isLeaf(); bool leaf = isLeaf();
out << leaf; state.stream << leaf;
attribute->writeDelta(out, _attributeValue, reference._attributeValue, leaf); state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, leaf);
if (!leaf) { if (!leaf) {
if (reference.isLeaf()) { MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
if (reference.isLeaf() || !state.shouldSubdivideReference()) {
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
_children[i]->write(attribute, out); nextState.setMinimum(state.minimum, i);
_children[i]->write(nextState);
} }
} else { } else {
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
if (_children[i] == reference._children[i]) { if (_children[i] == reference._children[i]) {
out << false; state.stream << false;
} else { } else {
out << true; nextState.setMinimum(state.minimum, i);
_children[i]->writeDelta(attribute, *reference._children[i], out); state.stream << true;
_children[i]->writeDelta(*reference._children[i], nextState);
} }
} }
} }
} }
} }
void MetavoxelNode::writeSpanners(MetavoxelStreamState& state) const {
foreach (const SharedObjectPointer& object, decodeInline<SharedObjectSet>(_attributeValue)) {
if (static_cast<Spanner*>(object.data())->testAndSetVisited()) {
state.stream << object;
}
}
if (!state.shouldSubdivide() || isLeaf()) {
return;
}
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
_children[i]->writeSpanners(nextState);
}
}
void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const {
SharedObjectSet oldSet = decodeInline<SharedObjectSet>(reference.getAttributeValue());
SharedObjectSet newSet = decodeInline<SharedObjectSet>(_attributeValue);
foreach (const SharedObjectPointer& object, oldSet) {
if (static_cast<Spanner*>(object.data())->testAndSetVisited() && !newSet.contains(object)) {
state.stream << object;
}
}
foreach (const SharedObjectPointer& object, newSet) {
if (static_cast<Spanner*>(object.data())->testAndSetVisited() && !oldSet.contains(object)) {
state.stream << object;
}
}
if (isLeaf() || !state.shouldSubdivide()) {
if (!reference.isLeaf() && state.shouldSubdivideReference()) {
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
reference._children[i]->writeSpanners(nextState);
}
}
return;
}
MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute,
state.stream, state.lod, state.referenceLOD };
if (reference.isLeaf() || !state.shouldSubdivideReference()) {
for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i);
_children[i]->writeSpanners(nextState);
}
return;
}
for (int i = 0; i < CHILD_COUNT; i++) {
if (_children[i] != reference._children[i]) {
nextState.setMinimum(state.minimum, i);
_children[i]->writeSpannerDelta(*reference._children[i], nextState);
}
}
}
void MetavoxelNode::decrementReferenceCount(const AttributePointer& attribute) { void MetavoxelNode::decrementReferenceCount(const AttributePointer& attribute) {
if (--_referenceCount == 0) { if (--_referenceCount == 0) {
destroy(attribute); destroy(attribute);
@ -604,10 +707,7 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
MetavoxelNode* child = node ? node->getChild(i) : NULL; MetavoxelNode* child = node ? node->getChild(i) : NULL;
nextVisitation.outputNodes[j] = child; nextVisitation.outputNodes[j] = child;
} }
nextVisitation.info.minimum = visitation.info.minimum + glm::vec3( nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, i);
(i & X_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f,
(i & Y_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f,
(i & Z_MAXIMUM_FLAG) ? nextVisitation.info.size : 0.0f);
static_cast<MetavoxelGuide*>(nextVisitation.info.inputValues.last().getInlineValue< static_cast<MetavoxelGuide*>(nextVisitation.info.inputValues.last().getInlineValue<
SharedObjectPointer>().data())->guide(nextVisitation); SharedObjectPointer>().data())->guide(nextVisitation);
for (int j = 0; j < nextVisitation.outputNodes.size(); j++) { for (int j = 0; j < nextVisitation.outputNodes.size(); j++) {

View file

@ -33,13 +33,21 @@ class SpannerRenderer;
/// Determines whether to subdivide each node when traversing. /// Determines whether to subdivide each node when traversing.
class MetavoxelLOD { class MetavoxelLOD {
STREAMABLE
public: public:
glm::vec3 position; STREAM glm::vec3 position;
float threshold; STREAM float threshold;
MetavoxelLOD(const glm::vec3& position = glm::vec3(), float threshold = 0.0f); MetavoxelLOD(const glm::vec3& position = glm::vec3(), float threshold = 0.0f);
bool isValid() const { return threshold > 0.0f; }
bool shouldSubdivide(const glm::vec3& minimum, float size) const;
}; };
DECLARE_STREAMABLE_METATYPE(MetavoxelLOD)
/// The base metavoxel representation shared between server and client. /// The base metavoxel representation shared between server and client.
class MetavoxelData { class MetavoxelData {
public: public:
@ -52,25 +60,35 @@ public:
float getSize() const { return _size; } float getSize() const { return _size; }
glm::vec3 getMinimum() const { return glm::vec3(_size, _size, _size) * -0.5f; }
Box getBounds() const; Box getBounds() const;
/// Applies the specified visitor to the contained voxels. /// Applies the specified visitor to the contained voxels.
void guide(MetavoxelVisitor& visitor); void guide(MetavoxelVisitor& visitor);
void insert(const AttributePointer& attribute, const SharedObjectPointer& object);
void insert(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); void insert(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object);
void remove(const AttributePointer& attribute, const SharedObjectPointer& object);
void remove(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); void remove(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object);
void toggle(const AttributePointer& attribute, const SharedObjectPointer& object);
void toggle(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object);
void clear(const AttributePointer& attribute); void clear(const AttributePointer& attribute);
/// Expands the tree, increasing its capacity in all dimensions. /// Expands the tree, increasing its capacity in all dimensions.
void expand(); void expand();
void read(Bitstream& in); void read(Bitstream& in, const MetavoxelLOD& lod = MetavoxelLOD());
void write(Bitstream& out) const; void write(Bitstream& out, const MetavoxelLOD& lod = MetavoxelLOD()) const;
void readDelta(const MetavoxelData& reference, Bitstream& in); void readDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, Bitstream& in, const MetavoxelLOD& lod);
void writeDelta(const MetavoxelData& reference, Bitstream& out) const; void writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD,
Bitstream& out, const MetavoxelLOD& lod) const;
MetavoxelNode* createRoot(const AttributePointer& attribute);
private: private:
@ -83,6 +101,22 @@ private:
QHash<AttributePointer, MetavoxelNode*> _roots; QHash<AttributePointer, MetavoxelNode*> _roots;
}; };
/// Holds the state used in streaming metavoxel data.
class MetavoxelStreamState {
public:
glm::vec3 minimum;
float size;
const AttributePointer& attribute;
Bitstream& stream;
const MetavoxelLOD& lod;
const MetavoxelLOD& referenceLOD;
bool shouldSubdivide() const { return lod.shouldSubdivide(minimum, size); }
bool shouldSubdivideReference() const { return referenceLOD.shouldSubdivide(minimum, size); }
void setMinimum(const glm::vec3& lastMinimum, int index);
};
/// A single node within a metavoxel layer. /// A single node within a metavoxel layer.
class MetavoxelNode { class MetavoxelNode {
public: public:
@ -104,11 +138,14 @@ public:
bool isLeaf() const; bool isLeaf() const;
void read(const AttributePointer& attribute, Bitstream& in); void read(MetavoxelStreamState& state);
void write(const AttributePointer& attribute, Bitstream& out) const; void write(MetavoxelStreamState& state) const;
void readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in); void readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state);
void writeDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& out) const; void writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const;
void writeSpanners(MetavoxelStreamState& state) const;
void writeSpannerDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const;
/// Increments the node's reference count. /// Increments the node's reference count.
void incrementReferenceCount() { _referenceCount++; } void incrementReferenceCount() { _referenceCount++; }

View file

@ -6,7 +6,6 @@
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. // Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
// //
#include "MetavoxelData.h"
#include "MetavoxelMessages.h" #include "MetavoxelMessages.h"
void MetavoxelEditMessage::apply(MetavoxelData& data) const { void MetavoxelEditMessage::apply(MetavoxelData& data) const {
@ -106,8 +105,7 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh
} }
void InsertSpannerEdit::apply(MetavoxelData& data) const { void InsertSpannerEdit::apply(MetavoxelData& data) const {
Spanner* spanner = static_cast<Spanner*>(this->spanner.data()); data.insert(attribute, spanner);
data.insert(attribute, spanner->getBounds(), spanner->getGranularity(), this->spanner);
} }
RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) : RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) :

View file

@ -9,10 +9,7 @@
#ifndef __interface__MetavoxelMessages__ #ifndef __interface__MetavoxelMessages__
#define __interface__MetavoxelMessages__ #define __interface__MetavoxelMessages__
#include "AttributeRegistry.h" #include "MetavoxelData.h"
#include "MetavoxelUtil.h"
class MetavoxelData;
/// Requests to close the session. /// Requests to close the session.
class CloseSessionMessage { class CloseSessionMessage {
@ -49,7 +46,7 @@ class ClientStateMessage {
public: public:
STREAM glm::vec3 position; STREAM MetavoxelLOD lod;
}; };
DECLARE_STREAMABLE_METATYPE(ClientStateMessage) DECLARE_STREAMABLE_METATYPE(ClientStateMessage)