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