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()));
}
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<ClientStateMessage>();
_position = state.position;
} else if (userType == MetavoxelEdit::Type) {
MetavoxelEdit edit = message.value<MetavoxelEdit>();
qDebug() << "got edit " << edit.granularity;
} else if (userType == MetavoxelEditMessage::Type) {
_server->applyEdit(message.value<MetavoxelEditMessage>());
} else if (userType == QMetaType::QVariantList) {
foreach (const QVariant& element, message.toList()) {

View file

@ -20,6 +20,7 @@
#include <DatagramSequencer.h>
#include <MetavoxelData.h>
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);

View file

@ -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<MetavoxelEditMessage>().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()) {

View file

@ -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);

View file

@ -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);
}

View file

@ -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<HighPriorityMessage>& 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);

View file

@ -72,28 +72,20 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) {
}
void MetavoxelData::read(Bitstream& in) {
// save the old roots and clear
QHash<AttributePointer, MetavoxelNode*> 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<AttributePointer, MetavoxelNode*>::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) {

View file

@ -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);

View file

@ -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<AttributePointer>(), QVector<AttributePointer>() << 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);
}

View file

@ -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__) */