diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index 4d9c45ed6c..598d8ea722 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -55,6 +55,7 @@ void MetavoxelServer::run() { _persister = new MetavoxelPersister(this); QThread* persistenceThread = new QThread(this); _persister->moveToThread(persistenceThread); + _persister->connect(persistenceThread, SIGNAL(finished()), SLOT(deleteLater())); persistenceThread->start(); // queue up the load diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 48181d0244..bc6db5d7b6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3641,6 +3641,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript scriptEngine->registerGlobalObject("AnimationCache", &_animationCache); scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector); scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance()); + scriptEngine->registerGlobalObject("Metavoxels", &_metavoxels); scriptEngine->registerGlobalObject("AvatarManager", &_avatarManager); diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 64b2646261..1cd41500fc 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -213,7 +213,12 @@ void Attribute::writeMetavoxelDelta(const MetavoxelNode& root, const MetavoxelNo } void Attribute::readMetavoxelSubdivision(MetavoxelData& data, MetavoxelStreamState& state) { - data.getRoot(state.attribute)->readSubdivision(state); + // copy if changed + MetavoxelNode* oldRoot = data.getRoot(state.attribute); + MetavoxelNode* newRoot = oldRoot->readSubdivision(state); + if (newRoot != oldRoot) { + data.setRoot(state.attribute, newRoot); + } } void Attribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelStreamState& state) { diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 0d4f8a52b4..f49ae1c04f 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,21 @@ QList Bitstream::getMetaObjectSubClasses(const QMetaObject* return getMetaObjectSubClasses().values(metaObject); } +QScriptValue sharedObjectPointerToScriptValue(QScriptEngine* engine, const SharedObjectPointer& pointer) { + return pointer ? engine->newQObject(pointer.data()) : engine->nullValue(); +} + +void sharedObjectPointerFromScriptValue(const QScriptValue& object, SharedObjectPointer& pointer) { + pointer = qobject_cast(object.toQObject()); +} + +void Bitstream::registerTypes(QScriptEngine* engine) { + foreach (const QMetaObject* metaObject, getMetaObjects()) { + engine->globalObject().setProperty(metaObject->className(), engine->newQMetaObject(metaObject)); + } + qScriptRegisterMetaType(engine, sharedObjectPointerToScriptValue, sharedObjectPointerFromScriptValue); +} + Bitstream::Bitstream(QDataStream& underlying, MetadataType metadataType, GenericsMode genericsMode, QObject* parent) : QObject(parent), _underlying(underlying), diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index dacfeb2ee9..7602424ded 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -32,6 +32,7 @@ class QByteArray; class QColor; class QDataStream; +class QScriptEngine; class QScriptValue; class QUrl; @@ -320,6 +321,10 @@ public: /// subclasses. static QList getMetaObjectSubClasses(const QMetaObject* metaObject); + /// Configures the supplied script engine with our registered meta-objects, allowing all of them to be instantiated from + /// scripts. + static void registerTypes(QScriptEngine* engine); + enum MetadataType { NO_METADATA, HASH_METADATA, FULL_METADATA }; enum GenericsMode { NO_GENERICS, FALLBACK_GENERICS, ALL_GENERICS }; diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 4a01679c68..9a1f5a4ae0 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -426,9 +426,9 @@ private: int _writePositionResetPacketNumber; SpanList _acknowledged; bool _messagesEnabled; - int _messageLengthPlaceholder; - int _messageReceivedOffset; - int _messageSize; + int _messageLengthPlaceholder; ///< the location in the buffer of the message length for the current message + int _messageReceivedOffset; ///< when reached, indicates that the most recent sent message has been received + int _messageSize; ///< the size of the most recent sent message; only valid when _messageReceivedOffset has been set }; #endif // hifi_DatagramSequencer_h diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index f3ea1ae8c5..0b9e3f3d8c 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "MetavoxelClientManager.h" #include "MetavoxelMessages.h" @@ -53,7 +55,24 @@ SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(cons return closestSpanner; } +void MetavoxelClientManager::setSphere(const glm::vec3& center, float radius, const QColor& color) { + Sphere* sphere = new Sphere(); + sphere->setTranslation(center); + sphere->setScale(radius); + sphere->setColor(color); + setSpanner(sphere); +} + +void MetavoxelClientManager::setSpanner(const SharedObjectPointer& object, bool reliable) { + MetavoxelEditMessage edit = { QVariant::fromValue(SetSpannerEdit(object)) }; + applyEdit(edit, reliable); +} + void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool reliable) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable)); + return; + } foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { if (node->getType() == NodeType::MetavoxelServer) { QMutexLocker locker(&node->getMutex()); diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index ad6c86c8fc..191af794f7 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -28,6 +28,10 @@ public: SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, float& distance); + + Q_INVOKABLE void setSphere(const glm::vec3& center, float radius, const QColor& color = QColor(Qt::gray)); + + Q_INVOKABLE void setSpanner(const SharedObjectPointer& object, bool reliable = false); Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false); diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 1362731a8a..41cf2b2a20 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -47,13 +47,8 @@ bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, if (!shouldSubdivide(minimum, size, multiplier)) { return false; // this one must be subdivided } - // the general check is whether we've gotten closer (as multiplied by the threshold) to any point in the volume, - // which we approximate as a sphere for simplicity - float halfSize = size * 0.5f; - glm::vec3 center = minimum + glm::vec3(halfSize, halfSize, halfSize); - float radius = sqrtf(3 * halfSize * halfSize); - return qMax(0.0f, glm::distance(position, center) - radius) * threshold <= - qMax(0.0f, glm::distance(reference.position, center) - radius) * reference.threshold; + // TODO: find some way of culling subtrees that can't possibly contain subdivided nodes + return true; } MetavoxelData::MetavoxelData() : _size(1.0f) { @@ -603,12 +598,18 @@ void MetavoxelData::writeDelta(const MetavoxelData& reference, const MetavoxelLO } } -MetavoxelNode* MetavoxelData::createRoot(const AttributePointer& attribute) { - MetavoxelNode*& root = _roots[attribute]; - if (root) { - root->decrementReferenceCount(attribute); +void MetavoxelData::setRoot(const AttributePointer& attribute, MetavoxelNode* root) { + MetavoxelNode*& rootReference = _roots[attribute]; + if (rootReference) { + rootReference->decrementReferenceCount(attribute); } - return root = new MetavoxelNode(attribute); + rootReference = root; +} + +MetavoxelNode* MetavoxelData::createRoot(const AttributePointer& attribute) { + MetavoxelNode* root = new MetavoxelNode(attribute); + setRoot(attribute, root); + return root; } bool MetavoxelData::deepEquals(const MetavoxelData& other, const MetavoxelLOD& lod) const { @@ -761,7 +762,7 @@ void MetavoxelNode::mergeChildren(const AttributePointer& attribute, bool postRe childValues[i] = _children[i]->_attributeValue; allLeaves &= _children[i]->isLeaf(); } - if (attribute->merge(_attributeValue, childValues, postRead) && allLeaves) { + if (attribute->merge(_attributeValue, childValues, postRead) && allLeaves && !postRead) { clearChildren(attribute); } } @@ -843,10 +844,14 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta _children[i] = new MetavoxelNode(state.attribute); _children[i]->readDelta(*reference._children[i], nextState); } else { - _children[i] = reference._children[i]; - _children[i]->incrementReferenceCount(); if (nextState.becameSubdivided()) { - _children[i]->readSubdivision(nextState); + _children[i] = reference._children[i]->readSubdivision(nextState); + if (_children[i] == reference._children[i]) { + _children[i]->incrementReferenceCount(); + } + } else { + _children[i] = reference._children[i]; + _children[i]->incrementReferenceCount(); } } } @@ -888,58 +893,68 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt } } -void MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { - bool leaf; - bool subdivideReference = state.shouldSubdivideReference(); - if (!subdivideReference) { +MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { + if (!state.shouldSubdivideReference()) { + bool leaf; state.stream >> leaf; - } else { - leaf = isLeaf(); - } - if (leaf) { - clearChildren(state.attribute); - - } else { + if (leaf) { + return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.attribute)); + + } else { + MetavoxelNode* newNode = new MetavoxelNode(getAttributeValue(state.attribute)); + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + newNode->_children[i] = new MetavoxelNode(state.attribute); + newNode->_children[i]->read(nextState); + } + return newNode; + } + } else if (!isLeaf()) { + MetavoxelNode* node = this; MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, state.stream, state.lod, state.referenceLOD }; - if (!subdivideReference) { - clearChildren(state.attribute); - for (int i = 0; i < CHILD_COUNT; i++) { - nextState.setMinimum(state.minimum, i); - _children[i] = new MetavoxelNode(state.attribute); - _children[i]->read(nextState); - } - } else { - for (int i = 0; i < CHILD_COUNT; i++) { - nextState.setMinimum(state.minimum, i); - if (nextState.becameSubdivided()) { - _children[i]->readSubdivision(nextState); + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + if (nextState.becameSubdivided()) { + MetavoxelNode* child = _children[i]->readSubdivision(nextState); + if (child != _children[i]) { + if (node == this) { + node = new MetavoxelNode(state.attribute, this); + } + node->_children[i] = child; + _children[i]->decrementReferenceCount(state.attribute); } } } + if (node != this) { + node->mergeChildren(state.attribute, true); + } + return node; } + return this; } void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const { bool leaf = isLeaf(); - bool subdivideReference = state.shouldSubdivideReference(); - if (!subdivideReference) { + if (!state.shouldSubdivideReference()) { state.stream << leaf; - } - if (!leaf) { - MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, - state.stream, state.lod, state.referenceLOD }; - if (!subdivideReference) { + if (!leaf) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); _children[i]->write(nextState); } - } else { - for (int i = 0; i < CHILD_COUNT; i++) { - nextState.setMinimum(state.minimum, i); - if (nextState.becameSubdivided()) { - _children[i]->writeSubdivision(nextState); - } + } + } else if (!leaf) { + MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, + state.stream, state.lod, state.referenceLOD }; + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + if (nextState.becameSubdivided()) { + _children[i]->writeSubdivision(nextState); } } } @@ -1042,13 +1057,16 @@ void MetavoxelNode::destroy(const AttributePointer& attribute) { } } -void MetavoxelNode::clearChildren(const AttributePointer& attribute) { +bool MetavoxelNode::clearChildren(const AttributePointer& attribute) { + bool cleared = false; for (int i = 0; i < CHILD_COUNT; i++) { if (_children[i]) { _children[i]->decrementReferenceCount(attribute); _children[i] = NULL; + cleared = true; } } + return cleared; } bool MetavoxelNode::deepEquals(const AttributePointer& attribute, const MetavoxelNode& other, diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index f558bf8e80..eeab5bd0f4 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -118,7 +118,8 @@ public: void writeDelta(const MetavoxelData& reference, const MetavoxelLOD& referenceLOD, Bitstream& out, const MetavoxelLOD& lod) const; - MetavoxelNode* getRoot(const AttributePointer& attribute) const { return _roots.value(attribute); } + void setRoot(const AttributePointer& attribute, MetavoxelNode* root); + MetavoxelNode* getRoot(const AttributePointer& attribute) const { return _roots.value(attribute); } MetavoxelNode* createRoot(const AttributePointer& attribute); /// Performs a deep comparison between this data and the specified other (as opposed to the == operator, which does a @@ -200,7 +201,7 @@ public: void readDelta(const MetavoxelNode& reference, MetavoxelStreamState& state); void writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const; - void readSubdivision(MetavoxelStreamState& state); + MetavoxelNode* readSubdivision(MetavoxelStreamState& state); void writeSubdivision(MetavoxelStreamState& state) const; void writeSpanners(MetavoxelStreamState& state) const; @@ -216,7 +217,7 @@ public: void destroy(const AttributePointer& attribute); - void clearChildren(const AttributePointer& attribute); + bool clearChildren(const AttributePointer& attribute); /// Performs a deep comparison between this and the specified other node. bool deepEquals(const AttributePointer& attribute, const MetavoxelNode& other, diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index d0a1842d31..efc6aa4be6 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "Bitstream.h" #include "MetavoxelUtil.h" @@ -27,10 +28,12 @@ SharedObject::SharedObject() : _remoteID(0), _remoteOriginID(0) { + QWriteLocker locker(&_weakHashLock); _weakHash.insert(_id, this); } void SharedObject::setID(int id) { + QWriteLocker locker(&_weakHashLock); _weakHash.remove(_id); _weakHash.insert(_id = id, this); } @@ -41,7 +44,10 @@ void SharedObject::incrementReferenceCount() { void SharedObject::decrementReferenceCount() { if (!_referenceCount.deref()) { - _weakHash.remove(_id); + { + QWriteLocker locker(&_weakHashLock); + _weakHash.remove(_id); + } delete this; } } @@ -127,6 +133,7 @@ void SharedObject::dump(QDebug debug) const { int SharedObject::_lastID = 0; WeakSharedObjectHash SharedObject::_weakHash; +QReadWriteLock SharedObject::_weakHashLock; void pruneWeakSharedObjectHash(WeakSharedObjectHash& hash) { for (WeakSharedObjectHash::iterator it = hash.begin(); it != hash.end(); ) { diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index ba643b449c..5ff5aa9680 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,9 @@ public: /// Returns the weak hash under which all local shared objects are registered. static const WeakSharedObjectHash& getWeakHash() { return _weakHash; } + /// Returns a reference to the weak hash lock. + static QReadWriteLock& getWeakHashLock() { return _weakHashLock; } + Q_INVOKABLE SharedObject(); /// Returns the unique local ID for this object. @@ -85,6 +89,7 @@ private: static int _lastID; static WeakSharedObjectHash _weakHash; + static QReadWriteLock _weakHashLock; }; /// Removes the null references from the supplied hash. diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index cd7c2670ec..c5d5019b1f 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -229,6 +230,7 @@ void ScriptEngine::init() { registerMenuItemProperties(&_engine); registerAnimationTypes(&_engine); registerAvatarTypes(&_engine); + Bitstream::registerTypes(&_engine); qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue); diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 3e21a72fd5..afc439c586 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "RegisteredMetaTypes.h" static int vec4MetaTypeId = qRegisterMetaType(); @@ -25,6 +27,7 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue); qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue); + qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue); qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue); qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); } @@ -101,6 +104,29 @@ void xColorFromScriptValue(const QScriptValue &object, xColor& color) { color.blue = object.property("blue").toVariant().toInt(); } +QScriptValue qColorToScriptValue(QScriptEngine* engine, const QColor& color) { + QScriptValue object = engine->newObject(); + object.setProperty("red", color.red()); + object.setProperty("green", color.green()); + object.setProperty("blue", color.blue()); + object.setProperty("alpha", color.alpha()); + return object; +} + +void qColorFromScriptValue(const QScriptValue& object, QColor& color) { + if (object.isNumber()) { + color.setRgb(object.toUInt32()); + + } else if (object.isString()) { + color.setNamedColor(object.toString()); + + } else { + QScriptValue alphaValue = object.property("alpha"); + color.setRgb(object.property("red").toInt32(), object.property("green").toInt32(), object.property("blue").toInt32(), + alphaValue.isNumber() ? alphaValue.toInt32() : 255); + } +} + QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay) { QScriptValue obj = engine->newObject(); QScriptValue origin = vec3toScriptValue(engine, pickRay.origin); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index d876965723..b925639e8a 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -19,6 +19,8 @@ #include "CollisionInfo.h" #include "SharedUtil.h" +class QColor; + Q_DECLARE_METATYPE(glm::vec4) Q_DECLARE_METATYPE(glm::vec3) Q_DECLARE_METATYPE(glm::vec2) @@ -42,6 +44,9 @@ void quatFromScriptValue(const QScriptValue &object, glm::quat& quat); QScriptValue xColorToScriptValue(QScriptEngine* engine, const xColor& color); void xColorFromScriptValue(const QScriptValue &object, xColor& color); +QScriptValue qColorToScriptValue(QScriptEngine* engine, const QColor& color); +void qColorFromScriptValue(const QScriptValue& object, QColor& color); + class PickRay { public: PickRay() : origin(0), direction(0) { };