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

View file

@ -78,6 +78,7 @@ private:
public:
int packetNumber;
MetavoxelData data;
MetavoxelLOD lod;
};
MetavoxelServer* _server;
@ -86,7 +87,7 @@ private:
SharedNodePointer _node;
glm::vec3 _position;
MetavoxelLOD _lod;
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(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(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
ReceiveRecord record = { 0, _data };
_receiveRecords.append(record);
ReceiveRecord receiveRecord = { 0, _data };
_receiveRecords.append(receiveRecord);
}
MetavoxelClient::~MetavoxelClient() {
@ -206,9 +211,14 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) {
void MetavoxelClient::simulate(float deltaTime) {
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);
_sequencer.endPacket();
// record the send
SendRecord record = { _sequencer.getOutgoingPacketNumber(), state.lod };
_sendRecords.append(record);
}
int MetavoxelClient::parseData(const QByteArray& packet) {
@ -227,7 +237,7 @@ void MetavoxelClient::readPacket(Bitstream& in) {
handleMessage(message, in);
// record the receipt
ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data };
ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data, _sendRecords.first().lod };
_receiveRecords.append(record);
// 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) {
_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) {
int userType = message.userType();
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) {
foreach (const QVariant& element, message.toList()) {

View file

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

View file

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

View file

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

View file

@ -27,6 +27,10 @@ MetavoxelLOD::MetavoxelLOD(const glm::vec3& position, float 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) {
}
@ -62,7 +66,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) {
const QVector<AttributePointer>& inputs = visitor.getInputs();
const QVector<AttributePointer>& outputs = visitor.getOutputs();
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()) } };
for (int i = 0; i < inputs.size(); 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:
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);
@ -113,8 +134,8 @@ private:
const SharedObjectPointer& _object;
};
InsertVisitor::InsertVisitor(const AttributePointer& attribute, const Box& bounds,
float granularity, const SharedObjectPointer& object) :
template<SpannerUpdateFunction F> SpannerUpdateVisitor<F>::SpannerUpdateVisitor(const AttributePointer& attribute,
const Box& bounds, float granularity, const SharedObjectPointer& object) :
MetavoxelVisitor(QVector<AttributePointer>() << attribute, QVector<AttributePointer>() << attribute),
_attribute(attribute),
_bounds(bounds),
@ -122,7 +143,7 @@ InsertVisitor::InsertVisitor(const AttributePointer& attribute, const Box& bound
_object(object) {
}
bool InsertVisitor::visit(MetavoxelInfo& info) {
template<SpannerUpdateFunction F> bool SpannerUpdateVisitor<F>::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_bounds)) {
return false;
}
@ -130,61 +151,45 @@ bool InsertVisitor::visit(MetavoxelInfo& info) {
return true;
}
SharedObjectSet set = info.inputValues.at(0).getInlineValue<SharedObjectSet>();
set.insert(_object);
F(set, _object);
info.outputValues[0] = AttributeValue(_attribute, encodeInline(set));
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,
float granularity, const SharedObjectPointer& object) {
// expand to fit the entire bounds
while (!getBounds().contains(bounds)) {
expand();
}
InsertVisitor visitor(attribute, bounds, granularity, object);
SpannerUpdateVisitor<insertSpanner> visitor(attribute, bounds, granularity, object);
guide(visitor);
}
class RemoveVisitor : public MetavoxelVisitor {
public:
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 SharedObjectPointer& object) {
Spanner* spanner = static_cast<Spanner*>(object.data());
remove(attribute, spanner->getBounds(), spanner->getGranularity(), object);
}
void MetavoxelData::remove(const AttributePointer& attribute, const Box& bounds,
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);
}
@ -231,7 +236,7 @@ void MetavoxelData::expand() {
_size *= 2.0f;
}
void MetavoxelData::read(Bitstream& in) {
void MetavoxelData::read(Bitstream& in, const MetavoxelLOD& lod) {
// clear out any existing roots
decrementRootReferenceCounts();
_roots.clear();
@ -239,27 +244,29 @@ void MetavoxelData::read(Bitstream& in) {
in >> _size;
// read in the new roots
int rootCount;
in >> rootCount;
for (int i = 0; i < rootCount; i++) {
forever {
AttributePointer attribute;
in >> attribute;
MetavoxelNode*& root = _roots[attribute];
root = new MetavoxelNode(attribute);
attribute->read(*root, in);
if (!attribute) {
break;
}
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 << _roots.size();
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
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
*this = reference;
@ -279,34 +286,36 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) {
}
}
int changedCount;
in >> changedCount;
for (int i = 0; i < changedCount; i++) {
forever {
AttributePointer attribute;
in >> attribute;
MetavoxelNode*& root = _roots[attribute];
if (root) {
MetavoxelNode* oldRoot = root;
root = new MetavoxelNode(attribute);
attribute->readDelta(*root, *oldRoot, in);
if (!attribute) {
break;
}
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);
} else {
root = new MetavoxelNode(attribute);
attribute->read(*root, in);
attribute->read(*this, state);
}
}
int removedCount;
in >> removedCount;
for (int i = 0; i < removedCount; i++) {
forever {
AttributePointer attribute;
in >> attribute;
if (!attribute) {
break;
}
_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
if (_size == reference._size && _roots == reference._roots) {
out << false;
@ -329,42 +338,29 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, Bitstream& out) c
expandedReference = expanded;
}
// count the number of roots added/changed, then write
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;
// write the added/changed roots
for (QHash<AttributePointer, MetavoxelNode*>::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 };
if (referenceRoot) {
it.key()->writeDelta(*it.value(), *referenceRoot, out);
it.key()->writeDelta(*it.value(), *referenceRoot, state);
} else {
it.key()->write(*it.value(), out);
it.key()->write(*it.value(), state);
}
}
}
out << AttributePointer();
// 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();
it != expandedReference->_roots.constEnd(); it++) {
if (!_roots.contains(it.key())) {
out << it.key();
}
}
out << AttributePointer();
// delete the expanded reference if we had to expand
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() {
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
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) {
_attributeValue = attributeValue.copy();
for (int i = 0; i < CHILD_COUNT; i++) {
@ -431,50 +446,72 @@ bool MetavoxelNode::isLeaf() const {
return true;
}
void MetavoxelNode::read(const AttributePointer& attribute, Bitstream& in) {
clearChildren(attribute);
void MetavoxelNode::read(MetavoxelStreamState& state) {
clearChildren(state.attribute);
if (!state.shouldSubdivide()) {
state.attribute->read(state.stream, _attributeValue, true);
return;
}
bool leaf;
in >> leaf;
attribute->read(in, _attributeValue, leaf);
state.stream >> leaf;
state.attribute->read(state.stream, _attributeValue, 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++) {
_children[i] = new MetavoxelNode(attribute);
_children[i]->read(attribute, in);
nextState.setMinimum(state.minimum, i);
_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();
out << leaf;
attribute->write(out, _attributeValue, leaf);
state.stream << leaf;
state.attribute->write(state.stream, _attributeValue, 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++) {
_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) {
clearChildren(attribute);
void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) {
clearChildren(state.attribute);
if (!state.shouldSubdivide()) {
state.attribute->readDelta(state.stream, _attributeValue, reference._attributeValue, true);
return;
}
bool leaf;
in >> leaf;
attribute->readDelta(in, _attributeValue, reference._attributeValue, leaf);
state.stream >> leaf;
state.attribute->readDelta(state.stream, _attributeValue, reference._attributeValue, 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++) {
_children[i] = new MetavoxelNode(attribute);
_children[i]->read(attribute, in);
nextState.setMinimum(state.minimum, i);
_children[i] = new MetavoxelNode(state.attribute);
_children[i]->read(nextState);
}
} else {
for (int i = 0; i < CHILD_COUNT; i++) {
bool changed;
in >> changed;
state.stream >> changed;
if (changed) {
_children[i] = new MetavoxelNode(attribute);
_children[i]->readDelta(attribute, *reference._children[i], in);
nextState.setMinimum(state.minimum, i);
_children[i] = new MetavoxelNode(state.attribute);
_children[i]->readDelta(*reference._children[i], nextState);
} else {
_children[i] = reference._children[i];
_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();
out << leaf;
attribute->writeDelta(out, _attributeValue, reference._attributeValue, leaf);
state.stream << leaf;
state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, 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++) {
_children[i]->write(attribute, out);
nextState.setMinimum(state.minimum, i);
_children[i]->write(nextState);
}
} else {
for (int i = 0; i < CHILD_COUNT; i++) {
if (_children[i] == reference._children[i]) {
out << false;
state.stream << false;
} else {
out << true;
_children[i]->writeDelta(attribute, *reference._children[i], out);
nextState.setMinimum(state.minimum, i);
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) {
if (--_referenceCount == 0) {
destroy(attribute);
@ -604,10 +707,7 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
MetavoxelNode* child = node ? node->getChild(i) : NULL;
nextVisitation.outputNodes[j] = child;
}
nextVisitation.info.minimum = visitation.info.minimum + glm::vec3(
(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);
nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, i);
static_cast<MetavoxelGuide*>(nextVisitation.info.inputValues.last().getInlineValue<
SharedObjectPointer>().data())->guide(nextVisitation);
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.
class MetavoxelLOD {
STREAMABLE
public:
glm::vec3 position;
float threshold;
STREAM glm::vec3 position;
STREAM float threshold;
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.
class MetavoxelData {
public:
@ -52,25 +60,35 @@ public:
float getSize() const { return _size; }
glm::vec3 getMinimum() const { return glm::vec3(_size, _size, _size) * -0.5f; }
Box getBounds() const;
/// Applies the specified visitor to the contained voxels.
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 remove(const AttributePointer& attribute, 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);
/// Expands the tree, increasing its capacity in all dimensions.
void expand();
void read(Bitstream& in);
void write(Bitstream& out) const;
void read(Bitstream& in, const MetavoxelLOD& lod = MetavoxelLOD());
void write(Bitstream& out, const MetavoxelLOD& lod = MetavoxelLOD()) const;
void readDelta(const MetavoxelData& reference, Bitstream& in);
void writeDelta(const MetavoxelData& reference, Bitstream& out) const;
void readDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, Bitstream& in, const MetavoxelLOD& lod);
void writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD,
Bitstream& out, const MetavoxelLOD& lod) const;
MetavoxelNode* createRoot(const AttributePointer& attribute);
private:
@ -83,6 +101,22 @@ private:
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.
class MetavoxelNode {
public:
@ -104,11 +138,14 @@ public:
bool isLeaf() const;
void read(const AttributePointer& attribute, Bitstream& in);
void write(const AttributePointer& attribute, Bitstream& out) const;
void read(MetavoxelStreamState& state);
void write(MetavoxelStreamState& state) const;
void readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in);
void writeDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& out) const;
void readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state);
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.
void incrementReferenceCount() { _referenceCount++; }

View file

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

View file

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