mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 18:21:16 +02:00
Lots of work on metavoxel LODs and spanners.
This commit is contained in:
parent
7a182ed659
commit
63b4a2453b
10 changed files with 355 additions and 171 deletions
|
@ -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>());
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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__) */
|
||||||
|
|
|
@ -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++) {
|
||||||
|
|
|
@ -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++; }
|
||||||
|
|
|
@ -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) :
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue