From 36f1e59201d3056d67c7d375a86bc5221a085819 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 10 Feb 2014 20:26:09 -0800 Subject: [PATCH 01/18] Working on support for sending messages through reliable channels. --- .../metavoxels/src/DatagramSequencer.cpp | 70 ++++++++++++++++--- libraries/metavoxels/src/DatagramSequencer.h | 16 +++++ tests/metavoxels/src/MetavoxelTests.cpp | 10 ++- 3 files changed, 86 insertions(+), 10 deletions(-) diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index fcbe6b5e87..77f893ccb6 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -343,16 +343,32 @@ void CircularBuffer::remove(int length) { } QByteArray CircularBuffer::readBytes(int offset, int length) const { - // write in up to two segments + QByteArray bytes(length, 0); + readBytes(offset, length, bytes.data()); + return bytes; +} + +void CircularBuffer::readBytes(int offset, int length, char* data) const { + // read in up to two segments QByteArray array; int start = (_position + offset) % _data.size(); int firstSegment = qMin(length, _data.size() - start); - array.append(_data.constData() + start, firstSegment); + memcpy(data, _data.constData() + start, firstSegment); int secondSegment = length - firstSegment; if (secondSegment > 0) { - array.append(_data.constData(), secondSegment); + memcpy(data + firstSegment, _data.constData(), secondSegment); + } +} + +void CircularBuffer::writeBytes(int offset, int length, const char* data) { + // write in up to two segments + int start = (_position + offset) % _data.size(); + int firstSegment = qMin(length, _data.size() - start); + memcpy(_data.data() + start, data, firstSegment); + int secondSegment = length - firstSegment; + if (secondSegment > 0) { + memcpy(_data.data(), data + firstSegment, secondSegment); } - return array; } void CircularBuffer::writeToStream(int offset, int length, QDataStream& out) const { @@ -561,7 +577,14 @@ int ReliableChannel::getBytesAvailable() const { } void ReliableChannel::sendMessage(const QVariant& message) { + // write a placeholder for the length, then fill it in when we know what it is + int placeholder = _buffer.pos(); + _dataStream << (quint32)0; _bitstream << message; + _bitstream.flush(); + + quint32 length = _buffer.pos() - placeholder; + _buffer.writeBytes(placeholder, sizeof(quint32), (const char*)&length); } void ReliableChannel::sendClearSharedObjectMessage(int id) { @@ -576,7 +599,8 @@ ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool o _bitstream(_dataStream), _priority(1.0f), _offset(0), - _writePosition(0) { + _writePosition(0), + _expectingMessage(true) { _buffer.open(output ? QIODevice::WriteOnly : QIODevice::ReadOnly); _dataStream.setByteOrder(QDataStream::LittleEndian); @@ -688,10 +712,32 @@ void ReliableChannel::readData(QDataStream& in) { readSome = true; } } + if (!readSome) { + return; + } - // let listeners know that there's data to read - if (readSome) { - emit _buffer.readyRead(); + forever { + // if we're expecting a message, peek into the buffer to see if we have the whole thing. + // if so, read it in, handle it, and loop back around in case there are more + if (_expectingMessage) { + int available = _buffer.bytesAvailable(); + if (available >= sizeof(quint32)) { + quint32 length; + _buffer.readBytes(_buffer.pos(), sizeof(quint32), (char*)&length); + if (available >= length) { + _dataStream.skipRawData(sizeof(quint32)); + QVariant message; + _bitstream >> message; + _bitstream.reset(); + handleMessage(message); + continue; + } + } + // otherwise, just let whoever's listening know that data is available + } else { + emit _buffer.readyRead(); + } + break; } // prune any read data from the buffer @@ -701,3 +747,11 @@ void ReliableChannel::readData(QDataStream& in) { } } +void ReliableChannel::handleMessage(const QVariant& message) { + if (message.userType() == ClearSharedObjectMessage::Type) { + _bitstream.clearSharedObject(message.value().id); + + } else { + emit receivedMessage(message); + } +} diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 27a4f05379..9adebfbfa4 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -185,6 +185,12 @@ public: /// Reads part of the data from the buffer. QByteArray readBytes(int offset, int length) const; + /// Reads part of the data from the buffer. + void readBytes(int offset, int length, char* data) const; + + /// Writes to part of the data in the buffer. + void writeBytes(int offset, int length, const char* data); + /// Writes part of the buffer to the supplied stream. void writeToStream(int offset, int length, QDataStream& out) const; @@ -267,8 +273,16 @@ public: int getBytesAvailable() const; + /// Sends a framed message on this channel. void sendMessage(const QVariant& message); + /// For input channels, sets whether the channel is expecting a framed message. + void setExpectingMessage(bool expectingMessage) { _expectingMessage = expectingMessage; } + +signals: + + void receivedMessage(const QVariant& message); + private slots: void sendClearSharedObjectMessage(int id); @@ -286,6 +300,7 @@ private: void spanAcknowledged(const DatagramSequencer::ChannelSpan& span); void readData(QDataStream& in); + void handleMessage(const QVariant& message); int _index; CircularBuffer _buffer; @@ -297,6 +312,7 @@ private: int _offset; int _writePosition; SpanList _acknowledged; + bool _expectingMessage; }; #endif /* defined(__interface__DatagramSequencer__) */ diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 15d7463742..49ff5714c0 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -83,8 +83,14 @@ Endpoint::Endpoint(const QByteArray& datagramHeader) : connect(_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readMessage(Bitstream&))); connect(_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleHighPriorityMessage(const QVariant&))); - connect(&_sequencer->getReliableInputChannel()->getBuffer(), SIGNAL(readyRead()), SLOT(readReliableChannel())); - connect(&_sequencer->getReliableInputChannel(1)->getBuffer(), SIGNAL(readyRead()), SLOT(readLowPriorityReliableChannel())); + + ReliableChannel* firstInput = _sequencer->getReliableInputChannel(); + firstInput->setExpectingMessage(false); + connect(&firstInput->getBuffer(), SIGNAL(readyRead()), SLOT(readReliableChannel())); + + ReliableChannel* secondInput = _sequencer->getReliableInputChannel(1); + secondInput->setExpectingMessage(false); + connect(&secondInput->getBuffer(), SIGNAL(readyRead()), SLOT(readLowPriorityReliableChannel())); // enqueue a large amount of data in a low-priority channel ReliableChannel* output = _sequencer->getReliableOutputChannel(1); From f9b0ff0608bbffc91f89f71bff70840ca61bb25e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Feb 2014 12:33:40 -0800 Subject: [PATCH 02/18] Various bits of streaming work: send delete messages for main channel on reliable channel, test messages on main channel. --- .../metavoxels/src/DatagramSequencer.cpp | 56 ++++++++------ libraries/metavoxels/src/DatagramSequencer.h | 16 ++-- libraries/metavoxels/src/MetavoxelMessages.h | 11 +++ tests/metavoxels/src/MetavoxelTests.cpp | 75 ++++++++++--------- tests/metavoxels/src/MetavoxelTests.h | 9 ++- tools/mtc/src/main.cpp | 4 +- 6 files changed, 96 insertions(+), 75 deletions(-) diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index 77f893ccb6..a60d4e9df3 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -42,6 +42,7 @@ DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader, QObject* _outgoingDatagramStream.setByteOrder(QDataStream::LittleEndian); connect(&_outputStream, SIGNAL(sharedObjectCleared(int)), SLOT(sendClearSharedObjectMessage(int))); + connect(this, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleHighPriorityMessage(const QVariant&))); memcpy(_outgoingDatagram.data(), datagramHeader.constData(), _datagramHeaderSize); } @@ -182,7 +183,7 @@ void DatagramSequencer::receivedDatagram(const QByteArray& datagram) { QVariant data; _inputStream >> data; if ((int)i >= _receivedHighPriorityMessages) { - handleHighPriorityMessage(data); + emit receivedHighPriorityMessage(data); } } _receivedHighPriorityMessages = highPriorityMessageCount; @@ -208,9 +209,22 @@ void DatagramSequencer::receivedDatagram(const QByteArray& datagram) { } void DatagramSequencer::sendClearSharedObjectMessage(int id) { - // for now, high priority - ClearSharedObjectMessage message = { id }; - sendHighPriorityMessage(QVariant::fromValue(message)); + // send it low-priority unless the channel has messages disabled + ReliableChannel* channel = getReliableOutputChannel(); + if (channel->getMessagesEnabled()) { + ClearMainChannelSharedObjectMessage message = { id }; + channel->sendMessage(QVariant::fromValue(message)); + + } else { + ClearSharedObjectMessage message = { id }; + sendHighPriorityMessage(QVariant::fromValue(message)); + } +} + +void DatagramSequencer::handleHighPriorityMessage(const QVariant& data) { + if (data.userType() == ClearSharedObjectMessage::Type) { + _inputStream.clearSharedObject(data.value().id); + } } void DatagramSequencer::sendRecordAcknowledged(const SendRecord& record) { @@ -303,15 +317,6 @@ void DatagramSequencer::sendPacket(const QByteArray& packet, const QVector().id); - - } else { - emit receivedHighPriorityMessage(data); - } -} - const int INITIAL_CIRCULAR_BUFFER_CAPACITY = 16; CircularBuffer::CircularBuffer(QObject* parent) : @@ -592,6 +597,16 @@ void ReliableChannel::sendClearSharedObjectMessage(int id) { sendMessage(QVariant::fromValue(message)); } +void ReliableChannel::handleMessage(const QVariant& message) { + if (message.userType() == ClearSharedObjectMessage::Type) { + _bitstream.clearSharedObject(message.value().id); + + } else if (message.userType() == ClearMainChannelSharedObjectMessage::Type) { + static_cast(parent())->_inputStream.clearSharedObject( + message.value().id); + } +} + ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool output) : QObject(sequencer), _index(index), @@ -600,12 +615,13 @@ ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool o _priority(1.0f), _offset(0), _writePosition(0), - _expectingMessage(true) { + _messagesEnabled(true) { _buffer.open(output ? QIODevice::WriteOnly : QIODevice::ReadOnly); _dataStream.setByteOrder(QDataStream::LittleEndian); connect(&_bitstream, SIGNAL(sharedObjectCleared(int)), SLOT(sendClearSharedObjectMessage(int))); + connect(this, SIGNAL(receivedMessage(const QVariant&)), SLOT(handleMessage(const QVariant&))); } void ReliableChannel::writeData(QDataStream& out, int bytes, QVector& spans) { @@ -719,7 +735,7 @@ void ReliableChannel::readData(QDataStream& in) { forever { // if we're expecting a message, peek into the buffer to see if we have the whole thing. // if so, read it in, handle it, and loop back around in case there are more - if (_expectingMessage) { + if (_messagesEnabled) { int available = _buffer.bytesAvailable(); if (available >= sizeof(quint32)) { quint32 length; @@ -729,7 +745,7 @@ void ReliableChannel::readData(QDataStream& in) { QVariant message; _bitstream >> message; _bitstream.reset(); - handleMessage(message); + emit receivedMessage(message); continue; } } @@ -747,11 +763,3 @@ void ReliableChannel::readData(QDataStream& in) { } } -void ReliableChannel::handleMessage(const QVariant& message) { - if (message.userType() == ClearSharedObjectMessage::Type) { - _bitstream.clearSharedObject(message.value().id); - - } else { - emit receivedMessage(message); - } -} diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 9adebfbfa4..7156175f51 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -94,6 +94,7 @@ signals: private slots: void sendClearSharedObjectMessage(int id); + void handleHighPriorityMessage(const QVariant& data); private: @@ -133,8 +134,6 @@ private: /// readyToWrite) as necessary. void sendPacket(const QByteArray& packet, const QVector& spans); - void handleHighPriorityMessage(const QVariant& data); - QList _sendRecords; QList _receiveRecords; @@ -273,12 +272,13 @@ public: int getBytesAvailable() const; + /// Sets whether we expect to write/read framed messages. + void setMessagesEnabled(bool enabled) { _messagesEnabled = enabled; } + bool getMessagesEnabled() const { return _messagesEnabled; } + /// Sends a framed message on this channel. void sendMessage(const QVariant& message); - /// For input channels, sets whether the channel is expecting a framed message. - void setExpectingMessage(bool expectingMessage) { _expectingMessage = expectingMessage; } - signals: void receivedMessage(const QVariant& message); @@ -286,7 +286,8 @@ signals: private slots: void sendClearSharedObjectMessage(int id); - + void handleMessage(const QVariant& message); + private: friend class DatagramSequencer; @@ -300,7 +301,6 @@ private: void spanAcknowledged(const DatagramSequencer::ChannelSpan& span); void readData(QDataStream& in); - void handleMessage(const QVariant& message); int _index; CircularBuffer _buffer; @@ -312,7 +312,7 @@ private: int _offset; int _writePosition; SpanList _acknowledged; - bool _expectingMessage; + bool _messagesEnabled; }; #endif /* defined(__interface__DatagramSequencer__) */ diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index c3cc78c5bc..1c547809fb 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -32,6 +32,17 @@ public: DECLARE_STREAMABLE_METATYPE(ClearSharedObjectMessage) +/// Clears the mapping for a shared object on the main channel (as opposed to the one on which the message was sent). +class ClearMainChannelSharedObjectMessage { + STREAMABLE + +public: + + STREAM int id; +}; + +DECLARE_STREAMABLE_METATYPE(ClearMainChannelSharedObjectMessage) + /// A message containing the state of a client. class ClientStateMessage { STREAMABLE diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 49ff5714c0..530f7e3108 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -22,10 +22,10 @@ static int highPriorityMessagesSent = 0; static int highPriorityMessagesReceived = 0; static int unreliableMessagesSent = 0; static int unreliableMessagesReceived = 0; +static int reliableMessagesSent = 0; +static int reliableMessagesReceived = 0; static int streamedBytesSent = 0; static int streamedBytesReceived = 0; -static int lowPriorityStreamedBytesSent = 0; -static int lowPriorityStreamedBytesReceived = 0; bool MetavoxelTests::run() { @@ -51,9 +51,8 @@ bool MetavoxelTests::run() { qDebug() << "Sent" << highPriorityMessagesSent << "high priority messages, received" << highPriorityMessagesReceived; qDebug() << "Sent" << unreliableMessagesSent << "unreliable messages, received" << unreliableMessagesReceived; + qDebug() << "Sent" << reliableMessagesSent << "reliable messages, received" << reliableMessagesReceived; qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived; - qDebug() << "Sent" << lowPriorityStreamedBytesSent << "low-priority streamed bytes, received" << - lowPriorityStreamedBytesReceived; qDebug() << "Sent" << datagramsSent << "datagrams, received" << datagramsReceived; qDebug() << "All tests passed!"; @@ -77,30 +76,31 @@ static QByteArray createRandomBytes() { Endpoint::Endpoint(const QByteArray& datagramHeader) : _sequencer(new DatagramSequencer(datagramHeader, this)), - _highPriorityMessagesToSend(0.0f) { + _highPriorityMessagesToSend(0.0f), + _reliableMessagesToSend(0.0f) { connect(_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendDatagram(const QByteArray&))); connect(_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readMessage(Bitstream&))); connect(_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleHighPriorityMessage(const QVariant&))); - ReliableChannel* firstInput = _sequencer->getReliableInputChannel(); - firstInput->setExpectingMessage(false); - connect(&firstInput->getBuffer(), SIGNAL(readyRead()), SLOT(readReliableChannel())); + connect(_sequencer->getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)), + SLOT(handleReliableMessage(const QVariant&))); ReliableChannel* secondInput = _sequencer->getReliableInputChannel(1); - secondInput->setExpectingMessage(false); - connect(&secondInput->getBuffer(), SIGNAL(readyRead()), SLOT(readLowPriorityReliableChannel())); + secondInput->setMessagesEnabled(false); + connect(&secondInput->getBuffer(), SIGNAL(readyRead()), SLOT(readReliableChannel())); // enqueue a large amount of data in a low-priority channel ReliableChannel* output = _sequencer->getReliableOutputChannel(1); output->setPriority(0.25f); - const int MIN_LOW_PRIORITY_DATA = 100000; - const int MAX_LOW_PRIORITY_DATA = 200000; - QByteArray bytes = createRandomBytes(MIN_LOW_PRIORITY_DATA, MAX_LOW_PRIORITY_DATA); - _lowPriorityDataStreamed.append(bytes); + output->setMessagesEnabled(false); + const int MIN_STREAM_BYTES = 100000; + const int MAX_STREAM_BYTES = 200000; + QByteArray bytes = createRandomBytes(MIN_STREAM_BYTES, MAX_STREAM_BYTES); + _dataStreamed.append(bytes); output->getBuffer().write(bytes); - lowPriorityStreamedBytesSent += bytes.size(); + streamedBytesSent += bytes.size(); } static QVariant createRandomMessage() { @@ -166,13 +166,17 @@ bool Endpoint::simulate(int iterationNumber) { _highPriorityMessagesToSend -= 1.0f; } - // stream some random data - const int MIN_BYTES_TO_STREAM = 10; - const int MAX_BYTES_TO_STREAM = 100; - QByteArray bytes = createRandomBytes(MIN_BYTES_TO_STREAM, MAX_BYTES_TO_STREAM); - _dataStreamed.append(bytes); - streamedBytesSent += bytes.size(); - _sequencer->getReliableOutputChannel()->getDataStream().writeRawData(bytes.constData(), bytes.size()); + // and some number of reliable messages + const float MIN_RELIABLE_MESSAGES = 0.0f; + const float MAX_RELIABLE_MESSAGES = 4.0f; + _reliableMessagesToSend += randFloatInRange(MIN_RELIABLE_MESSAGES, MAX_RELIABLE_MESSAGES); + while (_reliableMessagesToSend >= 1.0f) { + QVariant message = createRandomMessage(); + _reliableMessagesSent.append(message); + _sequencer->getReliableOutputChannel()->sendMessage(message); + reliableMessagesSent++; + _reliableMessagesToSend -= 1.0f; + } // send a packet try { @@ -249,8 +253,19 @@ void Endpoint::readMessage(Bitstream& in) { throw QString("Received unsent/already sent unreliable message."); } +void Endpoint::handleReliableMessage(const QVariant& message) { + if (_other->_reliableMessagesSent.isEmpty()) { + throw QString("Received unsent/already sent reliable message."); + } + QVariant sentMessage = _other->_reliableMessagesSent.takeFirst(); + if (!messagesEqual(message, sentMessage)) { + throw QString("Sent/received reliable message mismatch."); + } + reliableMessagesReceived++; +} + void Endpoint::readReliableChannel() { - CircularBuffer& buffer = _sequencer->getReliableInputChannel()->getBuffer(); + CircularBuffer& buffer = _sequencer->getReliableInputChannel(1)->getBuffer(); QByteArray bytes = buffer.read(buffer.bytesAvailable()); if (_other->_dataStreamed.size() < bytes.size()) { throw QString("Received unsent/already sent streamed data."); @@ -262,17 +277,3 @@ void Endpoint::readReliableChannel() { } streamedBytesReceived += bytes.size(); } - -void Endpoint::readLowPriorityReliableChannel() { - CircularBuffer& buffer = _sequencer->getReliableInputChannel(1)->getBuffer(); - QByteArray bytes = buffer.read(buffer.bytesAvailable()); - if (_other->_lowPriorityDataStreamed.size() < bytes.size()) { - throw QString("Received unsent/already sent low-priority streamed data."); - } - QByteArray compare = _other->_lowPriorityDataStreamed.readBytes(0, bytes.size()); - _other->_lowPriorityDataStreamed.remove(bytes.size()); - if (compare != bytes) { - throw QString("Sent/received low-priority streamed data mismatch."); - } - lowPriorityStreamedBytesReceived += bytes.size(); -} diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index b73f7eb07e..f19870ac15 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -48,9 +48,9 @@ private slots: void sendDatagram(const QByteArray& datagram); void handleHighPriorityMessage(const QVariant& message); void readMessage(Bitstream& in); + void handleReliableMessage(const QVariant& message); void readReliableChannel(); - void readLowPriorityReliableChannel(); - + private: DatagramSequencer* _sequencer; @@ -59,8 +59,9 @@ private: float _highPriorityMessagesToSend; QVariantList _highPriorityMessagesSent; QList _unreliableMessagesSent; + float _reliableMessagesToSend; + QVariantList _reliableMessagesSent; CircularBuffer _dataStreamed; - CircularBuffer _lowPriorityDataStreamed; }; /// A simple test message. @@ -88,7 +89,7 @@ public: DECLARE_STREAMABLE_METATYPE(TestMessageB) // A test message that demonstrates inheritance and composition. -class TestMessageC : public TestMessageA { +class TestMessageC : STREAM public TestMessageA { STREAMABLE public: diff --git a/tools/mtc/src/main.cpp b/tools/mtc/src/main.cpp index 050fe0e418..248c2ddd2d 100644 --- a/tools/mtc/src/main.cpp +++ b/tools/mtc/src/main.cpp @@ -121,7 +121,7 @@ void generateOutput (QTextStream& out, const QList& streamables) { out << " &&\n"; out << " "; } - out << "static_cast<" << base << "&>(first) == static_cast<" << base << "&>(second)"; + out << "static_cast(first) == static_cast(second)"; first = false; } foreach (const QString& field, str.fields) { @@ -147,7 +147,7 @@ void generateOutput (QTextStream& out, const QList& streamables) { out << " ||\n"; out << " "; } - out << "static_cast<" << base << "&>(first) != static_cast<" << base << "&>(second)"; + out << "static_cast(first) != static_cast(second)"; first = false; } foreach (const QString& field, str.fields) { From d6d95a586d6da16b68eec21fa54210ba4720d6c0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Feb 2014 14:16:14 -0800 Subject: [PATCH 03/18] Working on deleting attributes. --- interface/src/ui/MetavoxelEditor.cpp | 22 +++- interface/src/ui/MetavoxelEditor.h | 5 +- libraries/metavoxels/src/AttributeRegistry.h | 4 +- libraries/metavoxels/src/Bitstream.h | 2 +- libraries/metavoxels/src/SharedObject.cpp | 56 ---------- libraries/metavoxels/src/SharedObject.h | 110 ++++++++++++++----- 6 files changed, 104 insertions(+), 95 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index c97832d791..e37669e907 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -45,12 +45,19 @@ MetavoxelEditor::MetavoxelEditor() : attributeGroup->setLayout(attributeLayout); attributeLayout->addWidget(_attributes = new QListWidget()); - connect(_attributes, SIGNAL(itemSelectionChanged()), SLOT(updateValueEditor())); + connect(_attributes, SIGNAL(itemSelectionChanged()), SLOT(selectedAttributeChanged())); + + QHBoxLayout* attributeButtonLayout = new QHBoxLayout(); + attributeLayout->addLayout(attributeButtonLayout); QPushButton* newAttribute = new QPushButton("New..."); - attributeLayout->addWidget(newAttribute); + attributeButtonLayout->addWidget(newAttribute); connect(newAttribute, SIGNAL(clicked()), SLOT(createNewAttribute())); + attributeButtonLayout->addWidget(_deleteAttribute = new QPushButton("Delete")); + _deleteAttribute->setEnabled(false); + connect(_deleteAttribute, SIGNAL(clicked()), SLOT(deleteSelectedAttribute())); + QFormLayout* formLayout = new QFormLayout(); topLayout->addLayout(formLayout); @@ -141,19 +148,20 @@ bool MetavoxelEditor::eventFilter(QObject* watched, QEvent* event) { return false; } -void MetavoxelEditor::updateValueEditor() { +void MetavoxelEditor::selectedAttributeChanged() { QString selected = getSelectedAttribute(); if (selected.isNull()) { + _deleteAttribute->setEnabled(false); _value->setVisible(false); return; } + AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(selected); + _value->setVisible(true); if (_valueArea->widget()) { delete _valueArea->widget(); } - - AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(selected); QWidget* editor = attribute->createEditor(); if (editor) { _valueArea->setWidget(editor); @@ -188,6 +196,10 @@ void MetavoxelEditor::createNewAttribute() { updateAttributes(nameText); } +void MetavoxelEditor::deleteSelectedAttribute() { + +} + void MetavoxelEditor::centerGridPosition() { const float CENTER_OFFSET = 0.625f; float eyePosition = (glm::inverse(getGridRotation()) * Application::getInstance()->getCamera()->getPosition()).z - diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 9024837757..5e941f3540 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -17,6 +17,7 @@ class QComboBox; class QDoubleSpinBox; class QGroupBox; class QListWidget; +class QPushButton; class QScrollArea; /// Allows editing metavoxels. @@ -31,8 +32,9 @@ public: private slots: - void updateValueEditor(); + void selectedAttributeChanged(); void createNewAttribute(); + void deleteSelectedAttribute(); void centerGridPosition(); void alignGridPosition(); @@ -49,6 +51,7 @@ private: QVariant getValue() const; QListWidget* _attributes; + QPushButton* _deleteAttribute; QComboBox* _gridPlane; QDoubleSpinBox* _gridSpacing; QDoubleSpinBox* _gridPosition; diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 56cff7eeb4..431fc59fe2 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -24,7 +24,7 @@ class QScriptValue; class Attribute; -typedef QSharedPointer AttributePointer; +typedef SharedObjectPointerTemplate AttributePointer; /// Maintains information about metavoxel attribute types. class AttributeRegistry { @@ -141,7 +141,7 @@ public: }; /// Represents a registered attribute. -class Attribute : public QObject { +class Attribute : public SharedObject { Q_OBJECT public: diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index cc776a742a..87ee66c661 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -31,7 +31,7 @@ class Bitstream; class OwnedAttributeValue; class TypeStreamer; -typedef QSharedPointer AttributePointer; +typedef SharedObjectPointerTemplate AttributePointer; /// Streams integer identifiers that conform to the following pattern: each ID encountered in the stream is either one that /// has been sent (received) before, or is one more than the highest previously encountered ID (starting at zero). This allows diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index f97e285bcf..0b93826aa5 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -72,62 +72,6 @@ bool SharedObject::equals(const SharedObject* other) const { return true; } -SharedObjectPointer::SharedObjectPointer(SharedObject* data) : _data(data) { - if (_data) { - _data->incrementReferenceCount(); - } -} - -SharedObjectPointer::SharedObjectPointer(const SharedObjectPointer& other) : _data(other._data) { - if (_data) { - _data->incrementReferenceCount(); - } -} - -SharedObjectPointer::~SharedObjectPointer() { - if (_data) { - _data->decrementReferenceCount(); - } -} - -void SharedObjectPointer::detach() { - if (_data && _data->getReferenceCount() > 1) { - _data->decrementReferenceCount(); - (_data = _data->clone())->incrementReferenceCount(); - } -} - -void SharedObjectPointer::reset() { - if (_data) { - _data->decrementReferenceCount(); - } - _data = NULL; -} - -SharedObjectPointer& SharedObjectPointer::operator=(SharedObject* data) { - if (_data) { - _data->decrementReferenceCount(); - } - if ((_data = data)) { - _data->incrementReferenceCount(); - } - return *this; -} - -SharedObjectPointer& SharedObjectPointer::operator=(const SharedObjectPointer& other) { - if (_data) { - _data->decrementReferenceCount(); - } - if ((_data = other._data)) { - _data->incrementReferenceCount(); - } - return *this; -} - -uint qHash(const SharedObjectPointer& pointer, uint seed) { - return qHash(pointer.data(), seed); -} - SharedObjectEditor::SharedObjectEditor(const QMetaObject* metaObject, QWidget* parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(); layout->setAlignment(Qt::AlignTop); diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index e439c4c7f0..fedbeb50d8 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -44,49 +44,99 @@ private: }; /// A pointer to a shared object. -class SharedObjectPointer { +template class SharedObjectPointerTemplate { public: - SharedObjectPointer(SharedObject* data = NULL); - SharedObjectPointer(const SharedObjectPointer& other); - ~SharedObjectPointer(); - - SharedObject* data() { return _data; } - const SharedObject* data() const { return _data; } - const SharedObject* constData() const { return _data; } + SharedObjectPointerTemplate(T* data = NULL); + SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other); + ~SharedObjectPointerTemplate(); + T* data() const { return _data; } + void detach(); - void swap(SharedObjectPointer& other) { qSwap(_data, other._data); } + void swap(SharedObjectPointerTemplate& other) { qSwap(_data, other._data); } void reset(); - operator SharedObject*() { return _data; } - operator const SharedObject*() const { return _data; } - bool operator!() const { return !_data; } - - bool operator!=(const SharedObjectPointer& other) const { return _data != other._data; } - - SharedObject& operator*() { return *_data; } - const SharedObject& operator*() const { return *_data; } - - SharedObject* operator->() { return _data; } - const SharedObject* operator->() const { return _data; } - - SharedObjectPointer& operator=(SharedObject* data); - SharedObjectPointer& operator=(const SharedObjectPointer& other); - - bool operator==(const SharedObjectPointer& other) const { return _data == other._data; } - -private: + operator T*() const { return _data; } + T& operator*() const { return *_data; } + T* operator->() const { return _data; } - SharedObject* _data; + SharedObjectPointerTemplate& operator=(T* data); + SharedObjectPointerTemplate& operator=(const SharedObjectPointerTemplate& other); + + bool operator==(const SharedObjectPointerTemplate& other) const { return _data == other._data; } + bool operator!=(const SharedObjectPointerTemplate& other) const { return _data != other._data; } + +private: + + T* _data; }; -Q_DECLARE_METATYPE(SharedObjectPointer) +template inline SharedObjectPointerTemplate::SharedObjectPointerTemplate(T* data) : _data(data) { + if (_data) { + _data->incrementReferenceCount(); + } +} -uint qHash(const SharedObjectPointer& pointer, uint seed = 0); +template inline SharedObjectPointerTemplate::SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other) : + _data(other._data) { + + if (_data) { + _data->incrementReferenceCount(); + } +} + +template inline SharedObjectPointerTemplate::~SharedObjectPointerTemplate() { + if (_data) { + _data->decrementReferenceCount(); + } +} + +template inline void SharedObjectPointerTemplate::detach() { + if (_data && _data->getReferenceCount() > 1) { + _data->decrementReferenceCount(); + (_data = _data->clone())->incrementReferenceCount(); + } +} + +template inline void SharedObjectPointerTemplate::reset() { + if (_data) { + _data->decrementReferenceCount(); + } + _data = NULL; +} + +template inline SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=(T* data) { + if (_data) { + _data->decrementReferenceCount(); + } + if ((_data = data)) { + _data->incrementReferenceCount(); + } + return *this; +} + +template inline SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=( + const SharedObjectPointerTemplate& other) { + if (_data) { + _data->decrementReferenceCount(); + } + if ((_data = other._data)) { + _data->incrementReferenceCount(); + } + return *this; +} + +template uint qHash(const SharedObjectPointerTemplate& pointer, uint seed = 0) { + return qHash(pointer.data(), seed); +} + +typedef SharedObjectPointerTemplate SharedObjectPointer; + +Q_DECLARE_METATYPE(SharedObjectPointer) /// Allows editing shared object instances. class SharedObjectEditor : public QWidget { From 5b207e4f8e90c6fee98091429fc93bc9ac095ed5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Feb 2014 17:10:32 -0800 Subject: [PATCH 04/18] Work on creating new attributes. --- interface/src/ui/MetavoxelEditor.cpp | 17 +++++++--- .../metavoxels/src/AttributeRegistry.cpp | 4 +++ libraries/metavoxels/src/AttributeRegistry.h | 6 +++- libraries/metavoxels/src/Bitstream.cpp | 4 +-- libraries/metavoxels/src/MetavoxelUtil.cpp | 31 +++++++++++++++++++ libraries/metavoxels/src/MetavoxelUtil.h | 28 +++++++++++++++++ libraries/metavoxels/src/SharedObject.cpp | 13 ++++++-- libraries/metavoxels/src/SharedObject.h | 14 +++++++-- 8 files changed, 103 insertions(+), 14 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index e37669e907..9012248484 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -155,14 +155,13 @@ void MetavoxelEditor::selectedAttributeChanged() { _value->setVisible(false); return; } - AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(selected); - + _deleteAttribute->setEnabled(true); _value->setVisible(true); if (_valueArea->widget()) { delete _valueArea->widget(); } - QWidget* editor = attribute->createEditor(); + QWidget* editor = AttributeRegistry::getInstance()->getAttribute(selected)->createEditor(); if (editor) { _valueArea->setWidget(editor); } @@ -181,6 +180,10 @@ void MetavoxelEditor::createNewAttribute() { QLineEdit name; form.addRow("Name:", &name); + SharedObjectEditor editor(&Attribute::staticMetaObject, false); + editor.setObject(new QRgbAttribute()); + layout.addWidget(&editor); + QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); dialog.connect(&buttons, SIGNAL(accepted()), SLOT(accept())); dialog.connect(&buttons, SIGNAL(rejected()), SLOT(reject())); @@ -191,13 +194,17 @@ void MetavoxelEditor::createNewAttribute() { return; } QString nameText = name.text().trimmed(); - AttributeRegistry::getInstance()->registerAttribute(new QRgbAttribute(nameText)); + SharedObjectPointer attribute = editor.getObject(); + attribute->setObjectName(nameText); + AttributeRegistry::getInstance()->registerAttribute(attribute.staticCast()); updateAttributes(nameText); } void MetavoxelEditor::deleteSelectedAttribute() { - + AttributeRegistry::getInstance()->deregisterAttribute(getSelectedAttribute()); + _attributes->selectionModel()->clear(); + updateAttributes(); } void MetavoxelEditor::centerGridPosition() { diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 9595d96e1f..8483174dac 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -53,6 +53,10 @@ AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute return pointer; } +void AttributeRegistry::deregisterAttribute(const QString& name) { + _attributes.remove(name); +} + QScriptValue AttributeRegistry::getAttribute(QScriptContext* context, QScriptEngine* engine) { return engine->newQObject(getInstance()->getAttribute(context->argument(0).toString()).data(), QScriptEngine::QtOwnership, QScriptEngine::PreferExistingWrapperObject); diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 431fc59fe2..1235cefbb5 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -48,6 +48,9 @@ public: /// attribute AttributePointer registerAttribute(AttributePointer attribute); + /// Deregisters an attribute. + void deregisterAttribute(const QString& name); + /// Retrieves an attribute by name. AttributePointer getAttribute(const QString& name) const { return _attributes.value(name); } @@ -260,7 +263,8 @@ class SharedObjectAttribute : public InlineAttribute { public: - Q_INVOKABLE SharedObjectAttribute(const QString& name = QString(), const QMetaObject* metaObject = NULL, + Q_INVOKABLE SharedObjectAttribute(const QString& name = QString(), + const QMetaObject* metaObject = &SharedObject::staticMetaObject, const SharedObjectPointer& defaultValue = SharedObjectPointer()); virtual void read(Bitstream& in, void*& value, bool isLeaf) const; diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 262f2df7f5..61e300eae5 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -68,8 +68,8 @@ IDStreamer& IDStreamer::operator>>(int& value) { int Bitstream::registerMetaObject(const char* className, const QMetaObject* metaObject) { getMetaObjects().insert(className, metaObject); - // register it as a subclass of all of its superclasses - for (const QMetaObject* superClass = metaObject->superClass(); superClass != NULL; superClass = superClass->superClass()) { + // register it as a subclass of itself and all of its superclasses + for (const QMetaObject* superClass = metaObject; superClass != NULL; superClass = superClass->superClass()) { getMetaObjectSubClasses().insert(superClass, metaObject); } return 0; diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index d6b42b11fb..8b33416dc3 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -104,6 +105,12 @@ static QItemEditorCreatorBase* createDoubleEditorCreator() { return creator; } +static QItemEditorCreatorBase* createQMetaObjectEditorCreator() { + QItemEditorCreatorBase* creator = new LazyItemEditorCreator(); + getItemEditorFactory()->registerEditor(qMetaTypeId(), creator); + return creator; +} + static QItemEditorCreatorBase* createQColorEditorCreator() { QItemEditorCreatorBase* creator = new LazyItemEditorCreator(); getItemEditorFactory()->registerEditor(qMetaTypeId(), creator); @@ -123,6 +130,7 @@ static QItemEditorCreatorBase* createParameterizedURLEditorCreator() { } static QItemEditorCreatorBase* doubleEditorCreator = createDoubleEditorCreator(); +static QItemEditorCreatorBase* qMetaObjectEditorCreator = createQMetaObjectEditorCreator(); static QItemEditorCreatorBase* qColorEditorCreator = createQColorEditorCreator(); static QItemEditorCreatorBase* vec3EditorCreator = createVec3EditorCreator(); static QItemEditorCreatorBase* parameterizedURLEditorCreator = createParameterizedURLEditorCreator(); @@ -153,6 +161,29 @@ bool Box::contains(const Box& other) const { other.minimum.z >= minimum.z && other.maximum.z <= maximum.z; } +QMetaObjectEditor::QMetaObjectEditor(QWidget* parent) : QWidget(parent) { + QVBoxLayout* layout = new QVBoxLayout(); + layout->setContentsMargins(QMargins()); + layout->setAlignment(Qt::AlignTop); + setLayout(layout); + layout->addWidget(_box = new QComboBox()); + connect(_box, SIGNAL(currentIndexChanged(int)), SLOT(updateMetaObject())); + + foreach (const QMetaObject* metaObject, Bitstream::getMetaObjectSubClasses(&SharedObject::staticMetaObject)) { + _box->addItem(metaObject->className(), QVariant::fromValue(metaObject)); + } +} + +void QMetaObjectEditor::setMetaObject(const QMetaObject* metaObject) { + _metaObject = metaObject; + _box->setCurrentIndex(_metaObject ? _box->findText(_metaObject->className()) : -1); +} + +void QMetaObjectEditor::updateMetaObject() { + int index = _box->currentIndex(); + emit metaObjectChanged(_metaObject = (index == -1) ? NULL : _box->itemData(index).value()); +} + QColorEditor::QColorEditor(QWidget* parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(); layout->setContentsMargins(QMargins()); diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 7cfedd7a62..49039090a0 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -21,6 +21,7 @@ #include "Bitstream.h" class QByteArray; +class QComboBox; class QDoubleSpinBox; class QLineEdit; class QPushButton; @@ -50,6 +51,33 @@ public: DECLARE_STREAMABLE_METATYPE(Box) +/// Editor for meta-object values. +class QMetaObjectEditor : public QWidget { + Q_OBJECT + Q_PROPERTY(const QMetaObject* metaObject MEMBER _metaObject WRITE setMetaObject NOTIFY metaObjectChanged USER true) + +public: + + QMetaObjectEditor(QWidget* parent); + +signals: + + void metaObjectChanged(const QMetaObject* metaObject); + +public slots: + + void setMetaObject(const QMetaObject* metaObject); + +private slots: + + void updateMetaObject(); + +private: + + QComboBox* _box; + const QMetaObject* _metaObject; +}; + /// Editor for color values. class QColorEditor : public QWidget { Q_OBJECT diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index 0b93826aa5..37f7be54c7 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -16,6 +16,8 @@ #include "MetavoxelUtil.h" #include "SharedObject.h" +REGISTER_META_OBJECT(SharedObject) + SharedObject::SharedObject() : _referenceCount(0) { } @@ -72,7 +74,7 @@ bool SharedObject::equals(const SharedObject* other) const { return true; } -SharedObjectEditor::SharedObjectEditor(const QMetaObject* metaObject, QWidget* parent) : QWidget(parent) { +SharedObjectEditor::SharedObjectEditor(const QMetaObject* metaObject, bool nullable, QWidget* parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(); layout->setAlignment(Qt::AlignTop); setLayout(layout); @@ -81,9 +83,14 @@ SharedObjectEditor::SharedObjectEditor(const QMetaObject* metaObject, QWidget* p layout->addLayout(form); form->addRow("Type:", _type = new QComboBox()); - _type->addItem("(none)"); + if (nullable) { + _type->addItem("(none)"); + } foreach (const QMetaObject* metaObject, Bitstream::getMetaObjectSubClasses(metaObject)) { - _type->addItem(metaObject->className(), QVariant::fromValue(metaObject)); + // add add constructable subclasses + if (metaObject->constructorCount() > 0) { + _type->addItem(metaObject->className(), QVariant::fromValue(metaObject)); + } } connect(_type, SIGNAL(currentIndexChanged(int)), SLOT(updateType())); } diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index fedbeb50d8..b62b88d2ee 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -21,7 +21,7 @@ class SharedObject : public QObject { public: - SharedObject(); + Q_INVOKABLE SharedObject(); int getReferenceCount() const { return _referenceCount; } void incrementReferenceCount(); @@ -64,6 +64,8 @@ public: T& operator*() const { return *_data; } T* operator->() const { return _data; } + template SharedObjectPointerTemplate staticCast() const; + SharedObjectPointerTemplate& operator=(T* data); SharedObjectPointerTemplate& operator=(const SharedObjectPointerTemplate& other); @@ -109,6 +111,10 @@ template inline void SharedObjectPointerTemplate::reset() { _data = NULL; } +template template inline SharedObjectPointerTemplate SharedObjectPointerTemplate::staticCast() const { + return SharedObjectPointerTemplate(static_cast(_data)); +} + template inline SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=(T* data) { if (_data) { _data->decrementReferenceCount(); @@ -141,11 +147,13 @@ Q_DECLARE_METATYPE(SharedObjectPointer) /// Allows editing shared object instances. class SharedObjectEditor : public QWidget { Q_OBJECT - Q_PROPERTY(SharedObjectPointer object MEMBER _object WRITE setObject USER true) + Q_PROPERTY(SharedObjectPointer object READ getObject WRITE setObject USER true) public: - SharedObjectEditor(const QMetaObject* metaObject, QWidget* parent); + SharedObjectEditor(const QMetaObject* metaObject, bool nullable = true, QWidget* parent = NULL); + + const SharedObjectPointer& getObject() const { return _object; } public slots: From bb56e2847f35c384f5423d52122b5c86056deb98 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Feb 2014 20:00:07 -0800 Subject: [PATCH 05/18] Global edits, edits use virtual function. --- cmake/macros/AutoMTC.cmake | 15 +- interface/src/ui/MetavoxelEditor.cpp | 343 +++++++++++------- interface/src/ui/MetavoxelEditor.h | 74 +++- libraries/metavoxels/CMakeLists.txt | 6 +- libraries/metavoxels/src/MetavoxelData.cpp | 3 +- .../metavoxels/src/MetavoxelMessages.cpp | 57 ++- libraries/metavoxels/src/MetavoxelMessages.h | 46 ++- libraries/metavoxels/src/MetavoxelUtil.cpp | 4 + libraries/metavoxels/src/MetavoxelUtil.h | 2 + tests/metavoxels/CMakeLists.txt | 6 +- 10 files changed, 381 insertions(+), 175 deletions(-) diff --git a/cmake/macros/AutoMTC.cmake b/cmake/macros/AutoMTC.cmake index f0c9ebc6a0..f29c3400bb 100644 --- a/cmake/macros/AutoMTC.cmake +++ b/cmake/macros/AutoMTC.cmake @@ -3,20 +3,11 @@ macro(AUTO_MTC TARGET ROOT_DIR) add_subdirectory(${ROOT_DIR}/tools/mtc ${ROOT_DIR}/tools/mtc) endif (NOT TARGET mtc) + set(AUTOMTC_SRC ${TARGET}_automtc.cpp) + file(GLOB INCLUDE_FILES src/*.h) - add_custom_command(OUTPUT ${TARGET}_automtc.cpp COMMAND mtc -o ${TARGET}_automtc.cpp - ${INCLUDE_FILES} DEPENDS mtc ${INCLUDE_FILES}) - - find_package(Qt5Core REQUIRED) - find_package(Qt5Script REQUIRED) - find_package(Qt5Widgets REQUIRED) - - add_library(${TARGET}_automtc STATIC ${TARGET}_automtc.cpp) - - qt5_use_modules(${TARGET}_automtc Core Script Widgets) - - target_link_libraries(${TARGET} ${TARGET}_automtc) + add_custom_command(OUTPUT ${AUTOMTC_SRC} COMMAND mtc -o ${AUTOMTC_SRC} ${INCLUDE_FILES} DEPENDS mtc ${INCLUDE_FILES}) endmacro() diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 9012248484..0ba0b08633 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -81,6 +81,9 @@ MetavoxelEditor::MetavoxelEditor() : alignGridPosition(); centerGridPosition(); + formLayout->addRow("Tool:", _toolBox = new QComboBox()); + connect(_toolBox, SIGNAL(currentIndexChanged(int)), SLOT(updateTool())); + _value = new QGroupBox(); _value->setTitle("Value"); topLayout->addWidget(_value); @@ -91,14 +94,20 @@ MetavoxelEditor::MetavoxelEditor() : valueLayout->addWidget(_valueArea = new QScrollArea()); _valueArea->setWidgetResizable(true); + BoxSetTool* boxSetTool = new BoxSetTool(this); + topLayout->addWidget(boxSetTool); + _toolBox->addItem("Set Value (Box)", QVariant::fromValue(boxSetTool)); + + GlobalSetTool* globalSetTool = new GlobalSetTool(this); + topLayout->addWidget(globalSetTool); + _toolBox->addItem("Set Value (Global)", QVariant::fromValue(globalSetTool)); + updateAttributes(); connect(Application::getInstance(), SIGNAL(renderingInWorldInterface()), SLOT(render())); Application::getInstance()->getGLWidget()->installEventFilter(this); - resetState(); - show(); if (_gridProgram.isLinked()) { @@ -109,43 +118,42 @@ MetavoxelEditor::MetavoxelEditor() : _gridProgram.link(); } -bool MetavoxelEditor::eventFilter(QObject* watched, QEvent* event) { - switch (_state) { - case HOVERING_STATE: - if (event->type() == QEvent::MouseButtonPress && _startPosition != INVALID_VECTOR) { - _state = DRAGGING_STATE; - return true; - } - break; +QString MetavoxelEditor::getSelectedAttribute() const { + QList selectedItems = _attributes->selectedItems(); + return selectedItems.isEmpty() ? QString() : selectedItems.first()->text(); +} + +double MetavoxelEditor::getGridSpacing() const { + return pow(2.0, _gridSpacing->value()); +} + +double MetavoxelEditor::getGridPosition() const { + return _gridPosition->value(); +} + +glm::quat MetavoxelEditor::getGridRotation() const { + // for simplicity, we handle the other two planes by rotating them onto X/Y and performing computation there + switch (_gridPlane->currentIndex()) { + case GRID_PLANE_XY: + return glm::quat(); - case DRAGGING_STATE: - if (event->type() == QEvent::MouseButtonRelease) { - _state = RAISING_STATE; - return true; - } - break; + case GRID_PLANE_XZ: + return glm::angleAxis(-90.0f, 1.0f, 0.0f, 0.0f); - case RAISING_STATE: - if (event->type() == QEvent::MouseButtonPress) { - if (_height != 0) { - // find the start and end corners in X/Y - float base = _gridPosition->value(); - float top = base + _height; - glm::quat rotation = getGridRotation(); - glm::vec3 start = rotation * glm::vec3(glm::min(_startPosition, _endPosition), glm::min(base, top)); - float spacing = getGridSpacing(); - glm::vec3 end = rotation * glm::vec3(glm::max(_startPosition, _endPosition) + - glm::vec2(spacing, spacing), glm::max(base, top)); - - // find the minimum and maximum extents after rotation - applyValue(glm::min(start, end), glm::max(start, end)); - } - resetState(); - return true; - } - break; + case GRID_PLANE_YZ: + default: + return glm::angleAxis(90.0f, 0.0f, 1.0f, 0.0f); } - return false; +} + +QVariant MetavoxelEditor::getValue() const { + QWidget* editor = _valueArea->widget(); + return editor ? editor->metaObject()->userProperty().read(editor) : QVariant(); +} + +bool MetavoxelEditor::eventFilter(QObject* watched, QEvent* event) { + // pass along to the active tool + return getActiveTool()->eventFilter(watched, event); } void MetavoxelEditor::selectedAttributeChanged() { @@ -222,13 +230,15 @@ void MetavoxelEditor::alignGridPosition() { _gridPosition->setValue(step * floor(_gridPosition->value() / step)); } -void MetavoxelEditor::render() { - QString selected = getSelectedAttribute(); - if (selected.isNull()) { - resetState(); - return; +void MetavoxelEditor::updateTool() { + for (int i = 0; i < _toolBox->count(); i++) { + _toolBox->itemData(i).value()->setVisible(i == _toolBox->currentIndex()); } +} +const float GRID_BRIGHTNESS = 0.5f; + +void MetavoxelEditor::render() { glDisable(GL_LIGHTING); glDepthMask(GL_FALSE); @@ -238,85 +248,22 @@ void MetavoxelEditor::render() { glm::vec3 axis = glm::axis(rotation); glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); - glm::quat inverseRotation = glm::inverse(rotation); - glm::vec3 rayOrigin = inverseRotation * Application::getInstance()->getMouseRayOrigin(); - glm::vec3 rayDirection = inverseRotation * Application::getInstance()->getMouseRayDirection(); - float spacing = getGridSpacing(); - float position = _gridPosition->value(); - if (_state == RAISING_STATE) { - // find the plane at the mouse position, orthogonal to the plane, facing the eye position - glLineWidth(4.0f); - glm::vec3 eyePosition = inverseRotation * Application::getInstance()->getViewFrustum()->getOffsetPosition(); - glm::vec3 mousePoint = glm::vec3(_mousePosition, position); - glm::vec3 right = glm::cross(glm::vec3(0.0f, 0.0f, 1.0f), eyePosition - mousePoint); - glm::vec3 normal = glm::cross(right, glm::vec3(0.0f, 0.0f, 1.0f)); - float divisor = glm::dot(normal, rayDirection); - if (fabs(divisor) > EPSILON) { - float distance = (glm::dot(normal, mousePoint) - glm::dot(normal, rayOrigin)) / divisor; - float projection = rayOrigin.z + distance * rayDirection.z; - _height = spacing * roundf(projection / spacing) - position; - } - } else if (fabs(rayDirection.z) > EPSILON) { - // find the intersection of the rotated mouse ray with the plane - float distance = (position - rayOrigin.z) / rayDirection.z; - _mousePosition = glm::vec2(rayOrigin + rayDirection * distance); - glm::vec2 snappedPosition = spacing * glm::floor(_mousePosition / spacing); - - if (_state == HOVERING_STATE) { - _startPosition = _endPosition = snappedPosition; - glLineWidth(2.0f); - - } else if (_state == DRAGGING_STATE) { - _endPosition = snappedPosition; - glLineWidth(4.0f); - } - } else { - // cancel any operation in progress - resetState(); - } - - const float GRID_BRIGHTNESS = 0.5f; - if (_startPosition != INVALID_VECTOR) { - glm::vec2 minimum = glm::min(_startPosition, _endPosition); - glm::vec2 maximum = glm::max(_startPosition, _endPosition); - - glPushMatrix(); - glTranslatef(minimum.x, minimum.y, position); - glScalef(maximum.x + spacing - minimum.x, maximum.y + spacing - minimum.y, _height); - - glTranslatef(0.5f, 0.5f, 0.5f); - if (_state != HOVERING_STATE) { - const float BOX_ALPHA = 0.25f; - QColor color = getValue().value(); - if (color.isValid()) { - glColor4f(color.redF(), color.greenF(), color.blueF(), BOX_ALPHA); - } else { - glColor4f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS, BOX_ALPHA); - } - glEnable(GL_CULL_FACE); - glutSolidCube(1.0); - glDisable(GL_CULL_FACE); - } - glColor3f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS); - glutWireCube(1.0); - - glPopMatrix(); - - } else { - glColor3f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS); - } + getActiveTool()->render(); glLineWidth(1.0f); // center the grid around the camera position on the plane - glm::vec3 rotated = inverseRotation * Application::getInstance()->getCamera()->getPosition(); + glm::vec3 rotated = glm::inverse(rotation) * Application::getInstance()->getCamera()->getPosition(); + float spacing = getGridSpacing(); const int GRID_DIVISIONS = 300; glTranslatef(spacing * (floorf(rotated.x / spacing) - GRID_DIVISIONS / 2), - spacing * (floorf(rotated.y / spacing) - GRID_DIVISIONS / 2), position); + spacing * (floorf(rotated.y / spacing) - GRID_DIVISIONS / 2), _gridPosition->value()); float scale = GRID_DIVISIONS * spacing; glScalef(scale, scale, scale); + glColor3f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS); + _gridProgram.bind(); Application::getInstance()->getGeometryCache()->renderGrid(GRID_DIVISIONS, GRID_DIVISIONS); @@ -348,49 +295,173 @@ void MetavoxelEditor::updateAttributes(const QString& select) { } } -QString MetavoxelEditor::getSelectedAttribute() const { - QList selectedItems = _attributes->selectedItems(); - return selectedItems.isEmpty() ? QString() : selectedItems.first()->text(); +MetavoxelTool* MetavoxelEditor::getActiveTool() const { + return static_cast(_toolBox->itemData(_toolBox->currentIndex()).value()); } -double MetavoxelEditor::getGridSpacing() const { - return pow(2.0, _gridSpacing->value()); +ProgramObject MetavoxelEditor::_gridProgram; + +MetavoxelTool::MetavoxelTool(MetavoxelEditor* editor) : + _editor(editor) { + + QVBoxLayout* layout = new QVBoxLayout(); + setLayout(layout); + + setVisible(false); } -glm::quat MetavoxelEditor::getGridRotation() const { - // for simplicity, we handle the other two planes by rotating them onto X/Y and performing computation there - switch (_gridPlane->currentIndex()) { - case GRID_PLANE_XY: - return glm::quat(); +void MetavoxelTool::render() { + // nothing by default +} + +BoxSetTool::BoxSetTool(MetavoxelEditor* editor) : + MetavoxelTool(editor) { + + resetState(); +} + +void BoxSetTool::render() { + QString selected = _editor->getSelectedAttribute(); + if (selected.isNull()) { + resetState(); + return; + } + glm::quat rotation = _editor->getGridRotation(); + glm::quat inverseRotation = glm::inverse(rotation); + glm::vec3 rayOrigin = inverseRotation * Application::getInstance()->getMouseRayOrigin(); + glm::vec3 rayDirection = inverseRotation * Application::getInstance()->getMouseRayDirection(); + float spacing = _editor->getGridSpacing(); + float position = _editor->getGridPosition(); + if (_state == RAISING_STATE) { + // find the plane at the mouse position, orthogonal to the plane, facing the eye position + glLineWidth(4.0f); + glm::vec3 eyePosition = inverseRotation * Application::getInstance()->getViewFrustum()->getOffsetPosition(); + glm::vec3 mousePoint = glm::vec3(_mousePosition, position); + glm::vec3 right = glm::cross(glm::vec3(0.0f, 0.0f, 1.0f), eyePosition - mousePoint); + glm::vec3 normal = glm::cross(right, glm::vec3(0.0f, 0.0f, 1.0f)); + float divisor = glm::dot(normal, rayDirection); + if (fabs(divisor) > EPSILON) { + float distance = (glm::dot(normal, mousePoint) - glm::dot(normal, rayOrigin)) / divisor; + float projection = rayOrigin.z + distance * rayDirection.z; + _height = spacing * roundf(projection / spacing) - position; + } + } else if (fabs(rayDirection.z) > EPSILON) { + // find the intersection of the rotated mouse ray with the plane + float distance = (position - rayOrigin.z) / rayDirection.z; + _mousePosition = glm::vec2(rayOrigin + rayDirection * distance); + glm::vec2 snappedPosition = spacing * glm::floor(_mousePosition / spacing); + + if (_state == HOVERING_STATE) { + _startPosition = _endPosition = snappedPosition; + glLineWidth(2.0f); - case GRID_PLANE_XZ: - return glm::angleAxis(-90.0f, 1.0f, 0.0f, 0.0f); - - case GRID_PLANE_YZ: - default: - return glm::angleAxis(90.0f, 0.0f, 1.0f, 0.0f); + } else if (_state == DRAGGING_STATE) { + _endPosition = snappedPosition; + glLineWidth(4.0f); + } + } else { + // cancel any operation in progress + resetState(); + } + + if (_startPosition != INVALID_VECTOR) { + glm::vec2 minimum = glm::min(_startPosition, _endPosition); + glm::vec2 maximum = glm::max(_startPosition, _endPosition); + + glPushMatrix(); + glTranslatef(minimum.x, minimum.y, position); + glScalef(maximum.x + spacing - minimum.x, maximum.y + spacing - minimum.y, _height); + + glTranslatef(0.5f, 0.5f, 0.5f); + if (_state != HOVERING_STATE) { + const float BOX_ALPHA = 0.25f; + QColor color = _editor->getValue().value(); + if (color.isValid()) { + glColor4f(color.redF(), color.greenF(), color.blueF(), BOX_ALPHA); + } else { + glColor4f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS, BOX_ALPHA); + } + glEnable(GL_CULL_FACE); + glutSolidCube(1.0); + glDisable(GL_CULL_FACE); + } + glColor3f(GRID_BRIGHTNESS, GRID_BRIGHTNESS, GRID_BRIGHTNESS); + glutWireCube(1.0); + + glPopMatrix(); } } -void MetavoxelEditor::resetState() { +bool BoxSetTool::eventFilter(QObject* watched, QEvent* event) { + switch (_state) { + case HOVERING_STATE: + if (event->type() == QEvent::MouseButtonPress && _startPosition != INVALID_VECTOR) { + _state = DRAGGING_STATE; + return true; + } + break; + + case DRAGGING_STATE: + if (event->type() == QEvent::MouseButtonRelease) { + _state = RAISING_STATE; + return true; + } + break; + + case RAISING_STATE: + if (event->type() == QEvent::MouseButtonPress) { + if (_height != 0) { + // find the start and end corners in X/Y + float base = _editor->getGridPosition(); + float top = base + _height; + glm::quat rotation = _editor->getGridRotation(); + glm::vec3 start = rotation * glm::vec3(glm::min(_startPosition, _endPosition), glm::min(base, top)); + float spacing = _editor->getGridSpacing(); + glm::vec3 end = rotation * glm::vec3(glm::max(_startPosition, _endPosition) + + glm::vec2(spacing, spacing), glm::max(base, top)); + + // find the minimum and maximum extents after rotation + applyValue(glm::min(start, end), glm::max(start, end)); + } + resetState(); + return true; + } + break; + } + return false; +} + +void BoxSetTool::resetState() { _state = HOVERING_STATE; _startPosition = INVALID_VECTOR; _height = 0.0f; } -void MetavoxelEditor::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) { - AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(getSelectedAttribute()); +void BoxSetTool::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) { + AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute()); if (!attribute) { return; } - OwnedAttributeValue value(attribute, attribute->createFromVariant(getValue())); - MetavoxelEditMessage edit = { { minimum, maximum }, getGridSpacing(), value }; - Application::getInstance()->getMetavoxels()->applyEdit(edit); + OwnedAttributeValue value(attribute, attribute->createFromVariant(_editor->getValue())); + MetavoxelEditMessage message = { QVariant::fromValue(BoxSetEdit(Box(minimum, maximum), + _editor->getGridSpacing(), value)) }; + Application::getInstance()->getMetavoxels()->applyEdit(message); } -QVariant MetavoxelEditor::getValue() const { - QWidget* editor = _valueArea->widget(); - return editor ? editor->metaObject()->userProperty().read(editor) : QVariant(); +GlobalSetTool::GlobalSetTool(MetavoxelEditor* editor) : + MetavoxelTool(editor) { + + QPushButton* button = new QPushButton("Apply"); + layout()->addWidget(button); + connect(button, SIGNAL(clicked()), SLOT(apply())); } -ProgramObject MetavoxelEditor::_gridProgram; +void GlobalSetTool::apply() { + AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute()); + if (!attribute) { + return; + } + OwnedAttributeValue value(attribute, attribute->createFromVariant(_editor->getValue())); + MetavoxelEditMessage message = { QVariant::fromValue(GlobalSetEdit(value)) }; + Application::getInstance()->getMetavoxels()->applyEdit(message); +} diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 5e941f3540..be2afd0a36 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -20,6 +20,8 @@ class QListWidget; class QPushButton; class QScrollArea; +class MetavoxelTool; + /// Allows editing metavoxels. class MetavoxelEditor : public QDialog { Q_OBJECT @@ -28,6 +30,14 @@ public: MetavoxelEditor(); + QString getSelectedAttribute() const; + + double getGridSpacing() const; + double getGridPosition() const; + glm::quat getGridRotation() const; + + QVariant getValue() const; + virtual bool eventFilter(QObject* watched, QEvent* event); private slots: @@ -37,38 +47,84 @@ private slots: void deleteSelectedAttribute(); void centerGridPosition(); void alignGridPosition(); + void updateTool(); void render(); private: - void updateAttributes(const QString& select = QString()); - QString getSelectedAttribute() const; - double getGridSpacing() const; - glm::quat getGridRotation() const; - void resetState(); - void applyValue(const glm::vec3& minimum, const glm::vec3& maximum); - QVariant getValue() const; + void updateAttributes(const QString& select = QString()); + MetavoxelTool* getActiveTool() const; QListWidget* _attributes; QPushButton* _deleteAttribute; + QComboBox* _gridPlane; QDoubleSpinBox* _gridSpacing; QDoubleSpinBox* _gridPosition; + + QComboBox* _toolBox; + QGroupBox* _value; QScrollArea* _valueArea; + static ProgramObject _gridProgram; +}; + +/// Base class for editor tools. +class MetavoxelTool : public QWidget { + Q_OBJECT + +public: + + MetavoxelTool(MetavoxelEditor* editor); + + /// Renders the tool's interface, if any. + virtual void render(); + +protected: + + MetavoxelEditor* _editor; +}; + +/// Allows setting the value of a region by dragging out a box. +class BoxSetTool : public MetavoxelTool { + Q_OBJECT + +public: + + BoxSetTool(MetavoxelEditor* editor); + + virtual void render(); + + virtual bool eventFilter(QObject* watched, QEvent* event); + +private: + + void resetState(); + void applyValue(const glm::vec3& minimum, const glm::vec3& maximum); + enum State { HOVERING_STATE, DRAGGING_STATE, RAISING_STATE }; State _state; glm::vec2 _mousePosition; ///< the position of the mouse in rotated space - glm::vec2 _startPosition; ///< the first corner of the selection base glm::vec2 _endPosition; ///< the second corner of the selection base float _height; ///< the selection height +}; + +/// Allows setting the value across the entire space. +class GlobalSetTool : public MetavoxelTool { + Q_OBJECT + +public: - static ProgramObject _gridProgram; + GlobalSetTool(MetavoxelEditor* editor); + +private slots: + + void apply(); }; #endif /* defined(__interface__MetavoxelEditor__) */ diff --git a/libraries/metavoxels/CMakeLists.txt b/libraries/metavoxels/CMakeLists.txt index 989ed6d4a7..491d537b1a 100644 --- a/libraries/metavoxels/CMakeLists.txt +++ b/libraries/metavoxels/CMakeLists.txt @@ -11,12 +11,12 @@ set(TARGET_NAME metavoxels) find_package(Qt5Network REQUIRED) find_package(Qt5Widgets REQUIRED) -include(${MACRO_DIR}/SetupHifiLibrary.cmake) -setup_hifi_library(${TARGET_NAME}) - include(${MACRO_DIR}/AutoMTC.cmake) auto_mtc(${TARGET_NAME} ${ROOT_DIR}) +include(${MACRO_DIR}/SetupHifiLibrary.cmake) +setup_hifi_library(${TARGET_NAME} ${AUTOMTC_SRC}) + qt5_use_modules(${TARGET_NAME} Network Script Widgets) include(${MACRO_DIR}/IncludeGLM.cmake) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index b0e24405e6..6296b93693 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -43,8 +43,7 @@ MetavoxelData& MetavoxelData::operator=(const MetavoxelData& other) { Box MetavoxelData::getBounds() const { float halfSize = _size * 0.5f; - Box bounds = { glm::vec3(-halfSize, -halfSize, -halfSize), glm::vec3(halfSize, halfSize, halfSize) }; - return bounds; + return Box(glm::vec3(-halfSize, -halfSize, -halfSize), glm::vec3(halfSize, halfSize, halfSize)); } void MetavoxelData::guide(MetavoxelVisitor& visitor) { diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 380df4cac1..9f3ccedc0a 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -9,24 +9,35 @@ #include "MetavoxelData.h" #include "MetavoxelMessages.h" -class EditVisitor : public MetavoxelVisitor { +void MetavoxelEditMessage::apply(MetavoxelData& data) const { + static_cast(edit.data())->apply(data); +} + +MetavoxelEdit::~MetavoxelEdit() { +} + +BoxSetEdit::BoxSetEdit(const Box& region, float granularity, const OwnedAttributeValue& value) : + region(region), granularity(granularity), value(value) { +} + +class BoxSetEditVisitor : public MetavoxelVisitor { public: - EditVisitor(const MetavoxelEditMessage& edit); + BoxSetEditVisitor(const BoxSetEdit& edit); virtual bool visit(MetavoxelInfo& info); private: - const MetavoxelEditMessage& _edit; + const BoxSetEdit& _edit; }; -EditVisitor::EditVisitor(const MetavoxelEditMessage& edit) : +BoxSetEditVisitor::BoxSetEditVisitor(const BoxSetEdit& edit) : MetavoxelVisitor(QVector(), QVector() << edit.value.getAttribute()), _edit(edit) { } -bool EditVisitor::visit(MetavoxelInfo& info) { +bool BoxSetEditVisitor::visit(MetavoxelInfo& info) { // find the intersection between volume and voxel glm::vec3 minimum = glm::max(info.minimum, _edit.region.minimum); glm::vec3 maximum = glm::min(info.minimum + glm::vec3(info.size, info.size, info.size), _edit.region.maximum); @@ -48,12 +59,44 @@ bool EditVisitor::visit(MetavoxelInfo& info) { return true; // subdivide } -void MetavoxelEditMessage::apply(MetavoxelData& data) const { +void BoxSetEdit::apply(MetavoxelData& data) const { // expand to fit the entire edit while (!data.getBounds().contains(region)) { data.expand(); } - EditVisitor visitor(*this); + BoxSetEditVisitor visitor(*this); data.guide(visitor); } + +GlobalSetEdit::GlobalSetEdit(const OwnedAttributeValue& value) : + value(value) { +} + +class GlobalSetEditVisitor : public MetavoxelVisitor { +public: + + GlobalSetEditVisitor(const GlobalSetEdit& edit); + + virtual bool visit(MetavoxelInfo& info); + +private: + + const GlobalSetEdit& _edit; +}; + +GlobalSetEditVisitor::GlobalSetEditVisitor(const GlobalSetEdit& edit) : + MetavoxelVisitor(QVector(), QVector() << edit.value.getAttribute()), + _edit(edit) { +} + +bool GlobalSetEditVisitor::visit(MetavoxelInfo& info) { + info.outputValues[0] = _edit.value; + return false; // entirely contained +} + +void GlobalSetEdit::apply(MetavoxelData& data) const { + GlobalSetEditVisitor visitor(*this); + data.guide(visitor); +} + diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 1c547809fb..165accbbb1 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -67,13 +67,53 @@ class MetavoxelEditMessage { public: - STREAM Box region; - STREAM float granularity; - STREAM OwnedAttributeValue value; + STREAM QVariant edit; void apply(MetavoxelData& data) const; }; DECLARE_STREAMABLE_METATYPE(MetavoxelEditMessage) +/// Abstract base class for edits. +class MetavoxelEdit { +public: + + virtual ~MetavoxelEdit(); + + virtual void apply(MetavoxelData& data) const = 0; +}; + +/// An edit that sets the region within a box to a value. +class BoxSetEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM Box region; + STREAM float granularity; + STREAM OwnedAttributeValue value; + + BoxSetEdit(const Box& region = Box(), float granularity = 0.0f, + const OwnedAttributeValue& value = OwnedAttributeValue()); + + virtual void apply(MetavoxelData& data) const; +}; + +DECLARE_STREAMABLE_METATYPE(BoxSetEdit) + +/// An edit that sets the entire tree to a value. +class GlobalSetEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM OwnedAttributeValue value; + + GlobalSetEdit(const OwnedAttributeValue& value = OwnedAttributeValue()); + + virtual void apply(MetavoxelData& data) const; +}; + +DECLARE_STREAMABLE_METATYPE(GlobalSetEdit) + #endif /* defined(__interface__MetavoxelMessages__) */ diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index 8b33416dc3..f7c2a92b75 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -155,6 +155,10 @@ QByteArray signal(const char* signature) { return signal.replace("dummyMethod()", signature); } +Box::Box(const glm::vec3& minimum, const glm::vec3& maximum) : + minimum(minimum), maximum(maximum) { +} + bool Box::contains(const Box& other) const { return other.minimum.x >= minimum.x && other.maximum.x <= maximum.x && other.minimum.y >= minimum.y && other.maximum.y <= maximum.y && diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 49039090a0..37a6c8bcda 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -46,6 +46,8 @@ public: STREAM glm::vec3 minimum; STREAM glm::vec3 maximum; + Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3()); + bool contains(const Box& other) const; }; diff --git a/tests/metavoxels/CMakeLists.txt b/tests/metavoxels/CMakeLists.txt index 416f398470..9d21dd2a44 100644 --- a/tests/metavoxels/CMakeLists.txt +++ b/tests/metavoxels/CMakeLists.txt @@ -12,12 +12,12 @@ find_package(Qt5Network REQUIRED) find_package(Qt5Script REQUIRED) find_package(Qt5Widgets REQUIRED) -include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME} TRUE) - include(${MACRO_DIR}/AutoMTC.cmake) auto_mtc(${TARGET_NAME} ${ROOT_DIR}) +include(${MACRO_DIR}/SetupHifiProject.cmake) +setup_hifi_project(${TARGET_NAME} TRUE ${AUTOMTC_SRC}) + qt5_use_modules(${TARGET_NAME} Network Script Widgets) #include glm From 9c91d3c2e75589b85427f8fb9d8bcfc69019c3e2 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Feb 2014 10:25:10 -0800 Subject: [PATCH 06/18] Use the existing session stuff for metavoxels rather than a separate system. --- .../src/metavoxels/MetavoxelServer.cpp | 91 ++++++------------- .../src/metavoxels/MetavoxelServer.h | 26 ++---- interface/src/DatagramProcessor.cpp | 2 +- interface/src/MetavoxelSystem.cpp | 87 +++++------------- interface/src/MetavoxelSystem.h | 28 ++---- libraries/metavoxels/src/DatagramSequencer.h | 2 +- 6 files changed, 69 insertions(+), 167 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index fa934142d3..3f9f5114dd 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -28,15 +28,16 @@ void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) { edit.apply(_data); } -void MetavoxelServer::removeSession(const QUuid& sessionId) { - _sessions.take(sessionId)->deleteLater(); -} - const char METAVOXEL_SERVER_LOGGING_NAME[] = "metavoxel-server"; void MetavoxelServer::run() { commonInit(METAVOXEL_SERVER_LOGGING_NAME, NodeType::MetavoxelServer); + NodeList* nodeList = NodeList::getInstance(); + nodeList->addNodeTypeToInterestSet(NodeType::Agent); + + connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachSession(const SharedNodePointer&))); + _lastSend = QDateTime::currentMSecsSinceEpoch(); _sendTimer.start(SEND_INTERVAL); } @@ -50,25 +51,31 @@ void MetavoxelServer::readPendingDatagrams() { while (readAvailableDatagram(receivedPacket, senderSockAddr)) { if (nodeList->packetVersionAndHashMatch(receivedPacket)) { switch (packetTypeForPacket(receivedPacket)) { - case PacketTypeMetavoxelData: { - SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket); - if (matchingNode) { - processData(receivedPacket, matchingNode); - } + case PacketTypeMetavoxelData: + nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); break; - } + default: - NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket); + nodeList->processNodeData(senderSockAddr, receivedPacket); break; } } } } +void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) { + if (node->getType() == NodeType::Agent) { + QMutexLocker locker(&node->getMutex()); + node->setLinkedData(new MetavoxelSession(this, NodeList::getInstance()->nodeWithUUID(node->getUUID()))); + } +} + void MetavoxelServer::sendDeltas() { // send deltas for all sessions - foreach (MetavoxelSession* session, _sessions) { - session->sendDelta(); + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + if (node->getType() == NodeType::Agent) { + static_cast(node->getLinkedData())->sendDelta(); + } } // restart the send timer @@ -79,35 +86,10 @@ void MetavoxelServer::sendDeltas() { _sendTimer.start(qMax(0, 2 * SEND_INTERVAL - elapsed)); } -void MetavoxelServer::processData(const QByteArray& data, const SharedNodePointer& sendingNode) { - // read the session id - int headerPlusIDSize; - QUuid sessionID = readSessionID(data, sendingNode, headerPlusIDSize); - if (sessionID.isNull()) { - return; - } - - // forward to session, creating if necessary - MetavoxelSession*& session = _sessions[sessionID]; - if (!session) { - session = new MetavoxelSession(this, sessionID, QByteArray::fromRawData(data.constData(), headerPlusIDSize), - sendingNode); - } - session->receivedData(data, sendingNode); -} - -MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId, - const QByteArray& datagramHeader, const SharedNodePointer& sendingNode) : - QObject(server), +MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const SharedNodePointer& node) : _server(server), - _sessionId(sessionId), - _sequencer(datagramHeader), - _sendingNode(sendingNode) { - - const int TIMEOUT_INTERVAL = 30 * 1000; - _timeoutTimer.setInterval(TIMEOUT_INTERVAL); - _timeoutTimer.setSingleShot(true); - connect(&_timeoutTimer, SIGNAL(timeout()), SLOT(timedOut())); + _sequencer(byteArrayWithPopluatedHeader(PacketTypeMetavoxelData)), + _node(node) { connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&))); connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&))); @@ -117,19 +99,15 @@ MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& session // insert the baseline send record SendRecord record = { 0 }; _sendRecords.append(record); - - qDebug() << "Opened session [sessionId=" << _sessionId << ", sendingNode=" << sendingNode << "]"; } -void MetavoxelSession::receivedData(const QByteArray& data, const SharedNodePointer& sendingNode) { - // reset the timeout timer - _timeoutTimer.start(); +MetavoxelSession::~MetavoxelSession() { +} - // save the most recent sender - _sendingNode = sendingNode; - +int MetavoxelSession::parseData(const QByteArray& packet) { // process through sequencer - _sequencer.receivedDatagram(data); + _sequencer.receivedDatagram(packet); + return packet.size(); } void MetavoxelSession::sendDelta() { @@ -143,13 +121,8 @@ void MetavoxelSession::sendDelta() { _sendRecords.append(record); } -void MetavoxelSession::timedOut() { - qDebug() << "Session timed out [sessionId=" << _sessionId << ", sendingNode=" << _sendingNode << "]"; - _server->removeSession(_sessionId); -} - void MetavoxelSession::sendData(const QByteArray& data) { - NodeList::getInstance()->writeDatagram(data, _sendingNode); + NodeList::getInstance()->writeDatagram(data, _node); } void MetavoxelSession::readPacket(Bitstream& in) { @@ -164,11 +137,7 @@ void MetavoxelSession::clearSendRecordsBefore(int index) { void MetavoxelSession::handleMessage(const QVariant& message) { int userType = message.userType(); - if (userType == CloseSessionMessage::Type) { - qDebug() << "Session closed [sessionId=" << _sessionId << ", sendingNode=" << _sendingNode << "]"; - _server->removeSession(_sessionId); - - } else if (userType == ClientStateMessage::Type) { + if (userType == ClientStateMessage::Type) { ClientStateMessage state = message.value(); _position = state.position; diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index 60fdeca5a5..a7939ee115 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -9,12 +9,9 @@ #ifndef __hifi__MetavoxelServer__ #define __hifi__MetavoxelServer__ -#include #include #include -#include -#include #include #include @@ -35,45 +32,38 @@ public: const MetavoxelData& getData() const { return _data; } - void removeSession(const QUuid& sessionId); - virtual void run(); virtual void readPendingDatagrams(); private slots: - + + void maybeAttachSession(const SharedNodePointer& node); void sendDeltas(); private: - void processData(const QByteArray& data, const SharedNodePointer& sendingNode); - QTimer _sendTimer; qint64 _lastSend; - QHash _sessions; - MetavoxelData _data; }; /// Contains the state of a single client session. -class MetavoxelSession : public QObject { +class MetavoxelSession : public NodeData { Q_OBJECT public: - MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId, - const QByteArray& datagramHeader, const SharedNodePointer& sendingNode); + MetavoxelSession(MetavoxelServer* server, const SharedNodePointer& node); + virtual ~MetavoxelSession(); - void receivedData(const QByteArray& data, const SharedNodePointer& sendingNode); + virtual int parseData(const QByteArray& packet); void sendDelta(); private slots: - void timedOut(); - void sendData(const QByteArray& data); void readPacket(Bitstream& in); @@ -91,12 +81,10 @@ private: }; MetavoxelServer* _server; - QUuid _sessionId; - QTimer _timeoutTimer; DatagramSequencer _sequencer; - SharedNodePointer _sendingNode; + SharedNodePointer _node; glm::vec3 _position; diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index d8447168cd..18e3742bd7 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -94,7 +94,7 @@ void DatagramProcessor::processDatagrams() { break; } case PacketTypeMetavoxelData: - application->_metavoxels.processData(incomingPacket, senderSockAddr); + nodeList->findNodeAndUpdateWithDataFromPacket(incomingPacket); break; case PacketTypeBulkAvatarData: case PacketTypeKillAvatar: diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 34c3be5308..3c3683f0dc 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -25,12 +25,6 @@ MetavoxelSystem::MetavoxelSystem() : _buffer(QOpenGLBuffer::VertexBuffer) { } -MetavoxelSystem::~MetavoxelSystem() { - for (QHash::const_iterator it = _clients.begin(); it != _clients.end(); it++) { - delete it.value(); - } -} - void MetavoxelSystem::init() { if (!_program.isLinked()) { switchToResourcesParentIfRequired(); @@ -42,33 +36,35 @@ void MetavoxelSystem::init() { // let the script cache know to use our common access manager ScriptCache::getInstance()->setNetworkAccessManager(Application::getInstance()->getNetworkAccessManager()); } - - NodeList* nodeList = NodeList::getInstance(); - - connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer))); - connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); - _buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); _buffer.create(); + + connect(NodeList::getInstance(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachClient(const SharedNodePointer&))); } void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit) { - foreach (MetavoxelClient* client, _clients) { - client->applyEdit(edit); + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + if (node->getType() == NodeType::MetavoxelServer) { + MetavoxelClient* client = static_cast(node->getLinkedData()); + if (client) { + client->applyEdit(edit); + } + } } } -void MetavoxelSystem::processData(const QByteArray& data, const HifiSockAddr& sender) { - QMetaObject::invokeMethod(this, "receivedData", Q_ARG(const QByteArray&, data), Q_ARG(const HifiSockAddr&, sender)); -} - void MetavoxelSystem::simulate(float deltaTime) { // simulate the clients _points.clear(); - foreach (MetavoxelClient* client, _clients) { - client->simulate(deltaTime, _pointVisitor); + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + if (node->getType() == NodeType::MetavoxelServer) { + MetavoxelClient* client = static_cast(node->getLinkedData()); + if (client) { + client->simulate(deltaTime, _pointVisitor); + } + } } - + _buffer.bind(); int bytes = _points.size() * sizeof(Point); if (_buffer.size() < bytes) { @@ -120,39 +116,10 @@ void MetavoxelSystem::render() { _program.release(); } -void MetavoxelSystem::nodeAdded(SharedNodePointer node) { +void MetavoxelSystem::maybeAttachClient(const SharedNodePointer& node) { if (node->getType() == NodeType::MetavoxelServer) { - QMetaObject::invokeMethod(this, "addClient", Q_ARG(const SharedNodePointer&, node)); - } -} - -void MetavoxelSystem::nodeKilled(SharedNodePointer node) { - if (node->getType() == NodeType::MetavoxelServer) { - QMetaObject::invokeMethod(this, "removeClient", Q_ARG(const QUuid&, node->getUUID())); - } -} - -void MetavoxelSystem::addClient(const SharedNodePointer& node) { - MetavoxelClient* client = new MetavoxelClient(node); - _clients.insert(node->getUUID(), client); - _clientsBySessionID.insert(client->getSessionID(), client); -} - -void MetavoxelSystem::removeClient(const QUuid& uuid) { - MetavoxelClient* client = _clients.take(uuid); - _clientsBySessionID.remove(client->getSessionID()); - delete client; -} - -void MetavoxelSystem::receivedData(const QByteArray& data, const SharedNodePointer& sendingNode) { - int headerPlusIDSize; - QUuid sessionID = readSessionID(data, sendingNode, headerPlusIDSize); - if (sessionID.isNull()) { - return; - } - MetavoxelClient* client = _clientsBySessionID.value(sessionID); - if (client) { - client->receivedData(data); + QMutexLocker locker(&node->getMutex()); + node->setLinkedData(new MetavoxelClient(NodeList::getInstance()->nodeWithUUID(node->getUUID()))); } } @@ -179,16 +146,9 @@ bool MetavoxelSystem::PointVisitor::visit(MetavoxelInfo& info) { return false; } -static QByteArray createDatagramHeader(const QUuid& sessionID) { - QByteArray header = byteArrayWithPopluatedHeader(PacketTypeMetavoxelData); - header += sessionID.toRfc4122(); - return header; -} - MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) : _node(node), - _sessionID(QUuid::createUuid()), - _sequencer(createDatagramHeader(_sessionID)) { + _sequencer(byteArrayWithPopluatedHeader(PacketTypeMetavoxelData)) { connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&))); connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&))); @@ -223,9 +183,10 @@ void MetavoxelClient::simulate(float deltaTime, MetavoxelVisitor& visitor) { _data.guide(visitor); } -void MetavoxelClient::receivedData(const QByteArray& data) { +int MetavoxelClient::parseData(const QByteArray& packet) { // process through sequencer - _sequencer.receivedDatagram(data); + QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet)); + return packet.size(); } void MetavoxelClient::sendData(const QByteArray& data) { diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 7bb7935e4d..40765723fd 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -23,8 +23,6 @@ #include "renderer/ProgramObject.h" -class MetavoxelClient; - /// Renders a metavoxel tree. class MetavoxelSystem : public QObject { Q_OBJECT @@ -32,28 +30,20 @@ class MetavoxelSystem : public QObject { public: MetavoxelSystem(); - ~MetavoxelSystem(); void init(); void applyEdit(const MetavoxelEditMessage& edit); - void processData(const QByteArray& data, const HifiSockAddr& sender); - void simulate(float deltaTime); void render(); -public slots: +private slots: + + void maybeAttachClient(const SharedNodePointer& node); - void nodeAdded(SharedNodePointer node); - void nodeKilled(SharedNodePointer node); - private: - - Q_INVOKABLE void addClient(const SharedNodePointer& node); - Q_INVOKABLE void removeClient(const QUuid& uuid); - Q_INVOKABLE void receivedData(const QByteArray& data, const SharedNodePointer& sendingNode); - + class Point { public: glm::vec4 vertex; @@ -76,13 +66,10 @@ private: QVector _points; PointVisitor _pointVisitor; QOpenGLBuffer _buffer; - - QHash _clients; - QHash _clientsBySessionID; }; /// A client session associated with a single server. -class MetavoxelClient : public QObject { +class MetavoxelClient : public NodeData { Q_OBJECT public: @@ -90,13 +77,11 @@ public: MetavoxelClient(const SharedNodePointer& node); virtual ~MetavoxelClient(); - const QUuid& getSessionID() const { return _sessionID; } - void applyEdit(const MetavoxelEditMessage& edit); void simulate(float deltaTime, MetavoxelVisitor& visitor); - void receivedData(const QByteArray& data); + virtual int parseData(const QByteArray& packet); private slots: @@ -117,7 +102,6 @@ private: }; SharedNodePointer _node; - QUuid _sessionID; DatagramSequencer _sequencer; diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 7156175f51..13bdf4c7bf 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -70,7 +70,7 @@ public: /// Processes a datagram received from the other party, emitting readyToRead when the entire packet /// has been successfully assembled. - void receivedDatagram(const QByteArray& datagram); + Q_INVOKABLE void receivedDatagram(const QByteArray& datagram); signals: From 8920873d705acbb236d4e70828a22e000694ded0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Feb 2014 15:35:42 -0800 Subject: [PATCH 07/18] Working on support for "spanners" (objects that span multiple octree cells). --- .../metavoxels/src/AttributeRegistry.cpp | 16 +++++++++ libraries/metavoxels/src/AttributeRegistry.h | 25 +++++++++++++- libraries/metavoxels/src/Bitstream.h | 24 ++++++++++++++ libraries/metavoxels/src/MetavoxelData.cpp | 20 +++++++++++ libraries/metavoxels/src/MetavoxelData.h | 27 +++++++++++++++ .../metavoxels/src/MetavoxelMessages.cpp | 15 +++++++++ libraries/metavoxels/src/MetavoxelMessages.h | 33 +++++++++++++++++++ libraries/metavoxels/src/SharedObject.h | 5 +++ 8 files changed, 164 insertions(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 8483174dac..3cde1ce961 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -13,6 +13,7 @@ REGISTER_META_OBJECT(QRgbAttribute) REGISTER_META_OBJECT(SharedObjectAttribute) +REGISTER_META_OBJECT(SharedObjectSetAttribute) AttributeRegistry* AttributeRegistry::getInstance() { static AttributeRegistry registry; @@ -22,6 +23,7 @@ AttributeRegistry* AttributeRegistry::getInstance() { AttributeRegistry::AttributeRegistry() : _guideAttribute(registerAttribute(new SharedObjectAttribute("guide", &MetavoxelGuide::staticMetaObject, SharedObjectPointer(new DefaultMetavoxelGuide())))), + _spannersAttribute(registerAttribute(new SharedObjectSetAttribute("spanners", &Spanner::staticMetaObject))), _colorAttribute(registerAttribute(new QRgbAttribute("color"))), _normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) { } @@ -227,3 +229,17 @@ QWidget* SharedObjectAttribute::createEditor(QWidget* parent) const { editor->setObject(_defaultValue); return editor; } + +SharedObjectSetAttribute::SharedObjectSetAttribute(const QString& name, const QMetaObject* metaObject) : + InlineAttribute(name), + _metaObject(metaObject) { +} + +bool SharedObjectSetAttribute::merge(void*& parent, void* children[]) const { + for (int i = 0; i < MERGE_COUNT; i++) { + if (!decodeInline(children[i]).isEmpty()) { + return false; + } + } + return true; +} diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 1235cefbb5..ebcfb0c8d9 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -57,9 +57,12 @@ public: /// Returns a reference to the attribute hash. const QHash& getAttributes() const { return _attributes; } - /// Returns a reference to the standard PolymorphicDataPointer "guide" attribute. + /// Returns a reference to the standard SharedObjectPointer "guide" attribute. const AttributePointer& getGuideAttribute() const { return _guideAttribute; } + /// Returns a reference to the standard SharedObjectSet "spanners" attribute. + const AttributePointer& getSpannersAttribute() const { return _spannersAttribute; } + /// Returns a reference to the standard QRgb "color" attribute. const AttributePointer& getColorAttribute() const { return _colorAttribute; } @@ -72,6 +75,7 @@ private: QHash _attributes; AttributePointer _guideAttribute; + AttributePointer _spannersAttribute; AttributePointer _colorAttribute; AttributePointer _normalAttribute; }; @@ -281,4 +285,23 @@ private: const QMetaObject* _metaObject; }; +/// An attribute that takes the form of a set of shared objects. +class SharedObjectSetAttribute : public InlineAttribute { + Q_OBJECT + Q_PROPERTY(const QMetaObject* metaObject MEMBER _metaObject) + +public: + + Q_INVOKABLE SharedObjectSetAttribute(const QString& name = QString(), + const QMetaObject* metaObject = &SharedObject::staticMetaObject); + + const QMetaObject* getMetaObject() const { return _metaObject; } + + virtual bool merge(void*& parent, void* children[]) const; + +private: + + const QMetaObject* _metaObject; +}; + #endif /* defined(__interface__AttributeRegistry__) */ diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 87ee66c661..9a3ef95d96 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -266,6 +266,9 @@ public: template Bitstream& operator<<(const QList& list); template Bitstream& operator>>(QList& list); + template Bitstream& operator<<(const QSet& set); + template Bitstream& operator>>(QSet& set); + template Bitstream& operator<<(const QHash& hash); template Bitstream& operator>>(QHash& hash); @@ -348,6 +351,27 @@ template inline Bitstream& Bitstream::operator>>(QList& list) { return *this; } +template inline Bitstream& Bitstream::operator<<(const QSet& set) { + *this << set.size(); + foreach (const T& entry, set) { + *this << entry; + } + return *this; +} + +template inline Bitstream& Bitstream::operator>>(QSet& set) { + int size; + *this >> size; + set.clear(); + set.reserve(size); + for (int i = 0; i < size; i++) { + T entry; + *this >> entry; + set.insert(entry); + } + return *this; +} + template inline Bitstream& Bitstream::operator<<(const QHash& hash) { *this << hash.size(); for (typename QHash::const_iterator it = hash.constBegin(); it != hash.constEnd(); it++) { diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 6296b93693..5f400ef517 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -18,6 +18,7 @@ REGISTER_META_OBJECT(MetavoxelGuide) REGISTER_META_OBJECT(DefaultMetavoxelGuide) REGISTER_META_OBJECT(ScriptedMetavoxelGuide) REGISTER_META_OBJECT(ThrobbingMetavoxelGuide) +REGISTER_META_OBJECT(Spanner) MetavoxelData::MetavoxelData() : _size(1.0f) { } @@ -673,3 +674,22 @@ AttributeValue MetavoxelVisitation::getInheritedOutputValue(int index) const { return AttributeValue(visitor.getOutputs().at(index)); } +Spanner::Spanner() : _lastVisit(0) { +} + +void Spanner::setBounds(const Box& bounds) { + if (_bounds == bounds) { + return; + } + emit boundsWillChange(); + emit boundsChanged(_bounds = bounds); +} + +bool Spanner::testAndSetVisited(int visit) { + if (_lastVisit == visit) { + return false; + } + _lastVisit = visit; + return true; +} + diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 51cdd6cf64..4b001e2e33 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -242,4 +242,31 @@ public: AttributeValue getInheritedOutputValue(int index) const; }; +/// An object that spans multiple octree cells. +class Spanner : public SharedObject { + Q_OBJECT + Q_PROPERTY(Box bounds MEMBER _bounds WRITE setBounds NOTIFY boundsChanged) + +public: + + Spanner(); + + void setBounds(const Box& bounds); + const Box& getBounds() const { return _bounds; } + + /// Checks whether we've visited this object on the current traversal. If we have, returns false. + /// If we haven't, sets the last visit identifier and returns true. + bool testAndSetVisited(int visit); + +signals: + + void boundsWillChange(); + void boundsChanged(const Box& bounds); + +private: + + Box _bounds; + int _lastVisit; ///< the identifier of the last visit +}; + #endif /* defined(__interface__MetavoxelData__) */ diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 9f3ccedc0a..36f0fcc10a 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -100,3 +100,18 @@ void GlobalSetEdit::apply(MetavoxelData& data) const { data.guide(visitor); } +InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) : + attribute(attribute), + spanner(spanner) { +} + +void InsertSpannerEdit::apply(MetavoxelData& data) const { +} + +RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) : + attribute(attribute), + id(id) { +} + +void RemoveSpannerEdit::apply(MetavoxelData& data) const { +} diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 165accbbb1..65bee27d7d 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -116,4 +116,37 @@ public: DECLARE_STREAMABLE_METATYPE(GlobalSetEdit) +/// An edit that inserts a spanner into the tree. +class InsertSpannerEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM AttributePointer attribute; + STREAM SharedObjectPointer spanner; + + InsertSpannerEdit(const AttributePointer& attribute = AttributePointer(), + const SharedObjectPointer& spanner = SharedObjectPointer()); + + virtual void apply(MetavoxelData& data) const; +}; + +DECLARE_STREAMABLE_METATYPE(InsertSpannerEdit) + +/// An edit that removes a a spanner from the tree. +class RemoveSpannerEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM AttributePointer attribute; + STREAM int id; + + RemoveSpannerEdit(const AttributePointer& attribute = AttributePointer(), int id = 0); + + virtual void apply(MetavoxelData& data) const; +}; + +DECLARE_STREAMABLE_METATYPE(RemoveSpannerEdit) + #endif /* defined(__interface__MetavoxelMessages__) */ diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index b62b88d2ee..5a33b64e3d 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -11,6 +11,7 @@ #include #include +#include #include class QComboBox; @@ -144,6 +145,10 @@ typedef SharedObjectPointerTemplate SharedObjectPointer; Q_DECLARE_METATYPE(SharedObjectPointer) +typedef QSet SharedObjectSet; + +Q_DECLARE_METATYPE(SharedObjectSet) + /// Allows editing shared object instances. class SharedObjectEditor : public QWidget { Q_OBJECT From 3e40927d3a1426fc1122f7ebf56d90ecd33da8ef Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Feb 2014 18:01:48 -0800 Subject: [PATCH 08/18] More work on spanning objects. --- interface/src/ui/MetavoxelEditor.cpp | 93 +++++++++++++++---- interface/src/ui/MetavoxelEditor.h | 36 ++++++- .../metavoxels/src/AttributeRegistry.cpp | 4 + libraries/metavoxels/src/AttributeRegistry.h | 2 + libraries/metavoxels/src/MetavoxelData.cpp | 33 +++++++ libraries/metavoxels/src/MetavoxelData.h | 6 +- .../metavoxels/src/MetavoxelMessages.cpp | 3 +- 7 files changed, 156 insertions(+), 21 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 0ba0b08633..54a0c28266 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -94,14 +94,11 @@ MetavoxelEditor::MetavoxelEditor() : valueLayout->addWidget(_valueArea = new QScrollArea()); _valueArea->setWidgetResizable(true); - BoxSetTool* boxSetTool = new BoxSetTool(this); - topLayout->addWidget(boxSetTool); - _toolBox->addItem("Set Value (Box)", QVariant::fromValue(boxSetTool)); - - GlobalSetTool* globalSetTool = new GlobalSetTool(this); - topLayout->addWidget(globalSetTool); - _toolBox->addItem("Set Value (Global)", QVariant::fromValue(globalSetTool)); - + addTool(new BoxSetTool(this)); + addTool(new GlobalSetTool(this)); + addTool(new InsertSpannerTool(this)); + addTool(new RemoveSpannerTool(this)); + updateAttributes(); connect(Application::getInstance(), SIGNAL(renderingInWorldInterface()), SLOT(render())); @@ -153,23 +150,35 @@ QVariant MetavoxelEditor::getValue() const { bool MetavoxelEditor::eventFilter(QObject* watched, QEvent* event) { // pass along to the active tool - return getActiveTool()->eventFilter(watched, event); + MetavoxelTool* tool = getActiveTool(); + return tool && tool->eventFilter(watched, event); } void MetavoxelEditor::selectedAttributeChanged() { + _toolBox->clear(); + QString selected = getSelectedAttribute(); if (selected.isNull()) { _deleteAttribute->setEnabled(false); + _toolBox->setEnabled(false); _value->setVisible(false); return; } _deleteAttribute->setEnabled(true); + _toolBox->setEnabled(true); + + AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(selected); + foreach (MetavoxelTool* tool, _tools) { + if (tool->appliesTo(attribute)) { + _toolBox->addItem(tool->objectName(), QVariant::fromValue(tool)); + } + } _value->setVisible(true); if (_valueArea->widget()) { delete _valueArea->widget(); } - QWidget* editor = AttributeRegistry::getInstance()->getAttribute(selected)->createEditor(); + QWidget* editor = attribute->createEditor(); if (editor) { _valueArea->setWidget(editor); } @@ -231,9 +240,11 @@ void MetavoxelEditor::alignGridPosition() { } void MetavoxelEditor::updateTool() { - for (int i = 0; i < _toolBox->count(); i++) { - _toolBox->itemData(i).value()->setVisible(i == _toolBox->currentIndex()); + MetavoxelTool* active = getActiveTool(); + foreach (MetavoxelTool* tool, _tools) { + tool->setVisible(tool == active); } + _value->setVisible(active && active->getUsesValue()); } const float GRID_BRIGHTNESS = 0.5f; @@ -248,7 +259,10 @@ void MetavoxelEditor::render() { glm::vec3 axis = glm::axis(rotation); glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); - getActiveTool()->render(); + MetavoxelTool* tool = getActiveTool(); + if (tool) { + tool->render(); + } glLineWidth(1.0f); @@ -276,6 +290,11 @@ void MetavoxelEditor::render() { glDepthMask(GL_TRUE); } +void MetavoxelEditor::addTool(MetavoxelTool* tool) { + _tools.append(tool); + layout()->addWidget(tool); +} + void MetavoxelEditor::updateAttributes(const QString& select) { // remember the selection in order to preserve it QString selected = select.isNull() ? getSelectedAttribute() : select; @@ -296,26 +315,34 @@ void MetavoxelEditor::updateAttributes(const QString& select) { } MetavoxelTool* MetavoxelEditor::getActiveTool() const { - return static_cast(_toolBox->itemData(_toolBox->currentIndex()).value()); + int index = _toolBox->currentIndex(); + return (index == -1) ? NULL : static_cast(_toolBox->itemData(index).value()); } ProgramObject MetavoxelEditor::_gridProgram; -MetavoxelTool::MetavoxelTool(MetavoxelEditor* editor) : - _editor(editor) { +MetavoxelTool::MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue) : + _editor(editor), + _usesValue(usesValue) { QVBoxLayout* layout = new QVBoxLayout(); setLayout(layout); + setObjectName(name); setVisible(false); } +bool MetavoxelTool::appliesTo(const AttributePointer& attribute) const { + // shared object sets are a special case + return !attribute->inherits("SharedObjectSetAttribute"); +} + void MetavoxelTool::render() { // nothing by default } BoxSetTool::BoxSetTool(MetavoxelEditor* editor) : - MetavoxelTool(editor) { + MetavoxelTool(editor, "Set Value (Box)") { resetState(); } @@ -449,7 +476,7 @@ void BoxSetTool::applyValue(const glm::vec3& minimum, const glm::vec3& maximum) } GlobalSetTool::GlobalSetTool(MetavoxelEditor* editor) : - MetavoxelTool(editor) { + MetavoxelTool(editor, "Set Value (Global)") { QPushButton* button = new QPushButton("Apply"); layout()->addWidget(button); @@ -465,3 +492,33 @@ void GlobalSetTool::apply() { MetavoxelEditMessage message = { QVariant::fromValue(GlobalSetEdit(value)) }; Application::getInstance()->getMetavoxels()->applyEdit(message); } + +InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) : + MetavoxelTool(editor, "Insert Spanner") { + + QPushButton* button = new QPushButton("Insert"); + layout()->addWidget(button); + connect(button, SIGNAL(clicked()), SLOT(insert())); +} + +bool InsertSpannerTool::appliesTo(const AttributePointer& attribute) const { + return attribute->inherits("SharedObjectSetAttribute"); +} + +void InsertSpannerTool::insert() { + AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute()); + if (!attribute) { + return; + } + SharedObjectPointer spanner = _editor->getValue().value(); + MetavoxelEditMessage message = { QVariant::fromValue(InsertSpannerEdit(attribute, spanner)) }; + Application::getInstance()->getMetavoxels()->applyEdit(message); +} + +RemoveSpannerTool::RemoveSpannerTool(MetavoxelEditor* editor) : + MetavoxelTool(editor, "Remove Spanner", false) { +} + +bool RemoveSpannerTool::appliesTo(const AttributePointer& attribute) const { + return attribute->inherits("SharedObjectSetAttribute"); +} diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index be2afd0a36..e3574b9f67 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -10,6 +10,7 @@ #define __interface__MetavoxelEditor__ #include +#include #include "renderer/ProgramObject.h" @@ -53,6 +54,7 @@ private slots: private: + void addTool(MetavoxelTool* tool); void updateAttributes(const QString& select = QString()); MetavoxelTool* getActiveTool() const; @@ -63,6 +65,7 @@ private: QDoubleSpinBox* _gridSpacing; QDoubleSpinBox* _gridPosition; + QList _tools; QComboBox* _toolBox; QGroupBox* _value; @@ -77,7 +80,11 @@ class MetavoxelTool : public QWidget { public: - MetavoxelTool(MetavoxelEditor* editor); + MetavoxelTool(MetavoxelEditor* editor, const QString& name, bool usesValue = true); + + bool getUsesValue() const { return _usesValue; } + + virtual bool appliesTo(const AttributePointer& attribute) const; /// Renders the tool's interface, if any. virtual void render(); @@ -85,6 +92,7 @@ public: protected: MetavoxelEditor* _editor; + bool _usesValue; }; /// Allows setting the value of a region by dragging out a box. @@ -127,4 +135,30 @@ private slots: void apply(); }; +/// Allows inserting a spanner into the scene. +class InsertSpannerTool : public MetavoxelTool { + Q_OBJECT + +public: + + InsertSpannerTool(MetavoxelEditor* editor); + + virtual bool appliesTo(const AttributePointer& attribute) const; + +private slots: + + void insert(); +}; + +/// Allows removing a spanner from the scene. +class RemoveSpannerTool : public MetavoxelTool { + Q_OBJECT + +public: + + RemoveSpannerTool(MetavoxelEditor* editor); + + virtual bool appliesTo(const AttributePointer& attribute) const; +}; + #endif /* defined(__interface__MetavoxelEditor__) */ diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 3cde1ce961..22a629dd1a 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -243,3 +243,7 @@ bool SharedObjectSetAttribute::merge(void*& parent, void* children[]) const { } return true; } + +QWidget* SharedObjectSetAttribute::createEditor(QWidget* parent) const { + return new SharedObjectEditor(_metaObject, parent); +} diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index ebcfb0c8d9..1bcadf7f6c 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -299,6 +299,8 @@ public: virtual bool merge(void*& parent, void* children[]) const; + virtual QWidget* createEditor(QWidget* parent = NULL) const; + private: const QMetaObject* _metaObject; diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 5f400ef517..a746fda102 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -88,6 +88,39 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { } } +class InsertVisitor : public MetavoxelVisitor { +public: + + InsertVisitor(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object); + + virtual bool visit(MetavoxelInfo& info); + +private: + + const AttributePointer& _attribute; + const Box& _bounds; + const SharedObjectPointer& _object; +}; + +InsertVisitor::InsertVisitor(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object) : + MetavoxelVisitor(QVector() << attribute, QVector() << attribute), + _attribute(attribute), + _bounds(bounds), + _object(object) { +} + +bool InsertVisitor::visit(MetavoxelInfo& info) { + return false; +} + +void MetavoxelData::insert(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object) { + InsertVisitor visitor(attribute, bounds, object); + guide(visitor); +} + +void MetavoxelData::remove(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object) { +} + const int X_MAXIMUM_FLAG = 1; const int Y_MAXIMUM_FLAG = 2; const int Z_MAXIMUM_FLAG = 4; diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 4b001e2e33..a0249216f6 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -45,7 +45,11 @@ public: /// Applies the specified visitor to the contained voxels. void guide(MetavoxelVisitor& visitor); + + void insert(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object); + void remove(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object); + /// Expands the tree, increasing its capacity in all dimensions. void expand(); @@ -249,7 +253,7 @@ class Spanner : public SharedObject { public: - Spanner(); + Q_INVOKABLE Spanner(); void setBounds(const Box& bounds); const Box& getBounds() const { return _bounds; } diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 36f0fcc10a..56336ffa16 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -105,7 +105,8 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh spanner(spanner) { } -void InsertSpannerEdit::apply(MetavoxelData& data) const { +void InsertSpannerEdit::apply(MetavoxelData& data) const { + data.insert(attribute, static_cast(spanner.data())->getBounds(), spanner); } RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) : From 494685140bcead44191513394dc9ce5facab7128 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 17 Feb 2014 21:44:32 -0800 Subject: [PATCH 09/18] Various bits of work on spanners. --- interface/src/Application.cpp | 3 + interface/src/Application.h | 3 + interface/src/MetavoxelSystem.cpp | 47 ++++++++++++ interface/src/MetavoxelSystem.h | 26 +++++++ interface/src/ui/MetavoxelEditor.cpp | 23 ++++++ interface/src/ui/MetavoxelEditor.h | 7 ++ libraries/metavoxels/src/Bitstream.cpp | 4 + libraries/metavoxels/src/Bitstream.h | 3 + libraries/metavoxels/src/MetavoxelData.cpp | 72 +++++++++++++++++- libraries/metavoxels/src/MetavoxelData.h | 85 +++++++++++++++++++++- libraries/metavoxels/src/SharedObject.cpp | 4 + 11 files changed, 274 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b445efeb15..9c81ddca75 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2309,6 +2309,9 @@ void Application::update(float deltaTime) { _particles.update(); // update the particles... _particleCollisionSystem.update(); // collide the particles... + + // let external parties know we're updating + emit simulating(deltaTime); } void Application::updateMyAvatar(float deltaTime) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 574f578bde..4b10873bdf 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -208,6 +208,9 @@ public: signals: + /// Fired when we're simulating; allows external parties to hook in. + void simulating(float deltaTime); + /// Fired when we're rendering in-world interface elements; allows external parties to hook in. void renderingInWorldInterface(); diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 3c3683f0dc..9a5bb4cfd1 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -16,6 +16,9 @@ #include "Application.h" #include "MetavoxelSystem.h" +#include "renderer/Model.h" + +REGISTER_META_OBJECT(StaticModelRenderer) ProgramObject MetavoxelSystem::_program; int MetavoxelSystem::_pointScaleLocation; @@ -226,3 +229,47 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { } } } + +StaticModelRenderer::StaticModelRenderer() : + _model(new Model(this)) { +} + +void StaticModelRenderer::init(Spanner* spanner) { + _model->init(); + + StaticModel* staticModel = static_cast(spanner); + applyTranslation(staticModel->getTranslation()); + applyRotation(staticModel->getRotation()); + applyScale(staticModel->getScale()); + applyURL(staticModel->getURL()); + + connect(spanner, SIGNAL(translationChanged(const glm::vec3&)), SLOT(applyTranslation(const glm::vec3&))); + connect(spanner, SIGNAL(rotationChanged(const glm::vec3&)), SLOT(applyRotation(const glm::vec3&))); + connect(spanner, SIGNAL(scaleChanged(float)), SLOT(applyScale(float))); + connect(spanner, SIGNAL(urlChanged(const QUrl&)), SLOT(applyURL(const QUrl&))); +} + +void StaticModelRenderer::simulate(float deltaTime) { + _model->simulate(deltaTime); +} + +void StaticModelRenderer::render(float alpha) { + _model->render(alpha); +} + +void StaticModelRenderer::applyTranslation(const glm::vec3& translation) { + _model->setTranslation(translation); +} + +void StaticModelRenderer::applyRotation(const glm::vec3& rotation) { + _model->setRotation(glm::quat(glm::radians(rotation))); +} + +void StaticModelRenderer::applyScale(float scale) { + const float SCALE_MULTIPLIER = 0.0006f; + _model->setScale(glm::vec3(scale, scale, scale) * SCALE_MULTIPLIER); +} + +void StaticModelRenderer::applyURL(const QUrl& url) { + _model->setURL(url); +} diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 40765723fd..7cc8c114fd 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -23,6 +23,8 @@ #include "renderer/ProgramObject.h" +class Model; + /// Renders a metavoxel tree. class MetavoxelSystem : public QObject { Q_OBJECT @@ -110,4 +112,28 @@ private: QList _receiveRecords; }; +/// Renders static models. +class StaticModelRenderer : public SpannerRenderer { + Q_OBJECT + +public: + + Q_INVOKABLE StaticModelRenderer(); + + virtual void init(Spanner* spanner); + virtual void simulate(float deltaTime); + virtual void render(float alpha); + +private slots: + + void applyTranslation(const glm::vec3& translation); + void applyRotation(const glm::vec3& rotation); + void applyScale(float scale); + void applyURL(const QUrl& url); + +private: + + Model* _model; +}; + #endif /* defined(__interface__MetavoxelSystem__) */ diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 54a0c28266..003d283795 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -101,6 +101,7 @@ MetavoxelEditor::MetavoxelEditor() : updateAttributes(); + connect(Application::getInstance(), SIGNAL(simulating(float)), SLOT(simulate(float))); connect(Application::getInstance(), SIGNAL(renderingInWorldInterface()), SLOT(render())); Application::getInstance()->getGLWidget()->installEventFilter(this); @@ -247,6 +248,13 @@ void MetavoxelEditor::updateTool() { _value->setVisible(active && active->getUsesValue()); } +void MetavoxelEditor::simulate(float deltaTime) { + MetavoxelTool* tool = getActiveTool(); + if (tool) { + tool->simulate(deltaTime); + } +} + const float GRID_BRIGHTNESS = 0.5f; void MetavoxelEditor::render() { @@ -337,6 +345,10 @@ bool MetavoxelTool::appliesTo(const AttributePointer& attribute) const { return !attribute->inherits("SharedObjectSetAttribute"); } +void MetavoxelTool::simulate(float deltaTime) { + // nothing by default +} + void MetavoxelTool::render() { // nothing by default } @@ -501,6 +513,17 @@ InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) : connect(button, SIGNAL(clicked()), SLOT(insert())); } +void InsertSpannerTool::simulate(float deltaTime) { + SharedObjectPointer spanner = _editor->getValue().value(); + static_cast(spanner.data())->getRenderer()->simulate(deltaTime); +} + +void InsertSpannerTool::render() { + SharedObjectPointer spanner = _editor->getValue().value(); + const float SPANNER_ALPHA = 1.0f; + static_cast(spanner.data())->getRenderer()->render(SPANNER_ALPHA); +} + bool InsertSpannerTool::appliesTo(const AttributePointer& attribute) const { return attribute->inherits("SharedObjectSetAttribute"); } diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index e3574b9f67..a688a01cec 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -50,6 +50,7 @@ private slots: void alignGridPosition(); void updateTool(); + void simulate(float deltaTime); void render(); private: @@ -86,6 +87,8 @@ public: virtual bool appliesTo(const AttributePointer& attribute) const; + virtual void simulate(float deltaTime); + /// Renders the tool's interface, if any. virtual void render(); @@ -143,6 +146,10 @@ public: InsertSpannerTool(MetavoxelEditor* editor); + virtual void simulate(float deltaTime); + + virtual void render(); + virtual bool appliesTo(const AttributePointer& attribute) const; private slots: diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 61e300eae5..bf2cdd1e96 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -81,6 +81,10 @@ int Bitstream::registerTypeStreamer(int type, TypeStreamer* streamer) { return 0; } +const QMetaObject* Bitstream::getMetaObject(const QByteArray& className) { + return getMetaObjects().value(className); +} + QList Bitstream::getMetaObjectSubClasses(const QMetaObject* metaObject) { return getMetaObjectSubClasses().values(metaObject); } diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 9a3ef95d96..74cb7de073 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -196,6 +196,9 @@ public: /// \return zero; the function only returns a value so that it can be used in static initialization static int registerTypeStreamer(int type, TypeStreamer* streamer); + /// Returns the meta-object registered under the supplied class name, if any. + static const QMetaObject* getMetaObject(const QByteArray& className); + /// Returns the list of registered subclasses for the supplied meta-object. static QList getMetaObjectSubClasses(const QMetaObject* metaObject); diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index a746fda102..c8c3dbf577 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -19,6 +19,7 @@ REGISTER_META_OBJECT(DefaultMetavoxelGuide) REGISTER_META_OBJECT(ScriptedMetavoxelGuide) REGISTER_META_OBJECT(ThrobbingMetavoxelGuide) REGISTER_META_OBJECT(Spanner) +REGISTER_META_OBJECT(StaticModel) MetavoxelData::MetavoxelData() : _size(1.0f) { } @@ -707,7 +708,9 @@ AttributeValue MetavoxelVisitation::getInheritedOutputValue(int index) const { return AttributeValue(visitor.getOutputs().at(index)); } -Spanner::Spanner() : _lastVisit(0) { +Spanner::Spanner() : + _lastVisit(0), + _renderer(NULL) { } void Spanner::setBounds(const Box& bounds) { @@ -726,3 +729,70 @@ bool Spanner::testAndSetVisited(int visit) { return true; } +SpannerRenderer* Spanner::getRenderer() { + if (!_renderer) { + QByteArray className = getRendererClassName(); + const QMetaObject* metaObject = Bitstream::getMetaObject(className); + if (!metaObject) { + qDebug() << "Unknown class name:" << className; + metaObject = &SpannerRenderer::staticMetaObject; + } + _renderer = static_cast(metaObject->newInstance()); + _renderer->setParent(this); + _renderer->init(this); + } + return _renderer; +} + +QByteArray Spanner::getRendererClassName() const { + return "SpannerRendererer"; +} + +SpannerRenderer::SpannerRenderer() { +} + +void SpannerRenderer::init(Spanner* spanner) { + // nothing by default +} + +void SpannerRenderer::simulate(float deltaTime) { + // nothing by default +} + +void SpannerRenderer::render(float alpha) { + // nothing by default +} + +Transformable::Transformable() : _scale(1.0f) { +} + +void Transformable::setTranslation(const glm::vec3& translation) { + if (_translation != translation) { + emit translationChanged(_translation = translation); + } +} + +void Transformable::setRotation(const glm::vec3& rotation) { + if (_rotation != rotation) { + emit rotationChanged(_rotation = rotation); + } +} + +void Transformable::setScale(float scale) { + if (_scale != scale) { + emit scaleChanged(_scale = scale); + } +} + +StaticModel::StaticModel() { +} + +void StaticModel::setURL(const QUrl& url) { + if (_url != url) { + emit urlChanged(_url = url); + } +} + +QByteArray StaticModel::getRendererClassName() const { + return "StaticModelRenderer"; +} diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index a0249216f6..b06825ca70 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -28,6 +28,7 @@ class MetavoxelNode; class MetavoxelVisitation; class MetavoxelVisitor; class NetworkValue; +class SpannerRenderer; /// The base metavoxel representation shared between server and client. class MetavoxelData { @@ -249,11 +250,11 @@ public: /// An object that spans multiple octree cells. class Spanner : public SharedObject { Q_OBJECT - Q_PROPERTY(Box bounds MEMBER _bounds WRITE setBounds NOTIFY boundsChanged) + Q_PROPERTY(Box bounds MEMBER _bounds WRITE setBounds NOTIFY boundsChanged DESIGNABLE false) public: - Q_INVOKABLE Spanner(); + Spanner(); void setBounds(const Box& bounds); const Box& getBounds() const { return _bounds; } @@ -262,15 +263,95 @@ public: /// If we haven't, sets the last visit identifier and returns true. bool testAndSetVisited(int visit); + /// Returns a pointer to the renderer, creating it if necessary. + SpannerRenderer* getRenderer(); + signals: void boundsWillChange(); void boundsChanged(const Box& bounds); +protected: + + /// Returns the name of the class to instantiate in order to render this spanner. + virtual QByteArray getRendererClassName() const; + private: Box _bounds; int _lastVisit; ///< the identifier of the last visit + SpannerRenderer* _renderer; +}; + +/// Base class for objects that can render spanners. +class SpannerRenderer : public QObject { + Q_OBJECT + +public: + + Q_INVOKABLE SpannerRenderer(); + + virtual void init(Spanner* spanner); + virtual void simulate(float deltaTime); + virtual void render(float alpha); +}; + +/// An object with a 3D transform. +class Transformable : public Spanner { + Q_OBJECT + Q_PROPERTY(glm::vec3 translation MEMBER _translation WRITE setTranslation NOTIFY translationChanged) + Q_PROPERTY(glm::vec3 rotation MEMBER _rotation WRITE setRotation NOTIFY rotationChanged) + Q_PROPERTY(float scale MEMBER _scale WRITE setScale NOTIFY scaleChanged) + +public: + + Transformable(); + + void setTranslation(const glm::vec3& translation); + const glm::vec3& getTranslation() const { return _translation; } + + void setRotation(const glm::vec3& rotation); + const glm::vec3& getRotation() const { return _rotation; } + + void setScale(float scale); + float getScale() const { return _scale; } + +signals: + + void translationChanged(const glm::vec3& translation); + void rotationChanged(const glm::vec3& rotation); + void scaleChanged(float scale); + +private: + + glm::vec3 _translation; + glm::vec3 _rotation; + float _scale; +}; + +/// A static 3D model loaded from the network. +class StaticModel : public Transformable { + Q_OBJECT + Q_PROPERTY(QUrl url MEMBER _url WRITE setURL NOTIFY urlChanged) + +public: + + Q_INVOKABLE StaticModel(); + + void setURL(const QUrl& url); + const QUrl& getURL() const { return _url; } + +signals: + + void urlChanged(const QUrl& url); + +protected: + + virtual QByteArray getRendererClassName() const; + +private: + + QUrl _url; }; #endif /* defined(__interface__MetavoxelData__) */ diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index 37f7be54c7..7482d0efb6 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -93,6 +93,7 @@ SharedObjectEditor::SharedObjectEditor(const QMetaObject* metaObject, bool nulla } } connect(_type, SIGNAL(currentIndexChanged(int)), SLOT(updateType())); + updateType(); } void SharedObjectEditor::setObject(const SharedObjectPointer& object) { @@ -142,6 +143,9 @@ void SharedObjectEditor::updateType() { static_cast(layout())->addLayout(form); for (int i = QObject::staticMetaObject.propertyCount(); i < metaObject->propertyCount(); i++) { QMetaProperty property = metaObject->property(i); + if (!property.isDesignable()) { + continue; + } if (oldMetaObject && i < oldMetaObject->propertyCount() && getOwningAncestor(metaObject, i) == getOwningAncestor(oldMetaObject, i)) { // copy the state of the shared ancestry From 55e2ebd92f60de93a647d2c55026a063c4587f4c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Feb 2014 13:58:44 -0800 Subject: [PATCH 10/18] More spanner bits. --- interface/src/Menu.cpp | 1 + interface/src/renderer/Model.cpp | 4 +- interface/src/ui/MetavoxelEditor.cpp | 19 ++++++-- interface/src/ui/MetavoxelEditor.h | 4 +- libraries/metavoxels/src/MetavoxelUtil.cpp | 51 +++++++++++++++++++--- libraries/metavoxels/src/MetavoxelUtil.h | 31 +++++++++++-- libraries/metavoxels/src/SharedObject.cpp | 25 ++++++++++- libraries/metavoxels/src/SharedObject.h | 1 + 8 files changed, 117 insertions(+), 19 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c61b4cbdaf..a836d462c1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1088,6 +1088,7 @@ void Menu::showMetavoxelEditor() { _MetavoxelEditor = new MetavoxelEditor(); } _MetavoxelEditor->raise(); + _MetavoxelEditor->activateWindow(); } void Menu::audioMuteToggled() { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 48e1d0f70c..d8188dab63 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -276,7 +276,7 @@ bool Model::render(float alpha) { // render opaque meshes with alpha testing glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.5f); + glAlphaFunc(GL_GREATER, 0.5f * alpha); renderMeshes(alpha, false); @@ -916,7 +916,7 @@ void Model::renderMeshes(float alpha, bool translucent) { if (!mesh.colors.isEmpty()) { glEnableClientState(GL_COLOR_ARRAY); } else { - glColor3f(1.0f, 1.0f, 1.0f); + glColor4f(1.0f, 1.0f, 1.0f, alpha); } if (!mesh.texCoords.isEmpty()) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 003d283795..3b3333e267 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -29,7 +29,7 @@ enum GridPlane { const glm::vec2 INVALID_VECTOR(FLT_MAX, FLT_MAX); MetavoxelEditor::MetavoxelEditor() : - QDialog(Application::getInstance()->getGLWidget()) { + QWidget(Application::getInstance()->getGLWidget(), Qt::Tool | Qt::WindowStaysOnTopHint) { setWindowTitle("Metavoxel Editor"); setAttribute(Qt::WA_DeleteOnClose); @@ -519,9 +519,20 @@ void InsertSpannerTool::simulate(float deltaTime) { } void InsertSpannerTool::render() { - SharedObjectPointer spanner = _editor->getValue().value(); - const float SPANNER_ALPHA = 1.0f; - static_cast(spanner.data())->getRenderer()->render(SPANNER_ALPHA); + Spanner* spanner = static_cast(_editor->getValue().value().data()); + Transformable* transformable = qobject_cast(spanner); + if (transformable) { + // find the intersection of the mouse ray with the grid and place the transformable there + glm::quat rotation = _editor->getGridRotation(); + glm::quat inverseRotation = glm::inverse(rotation); + glm::vec3 rayOrigin = inverseRotation * Application::getInstance()->getMouseRayOrigin(); + glm::vec3 rayDirection = inverseRotation * Application::getInstance()->getMouseRayDirection(); + float position = _editor->getGridPosition(); + float distance = (position - rayOrigin.z) / rayDirection.z; + transformable->setTranslation(rotation * glm::vec3(glm::vec2(rayOrigin + rayDirection * distance), position)); + } + const float SPANNER_ALPHA = 0.25f; + spanner->getRenderer()->render(SPANNER_ALPHA); } bool InsertSpannerTool::appliesTo(const AttributePointer& attribute) const { diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index a688a01cec..1709d07497 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -9,8 +9,8 @@ #ifndef __interface__MetavoxelEditor__ #define __interface__MetavoxelEditor__ -#include #include +#include #include "renderer/ProgramObject.h" @@ -24,7 +24,7 @@ class QScrollArea; class MetavoxelTool; /// Allows editing metavoxels. -class MetavoxelEditor : public QDialog { +class MetavoxelEditor : public QWidget { Q_OBJECT public: diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index f7c2a92b75..22c17abf12 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -18,6 +17,7 @@ #include #include #include +#include #include #include @@ -54,6 +54,7 @@ public: DoubleEditor::DoubleEditor(QWidget* parent) : QDoubleSpinBox(parent) { setMinimum(-FLT_MAX); + setMaximum(FLT_MAX); } DelegatingItemEditorFactory::DelegatingItemEditorFactory() : @@ -117,6 +118,12 @@ static QItemEditorCreatorBase* createQColorEditorCreator() { return creator; } +static QItemEditorCreatorBase* createQUrlEditorCreator() { + QItemEditorCreatorBase* creator = new LazyItemEditorCreator(); + getItemEditorFactory()->registerEditor(qMetaTypeId(), creator); + return creator; +} + static QItemEditorCreatorBase* createVec3EditorCreator() { QItemEditorCreatorBase* creator = new LazyItemEditorCreator(); getItemEditorFactory()->registerEditor(qMetaTypeId(), creator); @@ -132,6 +139,7 @@ static QItemEditorCreatorBase* createParameterizedURLEditorCreator() { static QItemEditorCreatorBase* doubleEditorCreator = createDoubleEditorCreator(); static QItemEditorCreatorBase* qMetaObjectEditorCreator = createQMetaObjectEditorCreator(); static QItemEditorCreatorBase* qColorEditorCreator = createQColorEditorCreator(); +static QItemEditorCreatorBase* qUrlEditorCreator = createQUrlEditorCreator(); static QItemEditorCreatorBase* vec3EditorCreator = createVec3EditorCreator(); static QItemEditorCreatorBase* parameterizedURLEditorCreator = createParameterizedURLEditorCreator(); @@ -211,6 +219,36 @@ void QColorEditor::selectColor() { } } +QUrlEditor::QUrlEditor(QWidget* parent) : + QComboBox(parent) { + + setEditable(true); + setInsertPolicy(InsertAtTop); + + // populate initial URL list from settings + addItems(QSettings().value("editorURLs").toStringList()); + + connect(this, SIGNAL(activated(const QString&)), SLOT(updateURL(const QString&))); + connect(model(), SIGNAL(rowsInserted(const QModelIndex&,int,int)), SLOT(updateSettings())); +} + +void QUrlEditor::setURL(const QUrl& url) { + setCurrentText((_url = url).toString()); +} + +void QUrlEditor::updateURL(const QString& text) { + emit urlChanged(_url = text); +} + +void QUrlEditor::updateSettings() { + QStringList urls; + const int MAX_STORED_URLS = 10; + for (int i = 0, size = qMin(MAX_STORED_URLS, count()); i < size; i++) { + urls.append(itemText(i)); + } + QSettings().setValue("editorURLs", urls); +} + Vec3Editor::Vec3Editor(QWidget* parent) : QWidget(parent) { QHBoxLayout* layout = new QHBoxLayout(); layout->setContentsMargins(QMargins()); @@ -235,6 +273,7 @@ void Vec3Editor::updateVector() { QDoubleSpinBox* Vec3Editor::createComponentBox() { QDoubleSpinBox* box = new QDoubleSpinBox(); box->setMinimum(-FLT_MAX); + box->setMaximum(FLT_MAX); box->setMaximumWidth(100); connect(box, SIGNAL(valueChanged(double)), SLOT(updateVector())); return box; @@ -287,8 +326,9 @@ ParameterizedURLEditor::ParameterizedURLEditor(QWidget* parent) : lineContainer->setLayout(lineLayout); lineLayout->setContentsMargins(QMargins()); - lineLayout->addWidget(_line = new QLineEdit(), 1); - connect(_line, SIGNAL(textChanged(const QString&)), SLOT(updateURL())); + lineLayout->addWidget(&_urlEditor, 1); + connect(&_urlEditor, SIGNAL(urlChanged(const QUrl&)), SLOT(updateURL())); + connect(&_urlEditor, SIGNAL(urlChanged(const QUrl&)), SLOT(updateParameters())); QPushButton* refresh = new QPushButton("..."); connect(refresh, SIGNAL(clicked(bool)), SLOT(updateParameters())); @@ -296,8 +336,7 @@ ParameterizedURLEditor::ParameterizedURLEditor(QWidget* parent) : } void ParameterizedURLEditor::setURL(const ParameterizedURL& url) { - _url = url; - _line->setText(url.getURL().toString()); + _urlEditor.setURL((_url = url).getURL()); updateParameters(); } @@ -314,7 +353,7 @@ void ParameterizedURLEditor::updateURL() { widget->property("parameterName").toString()), widgetProperty.read(widget)); } } - emit urlChanged(_url = ParameterizedURL(_line->text(), parameters)); + emit urlChanged(_url = ParameterizedURL(_urlEditor.getURL(), parameters)); if (_program) { _program->disconnect(this); } diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 37a6c8bcda..19fd41e826 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -10,6 +10,7 @@ #define __interface__MetavoxelUtil__ #include +#include #include #include #include @@ -21,9 +22,7 @@ #include "Bitstream.h" class QByteArray; -class QComboBox; class QDoubleSpinBox; -class QLineEdit; class QPushButton; class HifiSockAddr; @@ -107,6 +106,32 @@ private: QColor _color; }; +/// Editor for URL values. +class QUrlEditor : public QComboBox { + Q_OBJECT + Q_PROPERTY(QUrl url READ getURL WRITE setURL NOTIFY urlChanged USER true) + +public: + + QUrlEditor(QWidget* parent = NULL); + + void setURL(const QUrl& url); + const QUrl& getURL() { return _url; } + +signals: + + void urlChanged(const QUrl& url); + +private slots: + + void updateURL(const QString& text); + void updateSettings(); + +private: + + QUrl _url; +}; + /// Editor for vector values. class Vec3Editor : public QWidget { Q_OBJECT @@ -200,7 +225,7 @@ private: ParameterizedURL _url; QSharedPointer _program; - QLineEdit* _line; + QUrlEditor _urlEditor; }; #endif /* defined(__interface__MetavoxelUtil__) */ diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index 7482d0efb6..2393785702 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -130,13 +130,17 @@ void SharedObjectEditor::updateType() { } delete form; } + QObject* oldObject = static_cast(_object.data()); + const QMetaObject* oldMetaObject = NULL; + if (oldObject) { + oldMetaObject = oldObject->metaObject(); + oldObject->disconnect(this); + } const QMetaObject* metaObject = _type->itemData(_type->currentIndex()).value(); if (metaObject == NULL) { _object.reset(); return; } - QObject* oldObject = static_cast(_object.data()); - const QMetaObject* oldMetaObject = oldObject ? oldObject->metaObject() : NULL; QObject* newObject = metaObject->newInstance(); QFormLayout* form = new QFormLayout(); @@ -162,6 +166,10 @@ void SharedObjectEditor::updateType() { if (widgetProperty.hasNotifySignal()) { connect(widget, signal(widgetProperty.notifySignal().methodSignature()), SLOT(propertyChanged())); } + if (property.hasNotifySignal()) { + widget->setProperty("notifySignalIndex", property.notifySignalIndex()); + connect(newObject, signal(property.notifySignal().methodSignature()), SLOT(updateProperty())); + } } } _object = static_cast(newObject); @@ -181,3 +189,16 @@ void SharedObjectEditor::propertyChanged() { property.write(object, widget->property(valuePropertyName)); } } + +void SharedObjectEditor::updateProperty() { + QFormLayout* form = static_cast(layout()->itemAt(1)); + for (int i = 0; i < form->rowCount(); i++) { + QWidget* widget = form->itemAt(i, QFormLayout::FieldRole)->widget(); + if (widget->property("notifySignalIndex").toInt() != senderSignalIndex()) { + continue; + } + QMetaProperty property = _object->metaObject()->property(widget->property("propertyIndex").toInt()); + QByteArray valuePropertyName = QItemEditorFactory::defaultFactory()->valuePropertyName(property.userType()); + widget->setProperty(valuePropertyName, property.read(_object.data())); + } +} diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 5a33b64e3d..008ea02e4b 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -168,6 +168,7 @@ private slots: void updateType(); void propertyChanged(); + void updateProperty(); private: From 0138ecb3b2c7538a15142cb26f197bed1764be1e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 19 Feb 2014 11:35:45 -0800 Subject: [PATCH 11/18] Layout tweaks. --- interface/src/ui/MetavoxelEditor.cpp | 10 ++++++++++ interface/src/ui/MetavoxelEditor.h | 2 ++ libraries/metavoxels/src/MetavoxelUtil.cpp | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 3b3333e267..5c099e3e41 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -92,6 +92,7 @@ MetavoxelEditor::MetavoxelEditor() : _value->setLayout(valueLayout); valueLayout->addWidget(_valueArea = new QScrollArea()); + _valueArea->setMinimumHeight(200); _valueArea->setWidgetResizable(true); addTool(new BoxSetTool(this)); @@ -181,6 +182,7 @@ void MetavoxelEditor::selectedAttributeChanged() { } QWidget* editor = attribute->createEditor(); if (editor) { + editor->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); _valueArea->setWidget(editor); } } @@ -539,6 +541,14 @@ bool InsertSpannerTool::appliesTo(const AttributePointer& attribute) const { return attribute->inherits("SharedObjectSetAttribute"); } +bool InsertSpannerTool::eventFilter(QObject* watched, QEvent* event) { + if (event->type() == QEvent::MouseButtonPress) { + insert(); + return true; + } + return false; +} + void InsertSpannerTool::insert() { AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute()); if (!attribute) { diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 1709d07497..e213be8d2c 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -152,6 +152,8 @@ public: virtual bool appliesTo(const AttributePointer& attribute) const; + virtual bool eventFilter(QObject* watched, QEvent* event); + private slots: void insert(); diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index 22c17abf12..16f561638b 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -274,7 +274,7 @@ QDoubleSpinBox* Vec3Editor::createComponentBox() { QDoubleSpinBox* box = new QDoubleSpinBox(); box->setMinimum(-FLT_MAX); box->setMaximum(FLT_MAX); - box->setMaximumWidth(100); + box->setMinimumWidth(50); connect(box, SIGNAL(valueChanged(double)), SLOT(updateVector())); return box; } From 25ae81e2deff52e8e18653b3abf94ba5dd37fca1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 19 Feb 2014 15:25:21 -0800 Subject: [PATCH 12/18] More work on spanners. --- interface/src/ui/MetavoxelEditor.cpp | 30 +++++++++++++++++++ interface/src/ui/MetavoxelEditor.h | 17 +++++++++++ libraries/metavoxels/src/MetavoxelData.cpp | 17 +++++++++++ libraries/metavoxels/src/MetavoxelData.h | 4 +++ .../metavoxels/src/MetavoxelMessages.cpp | 8 +++++ libraries/metavoxels/src/MetavoxelMessages.h | 17 ++++++++++- libraries/metavoxels/src/MetavoxelUtil.cpp | 23 ++++---------- libraries/metavoxels/src/MetavoxelUtil.h | 12 +++----- 8 files changed, 102 insertions(+), 26 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 5c099e3e41..87510e9347 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -99,6 +99,7 @@ MetavoxelEditor::MetavoxelEditor() : addTool(new GlobalSetTool(this)); addTool(new InsertSpannerTool(this)); addTool(new RemoveSpannerTool(this)); + addTool(new ClearSpannersTool(this)); updateAttributes(); @@ -566,3 +567,32 @@ RemoveSpannerTool::RemoveSpannerTool(MetavoxelEditor* editor) : bool RemoveSpannerTool::appliesTo(const AttributePointer& attribute) const { return attribute->inherits("SharedObjectSetAttribute"); } + +bool RemoveSpannerTool::eventFilter(QObject* watched, QEvent* event) { + if (event->type() == QEvent::MouseButtonPress) { + + return true; + } + return false; +} + +ClearSpannersTool::ClearSpannersTool(MetavoxelEditor* editor) : + MetavoxelTool(editor, "Clear Spanners", false) { + + QPushButton* button = new QPushButton("Clear"); + layout()->addWidget(button); + connect(button, SIGNAL(clicked()), SLOT(clear())); +} + +bool ClearSpannersTool::appliesTo(const AttributePointer& attribute) const { + return attribute->inherits("SharedObjectSetAttribute"); +} + +void ClearSpannersTool::clear() { + AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute()); + if (!attribute) { + return; + } + MetavoxelEditMessage message = { QVariant::fromValue(ClearSpannersEdit(attribute)) }; + Application::getInstance()->getMetavoxels()->applyEdit(message); +} diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index e213be8d2c..1bccfae9f5 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -168,6 +168,23 @@ public: RemoveSpannerTool(MetavoxelEditor* editor); virtual bool appliesTo(const AttributePointer& attribute) const; + + virtual bool eventFilter(QObject* watched, QEvent* event); +}; + +/// Allows removing all spanners from the scene. +class ClearSpannersTool : public MetavoxelTool { + Q_OBJECT + +public: + + ClearSpannersTool(MetavoxelEditor* editor); + + virtual bool appliesTo(const AttributePointer& attribute) const; + +private slots: + + void clear(); }; #endif /* defined(__interface__MetavoxelEditor__) */ diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index c8c3dbf577..dbe5b3a21d 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -100,6 +100,7 @@ private: const AttributePointer& _attribute; const Box& _bounds; + float _longestSide; const SharedObjectPointer& _object; }; @@ -107,14 +108,27 @@ InsertVisitor::InsertVisitor(const AttributePointer& attribute, const Box& bound MetavoxelVisitor(QVector() << attribute, QVector() << attribute), _attribute(attribute), _bounds(bounds), + _longestSide(bounds.getLongestSide()), _object(object) { } bool InsertVisitor::visit(MetavoxelInfo& info) { + Box bounds = info.getBounds(); + if (!bounds.intersects(_bounds)) { + return false; + } + if (info.size > _longestSide) { + return true; + } + info.outputValues[0] = AttributeValue(_attribute); return false; } void MetavoxelData::insert(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object) { + // expand to fit the entire bounds + while (!getBounds().contains(bounds)) { + expand(); + } InsertVisitor visitor(attribute, bounds, object); guide(visitor); } @@ -122,6 +136,9 @@ void MetavoxelData::insert(const AttributePointer& attribute, const Box& bounds, void MetavoxelData::remove(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object) { } +void MetavoxelData::clear(const AttributePointer& attribute) { +} + const int X_MAXIMUM_FLAG = 1; const int Y_MAXIMUM_FLAG = 2; const int Z_MAXIMUM_FLAG = 4; diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index b06825ca70..3b6637d2f9 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -51,6 +51,8 @@ public: void remove(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object); + void clear(const AttributePointer& attribute); + /// Expands the tree, increasing its capacity in all dimensions. void expand(); @@ -128,6 +130,8 @@ public: QVector inputValues; QVector outputValues; bool isLeaf; + + Box getBounds() const { return Box(minimum, minimum + glm::vec3(size, size, size)); } }; /// Interface for visitors to metavoxels. diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 56336ffa16..3b41a2e891 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -116,3 +116,11 @@ RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) void RemoveSpannerEdit::apply(MetavoxelData& data) const { } + +ClearSpannersEdit::ClearSpannersEdit(const AttributePointer& attribute) : + attribute(attribute) { +} + +void ClearSpannersEdit::apply(MetavoxelData& data) const { + data.clear(attribute); +} diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 65bee27d7d..d6f07c2966 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -133,7 +133,7 @@ public: DECLARE_STREAMABLE_METATYPE(InsertSpannerEdit) -/// An edit that removes a a spanner from the tree. +/// An edit that removes a spanner from the tree. class RemoveSpannerEdit : public MetavoxelEdit { STREAMABLE @@ -149,4 +149,19 @@ public: DECLARE_STREAMABLE_METATYPE(RemoveSpannerEdit) +/// An edit that clears all spanners from the tree. +class ClearSpannersEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM AttributePointer attribute; + + ClearSpannersEdit(const AttributePointer& attribute = AttributePointer()); + + virtual void apply(MetavoxelData& data) const; +}; + +DECLARE_STREAMABLE_METATYPE(ClearSpannersEdit) + #endif /* defined(__interface__MetavoxelMessages__) */ diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index 16f561638b..2e93fb1804 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -21,9 +21,6 @@ #include #include -#include -#include - #include "MetavoxelUtil.h" #include "ScriptCache.h" @@ -143,20 +140,6 @@ static QItemEditorCreatorBase* qUrlEditorCreator = createQUrlEditorCreator(); static QItemEditorCreatorBase* vec3EditorCreator = createVec3EditorCreator(); static QItemEditorCreatorBase* parameterizedURLEditorCreator = createParameterizedURLEditorCreator(); -QUuid readSessionID(const QByteArray& data, const SharedNodePointer& sendingNode, int& headerPlusIDSize) { - // get the header size - int headerSize = numBytesForPacketHeader(data); - - // read the session id - const int UUID_BYTES = 16; - headerPlusIDSize = headerSize + UUID_BYTES; - if (data.size() < headerPlusIDSize) { - qWarning() << "Metavoxel data too short [size=" << data.size() << ", sendingNode=" << sendingNode << "]\n"; - return QUuid(); - } - return QUuid::fromRfc4122(QByteArray::fromRawData(data.constData() + headerSize, UUID_BYTES)); -} - QByteArray signal(const char* signature) { static QByteArray prototype = SIGNAL(dummyMethod()); QByteArray signal = prototype; @@ -173,6 +156,12 @@ bool Box::contains(const Box& other) const { other.minimum.z >= minimum.z && other.maximum.z <= maximum.z; } +bool Box::intersects(const Box& other) const { + return other.maximum.x >= minimum.x && other.minimum.x <= maximum.x && + other.maximum.y >= minimum.y && other.minimum.y <= maximum.y && + other.maximum.z >= minimum.z && other.minimum.z <= maximum.z; +} + QMetaObjectEditor::QMetaObjectEditor(QWidget* parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(); layout->setContentsMargins(QMargins()); diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 19fd41e826..4b3fb43523 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -13,10 +13,8 @@ #include #include #include -#include #include -#include #include #include "Bitstream.h" @@ -25,14 +23,8 @@ class QByteArray; class QDoubleSpinBox; class QPushButton; -class HifiSockAddr; class NetworkProgram; -/// Reads and returns the session ID from a datagram. -/// \param[out] headerPlusIDSize the size of the header (including the session ID) within the data -/// \return the session ID, or a null ID if invalid (in which case a warning will be logged) -QUuid readSessionID(const QByteArray& data, const SharedNodePointer& sendingNode, int& headerPlusIDSize); - /// Performs the runtime equivalent of Qt's SIGNAL macro, which is to attach a prefix to the signature. QByteArray signal(const char* signature); @@ -48,6 +40,10 @@ public: Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3()); bool contains(const Box& other) const; + + bool intersects(const Box& other) const; + + float getLongestSide() const { return qMax(qMax(maximum.x - minimum.x, maximum.y - minimum.y), maximum.z - minimum.z); } }; DECLARE_STREAMABLE_METATYPE(Box) From f017d0472fa89528a0c9d7870b89f9375957d448 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 19 Feb 2014 18:17:26 -0800 Subject: [PATCH 13/18] More work on spanners. --- interface/src/MetavoxelSystem.h | 2 + .../metavoxels/src/AttributeRegistry.cpp | 8 ++ libraries/metavoxels/src/AttributeRegistry.h | 3 + libraries/metavoxels/src/MetavoxelData.cpp | 82 +++++++++++++++---- libraries/metavoxels/src/MetavoxelData.h | 11 ++- .../metavoxels/src/MetavoxelMessages.cpp | 3 +- 6 files changed, 89 insertions(+), 20 deletions(-) diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 7cc8c114fd..30ffd308df 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -83,6 +83,8 @@ public: void simulate(float deltaTime, MetavoxelVisitor& visitor); + void render(); + virtual int parseData(const QByteArray& packet); private slots: diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 22a629dd1a..bd83987666 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -235,6 +235,14 @@ SharedObjectSetAttribute::SharedObjectSetAttribute(const QString& name, const QM _metaObject(metaObject) { } +void SharedObjectSetAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { + in >> *((SharedObjectSet*)&value); +} + +void SharedObjectSetAttribute::write(Bitstream& out, void* value, bool isLeaf) const { + out << decodeInline(value); +} + bool SharedObjectSetAttribute::merge(void*& parent, void* children[]) const { for (int i = 0; i < MERGE_COUNT; i++) { if (!decodeInline(children[i]).isEmpty()) { diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 1bcadf7f6c..2e029f8201 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -297,6 +297,9 @@ public: const QMetaObject* getMetaObject() const { return _metaObject; } + virtual void read(Bitstream& in, void*& value, bool isLeaf) const; + virtual void write(Bitstream& out, void* value, bool isLeaf) const; + virtual bool merge(void*& parent, void* children[]) const; virtual QWidget* createEditor(QWidget* parent = NULL) const; diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index dbe5b3a21d..ab7309101b 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -54,7 +54,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { const QVector& outputs = visitor.getOutputs(); MetavoxelVisitation firstVisitation = { NULL, visitor, QVector(inputs.size() + 1), QVector(outputs.size()), { glm::vec3(_size, _size, _size) * -0.5f, _size, - QVector(inputs.size() + 1), QVector(outputs.size()) } }; + QVector(inputs.size() + 1), QVector(outputs.size()) } }; for (int i = 0; i < inputs.size(); i++) { MetavoxelNode* node = _roots.value(inputs.at(i)); firstVisitation.inputNodes[i] = node; @@ -71,7 +71,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { static_cast(firstVisitation.info.inputValues.last().getInlineValue< SharedObjectPointer>().data())->guide(firstVisitation); for (int i = 0; i < outputs.size(); i++) { - AttributeValue& value = firstVisitation.info.outputValues[i]; + OwnedAttributeValue& value = firstVisitation.info.outputValues[i]; if (!value.getAttribute()) { continue; } @@ -92,7 +92,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) { class InsertVisitor : public MetavoxelVisitor { public: - InsertVisitor(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object); + InsertVisitor(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); virtual bool visit(MetavoxelInfo& info); @@ -104,39 +104,86 @@ private: const SharedObjectPointer& _object; }; -InsertVisitor::InsertVisitor(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object) : +InsertVisitor::InsertVisitor(const AttributePointer& attribute, const Box& bounds, + float granularity, const SharedObjectPointer& object) : MetavoxelVisitor(QVector() << attribute, QVector() << attribute), _attribute(attribute), _bounds(bounds), - _longestSide(bounds.getLongestSide()), + _longestSide(qMax(bounds.getLongestSide(), granularity)), _object(object) { } bool InsertVisitor::visit(MetavoxelInfo& info) { - Box bounds = info.getBounds(); - if (!bounds.intersects(_bounds)) { + if (!info.getBounds().intersects(_bounds)) { return false; } if (info.size > _longestSide) { return true; } - info.outputValues[0] = AttributeValue(_attribute); + SharedObjectSet set = info.inputValues.at(0).getInlineValue(); + set.insert(_object); + info.outputValues[0] = AttributeValue(_attribute, encodeInline(set)); return false; } -void MetavoxelData::insert(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object) { +void MetavoxelData::insert(const AttributePointer& attribute, const Box& bounds, + float granularity, const SharedObjectPointer& object) { // expand to fit the entire bounds while (!getBounds().contains(bounds)) { expand(); } - InsertVisitor visitor(attribute, bounds, object); + InsertVisitor visitor(attribute, bounds, granularity, object); guide(visitor); } -void MetavoxelData::remove(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object) { +class RemoveVisitor : public MetavoxelVisitor { +public: + + RemoveVisitor(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); + + virtual bool visit(MetavoxelInfo& info); + +private: + + const AttributePointer& _attribute; + const Box& _bounds; + float _longestSide; + const SharedObjectPointer& _object; +}; + +RemoveVisitor::RemoveVisitor(const AttributePointer& attribute, const Box& bounds, + float granularity, const SharedObjectPointer& object) : + MetavoxelVisitor(QVector() << attribute, QVector() << 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(); + set.remove(_object); + info.outputValues[0] = AttributeValue(_attribute, encodeInline(set)); + return false; +} + +void MetavoxelData::remove(const AttributePointer& attribute, const Box& bounds, + float granularity, const SharedObjectPointer& object) { + RemoveVisitor visitor(attribute, bounds, granularity, object); + guide(visitor); } void MetavoxelData::clear(const AttributePointer& attribute) { + MetavoxelNode* node = _roots.take(attribute); + if (node) { + node->decrementReferenceCount(attribute); + } } const int X_MAXIMUM_FLAG = 1; @@ -490,7 +537,7 @@ 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++) { - AttributeValue& value = visitation.info.outputValues[i]; + OwnedAttributeValue& value = visitation.info.outputValues[i]; if (!value.getAttribute()) { continue; } @@ -508,7 +555,7 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { MetavoxelVisitation nextVisitation = { &visitation, visitation.visitor, QVector(visitation.inputNodes.size()), QVector(visitation.outputNodes.size()), { glm::vec3(), visitation.info.size * 0.5f, QVector(visitation.inputNodes.size()), - QVector(visitation.outputNodes.size()) } }; + QVector(visitation.outputNodes.size()) } }; for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { for (int j = 0; j < visitation.inputNodes.size(); j++) { MetavoxelNode* node = visitation.inputNodes.at(j); @@ -529,12 +576,12 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { static_cast(nextVisitation.info.inputValues.last().getInlineValue< SharedObjectPointer>().data())->guide(nextVisitation); for (int j = 0; j < nextVisitation.outputNodes.size(); j++) { - AttributeValue& value = nextVisitation.info.outputValues[j]; + OwnedAttributeValue& value = nextVisitation.info.outputValues[j]; if (!value.getAttribute()) { continue; } // replace the child - AttributeValue& parentValue = visitation.info.outputValues[j]; + OwnedAttributeValue& parentValue = visitation.info.outputValues[j]; if (!parentValue.getAttribute()) { // shallow-copy the parent node on first change parentValue = value; @@ -562,7 +609,7 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { } } for (int i = 0; i < visitation.outputNodes.size(); i++) { - AttributeValue& value = visitation.info.outputValues[i]; + OwnedAttributeValue& value = visitation.info.outputValues[i]; if (value.getAttribute()) { MetavoxelNode* node = visitation.outputNodes.at(i); node->mergeChildren(value.getAttribute()); @@ -725,7 +772,10 @@ AttributeValue MetavoxelVisitation::getInheritedOutputValue(int index) const { return AttributeValue(visitor.getOutputs().at(index)); } +const float DEFAULT_GRANULARITY = 0.01f; + Spanner::Spanner() : + _granularity(DEFAULT_GRANULARITY), _lastVisit(0), _renderer(NULL) { } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 3b6637d2f9..9443e71882 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -47,9 +47,9 @@ public: /// Applies the specified visitor to the contained voxels. void guide(MetavoxelVisitor& visitor); - void insert(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object); + void insert(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); - void remove(const AttributePointer& attribute, const Box& bounds, const SharedObjectPointer& object); + void remove(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); void clear(const AttributePointer& attribute); @@ -128,7 +128,7 @@ public: glm::vec3 minimum; ///< the minimum extent of the area covered by the voxel float size; ///< the size of the voxel in all dimensions QVector inputValues; - QVector outputValues; + QVector outputValues; bool isLeaf; Box getBounds() const { return Box(minimum, minimum + glm::vec3(size, size, size)); } @@ -255,6 +255,7 @@ public: class Spanner : public SharedObject { Q_OBJECT Q_PROPERTY(Box bounds MEMBER _bounds WRITE setBounds NOTIFY boundsChanged DESIGNABLE false) + Q_PROPERTY(float granularity MEMBER _granularity DESIGNABLE false) public: @@ -263,6 +264,9 @@ public: void setBounds(const Box& bounds); const Box& getBounds() const { return _bounds; } + void setGranularity(float granularity) { _granularity = granularity; } + float getGranularity() const { return _granularity; } + /// Checks whether we've visited this object on the current traversal. If we have, returns false. /// If we haven't, sets the last visit identifier and returns true. bool testAndSetVisited(int visit); @@ -283,6 +287,7 @@ protected: private: Box _bounds; + float _granularity; int _lastVisit; ///< the identifier of the last visit SpannerRenderer* _renderer; }; diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 3b41a2e891..c66ce61ee9 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -106,7 +106,8 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh } void InsertSpannerEdit::apply(MetavoxelData& data) const { - data.insert(attribute, static_cast(spanner.data())->getBounds(), spanner); + Spanner* spanner = static_cast(this->spanner.data()); + data.insert(attribute, spanner->getBounds(), spanner->getGranularity(), this->spanner); } RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) : From b408e31d91e8c72c7488ed78e960e5c7e4bd3ae8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 20 Feb 2014 17:18:15 -0800 Subject: [PATCH 14/18] More work on spanners. --- interface/src/MetavoxelSystem.cpp | 1 - interface/src/ui/MetavoxelEditor.cpp | 9 ++++ interface/src/ui/MetavoxelEditor.h | 1 + libraries/metavoxels/src/Bitstream.cpp | 55 ++++++++++++++++------ libraries/metavoxels/src/Bitstream.h | 5 ++ libraries/metavoxels/src/MetavoxelData.cpp | 11 +---- libraries/metavoxels/src/MetavoxelData.h | 4 -- libraries/metavoxels/src/SharedObject.cpp | 30 +++++++++++- libraries/metavoxels/src/SharedObject.h | 19 +++++++- 9 files changed, 101 insertions(+), 34 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 7365c99f0a..0421ca4747 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -218,7 +218,6 @@ int MetavoxelClient::parseData(const QByteArray& packet) { } void MetavoxelClient::sendData(const QByteArray& data) { - QMutexLocker locker(&_node->getMutex()); NodeList::getInstance()->writeDatagram(data, _node); } diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 87510e9347..832c6b5d39 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -151,6 +151,13 @@ QVariant MetavoxelEditor::getValue() const { return editor ? editor->metaObject()->userProperty().read(editor) : QVariant(); } +void MetavoxelEditor::detachValue() { + SharedObjectEditor* editor = qobject_cast(_valueArea->widget()); + if (editor) { + editor->detachObject(); + } +} + bool MetavoxelEditor::eventFilter(QObject* watched, QEvent* event) { // pass along to the active tool MetavoxelTool* tool = getActiveTool(); @@ -522,6 +529,7 @@ void InsertSpannerTool::simulate(float deltaTime) { } void InsertSpannerTool::render() { + _editor->detachValue(); Spanner* spanner = static_cast(_editor->getValue().value().data()); Transformable* transformable = qobject_cast(spanner); if (transformable) { @@ -532,6 +540,7 @@ void InsertSpannerTool::render() { glm::vec3 rayDirection = inverseRotation * Application::getInstance()->getMouseRayDirection(); float position = _editor->getGridPosition(); float distance = (position - rayOrigin.z) / rayDirection.z; + transformable->setTranslation(rotation * glm::vec3(glm::vec2(rayOrigin + rayDirection * distance), position)); } const float SPANNER_ALPHA = 0.25f; diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 1bccfae9f5..5b580129a9 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -38,6 +38,7 @@ public: glm::quat getGridRotation() const; QVariant getValue() const; + void detachValue(); virtual bool eventFilter(QObject* watched, QEvent* event); diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index bf2cdd1e96..919bc4cbc8 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -355,17 +355,7 @@ Bitstream& Bitstream::operator>>(QObject*& object) { object = NULL; return *this; } - object = metaObject->newInstance(); - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored(object)) { - continue; - } - const TypeStreamer* streamer = getTypeStreamers().value(property.userType()); - if (streamer) { - property.write(object, streamer->read(*this)); - } - } + readProperties(object = metaObject->newInstance()); return *this; } @@ -476,13 +466,34 @@ Bitstream& Bitstream::operator>(QScriptString& string) { } Bitstream& Bitstream::operator<(const SharedObjectPointer& object) { - return *this << object.data(); + if (!object) { + return *this << (int)0; + } + return *this << object->getID() << (QObject*)object.data(); } Bitstream& Bitstream::operator>(SharedObjectPointer& object) { - QObject* rawObject; - *this >> rawObject; - object = static_cast(rawObject); + int id; + *this >> id; + if (id == 0) { + object = SharedObjectPointer(); + return *this; + } + QPointer& pointer = _transientSharedObjects[id]; + if (pointer) { + const QMetaObject* metaObject; + _metaObjectStreamer >> metaObject; + if (metaObject != pointer->metaObject()) { + qWarning() << "Class mismatch: " << pointer->metaObject()->className() << metaObject->className(); + } + readProperties(pointer.data()); + + } else { + QObject* rawObject; + *this >> rawObject; + pointer = static_cast(rawObject); + } + object = static_cast(pointer.data()); return *this; } @@ -492,6 +503,20 @@ void Bitstream::clearSharedObject() { emit sharedObjectCleared(_sharedObjectStreamer.takePersistentID(object)); } +void Bitstream::readProperties(QObject* object) { + const QMetaObject* metaObject = object->metaObject(); + for (int i = 0; i < metaObject->propertyCount(); i++) { + QMetaProperty property = metaObject->property(i); + if (!property.isStored(object)) { + continue; + } + const TypeStreamer* streamer = getTypeStreamers().value(property.userType()); + if (streamer) { + property.write(object, streamer->read(*this)); + } + } +} + QHash& Bitstream::getMetaObjects() { static QHash metaObjects; return metaObjects; diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 74cb7de073..c06c4c3b5f 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -317,6 +318,8 @@ private slots: void clearSharedObject(); private: + + void readProperties(QObject* object); QDataStream& _underlying; quint8 _byte; @@ -328,6 +331,8 @@ private: RepeatedValueStreamer _scriptStringStreamer; RepeatedValueStreamer _sharedObjectStreamer; + QHash > _transientSharedObjects; + static QHash& getMetaObjects(); static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index c9ada9f82e..5665e70f91 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -548,7 +548,7 @@ void SpannerVisitor::prepare() { } bool SpannerVisitor::visit(MetavoxelInfo& info) { - for (int i = info.inputValues.size() - _spannerInputCount; i < info.inputValues.size(); i++) { + for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) { foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue()) { Spanner* spanner = static_cast(object.data()); if (spanner->testAndSetVisited()) { @@ -862,9 +862,6 @@ void SpannerRenderer::render(float alpha) { } Transformable::Transformable() : _scale(1.0f) { - connect(this, SIGNAL(translationChanged(const glm::vec3&)), SLOT(updateBounds())); - connect(this, SIGNAL(rotationChanged(const glm::vec3&)), SLOT(updateBounds())); - connect(this, SIGNAL(scaleChanged(float)), SLOT(updateBounds())); } void Transformable::setTranslation(const glm::vec3& translation) { @@ -885,12 +882,6 @@ void Transformable::setScale(float scale) { } } -void Transformable::updateBounds() { - // temporary fake bounds - glm::vec3 scaleVector(_scale, _scale, _scale); - setBounds(Box(_translation - scaleVector, _translation + scaleVector)); -} - StaticModel::StaticModel() { } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 9021213ee7..85bdd54938 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -360,10 +360,6 @@ signals: void rotationChanged(const glm::vec3& rotation); void scaleChanged(float scale); -protected slots: - - virtual void updateBounds(); - private: glm::vec3 _translation; diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index 2393785702..7e10068afe 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -18,7 +18,7 @@ REGISTER_META_OBJECT(SharedObject) -SharedObject::SharedObject() : _referenceCount(0) { +SharedObject::SharedObject() : _id(++_lastID), _referenceCount(0) { } void SharedObject::incrementReferenceCount() { @@ -74,6 +74,16 @@ bool SharedObject::equals(const SharedObject* other) const { return true; } +void SharedObject::dump(QDebug debug) const { + debug << this; + const QMetaObject* metaObject = this->metaObject(); + for (int i = 0; i < metaObject->propertyCount(); i++) { + debug << metaObject->property(i).name() << metaObject->property(i).read(this); + } +} + +int SharedObject::_lastID = 0; + SharedObjectEditor::SharedObjectEditor(const QMetaObject* metaObject, bool nullable, QWidget* parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(); layout->setAlignment(Qt::AlignTop); @@ -110,6 +120,22 @@ void SharedObjectEditor::setObject(const SharedObjectPointer& object) { } } +void SharedObjectEditor::detachObject() { + SharedObject* oldObject = _object.data(); + if (!_object.detach()) { + return; + } + oldObject->disconnect(this); + const QMetaObject* metaObject = _object->metaObject(); + + QFormLayout* form = static_cast(layout()->itemAt(1)); + for (int i = 0; i < form->rowCount(); i++) { + QWidget* widget = form->itemAt(i, QFormLayout::FieldRole)->widget(); + QMetaProperty property = metaObject->property(widget->property("propertyIndex").toInt()); + connect(_object.data(), signal(property.notifySignal().methodSignature()), SLOT(updateProperty())); + } +} + const QMetaObject* getOwningAncestor(const QMetaObject* metaObject, int propertyIndex) { while (propertyIndex < metaObject->propertyOffset()) { metaObject = metaObject->superClass(); @@ -182,7 +208,7 @@ void SharedObjectEditor::propertyChanged() { if (widget != sender()) { continue; } - _object.detach(); + detachObject(); QObject* object = _object.data(); QMetaProperty property = object->metaObject()->property(widget->property("propertyIndex").toInt()); QByteArray valuePropertyName = QItemEditorFactory::defaultFactory()->valuePropertyName(property.userType()); diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 008ea02e4b..94f6c192c5 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -13,6 +13,7 @@ #include #include #include +#include class QComboBox; @@ -24,6 +25,8 @@ public: Q_INVOKABLE SharedObject(); + int getID() { return _id; } + int getReferenceCount() const { return _referenceCount; } void incrementReferenceCount(); void decrementReferenceCount(); @@ -34,6 +37,9 @@ public: /// Tests this object for equality with another. virtual bool equals(const SharedObject* other) const; + // Dumps the contents of this object to the debug output. + virtual void dump(QDebug debug = qDebug()) const; + signals: /// Emitted when the reference count drops to one. @@ -41,7 +47,10 @@ signals: private: + int _id; int _referenceCount; + + static int _lastID; }; /// A pointer to a shared object. @@ -54,7 +63,8 @@ public: T* data() const { return _data; } - void detach(); + /// "Detaches" this object, making a new copy if its reference count is greater than one. + bool detach(); void swap(SharedObjectPointerTemplate& other) { qSwap(_data, other._data); } @@ -98,11 +108,13 @@ template inline SharedObjectPointerTemplate::~SharedObjectPointerTem } } -template inline void SharedObjectPointerTemplate::detach() { +template inline bool SharedObjectPointerTemplate::detach() { if (_data && _data->getReferenceCount() > 1) { _data->decrementReferenceCount(); (_data = _data->clone())->incrementReferenceCount(); + return true; } + return false; } template inline void SharedObjectPointerTemplate::reset() { @@ -160,6 +172,9 @@ public: const SharedObjectPointer& getObject() const { return _object; } + /// "Detaches" the object pointer, copying it if anyone else is holding a reference. + void detachObject(); + public slots: void setObject(const SharedObjectPointer& object); From 68fea8de1e49191f8b14eecfd629a9ac36558a0c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 21 Feb 2014 18:32:05 -0800 Subject: [PATCH 15/18] More merge fixes. --- assignment-client/src/metavoxels/MetavoxelServer.cpp | 2 +- interface/src/MetavoxelSystem.cpp | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index d50ca963eb..fa60d3a88c 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -88,7 +88,7 @@ void MetavoxelServer::sendDeltas() { MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const SharedNodePointer& node) : _server(server), - _sequencer(byteArrayWithPopluatedHeader(PacketTypeMetavoxelData)), + _sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData)), _node(node) { connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&))); diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index a14e133bc1..0421ca4747 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -168,19 +168,12 @@ bool MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) { return false; } -<<<<<<< HEAD MetavoxelSystem::RenderVisitor::RenderVisitor() : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute()) { } void MetavoxelSystem::RenderVisitor::visit(Spanner* spanner) { spanner->getRenderer()->render(1.0f); -======= -static QByteArray createDatagramHeader(const QUuid& sessionID) { - QByteArray header = byteArrayWithPopulatedHeader(PacketTypeMetavoxelData); - header += sessionID.toRfc4122(); - return header; ->>>>>>> 224f42c366bedfe91546888a9039c917ff6d416c } MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) : From 7bb3ea66acea8e6299595abafa87c84e8b244a48 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 21 Feb 2014 18:32:29 -0800 Subject: [PATCH 16/18] And another one. --- interface/src/MetavoxelSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 0421ca4747..59a714ece5 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -178,7 +178,7 @@ void MetavoxelSystem::RenderVisitor::visit(Spanner* spanner) { MetavoxelClient::MetavoxelClient(const SharedNodePointer& node) : _node(node), - _sequencer(byteArrayWithPopluatedHeader(PacketTypeMetavoxelData)) { + _sequencer(byteArrayWithPopulatedHeader(PacketTypeMetavoxelData)) { connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&))); connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&))); From 5cf6c434143cf1c37a991d380d8dfb884f762241 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sun, 23 Feb 2014 20:29:54 -0800 Subject: [PATCH 17/18] Fix for Windows build error. --- libraries/metavoxels/src/SharedObject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 94f6c192c5..9895073e44 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -38,7 +38,7 @@ public: virtual bool equals(const SharedObject* other) const; // Dumps the contents of this object to the debug output. - virtual void dump(QDebug debug = qDebug()) const; + virtual void dump(QDebug debug = QDebug(QtDebugMsg)) const; signals: From ba327232d5bc09190d03ede8837ff75db35bab8e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sun, 23 Feb 2014 21:07:00 -0800 Subject: [PATCH 18/18] Fixed another Window signed/unsigned mismatch. --- libraries/metavoxels/src/DatagramSequencer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index a60d4e9df3..0c7b8ce8ab 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -736,7 +736,7 @@ void ReliableChannel::readData(QDataStream& in) { // if we're expecting a message, peek into the buffer to see if we have the whole thing. // if so, read it in, handle it, and loop back around in case there are more if (_messagesEnabled) { - int available = _buffer.bytesAvailable(); + quint32 available = _buffer.bytesAvailable(); if (available >= sizeof(quint32)) { quint32 length; _buffer.readBytes(_buffer.pos(), sizeof(quint32), (char*)&length);