Basic editing with delta streaming up and running.

This commit is contained in:
Andrzej Kapolka 2014-01-27 15:49:50 -08:00
parent 62e8cbedbd
commit d5695395c4
10 changed files with 118 additions and 68 deletions

View file

@ -24,6 +24,10 @@ MetavoxelServer::MetavoxelServer(const unsigned char* dataBuffer, int numBytes)
connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas())); connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas()));
} }
void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) {
edit.apply(_data);
}
void MetavoxelServer::removeSession(const QUuid& sessionId) { void MetavoxelServer::removeSession(const QUuid& sessionId) {
delete _sessions.take(sessionId); delete _sessions.take(sessionId);
} }
@ -74,16 +78,18 @@ void MetavoxelServer::processData(const QByteArray& data, const HifiSockAddr& se
// forward to session, creating if necessary // forward to session, creating if necessary
MetavoxelSession*& session = _sessions[sessionID]; MetavoxelSession*& session = _sessions[sessionID];
if (!session) { if (!session) {
session = new MetavoxelSession(this, sessionID, QByteArray::fromRawData(data.constData(), headerPlusIDSize)); session = new MetavoxelSession(this, sessionID, QByteArray::fromRawData(data.constData(), headerPlusIDSize), sender);
} }
session->receivedData(data, sender); session->receivedData(data, sender);
} }
MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId, const QByteArray& datagramHeader) : MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId,
const QByteArray& datagramHeader, const HifiSockAddr& sender) :
QObject(server), QObject(server),
_server(server), _server(server),
_sessionId(sessionId), _sessionId(sessionId),
_sequencer(datagramHeader) { _sequencer(datagramHeader),
_sender(sender) {
const int TIMEOUT_INTERVAL = 30 * 1000; const int TIMEOUT_INTERVAL = 30 * 1000;
_timeoutTimer.setInterval(TIMEOUT_INTERVAL); _timeoutTimer.setInterval(TIMEOUT_INTERVAL);
@ -98,6 +104,8 @@ MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& session
// insert the baseline send record // insert the baseline send record
SendRecord record = { 0 }; SendRecord record = { 0 };
_sendRecords.append(record); _sendRecords.append(record);
qDebug() << "Opened session [sessionId=" << _sessionId << ", sender=" << _sender << "]";
} }
void MetavoxelSession::receivedData(const QByteArray& data, const HifiSockAddr& sender) { void MetavoxelSession::receivedData(const QByteArray& data, const HifiSockAddr& sender) {
@ -114,7 +122,7 @@ void MetavoxelSession::receivedData(const QByteArray& data, const HifiSockAddr&
void MetavoxelSession::sendDelta() { void MetavoxelSession::sendDelta() {
Bitstream& out = _sequencer.startPacket(); Bitstream& out = _sequencer.startPacket();
out << QVariant::fromValue(MetavoxelDeltaMessage()); out << QVariant::fromValue(MetavoxelDeltaMessage());
//writeDelta(_server->getData(), _sendRecords.first().data, out); _server->getData().writeDelta(_sendRecords.first().data, out);
_sequencer.endPacket(); _sequencer.endPacket();
// record the send // record the send
@ -143,13 +151,16 @@ void MetavoxelSession::clearSendRecordsBefore(int index) {
void MetavoxelSession::handleMessage(const QVariant& message) { void MetavoxelSession::handleMessage(const QVariant& message) {
int userType = message.userType(); int userType = message.userType();
if (userType == ClientStateMessage::Type) { if (userType == CloseSessionMessage::Type) {
qDebug() << "Session closed [sessionId=" << _sessionId << ", sender=" << _sender << "]";
_server->removeSession(_sessionId);
} else if (userType == ClientStateMessage::Type) {
ClientStateMessage state = message.value<ClientStateMessage>(); ClientStateMessage state = message.value<ClientStateMessage>();
_position = state.position; _position = state.position;
} else if (userType == MetavoxelEdit::Type) { } else if (userType == MetavoxelEditMessage::Type) {
MetavoxelEdit edit = message.value<MetavoxelEdit>(); _server->applyEdit(message.value<MetavoxelEditMessage>());
qDebug() << "got edit " << edit.granularity;
} else if (userType == QMetaType::QVariantList) { } else if (userType == QMetaType::QVariantList) {
foreach (const QVariant& element, message.toList()) { foreach (const QVariant& element, message.toList()) {

View file

@ -20,6 +20,7 @@
#include <DatagramSequencer.h> #include <DatagramSequencer.h>
#include <MetavoxelData.h> #include <MetavoxelData.h>
class MetavoxelEditMessage;
class MetavoxelSession; class MetavoxelSession;
/// Maintains a shared metavoxel system, accepting change requests and broadcasting updates. /// Maintains a shared metavoxel system, accepting change requests and broadcasting updates.
@ -30,6 +31,8 @@ public:
MetavoxelServer(const unsigned char* dataBuffer, int numBytes); MetavoxelServer(const unsigned char* dataBuffer, int numBytes);
void applyEdit(const MetavoxelEditMessage& edit);
const MetavoxelData& getData() const { return _data; } const MetavoxelData& getData() const { return _data; }
void removeSession(const QUuid& sessionId); void removeSession(const QUuid& sessionId);
@ -60,7 +63,8 @@ class MetavoxelSession : public QObject {
public: public:
MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId, const QByteArray& datagramHeader); MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId,
const QByteArray& datagramHeader, const HifiSockAddr& sender);
void receivedData(const QByteArray& data, const HifiSockAddr& sender); void receivedData(const QByteArray& data, const HifiSockAddr& sender);

View file

@ -41,7 +41,7 @@ void MetavoxelSystem::init() {
_buffer.create(); _buffer.create();
} }
void MetavoxelSystem::applyEdit(const MetavoxelEdit& edit) { void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit) {
foreach (MetavoxelClient* client, _clients) { foreach (MetavoxelClient* client, _clients) {
client->applyEdit(edit); client->applyEdit(edit);
} }
@ -190,7 +190,14 @@ MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) :
_receiveRecords.append(record); _receiveRecords.append(record);
} }
void MetavoxelClient::applyEdit(const MetavoxelEdit& edit) { MetavoxelClient::~MetavoxelClient() {
// close the session
Bitstream& out = _sequencer.startPacket();
out << QVariant::fromValue(CloseSessionMessage());
_sequencer.endPacket();
}
void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) {
// apply immediately to local tree // apply immediately to local tree
edit.apply(_data); edit.apply(_data);
@ -227,6 +234,13 @@ void MetavoxelClient::readPacket(Bitstream& in) {
// record the receipt // record the receipt
ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data }; ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data };
_receiveRecords.append(record); _receiveRecords.append(record);
// reapply local edits
foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) {
if (message.data.userType() == MetavoxelEditMessage::Type) {
message.data.value<MetavoxelEditMessage>().apply(_data);
}
}
} }
void MetavoxelClient::clearReceiveRecordsBefore(int index) { void MetavoxelClient::clearReceiveRecordsBefore(int index) {
@ -236,7 +250,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) {
// readDelta(_data, _receiveRecords.first().data, in); _data.readDelta(_receiveRecords.first().data, in);
} else if (userType == QMetaType::QVariantList) { } else if (userType == QMetaType::QVariantList) {
foreach (const QVariant& element, message.toList()) { foreach (const QVariant& element, message.toList()) {

View file

@ -35,7 +35,7 @@ public:
void init(); void init();
void applyEdit(const MetavoxelEdit& edit); void applyEdit(const MetavoxelEditMessage& edit);
void processData(const QByteArray& data, const HifiSockAddr& sender); void processData(const QByteArray& data, const HifiSockAddr& sender);
@ -87,10 +87,11 @@ class MetavoxelClient : public QObject {
public: public:
MetavoxelClient(const HifiSockAddr& address); MetavoxelClient(const HifiSockAddr& address);
virtual ~MetavoxelClient();
const QUuid& getSessionID() const { return _sessionID; } const QUuid& getSessionID() const { return _sessionID; }
void applyEdit(const MetavoxelEdit& edit); void applyEdit(const MetavoxelEditMessage& edit);
void simulate(float deltaTime, MetavoxelVisitor& visitor); void simulate(float deltaTime, MetavoxelVisitor& visitor);

View file

@ -348,7 +348,7 @@ void MetavoxelEditor::applyValue(const glm::vec3& minimum, const glm::vec3& maxi
return; return;
} }
OwnedAttributeValue value(attribute, attribute->createFromVariant(getValue())); OwnedAttributeValue value(attribute, attribute->createFromVariant(getValue()));
MetavoxelEdit edit = { minimum, maximum, getGridSpacing(), value }; MetavoxelEditMessage edit = { minimum, maximum, getGridSpacing(), value };
Application::getInstance()->getMetavoxels()->applyEdit(edit); Application::getInstance()->getMetavoxels()->applyEdit(edit);
} }

View file

@ -23,6 +23,12 @@ class DatagramSequencer : public QObject {
public: public:
class HighPriorityMessage {
public:
QVariant data;
int firstPacketNumber;
};
DatagramSequencer(const QByteArray& datagramHeader = QByteArray()); DatagramSequencer(const QByteArray& datagramHeader = QByteArray());
/// Returns the packet number of the last packet sent. /// Returns the packet number of the last packet sent.
@ -37,6 +43,9 @@ public:
/// Adds a message to the high priority queue. Will be sent with every outgoing packet until received. /// Adds a message to the high priority queue. Will be sent with every outgoing packet until received.
void sendHighPriorityMessage(const QVariant& data); void sendHighPriorityMessage(const QVariant& data);
/// Returns a reference to the list of high priority messages not yet acknowledged.
const QList<HighPriorityMessage>& getHighPriorityMessages() const { return _highPriorityMessages; }
/// Starts a new packet for transmission. /// Starts a new packet for transmission.
/// \return a reference to the Bitstream to use for writing to the packet /// \return a reference to the Bitstream to use for writing to the packet
Bitstream& startPacket(); Bitstream& startPacket();
@ -85,12 +94,6 @@ private:
bool operator<(const ReceiveRecord& other) const { return packetNumber < other.packetNumber; } bool operator<(const ReceiveRecord& other) const { return packetNumber < other.packetNumber; }
}; };
class HighPriorityMessage {
public:
QVariant data;
int firstPacketNumber;
};
/// Notes that the described send was acknowledged by the other party. /// Notes that the described send was acknowledged by the other party.
void sendRecordAcknowledged(const SendRecord& record); void sendRecordAcknowledged(const SendRecord& record);

View file

@ -72,28 +72,20 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) {
} }
void MetavoxelData::read(Bitstream& in) { void MetavoxelData::read(Bitstream& in) {
// save the old roots and clear // clear out any existing roots
QHash<AttributePointer, MetavoxelNode*> oldRoots = _roots; decrementRootReferenceCounts();
_roots.clear(); _roots.clear();
// read in the new roots, reusing old ones where appropriate // read in the new roots
int rootCount; int rootCount;
in >> rootCount; in >> rootCount;
for (int i = 0; i < rootCount; i++) { for (int i = 0; i < rootCount; i++) {
AttributePointer attribute; AttributePointer attribute;
in.getAttributeStreamer() >> attribute; in.getAttributeStreamer() >> attribute;
MetavoxelNode* root = oldRoots.take(attribute); MetavoxelNode*& root = _roots[attribute];
if (!root) { root = new MetavoxelNode(attribute);
root = new MetavoxelNode(attribute);
}
_roots.insert(attribute, root);
root->read(attribute, in); root->read(attribute, in);
} }
// clear out the remaining old roots
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = oldRoots.constBegin(); it != oldRoots.constEnd(); it++) {
it.value()->decrementReferenceCount(it.key());
}
} }
void MetavoxelData::write(Bitstream& out) const { void MetavoxelData::write(Bitstream& out) const {
@ -105,22 +97,25 @@ void MetavoxelData::write(Bitstream& out) const {
} }
void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) { void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) {
// shallow copy the reference
*this = reference;
int changedCount; int changedCount;
in >> changedCount; in >> changedCount;
for (int i = 0; i < changedCount; i++) { for (int i = 0; i < changedCount; i++) {
AttributePointer attribute; AttributePointer attribute;
in.getAttributeStreamer() >> attribute; in.getAttributeStreamer() >> attribute;
MetavoxelNode*& root = _roots[attribute]; MetavoxelNode*& root = _roots[attribute];
if (!root) { if (root) {
MetavoxelNode* oldRoot = root;
root = new MetavoxelNode(attribute); root = new MetavoxelNode(attribute);
} root->readDelta(attribute, *oldRoot, in);
MetavoxelNode* referenceRoot = reference._roots.value(attribute); oldRoot->decrementReferenceCount(attribute);
if (referenceRoot) {
root->readDelta(attribute, *referenceRoot, in);
} else { } else {
root = new MetavoxelNode(attribute);
root->read(attribute, in); root->read(attribute, in);
} }
} }
int removedCount; int removedCount;
@ -128,7 +123,7 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) {
for (int i = 0; i < removedCount; i++) { for (int i = 0; i < removedCount; i++) {
AttributePointer attribute; AttributePointer attribute;
in.getAttributeStreamer() >> attribute; in.getAttributeStreamer() >> attribute;
_roots.take(attribute)->decrementReferenceCount(attribute);
} }
} }
@ -231,22 +226,16 @@ bool MetavoxelNode::isLeaf() const {
} }
void MetavoxelNode::read(const AttributePointer& attribute, Bitstream& in) { void MetavoxelNode::read(const AttributePointer& attribute, Bitstream& in) {
clearChildren(attribute);
bool leaf; bool leaf;
in >> leaf; in >> leaf;
attribute->read(in, _attributeValue, leaf); attribute->read(in, _attributeValue, leaf);
if (leaf) { if (!leaf) {
clearChildren(attribute);
} else {
void* childValues[CHILD_COUNT];
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
if (!_children[i]) { _children[i] = new MetavoxelNode(attribute);
_children[i] = new MetavoxelNode(attribute);
}
_children[i]->read(attribute, in); _children[i]->read(attribute, in);
childValues[i] = _children[i]->_attributeValue;
} }
attribute->merge(_attributeValue, childValues);
} }
} }
@ -262,20 +251,28 @@ void MetavoxelNode::write(const AttributePointer& attribute, Bitstream& out) con
} }
void MetavoxelNode::readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in) { void MetavoxelNode::readDelta(const AttributePointer& attribute, const MetavoxelNode& reference, Bitstream& in) {
clearChildren(attribute);
bool leaf; bool leaf;
in >> leaf; in >> leaf;
attribute->readDelta(in, _attributeValue, reference._attributeValue, leaf); attribute->readDelta(in, _attributeValue, reference._attributeValue, leaf);
if (leaf) { if (!leaf) {
clearChildren(attribute);
} else {
if (reference.isLeaf()) { if (reference.isLeaf()) {
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
_children[i] = new MetavoxelNode(attribute);
_children[i]->read(attribute, in); _children[i]->read(attribute, in);
} }
} else { } else {
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
_children[i]->readDelta(attribute, *reference._children[i], in); bool changed;
in >> changed;
if (changed) {
_children[i] = new MetavoxelNode(attribute);
_children[i]->readDelta(attribute, *reference._children[i], in);
} else {
_children[i] = reference._children[i];
_children[i]->incrementReferenceCount();
}
} }
} }
} }
@ -292,7 +289,12 @@ void MetavoxelNode::writeDelta(const AttributePointer& attribute, const Metavoxe
} }
} else { } else {
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
_children[i]->writeDelta(attribute, *reference._children[i], out); if (_children[i] == reference._children[i]) {
out << false;
} else {
out << true;
_children[i]->writeDelta(attribute, *reference._children[i], out);
}
} }
} }
} }
@ -343,9 +345,16 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
visitation.info.isLeaf = visitation.allInputNodesLeaves(); visitation.info.isLeaf = visitation.allInputNodesLeaves();
bool keepGoing = visitation.visitor.visit(visitation.info); bool keepGoing = visitation.visitor.visit(visitation.info);
for (int i = 0; i < visitation.outputNodes.size(); i++) { for (int i = 0; i < visitation.outputNodes.size(); i++) {
const AttributeValue& value = visitation.info.outputValues[i]; AttributeValue& value = visitation.info.outputValues[i];
if (value.getAttribute()) { if (!value.getAttribute()) {
visitation.outputNodes[i] = new MetavoxelNode(value); continue;
}
MetavoxelNode*& node = visitation.outputNodes[i];
if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) {
// "set" to same value; disregard
value = AttributeValue();
} else {
node = new MetavoxelNode(value);
} }
} }
if (!keepGoing) { if (!keepGoing) {

View file

@ -67,6 +67,7 @@ public:
void setAttributeValue(const AttributeValue& attributeValue); void setAttributeValue(const AttributeValue& attributeValue);
AttributeValue getAttributeValue(const AttributePointer& attribute) const; AttributeValue getAttributeValue(const AttributePointer& attribute) const;
void* getAttributeValue() const { return _attributeValue; }
void mergeChildren(const AttributePointer& attribute); void mergeChildren(const AttributePointer& attribute);

View file

@ -12,16 +12,16 @@
class EditVisitor : public MetavoxelVisitor { class EditVisitor : public MetavoxelVisitor {
public: public:
EditVisitor(const MetavoxelEdit& edit); EditVisitor(const MetavoxelEditMessage& edit);
virtual bool visit(MetavoxelInfo& info); virtual bool visit(MetavoxelInfo& info);
private: private:
const MetavoxelEdit& _edit; const MetavoxelEditMessage& _edit;
}; };
EditVisitor::EditVisitor(const MetavoxelEdit& edit) : EditVisitor::EditVisitor(const MetavoxelEditMessage& edit) :
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << edit.value.getAttribute()), MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << edit.value.getAttribute()),
_edit(edit) { _edit(edit) {
} }
@ -48,7 +48,7 @@ bool EditVisitor::visit(MetavoxelInfo& info) {
return true; // subdivide return true; // subdivide
} }
void MetavoxelEdit::apply(MetavoxelData& data) const { void MetavoxelEditMessage::apply(MetavoxelData& data) const {
EditVisitor visitor(*this); EditVisitor visitor(*this);
data.guide(visitor); data.guide(visitor);
} }

View file

@ -14,6 +14,13 @@
class MetavoxelData; class MetavoxelData;
/// Requests to close the session.
class CloseSessionMessage {
STREAMABLE
};
DECLARE_STREAMABLE_METATYPE(CloseSessionMessage)
/// A message containing the state of a client. /// A message containing the state of a client.
class ClientStateMessage { class ClientStateMessage {
STREAMABLE STREAMABLE
@ -33,7 +40,7 @@ class MetavoxelDeltaMessage {
DECLARE_STREAMABLE_METATYPE(MetavoxelDeltaMessage) DECLARE_STREAMABLE_METATYPE(MetavoxelDeltaMessage)
/// A simple streamable edit. /// A simple streamable edit.
class MetavoxelEdit { class MetavoxelEditMessage {
STREAMABLE STREAMABLE
public: public:
@ -46,6 +53,6 @@ public:
void apply(MetavoxelData& data) const; void apply(MetavoxelData& data) const;
}; };
DECLARE_STREAMABLE_METATYPE(MetavoxelEdit) DECLARE_STREAMABLE_METATYPE(MetavoxelEditMessage)
#endif /* defined(__interface__MetavoxelMessages__) */ #endif /* defined(__interface__MetavoxelMessages__) */