Merge pull request #3173 from ey6es/metavoxels

More metavoxel progress: basic scriptability, fix for subdivisions, threading fixes.
This commit is contained in:
AndrewMeadows 2014-07-16 09:22:13 -07:00
commit e7bc2a37e8
15 changed files with 176 additions and 61 deletions

View file

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

View file

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

View file

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

View file

@ -14,6 +14,7 @@
#include <QCryptographicHash>
#include <QDataStream>
#include <QMetaType>
#include <QScriptEngine>
#include <QScriptValueIterator>
#include <QUrl>
#include <QtDebug>
@ -128,6 +129,21 @@ QList<const QMetaObject*> 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<SharedObject*>(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),

View file

@ -32,6 +32,7 @@
class QByteArray;
class QColor;
class QDataStream;
class QScriptEngine;
class QScriptValue;
class QUrl;
@ -320,6 +321,10 @@ public:
/// subclasses.
static QList<const QMetaObject*> 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 };

View file

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

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QThread>
#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());

View file

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

View file

@ -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,

View file

@ -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,

View file

@ -14,6 +14,7 @@
#include <QItemEditorFactory>
#include <QMetaProperty>
#include <QVBoxLayout>
#include <QWriteLocker>
#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(); ) {

View file

@ -17,6 +17,7 @@
#include <QMetaType>
#include <QObject>
#include <QPointer>
#include <QReadWriteLock>
#include <QSet>
#include <QWidget>
#include <QtDebug>
@ -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.

View file

@ -20,6 +20,7 @@
#include <AudioInjector.h>
#include <AudioRingBuffer.h>
#include <AvatarData.h>
#include <Bitstream.h>
#include <CollisionInfo.h>
#include <ModelsScriptingInterface.h>
#include <NetworkAccessManager.h>
@ -229,6 +230,7 @@ void ScriptEngine::init() {
registerMenuItemProperties(&_engine);
registerAnimationTypes(&_engine);
registerAvatarTypes(&_engine);
Bitstream::registerTypes(&_engine);
qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue);
qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue);

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QColor>
#include "RegisteredMetaTypes.h"
static int vec4MetaTypeId = qRegisterMetaType<glm::vec4>();
@ -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);

View file

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