From d5695395c44ece9ef4f2cb59057669bd52c653a0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 27 Jan 2014 15:49:50 -0800 Subject: [PATCH] Basic editing with delta streaming up and running. --- .../src/metavoxels/MetavoxelServer.cpp | 27 ++++-- .../src/metavoxels/MetavoxelServer.h | 6 +- interface/src/MetavoxelSystem.cpp | 20 +++- interface/src/MetavoxelSystem.h | 5 +- interface/src/ui/MetavoxelEditor.cpp | 2 +- libraries/metavoxels/src/DatagramSequencer.h | 15 +-- libraries/metavoxels/src/MetavoxelData.cpp | 91 ++++++++++--------- libraries/metavoxels/src/MetavoxelData.h | 1 + .../metavoxels/src/MetavoxelMessages.cpp | 8 +- libraries/metavoxels/src/MetavoxelMessages.h | 11 ++- 10 files changed, 118 insertions(+), 68 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index db67fe27ed..f18fbb6c87 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -24,6 +24,10 @@ MetavoxelServer::MetavoxelServer(const unsigned char* dataBuffer, int numBytes) connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas())); } +void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) { + edit.apply(_data); +} + void MetavoxelServer::removeSession(const QUuid& sessionId) { delete _sessions.take(sessionId); } @@ -74,16 +78,18 @@ void MetavoxelServer::processData(const QByteArray& data, const HifiSockAddr& se // forward to session, creating if necessary MetavoxelSession*& session = _sessions[sessionID]; 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); } -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), _server(server), _sessionId(sessionId), - _sequencer(datagramHeader) { + _sequencer(datagramHeader), + _sender(sender) { const int TIMEOUT_INTERVAL = 30 * 1000; _timeoutTimer.setInterval(TIMEOUT_INTERVAL); @@ -98,6 +104,8 @@ MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& session // insert the baseline send record SendRecord record = { 0 }; _sendRecords.append(record); + + qDebug() << "Opened session [sessionId=" << _sessionId << ", sender=" << _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() { Bitstream& out = _sequencer.startPacket(); out << QVariant::fromValue(MetavoxelDeltaMessage()); - //writeDelta(_server->getData(), _sendRecords.first().data, out); + _server->getData().writeDelta(_sendRecords.first().data, out); _sequencer.endPacket(); // record the send @@ -143,13 +151,16 @@ void MetavoxelSession::clearSendRecordsBefore(int index) { void MetavoxelSession::handleMessage(const QVariant& message) { 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(); _position = state.position; - } else if (userType == MetavoxelEdit::Type) { - MetavoxelEdit edit = message.value(); - qDebug() << "got edit " << edit.granularity; + } else if (userType == MetavoxelEditMessage::Type) { + _server->applyEdit(message.value()); } else if (userType == QMetaType::QVariantList) { foreach (const QVariant& element, message.toList()) { diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index 3853ac5cf0..c866a8871c 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -20,6 +20,7 @@ #include #include +class MetavoxelEditMessage; class MetavoxelSession; /// Maintains a shared metavoxel system, accepting change requests and broadcasting updates. @@ -30,6 +31,8 @@ public: MetavoxelServer(const unsigned char* dataBuffer, int numBytes); + void applyEdit(const MetavoxelEditMessage& edit); + const MetavoxelData& getData() const { return _data; } void removeSession(const QUuid& sessionId); @@ -60,7 +63,8 @@ class MetavoxelSession : public QObject { 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); diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index fdb3ef5fbf..546b8c9b5c 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -41,7 +41,7 @@ void MetavoxelSystem::init() { _buffer.create(); } -void MetavoxelSystem::applyEdit(const MetavoxelEdit& edit) { +void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit) { foreach (MetavoxelClient* client, _clients) { client->applyEdit(edit); } @@ -190,7 +190,14 @@ MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) : _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 edit.apply(_data); @@ -227,6 +234,13 @@ void MetavoxelClient::readPacket(Bitstream& in) { // record the receipt ReceiveRecord record = { _sequencer.getIncomingPacketNumber(), _data }; _receiveRecords.append(record); + + // reapply local edits + foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) { + if (message.data.userType() == MetavoxelEditMessage::Type) { + message.data.value().apply(_data); + } + } } void MetavoxelClient::clearReceiveRecordsBefore(int index) { @@ -236,7 +250,7 @@ void MetavoxelClient::clearReceiveRecordsBefore(int index) { void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { int userType = message.userType(); if (userType == MetavoxelDeltaMessage::Type) { - // readDelta(_data, _receiveRecords.first().data, in); + _data.readDelta(_receiveRecords.first().data, in); } else if (userType == QMetaType::QVariantList) { foreach (const QVariant& element, message.toList()) { diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index c3198fa681..2387a6c67d 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -35,7 +35,7 @@ public: void init(); - void applyEdit(const MetavoxelEdit& edit); + void applyEdit(const MetavoxelEditMessage& edit); void processData(const QByteArray& data, const HifiSockAddr& sender); @@ -87,10 +87,11 @@ class MetavoxelClient : public QObject { public: MetavoxelClient(const HifiSockAddr& address); + virtual ~MetavoxelClient(); const QUuid& getSessionID() const { return _sessionID; } - void applyEdit(const MetavoxelEdit& edit); + void applyEdit(const MetavoxelEditMessage& edit); void simulate(float deltaTime, MetavoxelVisitor& visitor); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index b71ff52add..12f727f139 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -348,7 +348,7 @@ void MetavoxelEditor::applyValue(const glm::vec3& minimum, const glm::vec3& maxi return; } OwnedAttributeValue value(attribute, attribute->createFromVariant(getValue())); - MetavoxelEdit edit = { minimum, maximum, getGridSpacing(), value }; + MetavoxelEditMessage edit = { minimum, maximum, getGridSpacing(), value }; Application::getInstance()->getMetavoxels()->applyEdit(edit); } diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index a7159bd9de..4ef827abeb 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -23,6 +23,12 @@ class DatagramSequencer : public QObject { public: + class HighPriorityMessage { + public: + QVariant data; + int firstPacketNumber; + }; + DatagramSequencer(const QByteArray& datagramHeader = QByteArray()); /// 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. void sendHighPriorityMessage(const QVariant& data); + /// Returns a reference to the list of high priority messages not yet acknowledged. + const QList& getHighPriorityMessages() const { return _highPriorityMessages; } + /// Starts a new packet for transmission. /// \return a reference to the Bitstream to use for writing to the packet Bitstream& startPacket(); @@ -85,12 +94,6 @@ private: 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. void sendRecordAcknowledged(const SendRecord& record); diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index c52aaddd4b..c9136d8cab 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -72,28 +72,20 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { } void MetavoxelData::read(Bitstream& in) { - // save the old roots and clear - QHash oldRoots = _roots; + // clear out any existing roots + decrementRootReferenceCounts(); _roots.clear(); - - // read in the new roots, reusing old ones where appropriate + + // read in the new roots int rootCount; in >> rootCount; for (int i = 0; i < rootCount; i++) { AttributePointer attribute; in.getAttributeStreamer() >> attribute; - MetavoxelNode* root = oldRoots.take(attribute); - if (!root) { - root = new MetavoxelNode(attribute); - } - _roots.insert(attribute, root); + MetavoxelNode*& root = _roots[attribute]; + root = new MetavoxelNode(attribute); root->read(attribute, in); } - - // clear out the remaining old roots - for (QHash::const_iterator it = oldRoots.constBegin(); it != oldRoots.constEnd(); it++) { - it.value()->decrementReferenceCount(it.key()); - } } void MetavoxelData::write(Bitstream& out) const { @@ -105,22 +97,25 @@ void MetavoxelData::write(Bitstream& out) const { } void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) { + // shallow copy the reference + *this = reference; + int changedCount; in >> changedCount; for (int i = 0; i < changedCount; i++) { AttributePointer attribute; in.getAttributeStreamer() >> attribute; MetavoxelNode*& root = _roots[attribute]; - if (!root) { + if (root) { + MetavoxelNode* oldRoot = root; root = new MetavoxelNode(attribute); - } - MetavoxelNode* referenceRoot = reference._roots.value(attribute); - if (referenceRoot) { - root->readDelta(attribute, *referenceRoot, in); - + root->readDelta(attribute, *oldRoot, in); + oldRoot->decrementReferenceCount(attribute); + } else { + root = new MetavoxelNode(attribute); root->read(attribute, in); - } + } } int removedCount; @@ -128,7 +123,7 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, Bitstream& in) { for (int i = 0; i < removedCount; i++) { AttributePointer 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) { + clearChildren(attribute); + bool leaf; in >> leaf; attribute->read(in, _attributeValue, leaf); - if (leaf) { - clearChildren(attribute); - - } else { - void* childValues[CHILD_COUNT]; + if (!leaf) { 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); - 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) { + clearChildren(attribute); + bool leaf; in >> leaf; attribute->readDelta(in, _attributeValue, reference._attributeValue, leaf); - if (leaf) { - clearChildren(attribute); - - } else { + if (!leaf) { if (reference.isLeaf()) { for (int i = 0; i < CHILD_COUNT; i++) { + _children[i] = new MetavoxelNode(attribute); _children[i]->read(attribute, in); } } else { 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 { 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(); bool keepGoing = visitation.visitor.visit(visitation.info); for (int i = 0; i < visitation.outputNodes.size(); i++) { - const AttributeValue& value = visitation.info.outputValues[i]; - if (value.getAttribute()) { - visitation.outputNodes[i] = new MetavoxelNode(value); + AttributeValue& value = visitation.info.outputValues[i]; + if (!value.getAttribute()) { + 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) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 56c786efbf..83821e47ad 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -67,6 +67,7 @@ public: void setAttributeValue(const AttributeValue& attributeValue); AttributeValue getAttributeValue(const AttributePointer& attribute) const; + void* getAttributeValue() const { return _attributeValue; } void mergeChildren(const AttributePointer& attribute); diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 961667deaa..02b040e5cc 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -12,16 +12,16 @@ class EditVisitor : public MetavoxelVisitor { public: - EditVisitor(const MetavoxelEdit& edit); + EditVisitor(const MetavoxelEditMessage& edit); virtual bool visit(MetavoxelInfo& info); private: - const MetavoxelEdit& _edit; + const MetavoxelEditMessage& _edit; }; -EditVisitor::EditVisitor(const MetavoxelEdit& edit) : +EditVisitor::EditVisitor(const MetavoxelEditMessage& edit) : MetavoxelVisitor(QVector(), QVector() << edit.value.getAttribute()), _edit(edit) { } @@ -48,7 +48,7 @@ bool EditVisitor::visit(MetavoxelInfo& info) { return true; // subdivide } -void MetavoxelEdit::apply(MetavoxelData& data) const { +void MetavoxelEditMessage::apply(MetavoxelData& data) const { EditVisitor visitor(*this); data.guide(visitor); } diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 0872f4b6c3..fb8db64506 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -14,6 +14,13 @@ class MetavoxelData; +/// Requests to close the session. +class CloseSessionMessage { + STREAMABLE +}; + +DECLARE_STREAMABLE_METATYPE(CloseSessionMessage) + /// A message containing the state of a client. class ClientStateMessage { STREAMABLE @@ -33,7 +40,7 @@ class MetavoxelDeltaMessage { DECLARE_STREAMABLE_METATYPE(MetavoxelDeltaMessage) /// A simple streamable edit. -class MetavoxelEdit { +class MetavoxelEditMessage { STREAMABLE public: @@ -46,6 +53,6 @@ public: void apply(MetavoxelData& data) const; }; -DECLARE_STREAMABLE_METATYPE(MetavoxelEdit) +DECLARE_STREAMABLE_METATYPE(MetavoxelEditMessage) #endif /* defined(__interface__MetavoxelMessages__) */