From e620518d2f938c14ae36717d8ec8ced13a436852 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 17:59:30 -0700 Subject: [PATCH 01/44] Working on streaming script values. --- libraries/metavoxels/src/Bitstream.cpp | 92 ++++++++++++++++++++++++++ libraries/metavoxels/src/Bitstream.h | 4 ++ 2 files changed, 96 insertions(+) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index d9242ad9b7..63ef8b09bb 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -543,6 +543,98 @@ Bitstream& Bitstream::operator>>(QScriptString& string) { return *this; } +enum ScriptValueType { + INVALID_SCRIPT_VALUE, + UNDEFINED_SCRIPT_VALUE, + NULL_SCRIPT_VALUE, + BOOL_SCRIPT_VALUE, + NUMBER_SCRIPT_VALUE, + STRING_SCRIPT_VALUE, + QVARIANT_SCRIPT_VALUE, + QOBJECT_SCRIPT_VALUE, + DATE_SCRIPT_VALUE, + REGEXP_SCRIPT_VALUE, + ARRAY_SCRIPT_VALUE, + OBJECT_SCRIPT_VALUE +}; + +const int SCRIPT_VALUE_BITS = 4; + +void writeScriptValueType(Bitstream& out, ScriptValueType type) { + out.write(&type, SCRIPT_VALUE_BITS); +} + +ScriptValueType readScriptValueType(Bitstream& in) { + ScriptValueType type = (ScriptValueType)0; + in.read(&type, SCRIPT_VALUE_BITS); + return type; +} + +Bitstream& Bitstream::operator<<(const QScriptValue& value) { + if (value.isUndefined()) { + writeScriptValueType(*this, UNDEFINED_SCRIPT_VALUE); + + } else if (value.isNull()) { + writeScriptValueType(*this, NULL_SCRIPT_VALUE); + + } else if (value.isBool()) { + writeScriptValueType(*this, BOOL_SCRIPT_VALUE); + + } else if (value.isNumber()) { + writeScriptValueType(*this, NUMBER_SCRIPT_VALUE); + + } else if (value.isString()) { + writeScriptValueType(*this, STRING_SCRIPT_VALUE); + + } else if (value.isArray()) { + writeScriptValueType(*this, ARRAY_SCRIPT_VALUE); + + } else if (value.isObject()) { + writeScriptValueType(*this, OBJECT_SCRIPT_VALUE); + + } else { + writeScriptValueType(*this, INVALID_SCRIPT_VALUE); + } + return *this; +} + +Bitstream& Bitstream::operator>>(QScriptValue& value) { + switch (readScriptValueType(*this)) { + case UNDEFINED_SCRIPT_VALUE: + value = QScriptValue(QScriptValue::UndefinedValue); + break; + + case NULL_SCRIPT_VALUE: + value = QScriptValue(QScriptValue::NullValue); + break; + + case BOOL_SCRIPT_VALUE: + value = QScriptValue(); + break; + + case NUMBER_SCRIPT_VALUE: + value = QScriptValue(); + break; + + case STRING_SCRIPT_VALUE: + value = QScriptValue(); + break; + + case ARRAY_SCRIPT_VALUE: + value = QScriptValue(); + break; + + case OBJECT_SCRIPT_VALUE: + value = QScriptValue(); + break; + + default: + value = QScriptValue(); + break; + } + return *this; +} + Bitstream& Bitstream::operator<<(const SharedObjectPointer& object) { _sharedObjectStreamer << object; return *this; diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 80adfc4e8b..3b1459109c 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -29,6 +29,7 @@ class QByteArray; class QColor; class QDataStream; +class QScriptValue; class QUrl; class Attribute; @@ -372,6 +373,9 @@ public: Bitstream& operator<<(const QScriptString& string); Bitstream& operator>>(QScriptString& string); + Bitstream& operator<<(const QScriptValue& value); + Bitstream& operator>>(QScriptValue& value); + Bitstream& operator<<(const SharedObjectPointer& object); Bitstream& operator>>(SharedObjectPointer& object); From 4d423c679c2700646d7d54bd6a4f9dd3a65d84a7 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 9 Jun 2014 10:21:55 -0700 Subject: [PATCH 02/44] Added some typedefs to simplify the various mapping types. --- libraries/metavoxels/src/Bitstream.cpp | 42 +++++++++++++------------- libraries/metavoxels/src/Bitstream.h | 20 ++++++++---- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 63ef8b09bb..e621484986 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -653,7 +653,7 @@ Bitstream& Bitstream::operator<(const QMetaObject* metaObject) { if (_metadataType == NO_METADATA) { return *this; } - const QVector& propertyWriters = getPropertyWriters().value(metaObject); + const PropertyWriterVector& propertyWriters = getPropertyWriters().value(metaObject); *this << propertyWriters.size(); QCryptographicHash hash(QCryptographicHash::Md5); foreach (const PropertyWriter& propertyWriter, propertyWriters) { @@ -692,7 +692,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { } int storedPropertyCount; *this >> storedPropertyCount; - QVector properties(storedPropertyCount); + PropertyReaderVector properties(storedPropertyCount); for (int i = 0; i < storedPropertyCount; i++) { TypeReader typeReader; *this >> typeReader; @@ -711,7 +711,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { QCryptographicHash hash(QCryptographicHash::Md5); bool matches = true; if (metaObject) { - const QVector& propertyWriters = getPropertyWriters().value(metaObject); + const PropertyWriterVector& propertyWriters = getPropertyWriters().value(metaObject); if (propertyWriters.size() == properties.size()) { for (int i = 0; i < propertyWriters.size(); i++) { const PropertyWriter& propertyWriter = propertyWriters.at(i); @@ -1082,17 +1082,17 @@ QHash& Bitstream::getTypeStreamers() { return typeStreamers; } -const QHash, const TypeStreamer*>& Bitstream::getEnumStreamers() { - static QHash, const TypeStreamer*> enumStreamers = createEnumStreamers(); +const QHash& Bitstream::getEnumStreamers() { + static QHash enumStreamers = createEnumStreamers(); return enumStreamers; } -QHash, const TypeStreamer*> Bitstream::createEnumStreamers() { - QHash, const TypeStreamer*> enumStreamers; +QHash Bitstream::createEnumStreamers() { + QHash enumStreamers; foreach (const QMetaObject* metaObject, getMetaObjects()) { for (int i = 0; i < metaObject->enumeratorCount(); i++) { QMetaEnum metaEnum = metaObject->enumerator(i); - const TypeStreamer*& streamer = enumStreamers[QPair(metaEnum.scope(), metaEnum.name())]; + const TypeStreamer*& streamer = enumStreamers[ScopeNamePair(metaEnum.scope(), metaEnum.name())]; if (!streamer) { streamer = new EnumTypeStreamer(metaEnum); } @@ -1114,15 +1114,15 @@ QHash Bitstream::createEnumStreamersByName() { return enumStreamersByName; } -const QHash >& Bitstream::getPropertyReaders() { - static QHash > propertyReaders = createPropertyReaders(); +const QHash& Bitstream::getPropertyReaders() { + static QHash propertyReaders = createPropertyReaders(); return propertyReaders; } -QHash > Bitstream::createPropertyReaders() { - QHash > propertyReaders; +QHash Bitstream::createPropertyReaders() { + QHash propertyReaders; foreach (const QMetaObject* metaObject, getMetaObjects()) { - QVector& readers = propertyReaders[metaObject]; + PropertyReaderVector& readers = propertyReaders[metaObject]; for (int i = 0; i < metaObject->propertyCount(); i++) { QMetaProperty property = metaObject->property(i); if (!property.isStored()) { @@ -1131,7 +1131,7 @@ QHash > Bitstream::createPropertyRea const TypeStreamer* streamer; if (property.isEnumType()) { QMetaEnum metaEnum = property.enumerator(); - streamer = getEnumStreamers().value(QPair( + streamer = getEnumStreamers().value(ScopeNamePair( QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); } else { @@ -1145,15 +1145,15 @@ QHash > Bitstream::createPropertyRea return propertyReaders; } -const QHash >& Bitstream::getPropertyWriters() { - static QHash > propertyWriters = createPropertyWriters(); +const QHash& Bitstream::getPropertyWriters() { + static QHash propertyWriters = createPropertyWriters(); return propertyWriters; } -QHash > Bitstream::createPropertyWriters() { - QHash > propertyWriters; +QHash Bitstream::createPropertyWriters() { + QHash propertyWriters; foreach (const QMetaObject* metaObject, getMetaObjects()) { - QVector& writers = propertyWriters[metaObject]; + PropertyWriterVector& writers = propertyWriters[metaObject]; for (int i = 0; i < metaObject->propertyCount(); i++) { QMetaProperty property = metaObject->property(i); if (!property.isStored()) { @@ -1162,7 +1162,7 @@ QHash > Bitstream::createPropertyWri const TypeStreamer* streamer; if (property.isEnumType()) { QMetaEnum metaEnum = property.enumerator(); - streamer = getEnumStreamers().value(QPair( + streamer = getEnumStreamers().value(ScopeNamePair( QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); } else { @@ -1416,7 +1416,7 @@ void FieldReader::readDelta(Bitstream& in, const TypeStreamer* streamer, QVarian } ObjectReader::ObjectReader(const QByteArray& className, const QMetaObject* metaObject, - const QVector& properties) : + const PropertyReaderVector& properties) : _className(className), _metaObject(metaObject), _properties(properties) { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 3b1459109c..4fe136f720 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -45,6 +45,10 @@ class TypeStreamer; typedef SharedObjectPointerTemplate AttributePointer; +typedef QPair ScopeNamePair; +typedef QVector PropertyReaderVector; +typedef QVector PropertyWriterVector; + /// 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 /// us to use the minimum number of bits to encode the IDs. @@ -426,14 +430,18 @@ private: static QHash& getMetaObjects(); static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); - static const QHash, const TypeStreamer*>& getEnumStreamers(); - static QHash, const TypeStreamer*> createEnumStreamers(); + + static const QHash& getEnumStreamers(); + static QHash createEnumStreamers(); + static const QHash& getEnumStreamersByName(); static QHash createEnumStreamersByName(); - static const QHash >& getPropertyReaders(); - static QHash > createPropertyReaders(); - static const QHash >& getPropertyWriters(); - static QHash > createPropertyWriters(); + + static const QHash& getPropertyReaders(); + static QHash createPropertyReaders(); + + static const QHash& getPropertyWriters(); + static QHash createPropertyWriters(); }; template inline void Bitstream::writeDelta(const T& value, const T& reference) { From ae22aa1a215d5fa540082d346b9aff24ece51946 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 9 Jun 2014 10:53:44 -0700 Subject: [PATCH 03/44] Working on JS type streaming. --- libraries/metavoxels/src/Bitstream.cpp | 72 +++++++++++++++++++++++++- libraries/metavoxels/src/Bitstream.h | 12 +++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index e621484986..8f813adf90 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -350,6 +350,14 @@ Bitstream& Bitstream::operator>>(uint& value) { return *this; } +Bitstream& Bitstream::operator<<(qint64 value) { + return write(&value, 64); +} + +Bitstream& Bitstream::operator>>(qint64& value) { + return read(&value, 64); +} + Bitstream& Bitstream::operator<<(float value) { return write(&value, 32); } @@ -358,6 +366,14 @@ Bitstream& Bitstream::operator>>(float& value) { return read(&value, 32); } +Bitstream& Bitstream::operator<<(double value) { + return write(&value, 64); +} + +Bitstream& Bitstream::operator>>(double& value) { + return read(&value, 64); +} + Bitstream& Bitstream::operator<<(const glm::vec3& value) { return *this << value.x << value.y << value.z; } @@ -420,6 +436,36 @@ Bitstream& Bitstream::operator>>(QUrl& url) { return *this; } +Bitstream& Bitstream::operator<<(const QDateTime& dateTime) { + return *this << dateTime.toMSecsSinceEpoch(); +} + +Bitstream& Bitstream::operator>>(QDateTime& dateTime) { + qint64 msecsSinceEpoch; + *this >> msecsSinceEpoch; + dateTime = QDateTime::fromMSecsSinceEpoch(msecsSinceEpoch); + return *this; +} + +Bitstream& Bitstream::operator<<(const QRegExp& regExp) { + *this << regExp.pattern(); + + return *this; +} + +Bitstream& Bitstream::operator>>(QRegExp& regExp) { + QString pattern; + *this >> pattern; + Qt::CaseSensitivity caseSensitivity = (Qt::CaseSensitivity)0; + read(&caseSensitivity, 1); + QRegExp::PatternSyntax syntax = (QRegExp::PatternSyntax)0; + read(&syntax, 3); + + regExp = QRegExp(pattern, caseSensitivity, syntax); + + return *this; +} + Bitstream& Bitstream::operator<<(const QVariant& value) { if (!value.isValid()) { _typeStreamerStreamer << NULL; @@ -550,8 +596,9 @@ enum ScriptValueType { BOOL_SCRIPT_VALUE, NUMBER_SCRIPT_VALUE, STRING_SCRIPT_VALUE, - QVARIANT_SCRIPT_VALUE, + VARIANT_SCRIPT_VALUE, QOBJECT_SCRIPT_VALUE, + QMETAOBJECT_SCRIPT_VALUE, DATE_SCRIPT_VALUE, REGEXP_SCRIPT_VALUE, ARRAY_SCRIPT_VALUE, @@ -579,12 +626,35 @@ Bitstream& Bitstream::operator<<(const QScriptValue& value) { } else if (value.isBool()) { writeScriptValueType(*this, BOOL_SCRIPT_VALUE); + *this << value.toBool(); } else if (value.isNumber()) { writeScriptValueType(*this, NUMBER_SCRIPT_VALUE); + *this << value.toNumber(); } else if (value.isString()) { writeScriptValueType(*this, STRING_SCRIPT_VALUE); + *this << value.toString(); + + } else if (value.isVariant()) { + writeScriptValueType(*this, VARIANT_SCRIPT_VALUE); + *this << value.toVariant(); + + } else if (value.isQObject()) { + writeScriptValueType(*this, QOBJECT_SCRIPT_VALUE); + *this << value.toQObject(); + + } else if (value.isQMetaObject()) { + writeScriptValueType(*this, QMETAOBJECT_SCRIPT_VALUE); + *this << value.toQMetaObject(); + + } else if (value.isDate()) { + writeScriptValueType(*this, DATE_SCRIPT_VALUE); + *this << value.toDateTime(); + + } else if (value.isRegExp()) { + writeScriptValueType(*this, REGEXP_SCRIPT_VALUE); + *this << value.toRegExp(); } else if (value.isArray()) { writeScriptValueType(*this, ARRAY_SCRIPT_VALUE); diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 4fe136f720..83733674a4 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -321,9 +321,15 @@ public: Bitstream& operator<<(uint value); Bitstream& operator>>(uint& value); + Bitstream& operator<<(qint64 value); + Bitstream& operator>>(qint64& value); + Bitstream& operator<<(float value); Bitstream& operator>>(float& value); + Bitstream& operator<<(double value); + Bitstream& operator>>(double& value); + Bitstream& operator<<(const glm::vec3& value); Bitstream& operator>>(glm::vec3& value); @@ -342,6 +348,12 @@ public: Bitstream& operator<<(const QUrl& url); Bitstream& operator>>(QUrl& url); + Bitstream& operator<<(const QDateTime& dateTime); + Bitstream& operator>>(QDateTime& dateTime); + + Bitstream& operator<<(const QRegExp& regExp); + Bitstream& operator>>(QRegExp& regExp); + Bitstream& operator<<(const QVariant& value); Bitstream& operator>>(QVariant& value); From 58bd1f7ab57c312933370a28242b1f8c8b68d97f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 9 Jun 2014 11:54:43 -0700 Subject: [PATCH 04/44] More script streaming bits. --- libraries/metavoxels/src/Bitstream.cpp | 110 ++++++++++++++++++++----- 1 file changed, 89 insertions(+), 21 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 8f813adf90..c3d0348ee8 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -449,8 +450,11 @@ Bitstream& Bitstream::operator>>(QDateTime& dateTime) { Bitstream& Bitstream::operator<<(const QRegExp& regExp) { *this << regExp.pattern(); - - return *this; + Qt::CaseSensitivity caseSensitivity = regExp.caseSensitivity(); + write(&caseSensitivity, 1); + QRegExp::PatternSyntax syntax = regExp.patternSyntax(); + write(&syntax, 3); + return *this << regExp.isMinimal(); } Bitstream& Bitstream::operator>>(QRegExp& regExp) { @@ -460,9 +464,10 @@ Bitstream& Bitstream::operator>>(QRegExp& regExp) { read(&caseSensitivity, 1); QRegExp::PatternSyntax syntax = (QRegExp::PatternSyntax)0; read(&syntax, 3); - regExp = QRegExp(pattern, caseSensitivity, syntax); - + bool minimal; + *this >> minimal; + regExp.setMinimal(minimal); return *this; } @@ -658,10 +663,20 @@ Bitstream& Bitstream::operator<<(const QScriptValue& value) { } else if (value.isArray()) { writeScriptValueType(*this, ARRAY_SCRIPT_VALUE); - + int length = value.property(ScriptCache::getInstance()->getLengthString()).toInt32(); + *this << length; + for (int i = 0; i < length; i++) { + *this << value.property(i); + } } else if (value.isObject()) { writeScriptValueType(*this, OBJECT_SCRIPT_VALUE); - + for (QScriptValueIterator it(value); it.hasNext(); ) { + it.next(); + *this << it.scriptName(); + *this << it.value(); + } + *this << QScriptString(); + } else { writeScriptValueType(*this, INVALID_SCRIPT_VALUE); } @@ -678,26 +693,79 @@ Bitstream& Bitstream::operator>>(QScriptValue& value) { value = QScriptValue(QScriptValue::NullValue); break; - case BOOL_SCRIPT_VALUE: - value = QScriptValue(); + case BOOL_SCRIPT_VALUE: { + bool boolValue; + *this >> boolValue; + value = QScriptValue(boolValue); break; - - case NUMBER_SCRIPT_VALUE: - value = QScriptValue(); + } + case NUMBER_SCRIPT_VALUE: { + qsreal numberValue; + *this >> numberValue; + value = QScriptValue(numberValue); break; - - case STRING_SCRIPT_VALUE: - value = QScriptValue(); + } + case STRING_SCRIPT_VALUE: { + QString stringValue; + *this >> stringValue; + value = QScriptValue(stringValue); break; - - case ARRAY_SCRIPT_VALUE: - value = QScriptValue(); + } + case VARIANT_SCRIPT_VALUE: { + QVariant variantValue; + *this >> variantValue; + value = ScriptCache::getInstance()->getEngine()->newVariant(variantValue); break; - - case OBJECT_SCRIPT_VALUE: - value = QScriptValue(); + } + case QOBJECT_SCRIPT_VALUE: { + QObject* object; + *this >> object; + ScriptCache::getInstance()->getEngine()->newQObject(object, QScriptEngine::ScriptOwnership); break; - + } + case QMETAOBJECT_SCRIPT_VALUE: { + const QMetaObject* metaObject; + *this >> metaObject; + ScriptCache::getInstance()->getEngine()->newQMetaObject(metaObject); + break; + } + case DATE_SCRIPT_VALUE: { + QDateTime dateTime; + *this >> dateTime; + value = ScriptCache::getInstance()->getEngine()->newDate(dateTime); + break; + } + case REGEXP_SCRIPT_VALUE: { + QRegExp regExp; + *this >> regExp; + value = ScriptCache::getInstance()->getEngine()->newRegExp(regExp); + break; + } + case ARRAY_SCRIPT_VALUE: { + int length; + *this >> length; + value = ScriptCache::getInstance()->getEngine()->newArray(length); + for (int i = 0; i < length; i++) { + QScriptValue element; + *this >> element; + value.setProperty(i, element); + } + break; + } + case OBJECT_SCRIPT_VALUE: { + value = ScriptCache::getInstance()->getEngine()->newObject(); + forever { + QScriptString name; + *this >> name; + if (!name.isValid()) { + break; + } + QScriptValue scriptValue; + *this >> scriptValue; + value.setProperty(name, scriptValue); + } + break; + } default: value = QScriptValue(); break; From fd469c543c7b8cb7ef778ad280adda64bb3f6768 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 9 Jun 2014 14:35:20 -0700 Subject: [PATCH 05/44] More script streaming bits. --- libraries/metavoxels/src/Bitstream.cpp | 276 ++++++++++++++++++++++- libraries/metavoxels/src/Bitstream.h | 4 + libraries/metavoxels/src/ScriptCache.cpp | 79 +++++++ libraries/metavoxels/src/ScriptCache.h | 5 + 4 files changed, 362 insertions(+), 2 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index c3d0348ee8..d27053aefb 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -31,6 +31,7 @@ REGISTER_SIMPLE_TYPE_STREAMER(uint) REGISTER_SIMPLE_TYPE_STREAMER(float) REGISTER_SIMPLE_TYPE_STREAMER(QByteArray) REGISTER_SIMPLE_TYPE_STREAMER(QColor) +REGISTER_SIMPLE_TYPE_STREAMER(QScriptValue) REGISTER_SIMPLE_TYPE_STREAMER(QString) REGISTER_SIMPLE_TYPE_STREAMER(QUrl) REGISTER_SIMPLE_TYPE_STREAMER(QVariantList) @@ -286,6 +287,12 @@ void Bitstream::writeDelta(const QVariant& value, const QVariant& reference) { streamer->writeRawDelta(*this, value, reference); } +void Bitstream::writeRawDelta(const QVariant& value, const QVariant& reference) { + const TypeStreamer* streamer = getTypeStreamers().value(value.userType()); + _typeStreamerStreamer << streamer; + streamer->writeRawDelta(*this, value, reference); +} + void Bitstream::readRawDelta(QVariant& value, const QVariant& reference) { TypeReader typeReader; _typeStreamerStreamer >> typeReader; @@ -310,6 +317,271 @@ void Bitstream::readRawDelta(QObject*& value, const QObject* reference) { value = objectReader.readDelta(*this, reference); } +void Bitstream::writeRawDelta(const QScriptValue& value, const QScriptValue& reference) { + if (reference.isUndefined() || reference.isNull()) { + *this << value; + + } else if (reference.isBool()) { + if (value.isBool()) { + *this << false; + *this << value.toBool(); + + } else { + *this << true; + *this << value; + } + } else if (reference.isNumber()) { + if (value.isNumber()) { + *this << false; + *this << value.toNumber(); + + } else { + *this << true; + *this << value; + } + } else if (reference.isString()) { + if (value.isString()) { + *this << false; + *this << value.toString(); + + } else { + *this << true; + *this << value; + } + } else if (reference.isVariant()) { + if (value.isVariant()) { + *this << false; + writeRawDelta(value.toVariant(), reference.toVariant()); + + } else { + *this << true; + *this << value; + } + } else if (reference.isQObject()) { + if (value.isQObject()) { + *this << false; + writeRawDelta(value.toQObject(), reference.toQObject()); + + } else { + *this << true; + *this << value; + } + } else if (reference.isQMetaObject()) { + if (value.isQMetaObject()) { + *this << false; + *this << value.toQMetaObject(); + + } else { + *this << true; + *this << value; + } + } else if (reference.isDate()) { + if (value.isDate()) { + *this << false; + *this << value.toDateTime(); + + } else { + *this << true; + *this << value; + } + } else if (reference.isRegExp()) { + if (value.isRegExp()) { + *this << false; + *this << value.toRegExp(); + + } else { + *this << true; + *this << value; + } + } else if (reference.isArray()) { + if (value.isArray()) { + *this << false; + int length = value.property(ScriptCache::getInstance()->getLengthString()).toInt32(); + *this << length; + int referenceLength = reference.property(ScriptCache::getInstance()->getLengthString()).toInt32(); + for (int i = 0; i < length; i++) { + if (i < referenceLength) { + writeDelta(value.property(i), reference.property(i)); + } else { + *this << value.property(i); + } + } + } else { + *this << true; + *this << value; + } + } else if (reference.isObject()) { + if (value.isObject()) { + *this << false; + for (QScriptValueIterator it(value); it.hasNext(); ) { + it.next(); + QScriptValue referenceValue = reference.property(it.scriptName()); + if (it.value() != referenceValue) { + *this << it.scriptName(); + writeRawDelta(it.value(), referenceValue); + } + } + for (QScriptValueIterator it(reference); it.hasNext(); ) { + it.next(); + if (!value.property(it.scriptName()).isValid()) { + *this << it.scriptName(); + writeRawDelta(QScriptValue(), it.value()); + } + } + *this << QScriptString(); + + } else { + *this << true; + *this << value; + } + } else { + *this << value; + } +} + +void Bitstream::readRawDelta(QScriptValue& value, const QScriptValue& reference) { + if (reference.isUndefined() || reference.isNull()) { + *this >> value; + + } else if (reference.isBool()) { + bool typeChanged; + *this >> typeChanged; + if (typeChanged) { + *this >> value; + + } else { + bool boolValue; + *this >> boolValue; + value = QScriptValue(boolValue); + } + } else if (reference.isNumber()) { + bool typeChanged; + *this >> typeChanged; + if (typeChanged) { + *this >> value; + + } else { + qsreal numberValue; + *this >> numberValue; + value = QScriptValue(numberValue); + } + } else if (reference.isString()) { + bool typeChanged; + *this >> typeChanged; + if (typeChanged) { + *this >> value; + + } else { + QString stringValue; + *this >> stringValue; + value = QScriptValue(stringValue); + } + } else if (reference.isVariant()) { + bool typeChanged; + *this >> typeChanged; + if (typeChanged) { + *this >> value; + + } else { + QVariant variant; + readRawDelta(variant, reference.toVariant()); + value = ScriptCache::getInstance()->getEngine()->newVariant(variant); + } + } else if (reference.isQObject()) { + bool typeChanged; + *this >> typeChanged; + if (typeChanged) { + *this >> value; + + } else { + QObject* object; + readRawDelta(object, reference.toQObject()); + value = ScriptCache::getInstance()->getEngine()->newQObject(object, QScriptEngine::ScriptOwnership); + } + } else if (reference.isQMetaObject()) { + bool typeChanged; + *this >> typeChanged; + if (typeChanged) { + *this >> value; + + } else { + const QMetaObject* metaObject; + *this >> metaObject; + value = ScriptCache::getInstance()->getEngine()->newQMetaObject(metaObject); + } + } else if (reference.isDate()) { + bool typeChanged; + *this >> typeChanged; + if (typeChanged) { + *this >> value; + + } else { + QDateTime dateTime; + *this >> dateTime; + value = ScriptCache::getInstance()->getEngine()->newDate(dateTime); + } + } else if (reference.isRegExp()) { + bool typeChanged; + *this >> typeChanged; + if (typeChanged) { + *this >> value; + + } else { + QRegExp regExp; + *this >> regExp; + value = ScriptCache::getInstance()->getEngine()->newRegExp(regExp); + } + } else if (reference.isArray()) { + bool typeChanged; + *this >> typeChanged; + if (typeChanged) { + *this >> value; + + } else { + int length; + *this >> length; + value = ScriptCache::getInstance()->getEngine()->newArray(length); + int referenceLength = reference.property(ScriptCache::getInstance()->getLengthString()).toInt32(); + for (int i = 0; i < length; i++) { + QScriptValue element; + if (i < referenceLength) { + readDelta(element, reference.property(i)); + } else { + *this >> element; + } + value.setProperty(i, element); + } + } + } else if (reference.isObject()) { + bool typeChanged; + *this >> typeChanged; + if (typeChanged) { + *this >> value; + + } else { + // start by shallow-copying the reference + value = ScriptCache::getInstance()->getEngine()->newObject(); + for (QScriptValueIterator it(reference); it.hasNext(); ) { + it.next(); + value.setProperty(it.scriptName(), it.value()); + } + // then apply the requested changes + forever { + QScriptString name; + *this >> name; + if (!name.isValid()) { + break; + } + QScriptValue scriptValue; + readRawDelta(scriptValue, reference.property(name)); + value.setProperty(name, scriptValue); + } + } + } else { + *this >> value; + } +} + Bitstream& Bitstream::operator<<(bool value) { if (value) { _byte |= (1 << _position); @@ -612,11 +884,11 @@ enum ScriptValueType { const int SCRIPT_VALUE_BITS = 4; -void writeScriptValueType(Bitstream& out, ScriptValueType type) { +static void writeScriptValueType(Bitstream& out, ScriptValueType type) { out.write(&type, SCRIPT_VALUE_BITS); } -ScriptValueType readScriptValueType(Bitstream& in) { +static ScriptValueType readScriptValueType(Bitstream& in) { ScriptValueType type = (ScriptValueType)0; in.read(&type, SCRIPT_VALUE_BITS); return type; diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 83733674a4..d05f6574c0 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -292,11 +292,15 @@ public: template void writeDelta(const T& value, const T& reference); template void readDelta(T& value, const T& reference); + void writeRawDelta(const QVariant& value, const QVariant& reference); void readRawDelta(QVariant& value, const QVariant& reference); void writeRawDelta(const QObject* value, const QObject* reference); void readRawDelta(QObject*& value, const QObject* reference); + void writeRawDelta(const QScriptValue& value, const QScriptValue& reference); + void readRawDelta(QScriptValue& value, const QScriptValue& reference); + template void writeRawDelta(const T& value, const T& reference); template void readRawDelta(T& value, const T& reference); diff --git a/libraries/metavoxels/src/ScriptCache.cpp b/libraries/metavoxels/src/ScriptCache.cpp index dd090613b7..9de624fb29 100644 --- a/libraries/metavoxels/src/ScriptCache.cpp +++ b/libraries/metavoxels/src/ScriptCache.cpp @@ -13,11 +13,90 @@ #include #include +#include #include #include "AttributeRegistry.h" #include "ScriptCache.h" +static int scriptValueMetaTypeId = qRegisterMetaType(); + +bool operator==(const QScriptValue& first, const QScriptValue& second) { + if (first.isUndefined()) { + return second.isUndefined(); + + } else if (first.isNull()) { + return second.isNull(); + + } else if (first.isBool()) { + return second.isBool() && first.toBool() == second.toBool(); + + } else if (first.isNumber()) { + return second.isNumber() && first.toNumber() == second.toNumber(); + + } else if (first.isString()) { + return second.isString() && first.toString() == second.toString(); + + } else if (first.isVariant()) { + return second.isVariant() && first.toVariant() == second.toVariant(); + + } else if (first.isQObject()) { + return second.isQObject() && first.toQObject() == second.toQObject(); + + } else if (first.isQMetaObject()) { + return second.isQMetaObject() && first.toQMetaObject() == second.toQMetaObject(); + + } else if (first.isDate()) { + return second.isDate() && first.toDateTime() == second.toDateTime(); + + } else if (first.isRegExp()) { + return second.isRegExp() && first.toRegExp() == second.toRegExp(); + + } else if (first.isArray()) { + if (!second.isArray()) { + return false; + } + int length = first.property(ScriptCache::getInstance()->getLengthString()).toInt32(); + if (second.property(ScriptCache::getInstance()->getLengthString()).toInt32() != length) { + return false; + } + for (int i = 0; i < length; i++) { + if (first.property(i) != second.property(i)) { + return false; + } + } + return true; + + } else if (first.isObject()) { + if (!second.isObject()) { + return false; + } + int propertyCount = 0; + for (QScriptValueIterator it(first); it.hasNext(); ) { + it.next(); + if (second.property(it.scriptName()) != it.value()) { + return false; + } + propertyCount++; + } + // make sure the second has exactly as many properties as the first + for (QScriptValueIterator it(second); it.hasNext(); ) { + it.next(); + if (--propertyCount < 0) { + return false; + } + } + return true; + + } else { + return !second.isValid(); + } +} + +bool operator!=(const QScriptValue& first, const QScriptValue& second) { + return !(first == second); +} + ScriptCache* ScriptCache::getInstance() { static ScriptCache cache; return &cache; diff --git a/libraries/metavoxels/src/ScriptCache.h b/libraries/metavoxels/src/ScriptCache.h index f393d0e0a8..d88a967081 100644 --- a/libraries/metavoxels/src/ScriptCache.h +++ b/libraries/metavoxels/src/ScriptCache.h @@ -65,6 +65,11 @@ private: QScriptString _generatorString; }; +Q_DECLARE_METATYPE(QScriptValue) + +bool operator==(const QScriptValue& first, const QScriptValue& second); +bool operator!=(const QScriptValue& first, const QScriptValue& second); + /// A program loaded from the network. class NetworkProgram : public Resource { Q_OBJECT From c8c8bccbf3b7768c88791ce2e6f37fe10b2a319a Mon Sep 17 00:00:00 2001 From: matsukaze Date: Mon, 9 Jun 2014 17:52:50 -0400 Subject: [PATCH 06/44] Job #19766 BUG: Stop or reload all scripts crashes interface fixed. QUrl(name).toString() does not equal name, therefore removing name from ScriptEngineHash was failing, and a dangling pointer was left in the script engine hash map. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 574df09ee2..9fb821bff4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3494,7 +3494,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript // start the script on a new thread... QUrl scriptUrl(scriptName); scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface); - _scriptEnginesHash.insert(scriptName, scriptEngine); + _scriptEnginesHash.insert(scriptUrl.toString(), scriptEngine); if (!scriptEngine->hasScript()) { qDebug() << "Application::loadScript(), script failed to load..."; From 8312e1642db0a0178997cb096684b14eb030aec9 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 15:15:43 -0700 Subject: [PATCH 07/44] replaced takeFirst() with dequeue() for consistency --- assignment-client/src/octree/OctreeQueryNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 372f15a76b..3531c3f9cb 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -384,7 +384,7 @@ bool OctreeQueryNode::hasNextNackedPacket() const { const QByteArray* OctreeQueryNode::getNextNackedPacket() { if (!_nackedSequenceNumbers.isEmpty()) { // could return null if packet is not in the history - return _sentPacketHistory.getPacket(_nackedSequenceNumbers.takeFirst()); + return _sentPacketHistory.getPacket(_nackedSequenceNumbers.dequeue()); } return NULL; } From e8b6338de9026938a34ac35191a4abb1d906ecc6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 9 Jun 2014 15:40:29 -0700 Subject: [PATCH 08/44] Fix IK for hydra hands. --- interface/src/avatar/SkeletonModel.cpp | 45 +++++++++----------------- interface/src/renderer/Model.cpp | 4 +-- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index ca40ba1d64..d5a13b0381 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -144,9 +144,9 @@ void SkeletonModel::getBodyShapes(QVector& shapes) const { void SkeletonModel::renderIKConstraints() { renderJointConstraints(getRightHandJointIndex()); renderJointConstraints(getLeftHandJointIndex()); - if (isActive() && _owningAvatar->isMyAvatar()) { - renderRagDoll(); - } + //if (isActive() && _owningAvatar->isMyAvatar()) { + // renderRagDoll(); + //} } class IndexValue { @@ -193,45 +193,30 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { if (parentJointIndex == -1) { return; } - + // rotate palm to align with its normal (normal points out of hand's palm) - glm::quat palmRotation; - glm::quat r0, r1; - if (!Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK) && - Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { - JointState parentState = _jointStates[parentJointIndex]; - palmRotation = parentState.getRotationFromBindToModelFrame(); - r0 = palmRotation; - } else { - JointState state = _jointStates[jointIndex]; - palmRotation = state.getRotationFromBindToModelFrame(); - } glm::quat inverseRotation = glm::inverse(_rotation); - glm::vec3 palmNormal = inverseRotation * palm.getNormal(); - palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palmNormal) * palmRotation; - r1 = palmRotation; - - // rotate palm to align with finger direction - glm::vec3 direction = inverseRotation * palm.getFingerDirection(); - palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation; - - // set hand position, rotation glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); + glm::vec3 palmNormal = inverseRotation * palm.getNormal(); + glm::vec3 fingerDirection = inverseRotation * palm.getFingerDirection(); + + glm::quat palmRotation = rotationBetween(glm::vec3(0.0f, -1.0f, 0.0f), palmNormal); + palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), fingerDirection) * palmRotation; + if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { setHandPosition(jointIndex, palmPosition, palmRotation); - } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { - glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); - setJointPosition(parentJointIndex, palmPosition + forearmVector * - geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), + float forearmLength = geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale); + glm::vec3 forearm = palmRotation * glm::vec3(sign * forearmLength, 0.0f, 0.0f); + setJointPosition(parentJointIndex, palmPosition + forearm, glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); JointState& parentState = _jointStates[parentJointIndex]; parentState.setRotationFromBindFrame(palmRotation, PALM_PRIORITY); // lock hand to forearm by slamming its rotation (in parent-frame) to identity _jointStates[jointIndex]._rotationInParentFrame = glm::quat(); } else { - setJointPosition(jointIndex, palmPosition, palmRotation, - true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); + setJointPosition(jointIndex, palmPosition, palmRotation, + true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); } } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 105301054b..aff023c2a0 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1275,8 +1275,8 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, const gl if (useRotation) { JointState& state = _jointStates[jointIndex]; - state.setRotation(rotation, true, priority); - endRotation = state.getRotation(); + state.setRotationFromBindFrame(rotation, priority); + endRotation = state.getRotationFromBindToModelFrame(); } // then, we go from the joint upwards, rotating the end as close as possible to the target From 589b2e8fb758d8af3872733a9e9a3fdd81a6976e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 9 Jun 2014 16:12:54 -0700 Subject: [PATCH 09/44] recover some code for one less magic vec3 --- interface/src/avatar/SkeletonModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index d5a13b0381..1b1b2e032b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -200,7 +200,7 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { glm::vec3 palmNormal = inverseRotation * palm.getNormal(); glm::vec3 fingerDirection = inverseRotation * palm.getFingerDirection(); - glm::quat palmRotation = rotationBetween(glm::vec3(0.0f, -1.0f, 0.0f), palmNormal); + glm::quat palmRotation = rotationBetween(geometry.palmDirection, palmNormal); palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), fingerDirection) * palmRotation; if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { From 590f045ed1ce8806f964d252042a173c6f15ff12 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 9 Jun 2014 16:51:41 -0700 Subject: [PATCH 10/44] Script value streaming tests, fixes. --- libraries/metavoxels/src/Bitstream.cpp | 9 ++- libraries/metavoxels/src/ScriptCache.cpp | 5 ++ libraries/metavoxels/src/ScriptCache.h | 1 + tests/metavoxels/src/MetavoxelTests.cpp | 88 +++++++++++++++++++++++- tests/metavoxels/src/MetavoxelTests.h | 9 ++- 5 files changed, 106 insertions(+), 6 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index d27053aefb..7595580c33 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -411,7 +411,7 @@ void Bitstream::writeRawDelta(const QScriptValue& value, const QScriptValue& ref *this << value; } } else if (reference.isObject()) { - if (value.isObject()) { + if (value.isObject()) { *this << false; for (QScriptValueIterator it(value); it.hasNext(); ) { it.next(); @@ -1401,14 +1401,17 @@ Bitstream& Bitstream::operator>(AttributePointer& attribute) { return *this; } +const QString INVALID_STRING("%INVALID%"); + Bitstream& Bitstream::operator<(const QScriptString& string) { - return *this << string.toString(); + return *this << (string.isValid() ? string.toString() : INVALID_STRING); } Bitstream& Bitstream::operator>(QScriptString& string) { QString rawString; *this >> rawString; - string = ScriptCache::getInstance()->getEngine()->toStringHandle(rawString); + string = (rawString == INVALID_STRING) ? QScriptString() : + ScriptCache::getInstance()->getEngine()->toStringHandle(rawString); return *this; } diff --git a/libraries/metavoxels/src/ScriptCache.cpp b/libraries/metavoxels/src/ScriptCache.cpp index 9de624fb29..9648a047cb 100644 --- a/libraries/metavoxels/src/ScriptCache.cpp +++ b/libraries/metavoxels/src/ScriptCache.cpp @@ -20,6 +20,7 @@ #include "ScriptCache.h" static int scriptValueMetaTypeId = qRegisterMetaType(); +static bool scriptValueComparators = QMetaType::registerComparators(); bool operator==(const QScriptValue& first, const QScriptValue& second) { if (first.isUndefined()) { @@ -97,6 +98,10 @@ bool operator!=(const QScriptValue& first, const QScriptValue& second) { return !(first == second); } +bool operator<(const QScriptValue& first, const QScriptValue& second) { + return first.lessThan(second); +} + ScriptCache* ScriptCache::getInstance() { static ScriptCache cache; return &cache; diff --git a/libraries/metavoxels/src/ScriptCache.h b/libraries/metavoxels/src/ScriptCache.h index d88a967081..5d29157b3d 100644 --- a/libraries/metavoxels/src/ScriptCache.h +++ b/libraries/metavoxels/src/ScriptCache.h @@ -69,6 +69,7 @@ Q_DECLARE_METATYPE(QScriptValue) bool operator==(const QScriptValue& first, const QScriptValue& second); bool operator!=(const QScriptValue& first, const QScriptValue& second); +bool operator<(const QScriptValue& first, const QScriptValue& second); /// A program loaded from the network. class NetworkProgram : public Resource { diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 81f1840342..4dc1cdddce 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -11,6 +11,8 @@ #include +#include + #include #include @@ -41,6 +43,8 @@ static int streamedBytesReceived = 0; static int sharedObjectsCreated = 0; static int sharedObjectsDestroyed = 0; static int objectMutationsPerformed = 0; +static int scriptObjectsCreated = 0; +static int scriptMutationsPerformed = 0; static QByteArray createRandomBytes(int minimumSize, int maximumSize) { QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0); @@ -79,6 +83,49 @@ static TestSharedObjectA::TestFlags getRandomTestFlags() { return flags; } +static QScriptValue createRandomScriptValue() { + scriptObjectsCreated++; + switch (randIntInRange(0, 3)) { + case 0: + return QScriptValue(QScriptValue::NullValue); + + case 1: + return QScriptValue(randomBoolean()); + + case 2: + return QScriptValue(randFloat()); + + case 3: + default: + return QScriptValue(QString(createRandomBytes())); + + case 4: { + int length = randIntInRange(2, 6); + QScriptValue value = ScriptCache::getInstance()->getEngine()->newArray(length); + for (int i = 0; i < length; i++) { + value.setProperty(i, createRandomScriptValue()); + } + return value; + } + case 5: { + QScriptValue value = ScriptCache::getInstance()->getEngine()->newObject(); + if (randomBoolean()) { + value.setProperty("foo", createRandomScriptValue()); + } + if (randomBoolean()) { + value.setProperty("bar", createRandomScriptValue()); + } + if (randomBoolean()) { + value.setProperty("baz", createRandomScriptValue()); + } + if (randomBoolean()) { + value.setProperty("bong", createRandomScriptValue()); + } + return value; + } + } +} + static TestMessageC createRandomMessageC() { TestMessageC message; message.foo = randomBoolean(); @@ -86,6 +133,7 @@ static TestMessageC createRandomMessageC() { message.baz = randFloat(); message.bong.foo = createRandomBytes(); message.bong.baz = getRandomTestEnum(); + message.bizzle = createRandomScriptValue(); return message; } @@ -201,6 +249,7 @@ bool MetavoxelTests::run() { datagramsReceived << "with" << bytesReceived << "bytes"; qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed; qDebug() << "Performed" << objectMutationsPerformed << "object mutations"; + qDebug() << "Created" << scriptObjectsCreated << "script objects, mutated" << scriptMutationsPerformed; qDebug(); qDebug() << "Running serialization tests..."; @@ -284,7 +333,7 @@ static QVariant createRandomMessage() { } static SharedObjectPointer mutate(const SharedObjectPointer& state) { - switch(randIntInRange(0, 3)) { + switch (randIntInRange(0, 4)) { case 0: { SharedObjectPointer newState = state->clone(true); static_cast(newState.data())->setFoo(randFloat()); @@ -303,6 +352,38 @@ static SharedObjectPointer mutate(const SharedObjectPointer& state) { objectMutationsPerformed++; return newState; } + case 3: { + SharedObjectPointer newState = state->clone(true); + QScriptValue oldValue = static_cast(newState.data())->getBizzle(); + QScriptValue newValue = ScriptCache::getInstance()->getEngine()->newObject(); + for (QScriptValueIterator it(oldValue); it.hasNext(); ) { + it.next(); + newValue.setProperty(it.scriptName(), it.value()); + } + switch (randIntInRange(0, 3)) { + case 0: { + QScriptValue oldArray = oldValue.property("foo"); + int oldLength = oldArray.property(ScriptCache::getInstance()->getLengthString()).toInt32(); + QScriptValue newArray = ScriptCache::getInstance()->getEngine()->newArray(oldLength); + for (int i = 0; i < oldLength; i++) { + newArray.setProperty(i, oldArray.property(i)); + } + newArray.setProperty(randIntInRange(0, oldLength - 1), createRandomScriptValue()); + break; + } + case 1: + newValue.setProperty("bar", QScriptValue(randFloat())); + break; + + default: + newValue.setProperty("baz", createRandomScriptValue()); + break; + } + static_cast(newState.data())->setBizzle(newValue); + scriptMutationsPerformed++; + objectMutationsPerformed++; + return newState; + } default: return state; } @@ -503,7 +584,10 @@ TestSharedObjectA::TestSharedObjectA(float foo, TestEnum baz, TestFlags bong) : _foo(foo), _baz(baz), _bong(bong) { - sharedObjectsCreated++; + sharedObjectsCreated++; + + _bizzle = ScriptCache::getInstance()->getEngine()->newObject(); + _bizzle.setProperty("foo", ScriptCache::getInstance()->getEngine()->newArray(4)); } TestSharedObjectA::~TestSharedObjectA() { diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index 345ea624df..ac9eda2659 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -16,6 +16,7 @@ #include #include +#include class SequencedTestMessage; @@ -96,7 +97,8 @@ class TestSharedObjectA : public SharedObject { Q_PROPERTY(float foo READ getFoo WRITE setFoo NOTIFY fooChanged) Q_PROPERTY(TestEnum baz READ getBaz WRITE setBaz) Q_PROPERTY(TestFlags bong READ getBong WRITE setBong) - + Q_PROPERTY(QScriptValue bizzle READ getBizzle WRITE setBizzle) + public: enum TestEnum { FIRST_TEST_ENUM, SECOND_TEST_ENUM, THIRD_TEST_ENUM }; @@ -116,6 +118,9 @@ public: void setBong(TestFlags bong) { _bong = bong; } TestFlags getBong() const { return _bong; } + void setBizzle(const QScriptValue& bizzle) { _bizzle = bizzle; } + const QScriptValue& getBizzle() const { return _bizzle; } + signals: void fooChanged(float foo); @@ -125,6 +130,7 @@ private: float _foo; TestEnum _baz; TestFlags _bong; + QScriptValue _bizzle; }; DECLARE_ENUM_METATYPE(TestSharedObjectA, TestEnum) @@ -204,6 +210,7 @@ class TestMessageC : STREAM public TestMessageA { public: STREAM TestMessageB bong; + STREAM QScriptValue bizzle; }; DECLARE_STREAMABLE_METATYPE(TestMessageC) From 3293ab788b7340c98fbc923d509b216445362e09 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 9 Jun 2014 17:19:36 -0700 Subject: [PATCH 11/44] Fix for script object deltas. --- libraries/metavoxels/src/Bitstream.cpp | 3 ++- tests/metavoxels/src/MetavoxelTests.cpp | 15 +++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 7595580c33..d7e15a9dd6 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -411,7 +411,8 @@ void Bitstream::writeRawDelta(const QScriptValue& value, const QScriptValue& ref *this << value; } } else if (reference.isObject()) { - if (value.isObject()) { + if (value.isObject() && !(value.isArray() || value.isRegExp() || value.isDate() || + value.isQMetaObject() || value.isQObject() || value.isVariant())) { *this << false; for (QScriptValueIterator it(value); it.hasNext(); ) { it.next(); diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 4dc1cdddce..c7e98ab0cf 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -83,9 +83,9 @@ static TestSharedObjectA::TestFlags getRandomTestFlags() { return flags; } -static QScriptValue createRandomScriptValue() { +static QScriptValue createRandomScriptValue(bool complex = false) { scriptObjectsCreated++; - switch (randIntInRange(0, 3)) { + switch (randIntInRange(0, complex ? 5 : 2)) { case 0: return QScriptValue(QScriptValue::NullValue); @@ -96,7 +96,6 @@ static QScriptValue createRandomScriptValue() { return QScriptValue(randFloat()); case 3: - default: return QScriptValue(QString(createRandomBytes())); case 4: { @@ -107,7 +106,7 @@ static QScriptValue createRandomScriptValue() { } return value; } - case 5: { + default: { QScriptValue value = ScriptCache::getInstance()->getEngine()->newObject(); if (randomBoolean()) { value.setProperty("foo", createRandomScriptValue()); @@ -133,7 +132,7 @@ static TestMessageC createRandomMessageC() { message.baz = randFloat(); message.bong.foo = createRandomBytes(); message.bong.baz = getRandomTestEnum(); - message.bizzle = createRandomScriptValue(); + message.bizzle = createRandomScriptValue(true); return message; } @@ -360,7 +359,7 @@ static SharedObjectPointer mutate(const SharedObjectPointer& state) { it.next(); newValue.setProperty(it.scriptName(), it.value()); } - switch (randIntInRange(0, 3)) { + switch (randIntInRange(0, 2)) { case 0: { QScriptValue oldArray = oldValue.property("foo"); int oldLength = oldArray.property(ScriptCache::getInstance()->getLengthString()).toInt32(); @@ -368,7 +367,7 @@ static SharedObjectPointer mutate(const SharedObjectPointer& state) { for (int i = 0; i < oldLength; i++) { newArray.setProperty(i, oldArray.property(i)); } - newArray.setProperty(randIntInRange(0, oldLength - 1), createRandomScriptValue()); + newArray.setProperty(randIntInRange(0, oldLength - 1), createRandomScriptValue(true)); break; } case 1: @@ -376,7 +375,7 @@ static SharedObjectPointer mutate(const SharedObjectPointer& state) { break; default: - newValue.setProperty("baz", createRandomScriptValue()); + newValue.setProperty("baz", createRandomScriptValue(true)); break; } static_cast(newState.data())->setBizzle(newValue); From d1549b00abffccc56dfad0951302054a15e71521 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 9 Jun 2014 17:22:44 -0700 Subject: [PATCH 12/44] Might as well include strings in the "simple" random script objects. --- tests/metavoxels/src/MetavoxelTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index c7e98ab0cf..6ec2331b14 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -85,7 +85,7 @@ static TestSharedObjectA::TestFlags getRandomTestFlags() { static QScriptValue createRandomScriptValue(bool complex = false) { scriptObjectsCreated++; - switch (randIntInRange(0, complex ? 5 : 2)) { + switch (randIntInRange(0, complex ? 5 : 3)) { case 0: return QScriptValue(QScriptValue::NullValue); From de61029f05923fb32f700037b2c815db51008431 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 17:30:09 -0700 Subject: [PATCH 13/44] Added dev menu option to disable nack packets --- interface/src/Application.cpp | 6 +++++- interface/src/Menu.cpp | 2 ++ interface/src/Menu.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 574df09ee2..22fe5887fd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2099,7 +2099,7 @@ void Application::updateMyAvatar(float deltaTime) { { quint64 now = usecTimestampNow(); quint64 sinceLastNack = now - _lastNackTime; - const quint64 TOO_LONG_SINCE_LAST_NACK = 250 * MSECS_PER_SECOND; + const quint64 TOO_LONG_SINCE_LAST_NACK = 1 * USECS_PER_SECOND; if (sinceLastNack > TOO_LONG_SINCE_LAST_NACK) { _lastNackTime = now; sendNack(); @@ -2109,6 +2109,10 @@ void Application::updateMyAvatar(float deltaTime) { void Application::sendNack() { + if (Menu::getInstance()->isOptionChecked(MenuOption::NackDisable)) { + return; + } + char packet[MAX_PACKET_SIZE]; NodeList* nodeList = NodeList::getInstance(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9ab47cdeda..9381790a42 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -393,6 +393,8 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::NackDisable, 0, false); + addDisabledActionAndSeparator(developerMenu, "Testing"); QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index f9af80119b..e1bbb382aa 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -373,6 +373,7 @@ namespace MenuOption { const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; + const QString NackDisable = "Disable NACK Packets"; const QString NameLocation = "Name this location"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString OctreeStats = "Voxel and Particle Statistics"; From 4665df4d1fd9f314a1c743a92abb5efb7419cffb Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 17:41:20 -0700 Subject: [PATCH 14/44] nackdisable to disablenack --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 22fe5887fd..3ed2d84df7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2109,7 +2109,7 @@ void Application::updateMyAvatar(float deltaTime) { void Application::sendNack() { - if (Menu::getInstance()->isOptionChecked(MenuOption::NackDisable)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::DisableNack)) { return; } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9381790a42..be5dd13d1c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -393,7 +393,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); - addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::NackDisable, 0, false); + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNack, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index e1bbb382aa..19e7ef98e2 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -320,6 +320,7 @@ namespace MenuOption { const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; + const QString DisableNack = "Disable NACK Packets"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; @@ -373,7 +374,6 @@ namespace MenuOption { const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; - const QString NackDisable = "Disable NACK Packets"; const QString NameLocation = "Name this location"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString OctreeStats = "Voxel and Particle Statistics"; From ffda98fe0b160083f7ab3bea64811f8271350a9f Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 17:50:29 -0700 Subject: [PATCH 15/44] var name change again --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3ed2d84df7..3cfec3190e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2109,7 +2109,7 @@ void Application::updateMyAvatar(float deltaTime) { void Application::sendNack() { - if (Menu::getInstance()->isOptionChecked(MenuOption::DisableNack)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { return; } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index be5dd13d1c..42874ea02e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -393,7 +393,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); - addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNack, 0, false); + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 19e7ef98e2..03ffa0b848 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -320,7 +320,7 @@ namespace MenuOption { const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; - const QString DisableNack = "Disable NACK Packets"; + const QString DisableNackPackets = "Disable NACK Packets"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; From b4e984086505814cbc426226777b74a113da8362 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Mon, 9 Jun 2014 23:15:45 -0400 Subject: [PATCH 16/44] Job #19766 BUG: Stop or reload all scripts crashes interface fix, part 2. Keep the scriptUrl internal to the ScriptEngine class and refer to it externally by the file name string. Change the ScriptEngine constructor to accept a filename QString, instead of a QUrl. Resolve constructor ambiguity in Particle, which creates anonymous ScriptEngine. --- interface/src/Application.cpp | 5 ++--- libraries/particles/src/Particle.cpp | 6 +++--- libraries/script-engine/src/ScriptEngine.cpp | 12 +++++------- libraries/script-engine/src/ScriptEngine.h | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9fb821bff4..3ec5588c61 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3492,9 +3492,8 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface); } else { // start the script on a new thread... - QUrl scriptUrl(scriptName); - scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface); - _scriptEnginesHash.insert(scriptUrl.toString(), scriptEngine); + scriptEngine = new ScriptEngine(scriptName, &_controllerScriptingInterface); + _scriptEnginesHash.insert(scriptName, scriptEngine); if (!scriptEngine->hasScript()) { qDebug() << "Application::loadScript(), script failed to load..."; diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 59265c00dc..90e59b9422 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -873,7 +873,7 @@ void Particle::endParticleScriptContext(ScriptEngine& engine, ParticleScriptObje void Particle::executeUpdateScripts() { // Only run this particle script if there's a script attached directly to the particle. if (!_script.isEmpty()) { - ScriptEngine engine(_script); + ScriptEngine engine(_script, QString("")); ParticleScriptObject particleScriptable(this); startParticleScriptContext(engine, particleScriptable); particleScriptable.emitUpdate(); @@ -884,7 +884,7 @@ void Particle::executeUpdateScripts() { void Particle::collisionWithParticle(Particle* other, const glm::vec3& penetration) { // Only run this particle script if there's a script attached directly to the particle. if (!_script.isEmpty()) { - ScriptEngine engine(_script); + ScriptEngine engine(_script, QString("")); ParticleScriptObject particleScriptable(this); startParticleScriptContext(engine, particleScriptable); ParticleScriptObject otherParticleScriptable(other); @@ -896,7 +896,7 @@ void Particle::collisionWithParticle(Particle* other, const glm::vec3& penetrati void Particle::collisionWithVoxel(VoxelDetail* voxelDetails, const glm::vec3& penetration) { // Only run this particle script if there's a script attached directly to the particle. if (!_script.isEmpty()) { - ScriptEngine engine(_script); + ScriptEngine engine(_script, QString("")); ParticleScriptObject particleScriptable(this); startParticleScriptContext(engine, particleScriptable); particleScriptable.emitCollisionWithVoxel(*voxelDetails, penetration); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index a4aae61248..025f316d29 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -93,7 +93,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam { } -ScriptEngine::ScriptEngine(const QUrl& scriptURL, +ScriptEngine::ScriptEngine(const QString& fileNameString, AbstractControllerScriptingInterface* controllerScriptingInterface) : _scriptContents(), _isFinished(false), @@ -110,21 +110,19 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, _controllerScriptingInterface(controllerScriptingInterface), _avatarData(NULL), _scriptName(), - _fileNameString(), + _fileNameString(fileNameString), _quatLibrary(), _vec3Library(), _uuidLibrary(), _animationCache(this) { - QString scriptURLString = scriptURL.toString(); - _fileNameString = scriptURLString; - - QUrl url(scriptURL); + QUrl url(fileNameString); + QString scriptUrlString = url.toString(); // if the scheme length is one or lower, maybe they typed in a file, let's try const int WINDOWS_DRIVE_LETTER_SIZE = 1; if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { - url = QUrl::fromLocalFile(scriptURLString); + url = QUrl::fromLocalFile(scriptUrlString); } // ok, let's see if it's valid... and if so, load it diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index bf2ac40568..f88017515e 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -40,7 +40,7 @@ const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 10 class ScriptEngine : public QObject { Q_OBJECT public: - ScriptEngine(const QUrl& scriptURL, + ScriptEngine(const QString& fileNameString, AbstractControllerScriptingInterface* controllerScriptingInterface = NULL); ScriptEngine(const QString& scriptContents = NO_SCRIPT, From c9ba71aa015ef86d2a9fc89effbd77a18cbebb4a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 10 Jun 2014 09:38:38 -0700 Subject: [PATCH 17/44] fix for broken neck on some body models --- interface/src/avatar/FaceModel.cpp | 2 +- interface/src/avatar/SkeletonModel.cpp | 10 ++++++++-- interface/src/avatar/SkeletonModel.h | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 601dad5563..c3f31ff6e7 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -30,7 +30,7 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { } setTranslation(neckPosition); glm::quat neckParentRotation; - if (!owningAvatar->getSkeletonModel().getNeckParentRotation(neckParentRotation)) { + if (!owningAvatar->getSkeletonModel().getNeckParentRotationFromDefaultOrientation(neckParentRotation)) { neckParentRotation = owningAvatar->getOrientation(); } setRotation(neckParentRotation); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 1b1b2e032b..576545f115 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -434,7 +434,7 @@ bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const { return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); } -bool SkeletonModel::getNeckParentRotation(glm::quat& neckParentRotation) const { +bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckParentRotation) const { if (!isActive()) { return false; } @@ -442,7 +442,13 @@ bool SkeletonModel::getNeckParentRotation(glm::quat& neckParentRotation) const { if (geometry.neckJointIndex == -1) { return false; } - return getJointRotationInWorldFrame(geometry.joints.at(geometry.neckJointIndex).parentIndex, neckParentRotation); + int parentIndex = geometry.joints.at(geometry.neckJointIndex).parentIndex; + glm::quat worldFrameRotation; + if (getJointRotationInWorldFrame(parentIndex, worldFrameRotation)) { + neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation; + return true; + } + return false; } bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 086973807d..3b8e67df47 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -86,9 +86,9 @@ public: /// \return whether or not the neck was found bool getNeckPosition(glm::vec3& neckPosition) const; - /// Returns the rotation of the neck joint's parent. + /// Returns the rotation of the neck joint's parent from default orientation /// \return whether or not the neck was found - bool getNeckParentRotation(glm::quat& neckRotation) const; + bool getNeckParentRotationFromDefaultOrientation(glm::quat& neckParentRotation) const; /// Retrieve the positions of up to two eye meshes. /// \return whether or not both eye meshes were found From d84beee3e49699454f4b44414ec11910ccf12204 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 10 Jun 2014 11:05:51 -0700 Subject: [PATCH 18/44] VoxelPacketProcessor -> OctreePacketProcessor added nodes bookkeeping in ReceivedPacketProcessor; added check in sendNack() to not send NACKs to nodes that have sent packets that are waiting in the message queue. --- interface/src/Application.cpp | 14 ++++++++++---- interface/src/Application.h | 8 ++++---- interface/src/DatagramProcessor.cpp | 4 ++-- interface/src/ui/ApplicationOverlay.cpp | 4 ++-- ...etProcessor.cpp => OctreePacketProcessor.cpp} | 10 +++++----- ...PacketProcessor.h => OctreePacketProcessor.h} | 10 +++++----- libraries/networking/src/NetworkPacket.cpp | 16 ++++++++-------- libraries/networking/src/NetworkPacket.h | 8 ++++---- libraries/networking/src/PacketSender.cpp | 2 +- .../networking/src/ReceivedPacketProcessor.cpp | 10 ++++++---- .../networking/src/ReceivedPacketProcessor.h | 11 +++++++++-- 11 files changed, 56 insertions(+), 41 deletions(-) rename interface/src/voxels/{VoxelPacketProcessor.cpp => OctreePacketProcessor.cpp} (92%) rename interface/src/voxels/{VoxelPacketProcessor.h => OctreePacketProcessor.h} (76%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3cfec3190e..9f62742e6c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -158,7 +158,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _mousePressed(false), _audio(STARTUP_JITTER_SAMPLES), _enableProcessVoxelsThread(true), - _voxelProcessor(), + _octreeProcessor(), _voxelHideShowThread(&_voxels), _packetsPerSecond(0), _bytesPerSecond(0), @@ -418,7 +418,7 @@ Application::~Application() { _audio.thread()->quit(); _audio.thread()->wait(); - _voxelProcessor.terminate(); + _octreeProcessor.terminate(); _voxelHideShowThread.terminate(); _voxelEditSender.terminate(); _particleEditSender.terminate(); @@ -517,7 +517,7 @@ void Application::initializeGL() { qDebug( "init() complete."); // create thread for parsing of voxel data independent of the main network and rendering threads - _voxelProcessor.initialize(_enableProcessVoxelsThread); + _octreeProcessor.initialize(_enableProcessVoxelsThread); _voxelEditSender.initialize(_enableProcessVoxelsThread); _voxelHideShowThread.initialize(_enableProcessVoxelsThread); _particleEditSender.initialize(_enableProcessVoxelsThread); @@ -1884,7 +1884,7 @@ void Application::updateThreads(float deltaTime) { // parse voxel packets if (!_enableProcessVoxelsThread) { - _voxelProcessor.threadRoutine(); + _octreeProcessor.threadRoutine(); _voxelHideShowThread.threadRoutine(); _voxelEditSender.threadRoutine(); _particleEditSender.threadRoutine(); @@ -2125,6 +2125,12 @@ void Application::sendNack() { || node->getType() == NodeType::ModelServer) ) { + // if there are octree packets from this node that are waiting to be processed, + // don't send a NACK since the missing packets may be among those waiting packets. + if (_octreeProcessor.hasPacketsToProcessFrom(node)) { + continue; + } + QUuid nodeUUID = node->getUUID(); _octreeSceneStatsLock.lockForRead(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 170be43493..2889dcb301 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -88,7 +88,7 @@ #include "voxels/VoxelFade.h" #include "voxels/VoxelHideShowThread.h" #include "voxels/VoxelImporter.h" -#include "voxels/VoxelPacketProcessor.h" +#include "voxels/OctreePacketProcessor.h" #include "voxels/VoxelSystem.h" @@ -129,7 +129,7 @@ static const float MIRROR_FIELD_OF_VIEW = 30.0f; class Application : public QApplication { Q_OBJECT - friend class VoxelPacketProcessor; + friend class OctreePacketProcessor; friend class VoxelEditPacketSender; friend class DatagramProcessor; @@ -192,7 +192,7 @@ public: ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } VoxelTree* getVoxelTree() { return _voxels.getTree(); } - const VoxelPacketProcessor& getVoxelPacketProcessor() const { return _voxelProcessor; } + const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; } ParticleTreeRenderer* getParticles() { return &_particles; } MetavoxelSystem* getMetavoxels() { return &_metavoxels; } ModelTreeRenderer* getModels() { return &_models; } @@ -533,7 +533,7 @@ private: Audio _audio; bool _enableProcessVoxelsThread; - VoxelPacketProcessor _voxelProcessor; + OctreePacketProcessor _octreeProcessor; VoxelHideShowThread _voxelHideShowThread; VoxelEditPacketSender _voxelEditSender; ParticleEditPacketSender _particleEditSender; diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 56078c1a8d..cdd7e7ef0f 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -71,7 +71,7 @@ void DatagramProcessor::processDatagrams() { case PacketTypeOctreeStats: case PacketTypeEnvironmentData: { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::networkReceive()... _voxelProcessor.queueReceivedPacket()"); + "Application::networkReceive()... _octreeProcessor.queueReceivedPacket()"); bool wantExtraDebugging = application->getLogger()->extraDebugging(); if (wantExtraDebugging && packetTypeForPacket(incomingPacket) == PacketTypeVoxelData) { @@ -92,7 +92,7 @@ void DatagramProcessor::processDatagrams() { if (matchedNode) { // add this packet to our list of voxel packets and process them on the voxel processing - application->_voxelProcessor.queueReceivedPacket(matchedNode, incomingPacket); + application->_octreeProcessor.queueReceivedPacket(matchedNode, incomingPacket); } break; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 49ec8ecddb..ec2d6c73b3 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -45,7 +45,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { QGLWidget* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); Audio* audio = application->getAudio(); - const VoxelPacketProcessor& voxelPacketProcessor = application->getVoxelPacketProcessor(); + const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor(); BandwidthMeter* bandwidthMeter = application->getBandwidthMeter(); NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay(); @@ -200,7 +200,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { // let's set horizontal offset to give stats some margin to mirror int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; - int voxelPacketsToProcess = voxelPacketProcessor.packetsToProcessCount(); + int voxelPacketsToProcess = octreePacketProcessor.packetsToProcessCount(); // Onscreen text about position, servers, etc Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, application->getFps(), application->getPacketsPerSecond(), application->getBytesPerSecond(), voxelPacketsToProcess); // Bandwidth meter diff --git a/interface/src/voxels/VoxelPacketProcessor.cpp b/interface/src/voxels/OctreePacketProcessor.cpp similarity index 92% rename from interface/src/voxels/VoxelPacketProcessor.cpp rename to interface/src/voxels/OctreePacketProcessor.cpp index 095c378c04..66190a5689 100644 --- a/interface/src/voxels/VoxelPacketProcessor.cpp +++ b/interface/src/voxels/OctreePacketProcessor.cpp @@ -1,5 +1,5 @@ // -// VoxelPacketProcessor.cpp +// OctreePacketProcessor.cpp // interface/src/voxels // // Created by Brad Hefta-Gaub on 8/12/13. @@ -13,18 +13,18 @@ #include "Application.h" #include "Menu.h" -#include "VoxelPacketProcessor.h" +#include "OctreePacketProcessor.h" -void VoxelPacketProcessor::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) { +void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "VoxelPacketProcessor::processPacket()"); + "OctreePacketProcessor::processPacket()"); QByteArray mutablePacket = packet; const int WAY_BEHIND = 300; if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) { - qDebug("VoxelPacketProcessor::processPacket() packets to process=%d", packetsToProcessCount()); + qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount()); } ssize_t messageLength = mutablePacket.size(); diff --git a/interface/src/voxels/VoxelPacketProcessor.h b/interface/src/voxels/OctreePacketProcessor.h similarity index 76% rename from interface/src/voxels/VoxelPacketProcessor.h rename to interface/src/voxels/OctreePacketProcessor.h index 36456c5cc2..bdf25806f3 100644 --- a/interface/src/voxels/VoxelPacketProcessor.h +++ b/interface/src/voxels/OctreePacketProcessor.h @@ -1,5 +1,5 @@ // -// VoxelPacketProcessor.h +// OctreePacketProcessor.h // interface/src/voxels // // Created by Brad Hefta-Gaub on 8/12/13. @@ -9,16 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_VoxelPacketProcessor_h -#define hifi_VoxelPacketProcessor_h +#ifndef hifi_OctreePacketProcessor_h +#define hifi_OctreePacketProcessor_h #include /// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes /// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() -class VoxelPacketProcessor : public ReceivedPacketProcessor { +class OctreePacketProcessor : public ReceivedPacketProcessor { Q_OBJECT protected: virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); }; -#endif // hifi_VoxelPacketProcessor_h +#endif // hifi_OctreePacketProcessor_h diff --git a/libraries/networking/src/NetworkPacket.cpp b/libraries/networking/src/NetworkPacket.cpp index bf18aa9b37..f9d6c7ea7b 100644 --- a/libraries/networking/src/NetworkPacket.cpp +++ b/libraries/networking/src/NetworkPacket.cpp @@ -17,9 +17,9 @@ #include "NetworkPacket.h" -void NetworkPacket::copyContents(const SharedNodePointer& destinationNode, const QByteArray& packet) { +void NetworkPacket::copyContents(const SharedNodePointer& sendingNode, const QByteArray& packet) { if (packet.size() && packet.size() <= MAX_PACKET_SIZE) { - _destinationNode = destinationNode; + _sendingNode = sendingNode; _byteArray = packet; } else { qDebug(">>> NetworkPacket::copyContents() unexpected length = %d", packet.size()); @@ -27,28 +27,28 @@ void NetworkPacket::copyContents(const SharedNodePointer& destinationNode, const } NetworkPacket::NetworkPacket(const NetworkPacket& packet) { - copyContents(packet.getDestinationNode(), packet.getByteArray()); + copyContents(packet.getSendingNode(), packet.getByteArray()); } -NetworkPacket::NetworkPacket(const SharedNodePointer& destinationNode, const QByteArray& packet) { - copyContents(destinationNode, packet); +NetworkPacket::NetworkPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) { + copyContents(sendingNode, packet); }; // copy assignment NetworkPacket& NetworkPacket::operator=(NetworkPacket const& other) { - copyContents(other.getDestinationNode(), other.getByteArray()); + copyContents(other.getSendingNode(), other.getByteArray()); return *this; } #ifdef HAS_MOVE_SEMANTICS // move, same as copy, but other packet won't be used further NetworkPacket::NetworkPacket(NetworkPacket && packet) { - copyContents(packet.getDestinationNode(), packet.getByteArray()); + copyContents(packet.getSendingNode(), packet.getByteArray()); } // move assignment NetworkPacket& NetworkPacket::operator=(NetworkPacket&& other) { - copyContents(other.getDestinationNode(), other.getByteArray()); + copyContents(other.getSendingNode(), other.getByteArray()); return *this; } #endif diff --git a/libraries/networking/src/NetworkPacket.h b/libraries/networking/src/NetworkPacket.h index 94ddf8d56e..deb4cb9fb9 100644 --- a/libraries/networking/src/NetworkPacket.h +++ b/libraries/networking/src/NetworkPacket.h @@ -34,15 +34,15 @@ public: NetworkPacket& operator= (NetworkPacket&& other); // move assignment #endif - NetworkPacket(const SharedNodePointer& destinationNode, const QByteArray& byteArray); + NetworkPacket(const SharedNodePointer& sendingNode, const QByteArray& byteArray); - const SharedNodePointer& getDestinationNode() const { return _destinationNode; } + const SharedNodePointer& getSendingNode() const { return _sendingNode; } const QByteArray& getByteArray() const { return _byteArray; } private: - void copyContents(const SharedNodePointer& destinationNode, const QByteArray& byteArray); + void copyContents(const SharedNodePointer& sendingNode, const QByteArray& byteArray); - SharedNodePointer _destinationNode; + SharedNodePointer _sendingNode; QByteArray _byteArray; }; diff --git a/libraries/networking/src/PacketSender.cpp b/libraries/networking/src/PacketSender.cpp index 5f7502a738..ae844d4f99 100644 --- a/libraries/networking/src/PacketSender.cpp +++ b/libraries/networking/src/PacketSender.cpp @@ -271,7 +271,7 @@ bool PacketSender::nonThreadedProcess() { unlock(); // send the packet through the NodeList... - NodeList::getInstance()->writeDatagram(temporary.getByteArray(), temporary.getDestinationNode()); + NodeList::getInstance()->writeDatagram(temporary.getByteArray(), temporary.getSendingNode()); packetsSentThisCall++; _packetsOverCheckInterval++; _totalPacketsSent++; diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index d54e165285..ea613082ce 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -17,13 +17,14 @@ void ReceivedPacketProcessor::terminating() { _hasPackets.wakeAll(); } -void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& destinationNode, const QByteArray& packet) { +void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) { // Make sure our Node and NodeList knows we've heard from this node. - destinationNode->setLastHeardMicrostamp(usecTimestampNow()); + sendingNode->setLastHeardMicrostamp(usecTimestampNow()); - NetworkPacket networkPacket(destinationNode, packet); + NetworkPacket networkPacket(sendingNode, packet); lock(); _packets.push_back(networkPacket); + _nodePacketCounts[sendingNode->getUUID()]++; unlock(); // Make sure to wake our actual processing thread because we now have packets for it to process. @@ -42,8 +43,9 @@ bool ReceivedPacketProcessor::process() { NetworkPacket& packet = _packets.front(); // get the oldest packet NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us _packets.erase(_packets.begin()); // remove the oldest packet + _nodePacketCounts[temporary.getSendingNode()->getUUID()]--; unlock(); // let others add to the packets - processPacket(temporary.getDestinationNode(), temporary.getByteArray()); // process our temporary copy + processPacket(temporary.getSendingNode(), temporary.getByteArray()); // process our temporary copy } return isStillRunning(); // keep running till they terminate us } diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index f8306b4896..dea7448af1 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -28,11 +28,16 @@ public: /// \param packetData pointer to received data /// \param ssize_t packetLength size of received data /// \thread network receive thread - void queueReceivedPacket(const SharedNodePointer& destinationNode, const QByteArray& packet); + void queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); /// Are there received packets waiting to be processed bool hasPacketsToProcess() const { return _packets.size() > 0; } + /// Are there received packets waiting to be processed from a certain node + bool hasPacketsToProcessFrom(const SharedNodePointer& sendingNode) const { + return _nodePacketCounts[sendingNode->getUUID()] > 0; + } + /// How many received packets waiting are to be processed int packetsToProcessCount() const { return _packets.size(); } @@ -51,7 +56,9 @@ protected: private: - std::vector _packets; + QVector _packets; + QHash _nodePacketCounts; + QWaitCondition _hasPackets; QMutex _waitingOnPacketsMutex; }; From b96b6c9857086c811b50b1d231b67d0b1c87127b Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 10 Jun 2014 12:24:47 -0700 Subject: [PATCH 19/44] added default constructor for NetworkPacket updated param comments in ReceivedPacketProcessor --- interface/src/Application.cpp | 2 +- libraries/networking/src/NetworkPacket.h | 1 + libraries/networking/src/ReceivedPacketProcessor.h | 6 ++---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9f62742e6c..eab15ed678 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2095,7 +2095,7 @@ void Application::updateMyAvatar(float deltaTime) { } } - // sent a nack packet containing missing sequence numbers of received packets + // sent nack packets containing missing sequence numbers of received packets from nodes { quint64 now = usecTimestampNow(); quint64 sinceLastNack = now - _lastNackTime; diff --git a/libraries/networking/src/NetworkPacket.h b/libraries/networking/src/NetworkPacket.h index deb4cb9fb9..52e8a36712 100644 --- a/libraries/networking/src/NetworkPacket.h +++ b/libraries/networking/src/NetworkPacket.h @@ -26,6 +26,7 @@ /// Storage of not-yet processed inbound, or not yet sent outbound generic UDP network packet class NetworkPacket { public: + NetworkPacket() { } NetworkPacket(const NetworkPacket& packet); // copy constructor NetworkPacket& operator= (const NetworkPacket& other); // copy assignment diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index dea7448af1..096005ffe7 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -43,10 +43,8 @@ public: protected: /// Callback for processing of recieved packets. Implement this to process the incoming packets. - /// \param sockaddr& senderAddress the address of the sender - /// \param packetData pointer to received data - /// \param ssize_t packetLength size of received data - /// \thread "this" individual processing thread + /// \param SharedNodePointer& sendingNode the node that sent this packet + /// \param QByteArray& the packet to be processed virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) = 0; /// Implements generic processing behavior for this thread. From 0ae7411bf0ccb59bb4340989968c77700fbe0e9b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 10 Jun 2014 13:37:53 -0700 Subject: [PATCH 20/44] fix some bugs in models --- interface/src/models/ModelTreeRenderer.cpp | 193 +++++++++++++-------- libraries/models/src/ModelTreeElement.cpp | 5 + 2 files changed, 124 insertions(+), 74 deletions(-) diff --git a/interface/src/models/ModelTreeRenderer.cpp b/interface/src/models/ModelTreeRenderer.cpp index 68bebd7b99..b20bdce8f5 100644 --- a/interface/src/models/ModelTreeRenderer.cpp +++ b/interface/src/models/ModelTreeRenderer.cpp @@ -57,21 +57,29 @@ void ModelTreeRenderer::render(RenderMode renderMode) { const FBXGeometry* ModelTreeRenderer::getGeometryForModel(const ModelItem& modelItem) { const FBXGeometry* result = NULL; + Model* model = getModel(modelItem); if (model) { result = &model->getGeometry()->getFBXGeometry(); - } return result; } Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) { Model* model = NULL; - + if (modelItem.isKnownID()) { if (_knownModelsItemModels.find(modelItem.getID()) != _knownModelsItemModels.end()) { model = _knownModelsItemModels[modelItem.getID()]; } else { + + // Make sure we only create new models on the thread that owns the ModelTreeRenderer + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "getModel", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(Model*, model), Q_ARG(const ModelItem&, modelItem)); + return model; + } + model = new Model(); model->init(); model->setURL(QUrl(modelItem.getModelURL())); @@ -81,6 +89,13 @@ Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) { if (_unknownModelsItemModels.find(modelItem.getCreatorTokenID()) != _unknownModelsItemModels.end()) { model = _unknownModelsItemModels[modelItem.getCreatorTokenID()]; } else { + // Make sure we only create new models on the thread that owns the ModelTreeRenderer + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "getModel", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(Model*, model), Q_ARG(const ModelItem&, modelItem)); + return model; + } + model = new Model(); model->init(); model->setURL(QUrl(modelItem.getModelURL())); @@ -187,92 +202,122 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) if (drawAsModel) { glPushMatrix(); + { const float alpha = 1.0f; Model* model = getModel(modelItem); - - model->setScaleToFit(true, radius * 2.0f); - model->setSnapModelToCenter(true); - - // set the rotation - glm::quat rotation = modelItem.getModelRotation(); - model->setRotation(rotation); - - // set the position - model->setTranslation(position); - // handle animations.. - if (modelItem.hasAnimation()) { - if (!modelItem.jointsMapped()) { - QStringList modelJointNames = model->getJointNames(); - modelItem.mapJoints(modelJointNames); + if (model) { + model->setScaleToFit(true, radius * 2.0f); + model->setSnapModelToCenter(true); + + // set the rotation + glm::quat rotation = modelItem.getModelRotation(); + model->setRotation(rotation); + + // set the position + model->setTranslation(position); + + // handle animations.. + if (modelItem.hasAnimation()) { + if (!modelItem.jointsMapped()) { + QStringList modelJointNames = model->getJointNames(); + modelItem.mapJoints(modelJointNames); + } + + QVector frameData = modelItem.getAnimationFrame(); + for (int i = 0; i < frameData.size(); i++) { + model->setJointState(i, true, frameData[i]); + } + } + + // make sure to simulate so everything gets set up correctly for rendering + model->simulate(0.0f); + + // TODO: should we allow modelItems to have alpha on their models? + Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE + ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + + if (modelItem.getGlowLevel() > 0.0f) { + Glower glower(modelItem.getGlowLevel()); + + if (model->isActive()) { + model->render(alpha, modelRenderMode); + } else { + // if we couldn't get a model, then just draw a sphere + glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]); + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glutSolidSphere(radius, 15, 15); + glPopMatrix(); + } + } else { + if (model->isActive()) { + model->render(alpha, modelRenderMode); + } else { + // if we couldn't get a model, then just draw a sphere + glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]); + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glutSolidSphere(radius, 15, 15); + glPopMatrix(); + } } - QVector frameData = modelItem.getAnimationFrame(); - for (int i = 0; i < frameData.size(); i++) { - model->setJointState(i, true, frameData[i]); - } - } - - // make sure to simulate so everything gets set up correctly for rendering - model->simulate(0.0f); + if (!isShadowMode && displayModelBounds) { - // TODO: should we allow modelItems to have alpha on their models? - Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE - ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; - - if (modelItem.getGlowLevel() > 0.0f) { - Glower glower(modelItem.getGlowLevel()); - model->render(alpha, modelRenderMode); + glm::vec3 unRotatedMinimum = model->getUnscaledMeshExtents().minimum; + glm::vec3 unRotatedMaximum = model->getUnscaledMeshExtents().maximum; + glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum; + + float width = unRotatedExtents.x; + float height = unRotatedExtents.y; + float depth = unRotatedExtents.z; + + Extents rotatedExtents = model->getUnscaledMeshExtents(); + calculateRotatedExtents(rotatedExtents, rotation); + + glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum; + + const glm::vec3& modelScale = model->getScale(); + + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + + // draw the orignal bounding cube + glColor4f(1.0f, 1.0f, 0.0f, 1.0f); + glutWireCube(size); + + // draw the rotated bounding cube + glColor4f(0.0f, 0.0f, 1.0f, 1.0f); + glPushMatrix(); + glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z); + glutWireCube(1.0); + glPopMatrix(); + + // draw the model relative bounding box + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z); + glColor3f(0.0f, 1.0f, 0.0f); + glutWireCube(1.0); + + glPopMatrix(); + + } } else { - model->render(alpha, modelRenderMode); - } - - if (!isShadowMode && displayModelBounds) { - - glm::vec3 unRotatedMinimum = model->getUnscaledMeshExtents().minimum; - glm::vec3 unRotatedMaximum = model->getUnscaledMeshExtents().maximum; - glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum; - - float width = unRotatedExtents.x; - float height = unRotatedExtents.y; - float depth = unRotatedExtents.z; - - Extents rotatedExtents = model->getUnscaledMeshExtents(); - calculateRotatedExtents(rotatedExtents, rotation); - - glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum; - - const glm::vec3& modelScale = model->getScale(); - + // if we couldn't get a model, then just draw a sphere + glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]); glPushMatrix(); glTranslatef(position.x, position.y, position.z); - - // draw the orignal bounding cube - glColor4f(1.0f, 1.0f, 0.0f, 1.0f); - glutWireCube(size); - - // draw the rotated bounding cube - glColor4f(0.0f, 0.0f, 1.0f, 1.0f); - glPushMatrix(); - glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z); - glutWireCube(1.0); - glPopMatrix(); - - // draw the model relative bounding box - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z); - glColor3f(0.0f, 1.0f, 0.0f); - glutWireCube(1.0); - + glutSolidSphere(radius, 15, 15); glPopMatrix(); - } - + } glPopMatrix(); } else { - glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]); + //glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]); + glColor3f(1.0f, 0.0f, 0.0f); glPushMatrix(); glTranslatef(position.x, position.y, position.z); glutSolidSphere(radius, 15, 15); diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index b0c7e125b4..75b9670d0f 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -186,6 +186,11 @@ bool ModelTreeElement::findDetailedRayIntersection(const glm::vec3& origin, cons if (fbxGeometry && fbxGeometry->meshExtents.isValid()) { Extents extents = fbxGeometry->meshExtents; + // NOTE: If the model has a bad mesh, then extents will be 0,0,0 & 0,0,0 + if (extents.minimum == extents.maximum && extents.minimum == glm::vec3(0,0,0)) { + extents.maximum = glm::vec3(1.0f,1.0f,1.0f); // in this case we will simulate the unit cube + } + // NOTE: these extents are model space, so we need to scale and center them accordingly // size is our "target size in world space" // we need to set our model scale so that the extents of the mesh, fit in a cube that size... From 5ab271330e0d9a768adc1685e069b5a7560febd1 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 10 Jun 2014 15:35:48 -0700 Subject: [PATCH 21/44] moved sendNack() into packetDistributor() ...for the purpose of enforcing packets sent per interval in OctreeSendThread. Corrected mistake in keeping track of number of special packets sent where sendSpecialPacket() was assumed to only send one packet per call. --- assignment-client/src/models/ModelServer.cpp | 4 +- assignment-client/src/models/ModelServer.h | 2 +- .../src/octree/OctreeSendThread.cpp | 49 +++++++++---------- .../src/octree/OctreeSendThread.h | 3 -- assignment-client/src/octree/OctreeServer.h | 2 +- .../src/particles/ParticleServer.cpp | 4 +- .../src/particles/ParticleServer.h | 2 +- assignment-client/src/voxels/VoxelServer.cpp | 3 +- assignment-client/src/voxels/VoxelServer.h | 2 +- 9 files changed, 34 insertions(+), 37 deletions(-) diff --git a/assignment-client/src/models/ModelServer.cpp b/assignment-client/src/models/ModelServer.cpp index 07359f001a..ae6ffaf969 100644 --- a/assignment-client/src/models/ModelServer.cpp +++ b/assignment-client/src/models/ModelServer.cpp @@ -86,7 +86,7 @@ bool ModelServer::hasSpecialPacketToSend(const SharedNodePointer& node) { return shouldSendDeletedModels; } -int ModelServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node) { +int ModelServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { unsigned char outputBuffer[MAX_PACKET_SIZE]; size_t packetLength = 0; @@ -99,6 +99,7 @@ int ModelServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodeP bool hasMoreToSend = true; // TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 models? + packetsSent = 0; while (hasMoreToSend) { hasMoreToSend = tree->encodeModelsDeletedSince(queryNode->getSequenceNumber(), deletedModelsSentAt, outputBuffer, MAX_PACKET_SIZE, packetLength); @@ -107,6 +108,7 @@ int ModelServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodeP NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node)); queryNode->packetSent(outputBuffer, packetLength); + packetsSent++; } nodeData->setLastDeletedModelsSentAt(deletePacketSentAt); diff --git a/assignment-client/src/models/ModelServer.h b/assignment-client/src/models/ModelServer.h index 7e7f239f2a..38acc7f1e1 100644 --- a/assignment-client/src/models/ModelServer.h +++ b/assignment-client/src/models/ModelServer.h @@ -37,7 +37,7 @@ public: // subclass may implement these method virtual void beforeRun(); virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node); + virtual int sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent); virtual void modelCreated(const ModelItem& newModel, const SharedNodePointer& senderNode); diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 30e3011ae8..bc0e84eea9 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -85,7 +85,6 @@ bool OctreeSendThread::process() { if (nodeData && !nodeData->isShuttingDown()) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); packetDistributor(nodeData, viewFrustumChanged); - resendNackedPackets(nodeData); } } } @@ -281,26 +280,6 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes return packetsSent; } -int OctreeSendThread::resendNackedPackets(OctreeQueryNode* nodeData) { - - const int MAX_PACKETS_RESEND = 10; - int packetsSent = 0; - - const QByteArray* packet; - while (nodeData->hasNextNackedPacket() && packetsSent < MAX_PACKETS_RESEND) { - packet = nodeData->getNextNackedPacket(); - if (packet) { - NodeList::getInstance()->writeDatagram(*packet, _node); - packetsSent++; - - _totalBytes += packet->size(); - _totalPackets++; - _totalWastedBytes += MAX_PACKET_SIZE - packet->size(); - } - } - return packetsSent; -} - /// Version of voxel distributor that sends the deepest LOD level at once int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged) { @@ -311,6 +290,11 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus return 0; } + // calculate max number of packets that can be sent during this interval + int clientMaxPacketsPerInterval = std::max(1, (nodeData->getMaxOctreePacketsPerSecond() / INTERVALS_PER_SECOND)); + int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); + + int truePacketsSent = 0; int trueBytesSent = 0; int packetsSentThisInterval = 0; @@ -408,9 +392,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus //quint64 startCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; //quint64 startCompressCalls = OctreePacketData::getCompressContentCalls(); - int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxOctreePacketsPerSecond() / INTERVALS_PER_SECOND)); - int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); - int extraPackingAttempts = 0; bool completedScene = false; while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval && !nodeData->isShuttingDown()) { @@ -581,12 +562,26 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // send the environment packet // TODO: should we turn this into a while loop to better handle sending multiple special packets if (_myServer->hasSpecialPacketToSend(_node) && !nodeData->isShuttingDown()) { - trueBytesSent += _myServer->sendSpecialPacket(nodeData, _node); + int specialPacketsSent; + trueBytesSent += _myServer->sendSpecialPacket(_node, nodeData, specialPacketsSent); nodeData->resetOctreePacket(); // because nodeData's _sequenceNumber has changed - truePacketsSent++; - packetsSentThisInterval++; + truePacketsSent += specialPacketsSent; + packetsSentThisInterval += specialPacketsSent; } + // Re-send packets that were nacked by the client + while (nodeData->hasNextNackedPacket() && packetsSentThisInterval < maxPacketsPerInterval) { + const QByteArray* packet = nodeData->getNextNackedPacket(); + if (packet) { + NodeList::getInstance()->writeDatagram(*packet, _node); + truePacketsSent++; + packetsSentThisInterval++; + + _totalBytes += packet->size(); + _totalPackets++; + _totalWastedBytes += MAX_PACKET_SIZE - packet->size(); + } + } quint64 end = usecTimestampNow(); int elapsedmsec = (end - start)/USECS_PER_MSEC; diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index e7599ebcd2..d8eed27802 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -55,9 +55,6 @@ private: int _nodeMissingCount; bool _isShuttingDown; - - int resendNackedPackets(OctreeQueryNode* nodeData); - }; #endif // hifi_OctreeSendThread_h diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index f0db93feb3..5595d139be 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -72,7 +72,7 @@ public: // subclass may implement these method virtual void beforeRun() { }; virtual bool hasSpecialPacketToSend(const SharedNodePointer& node) { return false; } - virtual int sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node) { return 0; } + virtual int sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { return 0; } static void attachQueryNodeToNode(Node* newNode); diff --git a/assignment-client/src/particles/ParticleServer.cpp b/assignment-client/src/particles/ParticleServer.cpp index e7a0f75dfd..674d22145f 100644 --- a/assignment-client/src/particles/ParticleServer.cpp +++ b/assignment-client/src/particles/ParticleServer.cpp @@ -86,7 +86,7 @@ bool ParticleServer::hasSpecialPacketToSend(const SharedNodePointer& node) { return shouldSendDeletedParticles; } -int ParticleServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node) { +int ParticleServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { unsigned char outputBuffer[MAX_PACKET_SIZE]; size_t packetLength = 0; @@ -99,6 +99,7 @@ int ParticleServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNo bool hasMoreToSend = true; // TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 particles? + packetsSent = 0; while (hasMoreToSend) { hasMoreToSend = tree->encodeParticlesDeletedSince(queryNode->getSequenceNumber(), deletedParticlesSentAt, outputBuffer, MAX_PACKET_SIZE, packetLength); @@ -107,6 +108,7 @@ int ParticleServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNo NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node)); queryNode->packetSent(outputBuffer, packetLength); + packetsSent++; } nodeData->setLastDeletedParticlesSentAt(deletePacketSentAt); diff --git a/assignment-client/src/particles/ParticleServer.h b/assignment-client/src/particles/ParticleServer.h index 3066c5fa98..d444368a9d 100644 --- a/assignment-client/src/particles/ParticleServer.h +++ b/assignment-client/src/particles/ParticleServer.h @@ -37,7 +37,7 @@ public: // subclass may implement these method virtual void beforeRun(); virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node); + virtual int sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent); virtual void particleCreated(const Particle& newParticle, const SharedNodePointer& senderNode); diff --git a/assignment-client/src/voxels/VoxelServer.cpp b/assignment-client/src/voxels/VoxelServer.cpp index 34b01f529a..b021ddd9f6 100644 --- a/assignment-client/src/voxels/VoxelServer.cpp +++ b/assignment-client/src/voxels/VoxelServer.cpp @@ -40,7 +40,7 @@ bool VoxelServer::hasSpecialPacketToSend(const SharedNodePointer& node) { return shouldSendEnvironments; } -int VoxelServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node) { +int VoxelServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { unsigned char* copyAt = _tempOutputBuffer; @@ -76,6 +76,7 @@ int VoxelServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodeP NodeList::getInstance()->writeDatagram((char*) _tempOutputBuffer, envPacketLength, SharedNodePointer(node)); queryNode->packetSent(_tempOutputBuffer, envPacketLength); + packetsSent = 1; return envPacketLength; } diff --git a/assignment-client/src/voxels/VoxelServer.h b/assignment-client/src/voxels/VoxelServer.h index 4e04c48cfd..b13f83b65f 100644 --- a/assignment-client/src/voxels/VoxelServer.h +++ b/assignment-client/src/voxels/VoxelServer.h @@ -46,7 +46,7 @@ public: // subclass may implement these method virtual void beforeRun(); virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node); + virtual int sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent); private: bool _sendEnvironments; From c6a9a8924dbb847e7bacdac8789c3a484cf8b07e Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 10 Jun 2014 16:43:53 -0700 Subject: [PATCH 22/44] changed NetworkPacket::_sendingNode to ::_node --- .../src/octree/OctreeSendThread.cpp | 1 - libraries/networking/src/NetworkPacket.cpp | 16 ++++++++-------- libraries/networking/src/NetworkPacket.h | 8 ++++---- libraries/networking/src/PacketSender.cpp | 2 +- .../networking/src/ReceivedPacketProcessor.cpp | 4 ++-- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index bc0e84eea9..cb149b1d96 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -294,7 +294,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus int clientMaxPacketsPerInterval = std::max(1, (nodeData->getMaxOctreePacketsPerSecond() / INTERVALS_PER_SECOND)); int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); - int truePacketsSent = 0; int trueBytesSent = 0; int packetsSentThisInterval = 0; diff --git a/libraries/networking/src/NetworkPacket.cpp b/libraries/networking/src/NetworkPacket.cpp index f9d6c7ea7b..a8110847e1 100644 --- a/libraries/networking/src/NetworkPacket.cpp +++ b/libraries/networking/src/NetworkPacket.cpp @@ -17,9 +17,9 @@ #include "NetworkPacket.h" -void NetworkPacket::copyContents(const SharedNodePointer& sendingNode, const QByteArray& packet) { +void NetworkPacket::copyContents(const SharedNodePointer& node, const QByteArray& packet) { if (packet.size() && packet.size() <= MAX_PACKET_SIZE) { - _sendingNode = sendingNode; + _node = node; _byteArray = packet; } else { qDebug(">>> NetworkPacket::copyContents() unexpected length = %d", packet.size()); @@ -27,28 +27,28 @@ void NetworkPacket::copyContents(const SharedNodePointer& sendingNode, const QBy } NetworkPacket::NetworkPacket(const NetworkPacket& packet) { - copyContents(packet.getSendingNode(), packet.getByteArray()); + copyContents(packet.getNode(), packet.getByteArray()); } -NetworkPacket::NetworkPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) { - copyContents(sendingNode, packet); +NetworkPacket::NetworkPacket(const SharedNodePointer& node, const QByteArray& packet) { + copyContents(node, packet); }; // copy assignment NetworkPacket& NetworkPacket::operator=(NetworkPacket const& other) { - copyContents(other.getSendingNode(), other.getByteArray()); + copyContents(other.getNode(), other.getByteArray()); return *this; } #ifdef HAS_MOVE_SEMANTICS // move, same as copy, but other packet won't be used further NetworkPacket::NetworkPacket(NetworkPacket && packet) { - copyContents(packet.getSendingNode(), packet.getByteArray()); + copyContents(packet.getNode(), packet.getByteArray()); } // move assignment NetworkPacket& NetworkPacket::operator=(NetworkPacket&& other) { - copyContents(other.getSendingNode(), other.getByteArray()); + copyContents(other.getNode(), other.getByteArray()); return *this; } #endif diff --git a/libraries/networking/src/NetworkPacket.h b/libraries/networking/src/NetworkPacket.h index 52e8a36712..0be35f9fff 100644 --- a/libraries/networking/src/NetworkPacket.h +++ b/libraries/networking/src/NetworkPacket.h @@ -35,15 +35,15 @@ public: NetworkPacket& operator= (NetworkPacket&& other); // move assignment #endif - NetworkPacket(const SharedNodePointer& sendingNode, const QByteArray& byteArray); + NetworkPacket(const SharedNodePointer& node, const QByteArray& byteArray); - const SharedNodePointer& getSendingNode() const { return _sendingNode; } + const SharedNodePointer& getNode() const { return _node; } const QByteArray& getByteArray() const { return _byteArray; } private: - void copyContents(const SharedNodePointer& sendingNode, const QByteArray& byteArray); + void copyContents(const SharedNodePointer& node, const QByteArray& byteArray); - SharedNodePointer _sendingNode; + SharedNodePointer _node; QByteArray _byteArray; }; diff --git a/libraries/networking/src/PacketSender.cpp b/libraries/networking/src/PacketSender.cpp index ae844d4f99..3edfc47c04 100644 --- a/libraries/networking/src/PacketSender.cpp +++ b/libraries/networking/src/PacketSender.cpp @@ -271,7 +271,7 @@ bool PacketSender::nonThreadedProcess() { unlock(); // send the packet through the NodeList... - NodeList::getInstance()->writeDatagram(temporary.getByteArray(), temporary.getSendingNode()); + NodeList::getInstance()->writeDatagram(temporary.getByteArray(), temporary.getNode()); packetsSentThisCall++; _packetsOverCheckInterval++; _totalPacketsSent++; diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index ea613082ce..46f1515016 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -43,9 +43,9 @@ bool ReceivedPacketProcessor::process() { NetworkPacket& packet = _packets.front(); // get the oldest packet NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us _packets.erase(_packets.begin()); // remove the oldest packet - _nodePacketCounts[temporary.getSendingNode()->getUUID()]--; + _nodePacketCounts[temporary.getNode()->getUUID()]--; unlock(); // let others add to the packets - processPacket(temporary.getSendingNode(), temporary.getByteArray()); // process our temporary copy + processPacket(temporary.getNode(), temporary.getByteArray()); // process our temporary copy } return isStillRunning(); // keep running till they terminate us } From faa5b1d2f253e3964cc8781fe821cb283d7b171a Mon Sep 17 00:00:00 2001 From: Dev5 Date: Tue, 10 Jun 2014 17:18:32 -0700 Subject: [PATCH 23/44] Added simple tree placement script that has a UI similar to edit voxels. It grows big trees, dont grow near something important. --- examples/growTrees.js | 837 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 837 insertions(+) create mode 100644 examples/growTrees.js diff --git a/examples/growTrees.js b/examples/growTrees.js new file mode 100644 index 0000000000..d853804e77 --- /dev/null +++ b/examples/growTrees.js @@ -0,0 +1,837 @@ +// +// growPlants.js +// examples +// +// Created by Benjamin Arnold on May 29, 2014 +// Copyright 2014 High Fidelity, Inc. +// +// This sample script allows the user to grow different types of plants on the voxels +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var zFightingSizeAdjust = 0.002; // used to adjust preview voxels to prevent z fighting +var previewLineWidth = 2.0; + +var voxelSize = 1; +var windowDimensions = Controller.getViewportDimensions(); +var toolIconUrl = "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/tools/"; + +var MAX_VOXEL_SCALE_POWER = 5; +var MIN_VOXEL_SCALE_POWER = -8; +var MAX_VOXEL_SCALE = Math.pow(2.0, MAX_VOXEL_SCALE_POWER); +var MIN_VOXEL_SCALE = Math.pow(2.0, MIN_VOXEL_SCALE_POWER); + + +var linePreviewTop = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 0, green: 255, blue: 0}, + alpha: 1, + visible: false, + lineWidth: previewLineWidth + }); + +var linePreviewBottom = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 0, green: 255, blue: 0}, + alpha: 1, + visible: false, + lineWidth: previewLineWidth + }); + +var linePreviewLeft = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 0, green: 255, blue: 0}, + alpha: 1, + visible: false, + lineWidth: previewLineWidth + }); + +var linePreviewRight = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 0, green: 255, blue: 0}, + alpha: 1, + visible: false, + lineWidth: previewLineWidth + }); + + +var UIColor = { red: 0, green: 160, blue: 0}; +var activeUIColor = { red: 0, green: 255, blue: 0}; + +var toolHeight = 50; +var toolWidth = 50; + +var editToolsOn = true; + +var voxelToolSelected = false; + +var scaleSelectorWidth = 144; +var scaleSelectorHeight = 37; + +var scaleSelectorX = windowDimensions.x / 5.0; +var scaleSelectorY = windowDimensions.y - scaleSelectorHeight; + +var voxelTool = Overlays.addOverlay("image", { + x: scaleSelectorX + scaleSelectorWidth + 1, y: windowDimensions.y - toolHeight, width: toolWidth, height: toolHeight, + subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight }, + imageURL: toolIconUrl + "voxel-tool.svg", + visible: editToolsOn, + color: UIColor, + alpha: 0.9 + }); + +var copyScale = true; +function ScaleSelector() { + this.x = scaleSelectorX; + this.y = scaleSelectorY; + this.width = scaleSelectorWidth; + this.height = scaleSelectorHeight; + + this.displayPower = false; + this.scale = 1.0; + this.power = 0; + + this.FIRST_PART = this.width * 40.0 / 100.0; + this.SECOND_PART = this.width * 37.0 / 100.0; + + this.buttonsOverlay = Overlays.addOverlay("image", { + x: this.x, y: this.y, + width: this.width, height: this.height, + //subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight }, + imageURL: toolIconUrl + "voxel-size-selector.svg", + alpha: 0.9, + visible: editToolsOn, + color: activeUIColor + }); + this.textOverlay = Overlays.addOverlay("text", { + x: this.x + this.FIRST_PART, y: this.y, + width: this.SECOND_PART, height: this.height, + topMargin: 13, + text: this.scale.toString(), + alpha: 0.0, + visible: editToolsOn, + color: activeUIColor + }); + this.powerOverlay = Overlays.addOverlay("text", { + x: this.x + this.FIRST_PART, y: this.y, + width: this.SECOND_PART, height: this.height, + leftMargin: 28, + text: this.power.toString(), + alpha: 0.0, + visible: false, + color: activeUIColor + }); + this.setScale = function(scale) { + if (scale > MAX_VOXEL_SCALE) { + scale = MAX_VOXEL_SCALE; + } + if (scale < MIN_VOXEL_SCALE) { + scale = MIN_VOXEL_SCALE; + } + + this.scale = scale; + this.power = Math.floor(Math.log(scale) / Math.log(2)); + this.update(); + } + + this.show = function(doShow) { + Overlays.editOverlay(this.buttonsOverlay, {visible: doShow}); + Overlays.editOverlay(this.textOverlay, {visible: doShow}); + Overlays.editOverlay(this.powerOverlay, {visible: doShow && this.displayPower}); + } + + this.move = function() { + this.x = swatchesX + swatchesWidth; + this.y = swatchesY; + + Overlays.editOverlay(this.buttonsOverlay, { + x: this.x, y: this.y, + }); + Overlays.editOverlay(this.textOverlay, { + x: this.x + this.FIRST_PART, y: this.y, + }); + Overlays.editOverlay(this.powerOverlay, { + x: this.x + this.FIRST_PART, y: this.y, + }); + } + + + this.switchDisplay = function() { + this.displayPower = !this.displayPower; + + if (this.displayPower) { + Overlays.editOverlay(this.textOverlay, { + leftMargin: 18, + text: "2" + }); + Overlays.editOverlay(this.powerOverlay, { + text: this.power.toString(), + visible: editToolsOn + }); + } else { + Overlays.editOverlay(this.textOverlay, { + leftMargin: 13, + text: this.scale.toString() + }); + Overlays.editOverlay(this.powerOverlay, { + visible: false + }); + } + } + + this.update = function() { + if (this.displayPower) { + Overlays.editOverlay(this.powerOverlay, {text: this.power.toString()}); + } else { + Overlays.editOverlay(this.textOverlay, {text: this.scale.toString()}); + } + } + + this.incrementScale = function() { + copyScale = false; + if (this.power < MAX_VOXEL_SCALE_POWER) { + ++this.power; + this.scale *= 2.0; + this.update(); + } + } + + this.decrementScale = function() { + copyScale = false; + if (MIN_VOXEL_SCALE_POWER < this.power) { + --this.power; + this.scale /= 2.0; + this.update(); + } + } + + this.clicked = function(x, y) { + if (this.x < x && x < this.x + this.width && + this.y < y && y < this.y + this.height) { + + if (x < this.x + this.FIRST_PART) { + this.decrementScale(); + } else if (x < this.x + this.FIRST_PART + this.SECOND_PART) { + this.switchDisplay(); + } else { + this.incrementScale(); + } + return true; + } + return false; + } + + this.cleanup = function() { + Overlays.deleteOverlay(this.buttonsOverlay); + Overlays.deleteOverlay(this.textOverlay); + Overlays.deleteOverlay(this.powerOverlay); + } + +} +var scaleSelector = new ScaleSelector(); + + +function calculateVoxelFromIntersection(intersection, operation) { + + var resultVoxel; + + var x; + var y; + var z; + + // if our "target voxel size" is larger than the voxel we intersected with, then we need to find the closest + // ancestor voxel of our target size that contains our intersected voxel. + if (voxelSize > intersection.voxel.s) { + x = Math.floor(intersection.voxel.x / voxelSize) * voxelSize; + y = Math.floor(intersection.voxel.y / voxelSize) * voxelSize; + z = Math.floor(intersection.voxel.z / voxelSize) * voxelSize; + } else { + // otherwise, calculate the enclosed voxel of size voxelSize that the intersection point falls inside of. + // if you have a voxelSize that's smaller than the voxel you're intersecting, this calculation will result + // in the subvoxel that the intersection point falls in, if the target voxelSize matches the intersecting + // voxel this still works and results in returning the intersecting voxel which is what we want + var adjustToCenter = Vec3.multiply(Voxels.getFaceVector(intersection.face), (voxelSize * -0.5)); + + var centerOfIntersectingVoxel = Vec3.sum(intersection.intersection, adjustToCenter); + x = Math.floor(centerOfIntersectingVoxel.x / voxelSize) * voxelSize; + y = Math.floor(centerOfIntersectingVoxel.y / voxelSize) * voxelSize; + z = Math.floor(centerOfIntersectingVoxel.z / voxelSize) * voxelSize; + } + resultVoxel = { x: x, y: y, z: z, s: voxelSize }; + var highlightAt = { x: x, y: y, z: z, s: voxelSize }; + + + + // we only do the "add to the face we're pointing at" adjustment, if the operation is an add + // operation, and the target voxel size is equal to or smaller than the intersecting voxel. + var wantAddAdjust = (operation == "add" && (voxelSize <= intersection.voxel.s)); + + // now we also want to calculate the "edge square" for the face for this voxel + if (intersection.face == "MIN_X_FACE") { + + highlightAt.x = x - zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.x -= voxelSize; + } + + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + + } else if (intersection.face == "MAX_X_FACE") { + + highlightAt.x = x + voxelSize + zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.x += resultVoxel.s; + } + + resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + + } else if (intersection.face == "MIN_Y_FACE") { + + highlightAt.y = y - zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.y -= voxelSize; + } + + resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + + } else if (intersection.face == "MAX_Y_FACE") { + + highlightAt.y = y + voxelSize + zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.y += voxelSize; + } + + resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust}; + resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust}; + resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust}; + + } else if (intersection.face == "MIN_Z_FACE") { + + highlightAt.z = z - zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.z -= voxelSize; + } + + resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z }; + resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z}; + resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z }; + resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z}; + + } else if (intersection.face == "MAX_Z_FACE") { + + highlightAt.z = z + voxelSize + zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.z += voxelSize; + } + + resultVoxel.bottomLeft = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z }; + resultVoxel.bottomRight = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z}; + resultVoxel.topLeft = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z }; + resultVoxel.topRight = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z}; + + } + return resultVoxel; +} + +var trackLastMouseX = 0; +var trackLastMouseY = 0; + +function showPreviewLines() { + + var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); + + var intersection = Voxels.findRayIntersection(pickRay); + + if (intersection.intersects) { + var resultVoxel = calculateVoxelFromIntersection(intersection, ""); + Overlays.editOverlay(linePreviewTop, { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true }); + Overlays.editOverlay(linePreviewBottom, { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true }); + Overlays.editOverlay(linePreviewLeft, { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true }); + Overlays.editOverlay(linePreviewRight, { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true }); + } else { + Overlays.editOverlay(linePreviewTop, { visible: false }); + Overlays.editOverlay(linePreviewBottom, { visible: false }); + Overlays.editOverlay(linePreviewLeft, { visible: false }); + Overlays.editOverlay(linePreviewRight, { visible: false }); + } +} + +function mouseMoveEvent(event) { + trackLastMouseX = event.x; + trackLastMouseY = event.y; + if (!voxelToolSelected) { + return; + } + showPreviewLines(); +} + + +// Array of possible trees, right now there is only one +var treeTypes = []; + +treeTypes.push({ + name: "Tall Green", + // Voxel Colors + wood: { r: 133, g: 81, b: 53 }, + leaves: { r: 22, g: 83, b: 31 }, + + // How tall the tree is + height: { min: 20, max: 60 }, + middleHeight: 0.3, + + // Chance of making a branch + branchChance: { min: 0.01, max: 0.1 }, + branchLength: { min: 30, max: 60 }, + branchThickness: { min: 2, max: 7}, + + // The width of the core, affects width and shape + coreWidth: { min: 1, max: 4 }, + + //TODO: Make this quadratic splines instead of linear + bottomThickness: { min: 2, max: 8 }, + middleThickness: { min: 1, max: 4 }, + topThickness: { min: 3, max: 6 }, + + //Modifies leaves at top + leafCapSizeOffset: 0 +}); + +// Applies noise to color +var colorNoiseRange = 0.2; + + +// Useful constants +var LEFT = 0; +var BACK = 1; +var RIGHT = 2; +var FRONT = 3; +var UP = 4; + +// Interpolates between min and max of treevar based on b +function interpolate(treeVar, b) { + return (treeVar.min + (treeVar.max - treeVar.min) * b); +} + +function makeBranch(x, y, z, step, length, dir, thickness, wood, leaves) { + var moveDir; + + var currentThickness; + //thickness attenuates to thickness - 3 + var finalThickness = thickness - 3; + if (finalThickness < 1) { + finalThickness = 1; + } + //Iterative branch generation + while (true) { + + //If we are at the end, place a ball of leaves + if (step == 0) { + makeSphere(x, y, z, 2 + finalThickness, leaves); + return; + } + //thickness attenuation + currentThickness = Math.round((finalThickness + (thickness - finalThickness) * (step/length))) - 1; + + + // If the branch is thick, grow a vertical slice + if (currentThickness > 0) { + for (var i = -currentThickness; i <= currentThickness; i++) { + var len = currentThickness - Math.abs(i); + switch (dir) { + case 0: //left + case 2: //right + growInDirection(x, y + i * voxelSize, z, len, len, BACK, wood, false, true); + growInDirection(x, y + i * voxelSize, z, len, len, FRONT, wood, false, false) + break; + case 1: //back + case 3: //front + growInDirection(x, y + i * voxelSize, z, len, len, LEFT, wood, false, true); + growInDirection(x, y + i * voxelSize, z, len, len, RIGHT, wood, false, false) + break; + } + } + } else { + //Otherwise place a single voxel + var colorNoise = (colorNoiseRange * Math.random() - colorNoiseRange * 0.5) + 1.0; + Voxels.setVoxel(x, y, z, voxelSize, wood.r * colorNoise, wood.g * colorNoise, wood.b * colorNoise); + } + + // determines random change in direction for branch + var r = Math.floor(Math.random() * 9); + + + if (r >= 6){ + moveDir = dir; //in same direction + } else if (r >= 4) { + moveDir = UP; //up + } + else if (dir == LEFT){ + if (r >= 2){ + moveDir = FRONT; + } + else{ + moveDir = BACK; + } + } + else if (dir == BACK){ + if (r >= 2){ + moveDir = LEFT; + } + else{ + moveDir = RIGHT; + } + } + else if (dir == RIGHT){ + if (r >= 2){ + moveDir = BACK; + } + else{ + moveDir = FRONT; + } + } + else if (dir == FRONT){ + if (r >= 2){ + moveDir = RIGHT; + } + else{ + moveDir = LEFT; + } + } + + //Move the branch by moveDir + switch (moveDir) { + case 0: //left + x = x - voxelSize; + break; + case 1: //back + z = z - voxelSize; + break; + case 2: //right + x = x + voxelSize; + break; + case 3: //front + z = z + voxelSize; + break; + case 4: //up + y = y + voxelSize; + break; + } + + step--; + } +} + +// Places a sphere of voxels +function makeSphere(x, y, z, radius, color) { + if (radius <= 0) { + return; + } + var width = radius * 2 + 1; + var distance; + + for (var i = -radius; i <= radius; i++){ + for (var j = -radius; j <= radius; j++){ + for (var k = -radius; k <= radius; k++){ + distance = Math.sqrt(i * i + j * j + k * k); + if (distance <= radius){ + var colorNoise = (colorNoiseRange * Math.random() - colorNoiseRange * 0.5) + 1.0; + Voxels.setVoxel(x + i * voxelSize, y + j * voxelSize, z + k * voxelSize, voxelSize, color.r * colorNoise, color.g * colorNoise, color.b * colorNoise); + } + } + } + } +} + +function growInDirection(x, y, z, step, length, dir, color, isSideBranching, addVoxel) { + + + if (addVoxel == true) { + var colorNoise = (colorNoiseRange * Math.random() - colorNoiseRange * 0.5) + 1.0; + Voxels.setVoxel(x, y, z, voxelSize, color.r * colorNoise, color.g * colorNoise, color.b * colorNoise); + } + + // If this is a main vein, it will branch outward perpendicular to its motion + if (isSideBranching == true){ + var step2; + if (step >= length - 1){ + step2 = length; + } + else{ + step2 = step + 1; + } + growInDirection(x, y, z, step, length, BACK, color, false, false); + growInDirection(x, y, z, step, length, FRONT, color, false, false); + } + + if (step < 1) return; + + // Recursively move in the direction + if (dir == LEFT) { //left + growInDirection(x - voxelSize, y, z, step - 1, length, dir, color, isSideBranching, true); + } + else if (dir == BACK) { //back + growInDirection(x, y, z - voxelSize, step - 1, length, dir, color, isSideBranching, true); + } + else if (dir == RIGHT) { //right + growInDirection(x + voxelSize, y, z, step - 1, length, dir, color, isSideBranching, true); + } + else if (dir == FRONT) {//front + growInDirection(x, y, z + voxelSize, step - 1, length, dir, color, isSideBranching, true); + } + +} + +// Grows the thickness of the tree +function growHorizontalSlice(x, y, z, thickness, color, side) { + // The side variable determines which directions we should grow in + // it is an optimization that prevents us from visiting voxels multiple + // times for trees with a coreWidth > 1 + + // side: + // 8 == all directions + // 0 1 2 + // 3 -1 4 + // 5 6 7 + + Voxels.setVoxel(x, y, z, voxelSize, color.r, color.g, color.b); + + //We are done if there is no thickness + if (thickness == 0) { + return; + } + + + switch (side) { + case 0: + growInDirection(x, y, z, thickness, thickness, LEFT, color, true, false); + break; + case 1: + growInDirection(x, y, z, thickness, thickness, BACK, color, false, false); + break; + case 2: + growInDirection(x, y, z, thickness, thickness, RIGHT, color, true, false); + break; + case 3: + growInDirection(x, y, z, thickness, thickness, LEFT, color, false, false); + break; + case 4: + growInDirection(x, y, z, thickness, thickness, BACK, color, false, false); + break; + case 5: + growInDirection(x, y, z, thickness, thickness, RIGHT, color, true, false); + break; + case 6: + growInDirection(x, y, z, thickness, thickness, FRONT, color, false, false); + break; + case 7: + growInDirection(x, y, z, thickness, thickness, RIGHT, color, true, false); + break; + case 8: + if (thickness > 1){ + growInDirection(x, y, z, thickness, thickness, LEFT, color, true, false); + growInDirection(x, y, z, thickness, thickness, RIGHT, color, true, false) + } else if (thickness == 1){ + Voxels.setVoxel(x - voxelSize, y, z, voxelSize, color.r, color.g, color.b); + Voxels.setVoxel(x + voxelSize, y, z, voxelSize, color.r, color.g, color.b); + Voxels.setVoxel(x, y, z - voxelSize, voxelSize, color.r, color.g, color.b); + Voxels.setVoxel(x, y, z + voxelSize, voxelSize, color.r, color.g, color.b); + } + break; + } +} + +function computeSide(x, z, coreWidth) { + // side: + // 8 == all directions + // 0 1 2 + // 3 -1 4 + // 5 6 7 + + // if the core is only a single block, we can grow out in all directions + if (coreWidth == 1){ + return 8; + } + + // Back face + if (z == 0) { + if (x == 0) { + return 0; + } else if (x == coreWidth - 1) { + return 2; + } else { + return 1; + } + } + + // Front face + if (z == (coreWidth - 1)) { + if (x == 0) { + return 5; + } else if (x == (coreWidth - 1)) { + return 7; + } else { + return 6; + } + } + + // Left face + if (x == 0) { + return 3; + } + + // Right face + if (x == (coreWidth - 1)) { + return 4; + } + + //Interior + return -1; +} + + +function growTree(x, y, z, tree) { + + // The size of the tree, from 0-1 + var treeSize = Math.random(); + + // Get tree properties by interpolating with the treeSize + var height = interpolate(tree.height, treeSize); + var baseHeight = Math.ceil(tree.middleHeight * height); + var bottomThickness = interpolate(tree.bottomThickness, treeSize); + var middleThickness = interpolate(tree.middleThickness, treeSize); + var topThickness = interpolate(tree.topThickness, treeSize); + var coreWidth = Math.ceil(interpolate(tree.coreWidth, treeSize)); + + var thickness; + var side; + + //Loop upwards through each slice of the tree + for (var i = 0; i < height; i++){ + + //Branch properties are based on current height as well as the overall tree size + var branchChance = interpolate(tree.branchChance, i / height); + var branchLength = Math.ceil(interpolate(tree.branchLength, (i / height) * treeSize)); + var branchThickness = Math.round(interpolate(tree.branchThickness, (i / height) * treeSize)); + + // Get the "thickness" of the tree by doing linear interpolation between the middle thickness + // and the top and bottom thickness. + if (i <= baseHeight && baseHeight != 0){ + thickness = (i / (baseHeight) * (middleThickness - bottomThickness) + bottomThickness); + } else { + var denom = ((height - baseHeight)) * (topThickness - middleThickness) + middleThickness; + if (denom != 0) { + thickness = (i - baseHeight) / denom; + } else { + thickness = 0; + } + } + // The core of the tree is a vertical rectangular prism through the middle of the tree + + //Loop through the "core", which helps shape the trunk + var startX = x - Math.floor(coreWidth / 2) * voxelSize; + var startZ = z - Math.floor(coreWidth / 2) * voxelSize; + for (var j = 0; j < coreWidth; j++) { + for (var k = 0; k < coreWidth; k++) { + //determine which side of the tree we are on + side = computeSide(j, k, coreWidth); + //grow a horizontal slice of the tree + growHorizontalSlice(startX + j * voxelSize, y + i * voxelSize, startZ + k * voxelSize, Math.floor(thickness), tree.wood, side); + + // Branches + if (side != -1) { + var r = Math.random(); + if (r <= branchChance){ + var dir = Math.floor((Math.random() * 4)); + makeBranch(startX + j * voxelSize, y + i * voxelSize, startZ + k * voxelSize, branchLength, branchLength, dir, branchThickness, tree.wood, tree.leaves); + + } + } + } + } + } + + makeSphere(x, y + height * voxelSize, z, topThickness + coreWidth + tree.leafCapSizeOffset, tree.leaves); +} + +function mousePressEvent(event) { + var mouseX = event.x; + var mouseY = event.y; + + var clickedOnSomething = false; + // Check if we clicked an overlay + var clickedOverlay = Overlays.getOverlayAtPoint({x: mouseX, y: mouseY}); + + if (clickedOverlay == voxelTool) { + voxelToolSelected = !voxelToolSelected; + + if (voxelToolSelected == true) { + Overlays.editOverlay(voxelTool, { + color: activeUIColor + }); + } else { + Overlays.editOverlay(voxelTool, { + color: UIColor + }); + } + + clickedOnSomething = true; + } else if (scaleSelector.clicked(event.x, event.y)) { + clickedOnSomething = true; + voxelSize = scaleSelector.scale; + } + + // Return if we clicked on the UI or the voxel tool is disabled + if (clickedOnSomething || !voxelToolSelected) { + return; + } + + // Compute the picking ray for the click + var pickRay = Camera.computePickRay(event.x, event.y); + var intersection = Voxels.findRayIntersection(pickRay); + var resultVoxel = calculateVoxelFromIntersection(intersection, "add"); + + // Currently not in use, could randomly select a tree + var treeIndex = Math.floor(Math.random() * treeTypes.length); + + // Grow the first tree type + growTree(resultVoxel.x, resultVoxel.y, resultVoxel.z, treeTypes[0]); + +} + +function update() { + +} + +function scriptEnding() { + Overlays.deleteOverlay(linePreviewTop); + Overlays.deleteOverlay(linePreviewBottom); + Overlays.deleteOverlay(linePreviewLeft); + Overlays.deleteOverlay(linePreviewRight); + scaleSelector.cleanup(); + Overlays.deleteOverlay(voxelTool); +} + +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseMoveEvent.connect(mouseMoveEvent); + +Script.scriptEnding.connect(scriptEnding); + +Script.update.connect(update); + +Voxels.setPacketsPerSecond(10000); From a48f38b1d263a04f0fba5fce7a3502175e2078b9 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Tue, 10 Jun 2014 21:32:23 -0400 Subject: [PATCH 24/44] Revert "Job #19766 BUG: Stop or reload all scripts crashes interface fix, part 2." This reverts commit b4e984086505814cbc426226777b74a113da8362. --- interface/src/Application.cpp | 5 +++-- libraries/particles/src/Particle.cpp | 6 +++--- libraries/script-engine/src/ScriptEngine.cpp | 12 +++++++----- libraries/script-engine/src/ScriptEngine.h | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3ec5588c61..9fb821bff4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3492,8 +3492,9 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface); } else { // start the script on a new thread... - scriptEngine = new ScriptEngine(scriptName, &_controllerScriptingInterface); - _scriptEnginesHash.insert(scriptName, scriptEngine); + QUrl scriptUrl(scriptName); + scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface); + _scriptEnginesHash.insert(scriptUrl.toString(), scriptEngine); if (!scriptEngine->hasScript()) { qDebug() << "Application::loadScript(), script failed to load..."; diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 90e59b9422..59265c00dc 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -873,7 +873,7 @@ void Particle::endParticleScriptContext(ScriptEngine& engine, ParticleScriptObje void Particle::executeUpdateScripts() { // Only run this particle script if there's a script attached directly to the particle. if (!_script.isEmpty()) { - ScriptEngine engine(_script, QString("")); + ScriptEngine engine(_script); ParticleScriptObject particleScriptable(this); startParticleScriptContext(engine, particleScriptable); particleScriptable.emitUpdate(); @@ -884,7 +884,7 @@ void Particle::executeUpdateScripts() { void Particle::collisionWithParticle(Particle* other, const glm::vec3& penetration) { // Only run this particle script if there's a script attached directly to the particle. if (!_script.isEmpty()) { - ScriptEngine engine(_script, QString("")); + ScriptEngine engine(_script); ParticleScriptObject particleScriptable(this); startParticleScriptContext(engine, particleScriptable); ParticleScriptObject otherParticleScriptable(other); @@ -896,7 +896,7 @@ void Particle::collisionWithParticle(Particle* other, const glm::vec3& penetrati void Particle::collisionWithVoxel(VoxelDetail* voxelDetails, const glm::vec3& penetration) { // Only run this particle script if there's a script attached directly to the particle. if (!_script.isEmpty()) { - ScriptEngine engine(_script, QString("")); + ScriptEngine engine(_script); ParticleScriptObject particleScriptable(this); startParticleScriptContext(engine, particleScriptable); particleScriptable.emitCollisionWithVoxel(*voxelDetails, penetration); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 025f316d29..a4aae61248 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -93,7 +93,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam { } -ScriptEngine::ScriptEngine(const QString& fileNameString, +ScriptEngine::ScriptEngine(const QUrl& scriptURL, AbstractControllerScriptingInterface* controllerScriptingInterface) : _scriptContents(), _isFinished(false), @@ -110,19 +110,21 @@ ScriptEngine::ScriptEngine(const QString& fileNameString, _controllerScriptingInterface(controllerScriptingInterface), _avatarData(NULL), _scriptName(), - _fileNameString(fileNameString), + _fileNameString(), _quatLibrary(), _vec3Library(), _uuidLibrary(), _animationCache(this) { - QUrl url(fileNameString); - QString scriptUrlString = url.toString(); + QString scriptURLString = scriptURL.toString(); + _fileNameString = scriptURLString; + + QUrl url(scriptURL); // if the scheme length is one or lower, maybe they typed in a file, let's try const int WINDOWS_DRIVE_LETTER_SIZE = 1; if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { - url = QUrl::fromLocalFile(scriptUrlString); + url = QUrl::fromLocalFile(scriptURLString); } // ok, let's see if it's valid... and if so, load it diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index f88017515e..bf2ac40568 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -40,7 +40,7 @@ const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 10 class ScriptEngine : public QObject { Q_OBJECT public: - ScriptEngine(const QString& fileNameString, + ScriptEngine(const QUrl& scriptURL, AbstractControllerScriptingInterface* controllerScriptingInterface = NULL); ScriptEngine(const QString& scriptContents = NO_SCRIPT, From 46f2ab73bccf6fa8669856534f0c20f96ee8c416 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Tue, 10 Jun 2014 22:29:58 -0400 Subject: [PATCH 25/44] Job #19766 BUG: Stop or reload all scripts crashes interface fixed, part 3 Move the conversion of scriptName to QUrl to the beginning of Application::loadScript. Use the scriptURLString to query the _scriptEngineHash map. --- CMakeLists.txt | 4 + assignment-client/src/AssignmentClient.cpp | 123 +++++++++++++++------ assignment-client/src/AssignmentClient.h | 48 ++++++++ interface/src/Application.cpp | 9 +- interface/src/Audio.cpp | 29 ++++- 5 files changed, 175 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cb1e4224cf..298b9a791e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,10 @@ if (NOT QT_CMAKE_PREFIX_PATH) set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) endif () +if (NOT ZLIB_ROOT) + set(ZLIB_ROOT $ENV{ZLIB_ROOT}) +endif () + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT_CMAKE_PREFIX_PATH}) # set our Base SDK to 10.8 diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 009bd42e88..a2faaab651 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -33,6 +33,64 @@ SharedAssignmentPointer AssignmentClient::_currentAssignment; int hifiSockAddrMeta = qRegisterMetaType("HifiSockAddr"); +template +class Parse : public Parser { +public: + Parse(const QString& option, bool required, T* value) : Parser(option, required), _value(value) {} + bool parse(const QStringList& argumentList); +private: + T* _value; +}; + +template<> +bool Parse::parse(const QStringList& argumentList) { + int argumentIndex = findToken(argumentList); + if (argumentIndex != -1) { + argumentIndex++; + if (argumentList.size() > argumentIndex) { + bool ok; + int value = argumentList[argumentIndex].toInt(&ok); + if (ok) { + *_value = static_cast(value); + } + validateValue(ok); + } else { + valueNotSpecified(); + } + } + return isValid(); +} + +template<> +bool Parse::parse(const QStringList& argumentList) { + int argumentIndex = findToken(argumentList); + if (argumentIndex != -1) { + argumentIndex++; + if (argumentList.size() > argumentIndex) { + *_value = QString(argumentList[argumentIndex]); + validateValue(!_value->isNull()); + } else { + valueNotSpecified(); + } + } + return isValid(); +} + +template<> +bool Parse::parse(const QStringList& argumentList) { + int argumentIndex = findToken(argumentList); + if (argumentIndex != -1) { + argumentIndex++; + if (argumentList.size() > argumentIndex) { + *_value = argumentList[argumentIndex]; + validateValue(true); + } else { + valueNotSpecified(); + } + } + return isValid(); +} + AssignmentClient::AssignmentClient(int &argc, char **argv) : QCoreApplication(argc, argv), _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME) @@ -43,40 +101,42 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : QSettings::setDefaultFormat(QSettings::IniFormat); QStringList argumentList = arguments(); - + + // Define parser tokens + const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "-t"; + const QString ASSIGNMENT_POOL_OPTION = "--pool"; + const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "--wallet"; + const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "-a"; + + // Define parser results + Assignment::Type requestAssignmentType = Assignment::AllTypes; + QString assignmentPool; + QUuid walletUUID; + + // Define parsers + _parsers.insert(ASSIGNMENT_TYPE_OVERRIDE_OPTION, new Parse(ASSIGNMENT_TYPE_OVERRIDE_OPTION, false, &requestAssignmentType)); + _parsers.insert(ASSIGNMENT_POOL_OPTION, new Parse(ASSIGNMENT_POOL_OPTION, false, &assignmentPool)); + _parsers.insert(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION, new Parse(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION, false, &walletUUID)); + _parsers.insert(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION, new Parse(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION, false, &_assignmentServerHostname)); + // register meta type is required for queued invoke method on Assignment subclasses // set the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); - const QString ASSIGNMENT_TYPE_OVVERIDE_OPTION = "-t"; - int argumentIndex = argumentList.indexOf(ASSIGNMENT_TYPE_OVVERIDE_OPTION); - - Assignment::Type requestAssignmentType = Assignment::AllTypes; - - if (argumentIndex != -1) { - requestAssignmentType = (Assignment::Type) argumentList[argumentIndex + 1].toInt(); + foreach (Parser* option, _parsers) { + if (option) { + option->parse(argumentList); + } } - - const QString ASSIGNMENT_POOL_OPTION = "--pool"; - - argumentIndex = argumentList.indexOf(ASSIGNMENT_POOL_OPTION); - - QString assignmentPool; - - if (argumentIndex != -1) { - assignmentPool = argumentList[argumentIndex + 1]; - } - + // setup our _requestAssignment member variable from the passed arguments _requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool); // check if we were passed a wallet UUID on the command line // this would represent where the user running AC wants funds sent to - - const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "--wallet"; - if ((argumentIndex = argumentList.indexOf(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) != -1) { - QUuid walletUUID = QString(argumentList[argumentIndex + 1]); + if (_parsers[ASSIGNMENT_WALLET_DESTINATION_ID_OPTION]->exists() && + _parsers[ASSIGNMENT_WALLET_DESTINATION_ID_OPTION]->isValid()) { qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID); _requestAssignment.setWalletUUID(walletUUID); } @@ -84,14 +144,9 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : // create a NodeList as an unassigned client NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned); - // check for an overriden assignment server hostname - const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "-a"; - - argumentIndex = argumentList.indexOf(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION); - - if (argumentIndex != -1) { - _assignmentServerHostname = argumentList[argumentIndex + 1]; - + // check for an overriden assignment server hostname + if (_parsers[CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION]->exists() && + _parsers[CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION]->isValid()) { // set the custom assignment socket on our NodeList HifiSockAddr customAssignmentSocket = HifiSockAddr(_assignmentServerHostname, DEFAULT_DOMAIN_SERVER_PORT); @@ -113,6 +168,12 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : this, &AssignmentClient::handleAuthenticationRequest); } +AssignmentClient::~AssignmentClient() { + foreach (Parser* option, _parsers) { + delete option; + } +} + void AssignmentClient::sendAssignmentRequest() { if (!_currentAssignment) { NodeList::getInstance()->sendAssignment(_requestAssignment); diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 9834402dbf..8951d44135 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -16,11 +16,57 @@ #include "ThreadedAssignment.h" +class Parser { +public: + Parser(const QString& option, bool required) : _option(option), _required(required), _exists(false), _isValid(false) {} + virtual bool parse(const QStringList& argumentList) { return false; } + bool exists() { return _exists; } + bool isValid() { return _isValid; } + +protected: + int findToken(const QStringList& argumentList) { + int argumentIndex = argumentList.indexOf(_option); + validateOption(argumentIndex); + return argumentIndex; + } + + void validateOption(int index) { + _exists = true; + if (index == -1) { + _exists = false; + if (_required) { + qDebug() << "Command line option " << _option << " is missing"; + } + } + } + + void valueNotSpecified() { + _isValid = false; + qDebug() << "Command line option " << _option << " value is missing"; + } + + void validateValue(bool ok) { + _isValid = ok; + if (!ok) { + qDebug() << "Command line option " << _option << " value is invalid"; + } + } + +private: + QString _option; + bool _required; + bool _exists; + bool _isValid; +}; + class AssignmentClient : public QCoreApplication { Q_OBJECT public: AssignmentClient(int &argc, char **argv); + ~AssignmentClient(); + static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; } + private slots: void sendAssignmentRequest(); void readPendingDatagrams(); @@ -31,6 +77,8 @@ private: Assignment _requestAssignment; static SharedAssignmentPointer _currentAssignment; QString _assignmentServerHostname; + + QMap _parsers; }; #endif // hifi_AssignmentClient_h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9fb821bff4..25a5ba8007 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3483,8 +3483,10 @@ void Application::saveScripts() { } ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor) { - if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptName) && !_scriptEnginesHash[scriptName]->isFinished()){ - return _scriptEnginesHash[scriptName]; + QUrl scriptUrl(scriptName); + const QString& scriptURLString = scriptUrl.toString(); + if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptURLString) && !_scriptEnginesHash[scriptURLString]->isFinished()){ + return _scriptEnginesHash[scriptURLString]; } ScriptEngine* scriptEngine; @@ -3492,9 +3494,8 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface); } else { // start the script on a new thread... - QUrl scriptUrl(scriptName); scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface); - _scriptEnginesHash.insert(scriptUrl.toString(), scriptEngine); + _scriptEnginesHash.insert(scriptURLString, scriptEngine); if (!scriptEngine->hasScript()) { qDebug() << "Application::loadScript(), script failed to load..."; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index ebc228a13d..1ecfad9007 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -219,8 +219,9 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { pPropertyStore->Release(); pPropertyStore = NULL; //QAudio devices seems to only take the 31 first characters of the Friendly Device Name. - const DWORD QT_WIN_MAX_AUDIO_DEVICENAME_LEN = 31; - deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal).left(QT_WIN_MAX_AUDIO_DEVICENAME_LEN); + //const DWORD QT_WIN_MAX_AUDIO_DEVICENAME_LEN = 31; + // deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal).left(QT_WIN_MAX_AUDIO_DEVICENAME_LEN); + deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal); qDebug() << (mode == QAudio::AudioOutput ? "output" : "input") << " device:" << deviceName; PropVariantClear(&pv); } @@ -1077,13 +1078,35 @@ void Audio::renderToolBox(int x, int y, bool boxed) { } _iconBounds = QRect(x, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE); + + static quint64 last = 0; // Hold the last time sample + if (!_muted) { + last = 0; + glColor3f(1,1,1); glBindTexture(GL_TEXTURE_2D, _micTextureId); } else { + quint64 usecTimestampNow(); + static const float CYCLE_DURATION = 3.0f; // Seconds + quint64 now = usecTimestampNow(); + float delta = (float)(now - last) / 1000000.0f; + float from = 1.0f; // Linear fade down (upper bound) + float to = 0.3f; // Linear fade down (lower bound) + + if (delta > CYCLE_DURATION) { + last = now; + delta -= (int)delta; + } else if (delta > (CYCLE_DURATION * 0.5f)) { + // Linear fade up + from = 0.3f; // lower bound + to = 1.0f; // upper bound + } + // Compute a linear ramp to fade the color from full to partial saturation + float linearRamp = (from - to) * delta / CYCLE_DURATION + to; + glColor3f(linearRamp, linearRamp, linearRamp); glBindTexture(GL_TEXTURE_2D, _muteTextureId); } - glColor3f(1,1,1); glBegin(GL_QUADS); glTexCoord2f(1, 1); From 1e1cc69287d8cdaaf304bbfc05da56ae9564016f Mon Sep 17 00:00:00 2001 From: matsukaze Date: Tue, 10 Jun 2014 22:37:34 -0400 Subject: [PATCH 26/44] Revert "Job #19766 BUG: Stop or reload all scripts crashes interface fixed, part 3" This reverts commit 46f2ab73bccf6fa8669856534f0c20f96ee8c416. --- CMakeLists.txt | 4 - assignment-client/src/AssignmentClient.cpp | 123 ++++++--------------- assignment-client/src/AssignmentClient.h | 48 -------- interface/src/Application.cpp | 9 +- interface/src/Audio.cpp | 29 +---- 5 files changed, 38 insertions(+), 175 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 298b9a791e..cb1e4224cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,10 +20,6 @@ if (NOT QT_CMAKE_PREFIX_PATH) set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) endif () -if (NOT ZLIB_ROOT) - set(ZLIB_ROOT $ENV{ZLIB_ROOT}) -endif () - set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT_CMAKE_PREFIX_PATH}) # set our Base SDK to 10.8 diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index a2faaab651..009bd42e88 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -33,64 +33,6 @@ SharedAssignmentPointer AssignmentClient::_currentAssignment; int hifiSockAddrMeta = qRegisterMetaType("HifiSockAddr"); -template -class Parse : public Parser { -public: - Parse(const QString& option, bool required, T* value) : Parser(option, required), _value(value) {} - bool parse(const QStringList& argumentList); -private: - T* _value; -}; - -template<> -bool Parse::parse(const QStringList& argumentList) { - int argumentIndex = findToken(argumentList); - if (argumentIndex != -1) { - argumentIndex++; - if (argumentList.size() > argumentIndex) { - bool ok; - int value = argumentList[argumentIndex].toInt(&ok); - if (ok) { - *_value = static_cast(value); - } - validateValue(ok); - } else { - valueNotSpecified(); - } - } - return isValid(); -} - -template<> -bool Parse::parse(const QStringList& argumentList) { - int argumentIndex = findToken(argumentList); - if (argumentIndex != -1) { - argumentIndex++; - if (argumentList.size() > argumentIndex) { - *_value = QString(argumentList[argumentIndex]); - validateValue(!_value->isNull()); - } else { - valueNotSpecified(); - } - } - return isValid(); -} - -template<> -bool Parse::parse(const QStringList& argumentList) { - int argumentIndex = findToken(argumentList); - if (argumentIndex != -1) { - argumentIndex++; - if (argumentList.size() > argumentIndex) { - *_value = argumentList[argumentIndex]; - validateValue(true); - } else { - valueNotSpecified(); - } - } - return isValid(); -} - AssignmentClient::AssignmentClient(int &argc, char **argv) : QCoreApplication(argc, argv), _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME) @@ -101,42 +43,40 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : QSettings::setDefaultFormat(QSettings::IniFormat); QStringList argumentList = arguments(); - - // Define parser tokens - const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "-t"; - const QString ASSIGNMENT_POOL_OPTION = "--pool"; - const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "--wallet"; - const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "-a"; - - // Define parser results - Assignment::Type requestAssignmentType = Assignment::AllTypes; - QString assignmentPool; - QUuid walletUUID; - - // Define parsers - _parsers.insert(ASSIGNMENT_TYPE_OVERRIDE_OPTION, new Parse(ASSIGNMENT_TYPE_OVERRIDE_OPTION, false, &requestAssignmentType)); - _parsers.insert(ASSIGNMENT_POOL_OPTION, new Parse(ASSIGNMENT_POOL_OPTION, false, &assignmentPool)); - _parsers.insert(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION, new Parse(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION, false, &walletUUID)); - _parsers.insert(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION, new Parse(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION, false, &_assignmentServerHostname)); - + // register meta type is required for queued invoke method on Assignment subclasses // set the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); - foreach (Parser* option, _parsers) { - if (option) { - option->parse(argumentList); - } + const QString ASSIGNMENT_TYPE_OVVERIDE_OPTION = "-t"; + int argumentIndex = argumentList.indexOf(ASSIGNMENT_TYPE_OVVERIDE_OPTION); + + Assignment::Type requestAssignmentType = Assignment::AllTypes; + + if (argumentIndex != -1) { + requestAssignmentType = (Assignment::Type) argumentList[argumentIndex + 1].toInt(); } - + + const QString ASSIGNMENT_POOL_OPTION = "--pool"; + + argumentIndex = argumentList.indexOf(ASSIGNMENT_POOL_OPTION); + + QString assignmentPool; + + if (argumentIndex != -1) { + assignmentPool = argumentList[argumentIndex + 1]; + } + // setup our _requestAssignment member variable from the passed arguments _requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool); // check if we were passed a wallet UUID on the command line // this would represent where the user running AC wants funds sent to - if (_parsers[ASSIGNMENT_WALLET_DESTINATION_ID_OPTION]->exists() && - _parsers[ASSIGNMENT_WALLET_DESTINATION_ID_OPTION]->isValid()) { + + const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "--wallet"; + if ((argumentIndex = argumentList.indexOf(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) != -1) { + QUuid walletUUID = QString(argumentList[argumentIndex + 1]); qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID); _requestAssignment.setWalletUUID(walletUUID); } @@ -144,9 +84,14 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : // create a NodeList as an unassigned client NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned); - // check for an overriden assignment server hostname - if (_parsers[CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION]->exists() && - _parsers[CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION]->isValid()) { + // check for an overriden assignment server hostname + const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "-a"; + + argumentIndex = argumentList.indexOf(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION); + + if (argumentIndex != -1) { + _assignmentServerHostname = argumentList[argumentIndex + 1]; + // set the custom assignment socket on our NodeList HifiSockAddr customAssignmentSocket = HifiSockAddr(_assignmentServerHostname, DEFAULT_DOMAIN_SERVER_PORT); @@ -168,12 +113,6 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : this, &AssignmentClient::handleAuthenticationRequest); } -AssignmentClient::~AssignmentClient() { - foreach (Parser* option, _parsers) { - delete option; - } -} - void AssignmentClient::sendAssignmentRequest() { if (!_currentAssignment) { NodeList::getInstance()->sendAssignment(_requestAssignment); diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 8951d44135..9834402dbf 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -16,57 +16,11 @@ #include "ThreadedAssignment.h" -class Parser { -public: - Parser(const QString& option, bool required) : _option(option), _required(required), _exists(false), _isValid(false) {} - virtual bool parse(const QStringList& argumentList) { return false; } - bool exists() { return _exists; } - bool isValid() { return _isValid; } - -protected: - int findToken(const QStringList& argumentList) { - int argumentIndex = argumentList.indexOf(_option); - validateOption(argumentIndex); - return argumentIndex; - } - - void validateOption(int index) { - _exists = true; - if (index == -1) { - _exists = false; - if (_required) { - qDebug() << "Command line option " << _option << " is missing"; - } - } - } - - void valueNotSpecified() { - _isValid = false; - qDebug() << "Command line option " << _option << " value is missing"; - } - - void validateValue(bool ok) { - _isValid = ok; - if (!ok) { - qDebug() << "Command line option " << _option << " value is invalid"; - } - } - -private: - QString _option; - bool _required; - bool _exists; - bool _isValid; -}; - class AssignmentClient : public QCoreApplication { Q_OBJECT public: AssignmentClient(int &argc, char **argv); - ~AssignmentClient(); - static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; } - private slots: void sendAssignmentRequest(); void readPendingDatagrams(); @@ -77,8 +31,6 @@ private: Assignment _requestAssignment; static SharedAssignmentPointer _currentAssignment; QString _assignmentServerHostname; - - QMap _parsers; }; #endif // hifi_AssignmentClient_h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 25a5ba8007..9fb821bff4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3483,10 +3483,8 @@ void Application::saveScripts() { } ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor) { - QUrl scriptUrl(scriptName); - const QString& scriptURLString = scriptUrl.toString(); - if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptURLString) && !_scriptEnginesHash[scriptURLString]->isFinished()){ - return _scriptEnginesHash[scriptURLString]; + if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptName) && !_scriptEnginesHash[scriptName]->isFinished()){ + return _scriptEnginesHash[scriptName]; } ScriptEngine* scriptEngine; @@ -3494,8 +3492,9 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface); } else { // start the script on a new thread... + QUrl scriptUrl(scriptName); scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface); - _scriptEnginesHash.insert(scriptURLString, scriptEngine); + _scriptEnginesHash.insert(scriptUrl.toString(), scriptEngine); if (!scriptEngine->hasScript()) { qDebug() << "Application::loadScript(), script failed to load..."; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 1ecfad9007..ebc228a13d 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -219,9 +219,8 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { pPropertyStore->Release(); pPropertyStore = NULL; //QAudio devices seems to only take the 31 first characters of the Friendly Device Name. - //const DWORD QT_WIN_MAX_AUDIO_DEVICENAME_LEN = 31; - // deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal).left(QT_WIN_MAX_AUDIO_DEVICENAME_LEN); - deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal); + const DWORD QT_WIN_MAX_AUDIO_DEVICENAME_LEN = 31; + deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal).left(QT_WIN_MAX_AUDIO_DEVICENAME_LEN); qDebug() << (mode == QAudio::AudioOutput ? "output" : "input") << " device:" << deviceName; PropVariantClear(&pv); } @@ -1078,35 +1077,13 @@ void Audio::renderToolBox(int x, int y, bool boxed) { } _iconBounds = QRect(x, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE); - - static quint64 last = 0; // Hold the last time sample - if (!_muted) { - last = 0; - glColor3f(1,1,1); glBindTexture(GL_TEXTURE_2D, _micTextureId); } else { - quint64 usecTimestampNow(); - static const float CYCLE_DURATION = 3.0f; // Seconds - quint64 now = usecTimestampNow(); - float delta = (float)(now - last) / 1000000.0f; - float from = 1.0f; // Linear fade down (upper bound) - float to = 0.3f; // Linear fade down (lower bound) - - if (delta > CYCLE_DURATION) { - last = now; - delta -= (int)delta; - } else if (delta > (CYCLE_DURATION * 0.5f)) { - // Linear fade up - from = 0.3f; // lower bound - to = 1.0f; // upper bound - } - // Compute a linear ramp to fade the color from full to partial saturation - float linearRamp = (from - to) * delta / CYCLE_DURATION + to; - glColor3f(linearRamp, linearRamp, linearRamp); glBindTexture(GL_TEXTURE_2D, _muteTextureId); } + glColor3f(1,1,1); glBegin(GL_QUADS); glTexCoord2f(1, 1); From 679846267e32a0929045dd86cd914f8c4c80ff91 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Tue, 10 Jun 2014 22:42:01 -0400 Subject: [PATCH 27/44] Job #19766 BUG: Stop or reload all scripts crashes interface fixed, part 3 Same comments as before, but without the local files changes mistakenly checked in. --- interface/src/Application.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9fb821bff4..25a5ba8007 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3483,8 +3483,10 @@ void Application::saveScripts() { } ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor) { - if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptName) && !_scriptEnginesHash[scriptName]->isFinished()){ - return _scriptEnginesHash[scriptName]; + QUrl scriptUrl(scriptName); + const QString& scriptURLString = scriptUrl.toString(); + if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptURLString) && !_scriptEnginesHash[scriptURLString]->isFinished()){ + return _scriptEnginesHash[scriptURLString]; } ScriptEngine* scriptEngine; @@ -3492,9 +3494,8 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface); } else { // start the script on a new thread... - QUrl scriptUrl(scriptName); scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface); - _scriptEnginesHash.insert(scriptUrl.toString(), scriptEngine); + _scriptEnginesHash.insert(scriptURLString, scriptEngine); if (!scriptEngine->hasScript()) { qDebug() << "Application::loadScript(), script failed to load..."; From 41b9c3b7049cc46732cafa9bf833c5c1537b0fd5 Mon Sep 17 00:00:00 2001 From: Dev5 Date: Wed, 11 Jun 2014 09:06:00 -0700 Subject: [PATCH 28/44] Removed empty update function --- examples/growTrees.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/growTrees.js b/examples/growTrees.js index d853804e77..142c72300a 100644 --- a/examples/growTrees.js +++ b/examples/growTrees.js @@ -814,9 +814,6 @@ function mousePressEvent(event) { } -function update() { - -} function scriptEnding() { Overlays.deleteOverlay(linePreviewTop); @@ -832,6 +829,4 @@ Controller.mouseMoveEvent.connect(mouseMoveEvent); Script.scriptEnding.connect(scriptEnding); -Script.update.connect(update); - Voxels.setPacketsPerSecond(10000); From fc07ceb412d1975d3b3fc07374073e3eb55bc1c9 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 11 Jun 2014 10:54:44 -0700 Subject: [PATCH 29/44] added killNode() slot for _packetCounts garbage collection --- interface/src/Application.cpp | 1 + libraries/networking/src/ReceivedPacketProcessor.cpp | 4 ++++ libraries/networking/src/ReceivedPacketProcessor.h | 3 +++ 3 files changed, 8 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eab15ed678..2b3256141e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -244,6 +244,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer))); connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer))); + connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_octreeProcessor, SLOT(nodeKilled(SharedNodePointer))); connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle); connect(nodeList, SIGNAL(uuidChanged(const QUuid&)), _myAvatar, SLOT(setSessionUUID(const QUuid&))); connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset); diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index 46f1515016..d556e8a059 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -49,3 +49,7 @@ bool ReceivedPacketProcessor::process() { } return isStillRunning(); // keep running till they terminate us } + +void ReceivedPacketProcessor::killNode(const SharedNodePointer& node) { + _nodePacketCounts.remove(node->getUUID()); +} diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index 096005ffe7..80fe75aaa7 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -41,6 +41,9 @@ public: /// How many received packets waiting are to be processed int packetsToProcessCount() const { return _packets.size(); } +public slots: + void killNode(const SharedNodePointer& node); + protected: /// Callback for processing of recieved packets. Implement this to process the incoming packets. /// \param SharedNodePointer& sendingNode the node that sent this packet From 760627003f353a1552e8e94b050698b2c233bd5a Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 11 Jun 2014 11:11:04 -0700 Subject: [PATCH 30/44] killNode() to nodeKilled() --- libraries/networking/src/ReceivedPacketProcessor.cpp | 4 ++-- libraries/networking/src/ReceivedPacketProcessor.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index d556e8a059..e919017128 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -50,6 +50,6 @@ bool ReceivedPacketProcessor::process() { return isStillRunning(); // keep running till they terminate us } -void ReceivedPacketProcessor::killNode(const SharedNodePointer& node) { - _nodePacketCounts.remove(node->getUUID()); +void ReceivedPacketProcessor::nodeKilled(const SharedNodePointer& node) { + int numRemoved = _nodePacketCounts.remove(node->getUUID()); } diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index 80fe75aaa7..23303cbb55 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -42,7 +42,7 @@ public: int packetsToProcessCount() const { return _packets.size(); } public slots: - void killNode(const SharedNodePointer& node); + void nodeKilled(const SharedNodePointer& node); protected: /// Callback for processing of recieved packets. Implement this to process the incoming packets. From decd6109fbda6682d97ae23432bfe9b2ac5c4cd8 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 11 Jun 2014 11:57:54 -0700 Subject: [PATCH 31/44] made nodeKilled signatures match --- libraries/networking/src/ReceivedPacketProcessor.cpp | 2 +- libraries/networking/src/ReceivedPacketProcessor.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index e919017128..59165b45b6 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -50,6 +50,6 @@ bool ReceivedPacketProcessor::process() { return isStillRunning(); // keep running till they terminate us } -void ReceivedPacketProcessor::nodeKilled(const SharedNodePointer& node) { +void ReceivedPacketProcessor::nodeKilled(SharedNodePointer node) { int numRemoved = _nodePacketCounts.remove(node->getUUID()); } diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index 23303cbb55..94ad2d9c41 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -42,7 +42,7 @@ public: int packetsToProcessCount() const { return _packets.size(); } public slots: - void nodeKilled(const SharedNodePointer& node); + void nodeKilled(SharedNodePointer node); protected: /// Callback for processing of recieved packets. Implement this to process the incoming packets. From 2080cc3dee753d072b005bbac3e868ab8bd0716a Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 11 Jun 2014 11:59:15 -0700 Subject: [PATCH 32/44] removed debug variable --- libraries/networking/src/ReceivedPacketProcessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index 59165b45b6..32fc4e26f3 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -51,5 +51,5 @@ bool ReceivedPacketProcessor::process() { } void ReceivedPacketProcessor::nodeKilled(SharedNodePointer node) { - int numRemoved = _nodePacketCounts.remove(node->getUUID()); + _nodePacketCounts.remove(node->getUUID()); } From a8c97800048043e4908743601ae95b3c92fe80d9 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 11 Jun 2014 12:13:27 -0700 Subject: [PATCH 33/44] updated connect() to qt5 format --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2b3256141e..a5cb6a0c12 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -244,7 +244,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer))); connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer))); - connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_octreeProcessor, SLOT(nodeKilled(SharedNodePointer))); + connect(NodeList::getInstance(), &NodeList::nodeKilled, &_octreeProcessor, &ReceivedPacketProcessor::nodeKilled); connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle); connect(nodeList, SIGNAL(uuidChanged(const QUuid&)), _myAvatar, SLOT(setSessionUUID(const QUuid&))); connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset); From 82bf6002e2c3c0aaa471b8f7f5233e645cfe5174 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 11 Jun 2014 14:57:05 -0700 Subject: [PATCH 34/44] only display the OAuthWebViewHandler when we need to ask user for authorization --- interface/src/Menu.cpp | 9 ++++++--- interface/src/Menu.h | 2 ++ interface/src/ui/OAuthWebViewHandler.cpp | 17 ++++++++++++++++- interface/src/ui/OAuthWebViewHandler.h | 1 + 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f791d20588..c2b6c293b9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -103,6 +103,7 @@ Menu::Menu() : _fastFPSAverage(ONE_SECOND_OF_FRAMES), _loginAction(NULL), _preferencesDialog(NULL), + _loginDialog(NULL), _snapshotsLocation() { Application *appInstance = Application::getInstance(); @@ -913,9 +914,11 @@ void sendFakeEnterEvent() { const float DIALOG_RATIO_OF_WINDOW = 0.30f; void Menu::loginForCurrentDomain() { - LoginDialog* loginDialog = new LoginDialog(Application::getInstance()->getWindow()); - loginDialog->show(); - loginDialog->resizeAndPosition(false); + if (!_loginDialog) { + _loginDialog = new LoginDialog(Application::getInstance()->getWindow()); + _loginDialog->show(); + _loginDialog->resizeAndPosition(false); + } } void Menu::editPreferences() { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 69015a938b..a0fafc0514 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -27,6 +27,7 @@ #include "ui/PreferencesDialog.h" #include "ui/ChatWindow.h" #include "ui/JSConsole.h" +#include "ui/LoginDialog.h" #include "ui/ScriptEditorWindow.h" const float ADJUST_LOD_DOWN_FPS = 40.0; @@ -270,6 +271,7 @@ private: QPointer _preferencesDialog; QPointer _attachmentsDialog; QPointer _animationsDialog; + QPointer _loginDialog; QAction* _chatAction; QString _snapshotsLocation; }; diff --git a/interface/src/ui/OAuthWebViewHandler.cpp b/interface/src/ui/OAuthWebViewHandler.cpp index 5415d5d9c3..5b4431bd0f 100644 --- a/interface/src/ui/OAuthWebViewHandler.cpp +++ b/interface/src/ui/OAuthWebViewHandler.cpp @@ -103,8 +103,9 @@ void OAuthWebViewHandler::displayWebviewForAuthorizationURL(const QUrl& authoriz codedAuthorizationURL.setQuery(authQuery); } + connect(_activeWebView.data(), &QWebView::urlChanged, this, &OAuthWebViewHandler::handleURLChanged); + _activeWebView->load(codedAuthorizationURL); - _activeWebView->show(); connect(_activeWebView->page()->networkAccessManager(), &QNetworkAccessManager::sslErrors, this, &OAuthWebViewHandler::handleSSLErrors); @@ -137,3 +138,17 @@ void OAuthWebViewHandler::handleLoadFinished(bool success) { void OAuthWebViewHandler::handleWebViewDestroyed(QObject* destroyedObject) { _webViewRedisplayTimer.restart(); } + +void OAuthWebViewHandler::handleURLChanged(const QUrl& url) { + // check if this is the authorization screen - if it is then we need to show the OAuthWebViewHandler + const QString ACCESS_TOKEN_URL_REGEX_STRING = "redirect_uri=[\\w:\\/\\.]+&access_token="; + QRegExp accessTokenRegex(ACCESS_TOKEN_URL_REGEX_STRING); + + if (accessTokenRegex.indexIn(url.toString()) != -1) { + _activeWebView->show(); + } else if (url.toString() == DEFAULT_NODE_AUTH_URL.toString() + "/login") { + // this is a login request - we're going to close the webview and signal the AccountManager that we need a login + _activeWebView->close(); + AccountManager::getInstance().checkAndSignalForAccessToken(); + } +} diff --git a/interface/src/ui/OAuthWebViewHandler.h b/interface/src/ui/OAuthWebViewHandler.h index 3a30705f88..8f0c01c90d 100644 --- a/interface/src/ui/OAuthWebViewHandler.h +++ b/interface/src/ui/OAuthWebViewHandler.h @@ -32,6 +32,7 @@ private slots: void handleSSLErrors(QNetworkReply* networkReply, const QList& errorList); void handleLoadFinished(bool success); void handleWebViewDestroyed(QObject* destroyedObject); + void handleURLChanged(const QUrl& url); private: QPointer _activeWebView; QElapsedTimer _webViewRedisplayTimer; From ac0b037f0f8398fc97efbe187dd50d845e3cad44 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 11 Jun 2014 15:25:00 -0700 Subject: [PATCH 35/44] removed connect(); put call into Application::nodeKilled OctreePacketReceiver::nodeKilled() doesn't get called when NodeList::nodeKilled() is emitted for some unknown reason --- interface/src/Application.cpp | 6 +++++- libraries/networking/src/LimitedNodeList.cpp | 1 + libraries/networking/src/ReceivedPacketProcessor.cpp | 6 +++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a5cb6a0c12..7a7d7c10f8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -244,7 +244,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer))); connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer))); - connect(NodeList::getInstance(), &NodeList::nodeKilled, &_octreeProcessor, &ReceivedPacketProcessor::nodeKilled); connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle); connect(nodeList, SIGNAL(uuidChanged(const QUuid&)), _myAvatar, SLOT(setSessionUUID(const QUuid&))); connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset); @@ -3249,6 +3248,11 @@ void Application::nodeAdded(SharedNodePointer node) { } void Application::nodeKilled(SharedNodePointer node) { + + // this is here because connecting NodeList::nodeKilled to OctreePacketProcessor::nodeKilled doesn't work: + // OctreePacketProcessor::nodeKilled is not called when NodeList::nodeKilled is emitted for some reason. + _octreeProcessor.nodeKilled(node); + if (node->getType() == NodeType::VoxelServer) { QUuid nodeUUID = node->getUUID(); // see if this is the first we've heard of this node... diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index c0d7941edf..e1babb24ce 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -367,6 +367,7 @@ void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) { NodeHash::iterator LimitedNodeList::killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill) { qDebug() << "Killed" << *nodeItemToKill.value(); emit nodeKilled(nodeItemToKill.value()); +printf("\t\t\t emitting nodeKilled: %s\n", nodeItemToKill.value()->getUUID().toString().toLatin1().data()); return _nodeHash.erase(nodeItemToKill); } diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index 32fc4e26f3..28a9397c60 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -51,5 +51,9 @@ bool ReceivedPacketProcessor::process() { } void ReceivedPacketProcessor::nodeKilled(SharedNodePointer node) { - _nodePacketCounts.remove(node->getUUID()); + lock(); + int numRemoved = _nodePacketCounts.remove(node->getUUID()); + unlock(); + qDebug() << "RPP::killNode *************************************"; + printf("\t\t RPP::killNode: %s killed %d nodes\n", node->getUUID().toString().toLatin1().data(), numRemoved); } From 0601c24b2485370a8e01a7147f9a68ff09f42a23 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 11 Jun 2014 15:26:22 -0700 Subject: [PATCH 36/44] removed debug prints --- libraries/networking/src/LimitedNodeList.cpp | 1 - libraries/networking/src/ReceivedPacketProcessor.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index e1babb24ce..c0d7941edf 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -367,7 +367,6 @@ void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) { NodeHash::iterator LimitedNodeList::killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill) { qDebug() << "Killed" << *nodeItemToKill.value(); emit nodeKilled(nodeItemToKill.value()); -printf("\t\t\t emitting nodeKilled: %s\n", nodeItemToKill.value()->getUUID().toString().toLatin1().data()); return _nodeHash.erase(nodeItemToKill); } diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index 28a9397c60..5513376c65 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -54,6 +54,4 @@ void ReceivedPacketProcessor::nodeKilled(SharedNodePointer node) { lock(); int numRemoved = _nodePacketCounts.remove(node->getUUID()); unlock(); - qDebug() << "RPP::killNode *************************************"; - printf("\t\t RPP::killNode: %s killed %d nodes\n", node->getUUID().toString().toLatin1().data(), numRemoved); } From 7aef5edb8fcd7f9c2839101f33239eac8743556e Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 11 Jun 2014 15:27:24 -0700 Subject: [PATCH 37/44] removed debug var --- libraries/networking/src/ReceivedPacketProcessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index 5513376c65..3ef518bbc2 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -52,6 +52,6 @@ bool ReceivedPacketProcessor::process() { void ReceivedPacketProcessor::nodeKilled(SharedNodePointer node) { lock(); - int numRemoved = _nodePacketCounts.remove(node->getUUID()); + _nodePacketCounts.remove(node->getUUID()); unlock(); } From eff097638ce6c12e700e561331594b8b6976f986 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 11 Jun 2014 17:02:08 -0700 Subject: [PATCH 38/44] Implementd sixense mouse emulation --- interface/src/Application.cpp | 10 +++- interface/src/devices/SixenseManager.cpp | 68 +++++++++++++++++++++ interface/src/devices/SixenseManager.h | 9 +++ interface/src/ui/ApplicationOverlay.cpp | 75 +++++++++++++++++++++++- 4 files changed, 159 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2b3256141e..6035cdd7cb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1090,6 +1090,13 @@ void Application::focusOutEvent(QFocusEvent* event) { } void Application::mouseMoveEvent(QMouseEvent* event) { + + bool showMouse = true; + // If this mouse move event is emitted by a controller, dont show the mouse cursor + if (event->type() == CONTROLLER_MOVE_EVENT) { + showMouse = false; + } + _controllerScriptingInterface.emitMouseMoveEvent(event); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it @@ -1097,10 +1104,9 @@ void Application::mouseMoveEvent(QMouseEvent* event) { return; } - _lastMouseMove = usecTimestampNow(); - if (_mouseHidden && !OculusManager::isConnected()) { + if (_mouseHidden && showMouse && !OculusManager::isConnected()) { getGLWidget()->setCursor(Qt::ArrowCursor); _mouseHidden = false; _seenMouseMove = true; diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 8cd3cc059e..4ecb416a92 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -39,6 +39,10 @@ SixenseManager::SixenseManager() { sixenseInit(); #endif + _triggerPressed = false; + _bumperPressed = false; + _oldPos.setX(-1); + _oldPos.setY(-1); } SixenseManager::~SixenseManager() { @@ -107,6 +111,12 @@ void SixenseManager::update(float deltaTime) { palm->setTrigger(data->trigger); palm->setJoystick(data->joystick_x, data->joystick_y); + + // Emulate the mouse so we can use scripts + if (numActiveControllers == 2) { + emulateMouse(palm); + } + // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters. glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); position *= METERS_PER_MILLIMETER; @@ -313,5 +323,63 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) } } } + +//Injecting mouse movements and clicks +void SixenseManager::emulateMouse(PalmData *palm) { + MyAvatar* avatar = Application::getInstance()->getAvatar(); + QPoint pos; + // Get directon relative to avatar orientation + glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection(); + + // Get the angles, scaled between 0-1 + float xAngle = (atan2(direction.z, direction.x) + M_PI_2) + 0.5f; + float yAngle = 1.0f - ((atan2(direction.z, direction.y) + M_PI_2) + 0.5f); + + float cursorRange = Application::getInstance()->getGLWidget()->width(); + + pos.setX(cursorRange * xAngle); + pos.setY(cursorRange * yAngle); + + //If position has changed, emit a mouse move to the application + if (pos.x() != _oldPos.x() || pos.y() != _oldPos.y()) { + QMouseEvent mouseEvent(static_cast(CONTROLLER_MOVE_EVENT), pos, Qt::NoButton, Qt::NoButton, 0); + + Application::getInstance()->mouseMoveEvent(&mouseEvent); + } + _oldPos = pos; + + //Check for bumper press ( Right Click ) + if (palm->getControllerButtons() & BUTTON_FWD) { + if (!_bumperPressed) { + _bumperPressed = true; + QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, Qt::RightButton, Qt::RightButton, 0); + + Application::getInstance()->mousePressEvent(&mouseEvent); + } + } else if (_bumperPressed) { + QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, Qt::RightButton, Qt::RightButton, 0); + + Application::getInstance()->mouseReleaseEvent(&mouseEvent); + + _bumperPressed = false; + } + + //Check for trigger press ( Left Click ) + if (palm->getTrigger() == 1.0f) { + if (!_triggerPressed) { + _triggerPressed = true; + QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, Qt::LeftButton, Qt::LeftButton, 0); + + Application::getInstance()->mousePressEvent(&mouseEvent); + } + } else if (_triggerPressed) { + QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, Qt::LeftButton, Qt::LeftButton, 0); + + Application::getInstance()->mouseReleaseEvent(&mouseEvent); + + _triggerPressed = false; + } +} + #endif // HAVE_SIXENSE diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index a98d4c0e4e..061b3cc625 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -27,6 +27,9 @@ const unsigned int BUTTON_3 = 1U << 3; const unsigned int BUTTON_4 = 1U << 4; const unsigned int BUTTON_FWD = 1U << 7; +// Event type that represents moving the controller +const unsigned int CONTROLLER_MOVE_EVENT = 1500U; + /// Handles interaction with the Sixense SDK (e.g., Razer Hydra). class SixenseManager : public QObject { Q_OBJECT @@ -44,6 +47,7 @@ public slots: private: #ifdef HAVE_SIXENSE void updateCalibration(const sixenseControllerData* controllers); + void emulateMouse(PalmData *palm); int _calibrationState; @@ -65,6 +69,11 @@ private: #endif quint64 _lastMovement; glm::vec3 _amountMoved; + + // for mouse emulation + bool _triggerPressed; + bool _bumperPressed; + QPoint _oldPos; }; #endif // hifi_SixenseManager_h diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index a48e0a2c1a..750be96cc9 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -35,6 +35,78 @@ ApplicationOverlay::~ApplicationOverlay() { const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; +void renderControllerPointer() +{ + Application* application = Application::getInstance(); + QGLWidget* glWidget = application->getGLWidget(); + MyAvatar* myAvatar = application->getAvatar(); + + const HandData* handData = Application::getInstance()->getAvatar()->getHandData(); + int numberOfPalms = handData->getNumPalms(); + + + int palmIndex = 3; + const PalmData* palmData = NULL; + + if (palmIndex >= handData->getPalms().size()) { + return; + } + + if (handData->getPalms()[palmIndex].isActive()) { + palmData = &handData->getPalms()[palmIndex]; + } else { + return; + } + + // Get directon relative to avatar orientation + glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection(); + + // Get the angles, scaled between 0-1 + float xAngle = (atan2(direction.z, direction.x) + M_PI_2) + 0.5f; + float yAngle = 1.0f - ((atan2(direction.z, direction.y) + M_PI_2) + 0.5f); + + float cursorRange = glWidget->width(); + + int mouseX = cursorRange * xAngle; + int mouseY = cursorRange * yAngle; + + if (mouseX < 0) { + mouseX = 0; + } else if (mouseX > glWidget->width()) { + mouseX = glWidget->width(); + } + if (mouseY < 0) { + mouseY = 0; + } else if (mouseY > glWidget->width()) { + mouseY = glWidget->width(); + } + + const float pointerWidth = 40; + const float pointerHeight = 40; + const float crossPad = 16; + + mouseX -= pointerWidth / 2.0f; + mouseY += pointerHeight / 2.0f; + + glBegin(GL_QUADS); + + glColor3f(0, 0, 1); + + //Horizontal crosshair + glVertex2i(mouseX, mouseY - crossPad); + glVertex2i(mouseX + pointerWidth, mouseY - crossPad); + glVertex2i(mouseX + pointerWidth, mouseY - pointerHeight + crossPad); + glVertex2i(mouseX, mouseY - pointerHeight + crossPad); + + //Vertical crosshair + glVertex2i(mouseX + crossPad, mouseY); + glVertex2i(mouseX + pointerWidth - crossPad, mouseY); + glVertex2i(mouseX + pointerWidth - crossPad, mouseY - pointerHeight); + glVertex2i(mouseX + crossPad, mouseY - pointerHeight); + + glEnd(); +} + // Renders the overlays either to a texture or to the screen void ApplicationOverlay::renderOverlay(bool renderToTexture) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); @@ -254,8 +326,9 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { glVertex2i(mouseX + crossPad, mouseY - pointerHeight); glEnd(); + } else { //only render controller pointer if we aren't already rendering a mouse pointer + renderControllerPointer(); } - glPopMatrix(); glMatrixMode(GL_MODELVIEW); From 2fec7400e2d06d2f9f730d32f42db8be802ec511 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 11 Jun 2014 17:21:59 -0700 Subject: [PATCH 39/44] Added menu options for sixense mouse input --- interface/src/Menu.cpp | 5 ++++ interface/src/Menu.h | 3 ++ interface/src/devices/SixenseManager.cpp | 35 ++++++++++++++++++++---- interface/src/ui/ApplicationOverlay.cpp | 10 +++++-- 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f791d20588..f78b8a822f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -379,6 +379,11 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(oculusOptionsMenu, MenuOption::AllowOculusCameraModeChange, 0, false); addCheckableActionToQMenuAndActionHash(oculusOptionsMenu, MenuOption::DisplayOculusOverlays, 0, true); + QMenu* sixenseOptionsMenu = developerMenu->addMenu("Sixense Options"); + addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true); + addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseLeftHanded, 0, false); + addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseInvertInputButtons, 0, false); + QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); addCheckableActionToQMenuAndActionHash(handOptionsMenu, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 69015a938b..40c6e646d9 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -397,6 +397,9 @@ namespace MenuOption { const QString SettingsExport = "Export Settings"; const QString SettingsImport = "Import Settings"; const QString SimpleShadows = "Simple"; + const QString SixenseInvertInputButtons = "Invert Sixense Mouse Input Buttons"; + const QString SixenseLeftHanded = "Left Handed Sixense Mouse Input"; + const QString SixenseMouseInput = "Enable Sixense Mouse Input"; const QString ShowBordersVoxelNodes = "Show Voxel Nodes"; const QString ShowBordersModelNodes = "Show Model Nodes"; const QString ShowBordersParticleNodes = "Show Particle Nodes"; diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 4ecb416a92..f347d09af9 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -113,8 +113,16 @@ void SixenseManager::update(float deltaTime) { // Emulate the mouse so we can use scripts - if (numActiveControllers == 2) { - emulateMouse(palm); + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLeftHanded)) { + if (numActiveControllers == 1){ + emulateMouse(palm); + } + } else { + if (numActiveControllers == 2) { + emulateMouse(palm); + } + } } // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters. @@ -348,16 +356,28 @@ void SixenseManager::emulateMouse(PalmData *palm) { } _oldPos = pos; + Qt::MouseButton bumperButton; + Qt::MouseButton triggerButton; + + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseInvertInputButtons)) { + bumperButton = Qt::LeftButton; + triggerButton = Qt::RightButton; + } else { + bumperButton = Qt::RightButton; + triggerButton = Qt::LeftButton; + } + //Check for bumper press ( Right Click ) if (palm->getControllerButtons() & BUTTON_FWD) { if (!_bumperPressed) { _bumperPressed = true; - QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, Qt::RightButton, Qt::RightButton, 0); + + QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, bumperButton, bumperButton, 0); Application::getInstance()->mousePressEvent(&mouseEvent); } } else if (_bumperPressed) { - QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, Qt::RightButton, Qt::RightButton, 0); + QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, bumperButton, bumperButton, 0); Application::getInstance()->mouseReleaseEvent(&mouseEvent); @@ -368,17 +388,20 @@ void SixenseManager::emulateMouse(PalmData *palm) { if (palm->getTrigger() == 1.0f) { if (!_triggerPressed) { _triggerPressed = true; - QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, Qt::LeftButton, Qt::LeftButton, 0); + + QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, triggerButton, triggerButton, 0); Application::getInstance()->mousePressEvent(&mouseEvent); } } else if (_triggerPressed) { - QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent mouseEvent(QEvent::MouseButtonRelease, pos, triggerButton, triggerButton, 0); Application::getInstance()->mouseReleaseEvent(&mouseEvent); _triggerPressed = false; } + + } #endif // HAVE_SIXENSE diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 750be96cc9..401062bb36 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -45,7 +45,12 @@ void renderControllerPointer() int numberOfPalms = handData->getNumPalms(); - int palmIndex = 3; + int palmIndex; + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLeftHanded)) { + palmIndex = 2; + } else { + palmIndex = 3; + } const PalmData* palmData = NULL; if (palmIndex >= handData->getPalms().size()) { @@ -326,7 +331,8 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { glVertex2i(mouseX + crossPad, mouseY - pointerHeight); glEnd(); - } else { //only render controller pointer if we aren't already rendering a mouse pointer + } else if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { + //only render controller pointer if we aren't already rendering a mouse pointer renderControllerPointer(); } glPopMatrix(); From d993fd52f2d678e02fed0aafb5142b218634f13f Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 11 Jun 2014 17:27:00 -0700 Subject: [PATCH 40/44] Cleaned up a small bit of code --- interface/src/devices/SixenseManager.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index f347d09af9..2a0db69d52 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -114,14 +114,9 @@ void SixenseManager::update(float deltaTime) { // Emulate the mouse so we can use scripts if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { - if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLeftHanded)) { - if (numActiveControllers == 1){ - emulateMouse(palm); - } - } else { - if (numActiveControllers == 2) { - emulateMouse(palm); - } + // Check if we are on the correct palm + if ((Menu::getInstance()->isOptionChecked(MenuOption::SixenseLeftHanded) && numActiveControllers == 1) || numActiveControllers == 2) { + emulateMouse(palm); } } From 14a591c5d853631102e6003cbae2f108bfabc43f Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 11 Jun 2014 17:35:50 -0700 Subject: [PATCH 41/44] Move to previous line --- interface/src/ui/ApplicationOverlay.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 401062bb36..924c2e9d84 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -35,8 +35,7 @@ ApplicationOverlay::~ApplicationOverlay() { const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; -void renderControllerPointer() -{ +void renderControllerPointer() { Application* application = Application::getInstance(); QGLWidget* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); From 32a9eed88d8728f1221b14f6799a0cda672305bd Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 11 Jun 2014 18:05:10 -0700 Subject: [PATCH 42/44] Fixed build failure --- interface/src/devices/SixenseManager.cpp | 9 +++++---- interface/src/devices/SixenseManager.h | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 2a0db69d52..abbb32ec5e 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -41,8 +41,8 @@ SixenseManager::SixenseManager() { #endif _triggerPressed = false; _bumperPressed = false; - _oldPos.setX(-1); - _oldPos.setY(-1); + _oldX = -1; + _oldY = -1; } SixenseManager::~SixenseManager() { @@ -344,12 +344,13 @@ void SixenseManager::emulateMouse(PalmData *palm) { pos.setY(cursorRange * yAngle); //If position has changed, emit a mouse move to the application - if (pos.x() != _oldPos.x() || pos.y() != _oldPos.y()) { + if (pos.x() != _oldX || pos.y() != _oldY) { QMouseEvent mouseEvent(static_cast(CONTROLLER_MOVE_EVENT), pos, Qt::NoButton, Qt::NoButton, 0); Application::getInstance()->mouseMoveEvent(&mouseEvent); } - _oldPos = pos; + _oldX = pos.x(); + _oldY = pos.y(); Qt::MouseButton bumperButton; Qt::MouseButton triggerButton; diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 061b3cc625..93888ce944 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -73,7 +73,8 @@ private: // for mouse emulation bool _triggerPressed; bool _bumperPressed; - QPoint _oldPos; + int _oldX; + int _oldY; }; #endif // hifi_SixenseManager_h From 1503946b7c0046ca751c4487d0bf65287395f567 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Jun 2014 21:11:49 -0700 Subject: [PATCH 43/44] Fix build warning in Audio.cpp \interface\src\Audio.cpp(309): warning C4018: '<' : signed/unsigned mismatch --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index ebc228a13d..2cbe3a062f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -306,7 +306,7 @@ void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples, } else { // this is a 48 to 24 resampling but both source and destination are two channels // squish two samples into one in each channel - for (int i = 0; i < numSourceSamples; i += 4) { + for (unsigned int i = 0; i < numSourceSamples; i += 4) { destinationSamples[i / 2] = (sourceSamples[i] / 2) + (sourceSamples[i + 2] / 2); destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] / 2) + (sourceSamples[i + 3] / 2); } From d689c6b39fe31753cd4b5b5519d34cd566516e63 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 12 Jun 2014 13:15:54 -0700 Subject: [PATCH 44/44] fix reference to attribute in STUN packet --- libraries/networking/src/NodeList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 9a298ce26c..b872ec12cf 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -281,7 +281,7 @@ void NodeList::processSTUNResponse(const QByteArray& packet) { int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN; uint8_t addressFamily = 0; - memcpy(&addressFamily, packet.data(), sizeof(addressFamily)); + memcpy(&addressFamily, packet.data() + byteIndex, sizeof(addressFamily)); byteIndex += sizeof(addressFamily);