From 7f6dc7ac2fbc98562ae3f301deed701db5d4742a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 2 Apr 2014 09:56:30 -0700 Subject: [PATCH 01/37] Updated translations. --- interface/interface_en.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 3f859c2cd1..c990ef0f20 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) From 40844d2000ede56d4ac04f6de713e2def80935d7 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 2 Apr 2014 12:40:01 -0700 Subject: [PATCH 02/37] Working on ability to set a region of the metavoxel data directly. --- .../src/metavoxels/MetavoxelServer.cpp | 2 + libraries/metavoxels/src/Bitstream.h | 7 ++ libraries/metavoxels/src/MetavoxelData.cpp | 92 ++++++++++++++++++- libraries/metavoxels/src/MetavoxelData.h | 18 +++- .../metavoxels/src/MetavoxelMessages.cpp | 9 ++ libraries/metavoxels/src/MetavoxelMessages.h | 17 ++++ 6 files changed, 139 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index 98c91d44e7..23c8f2189c 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -95,6 +95,8 @@ MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const SharedNodePoin connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&))); connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int))); connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleMessage(const QVariant&))); + connect(_sequencer.getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)), + SLOT(handleMessage(const QVariant&))); // insert the baseline send record SendRecord record = { 0 }; diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 760154a928..8f36ce9a08 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -920,6 +920,13 @@ public: _Pragma(STRINGIFY(unused(_TypePtr##X))) #endif +/// Registers a simple type and its streamer. +template int registerSimpleMetaType() { + int type = qRegisterMetaType(); + Bitstream::registerTypeStreamer(type, new SimpleTypeStreamer()); + return type; +} + /// Registers a streamable type and its streamer. template int registerStreamableMetaType() { int type = qRegisterMetaType(); diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index e548de46c7..c89967b3a0 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -24,6 +24,8 @@ REGISTER_META_OBJECT(Spanner) REGISTER_META_OBJECT(Sphere) REGISTER_META_OBJECT(StaticModel) +static int metavoxelDataTypeId = registerSimpleMetaType(); + MetavoxelLOD::MetavoxelLOD(const glm::vec3& position, float threshold) : position(position), threshold(threshold) { @@ -327,6 +329,67 @@ const int Y_MAXIMUM_FLAG = 2; const int Z_MAXIMUM_FLAG = 4; const int MAXIMUM_FLAG_MASK = X_MAXIMUM_FLAG | Y_MAXIMUM_FLAG | Z_MAXIMUM_FLAG; +static glm::vec3 getNextMinimum(const glm::vec3& minimum, float nextSize, int index) { + return minimum + glm::vec3( + (index & X_MAXIMUM_FLAG) ? nextSize : 0.0f, + (index & Y_MAXIMUM_FLAG) ? nextSize : 0.0f, + (index & Z_MAXIMUM_FLAG) ? nextSize : 0.0f); +} + +static void setNode(const AttributePointer& attribute, MetavoxelNode*& node, MetavoxelNode* other) { + if (node) { + node->decrementReferenceCount(attribute); + } + (node = other)->incrementReferenceCount(); +} + +static void setNode(const AttributeValue& value, MetavoxelNode*& node, const glm::vec3& minimum, float size, + MetavoxelNode* other, const glm::vec3& otherMinimum, float otherSize) { + if (otherSize >= size) { + setNode(value.getAttribute(), node, other); + return; + } + if (!node) { + node = new MetavoxelNode(value); + } + int index = 0; + float otherHalfSize = otherSize * 0.5f; + float nextSize = size * 0.5f; + if (otherMinimum.x + otherHalfSize >= minimum.x + nextSize) { + index |= X_MAXIMUM_FLAG; + } + if (otherMinimum.y + otherHalfSize >= minimum.y + nextSize) { + index |= Y_MAXIMUM_FLAG; + } + if (otherMinimum.z + otherHalfSize >= minimum.z + nextSize) { + index |= Z_MAXIMUM_FLAG; + } + if (node->isLeaf()) { + for (int i = 1; i < MetavoxelNode::CHILD_COUNT; i++) { + node->setChild((index + i) % MetavoxelNode::CHILD_COUNT, new MetavoxelNode( + node->getAttributeValue(value.getAttribute()))); + } + } + MetavoxelNode* nextNode = node->getChild(index); + setNode(node->getAttributeValue(value.getAttribute()), nextNode, getNextMinimum(minimum, nextSize, index), + nextSize, other, otherMinimum, otherSize); + node->setChild(index, nextNode); +} + +void MetavoxelData::set(const glm::vec3& minimum, const MetavoxelData& data) { + // expand to fit the entire data + Box bounds = minimum + glm::vec3(data.getSize(), data.getSize(), data.getSize()); + while (!getBounds().contains(bounds)) { + expand(); + } + + // set each attribute separately + for (QHash::const_iterator it = data._roots.constBegin(); + it != data._roots.constEnd(); it++) { + setNode(it.key(), _roots[it.key()], getMinimum(), getSize(), it.value(), minimum, data.getSize()); + } +} + static int getOppositeIndex(int index) { return index ^ MAXIMUM_FLAG_MASK; } @@ -511,6 +574,14 @@ MetavoxelNode* MetavoxelData::createRoot(const AttributePointer& attribute) { return root = new MetavoxelNode(attribute); } +bool MetavoxelData::operator==(const MetavoxelData& other) const { + return _size == other._size && _roots == other._roots; +} + +bool MetavoxelData::operator!=(const MetavoxelData& other) const { + return _size != other._size || _roots != other._roots; +} + void MetavoxelData::incrementRootReferenceCounts() { for (QHash::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) { it.value()->incrementReferenceCount(); @@ -523,11 +594,22 @@ void MetavoxelData::decrementRootReferenceCounts() { } } -static glm::vec3 getNextMinimum(const glm::vec3& minimum, float nextSize, int index) { - return minimum + glm::vec3( - (index & X_MAXIMUM_FLAG) ? nextSize : 0.0f, - (index & Y_MAXIMUM_FLAG) ? nextSize : 0.0f, - (index & Z_MAXIMUM_FLAG) ? nextSize : 0.0f); +Bitstream& operator<<(Bitstream& out, const MetavoxelData& data) { + data.write(out); + return out; +} + +Bitstream& operator>>(Bitstream& in, MetavoxelData& data) { + data.read(in); + return in; +} + +template<> void Bitstream::writeDelta(const MetavoxelData& value, const MetavoxelData& reference) { + value.writeDelta(reference, MetavoxelLOD(), *this, MetavoxelLOD()); +} + +template<> void Bitstream::readDelta(MetavoxelData& value, const MetavoxelData& reference) { + value.readDelta(reference, MetavoxelLOD(), *this, MetavoxelLOD()); } bool MetavoxelStreamState::shouldSubdivide() const { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index fa408aafb7..4db2e919b4 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -90,6 +90,9 @@ public: SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, float& distance, const MetavoxelLOD& lod = MetavoxelLOD()); + /// Sets part of the data. + void set(const glm::vec3& minimum, const MetavoxelData& data); + /// Expands the tree, increasing its capacity in all dimensions. void expand(); @@ -103,6 +106,9 @@ public: MetavoxelNode* getRoot(const AttributePointer& attribute) const { return _roots.value(attribute); } MetavoxelNode* createRoot(const AttributePointer& attribute); + bool operator==(const MetavoxelData& other) const; + bool operator!=(const MetavoxelData& other) const; + private: friend class MetavoxelVisitation; @@ -114,6 +120,16 @@ private: QHash _roots; }; +Bitstream& operator<<(Bitstream& out, const MetavoxelData& data); + +Bitstream& operator>>(Bitstream& in, MetavoxelData& data); + +template<> void Bitstream::writeDelta(const MetavoxelData& value, const MetavoxelData& reference); + +template<> void Bitstream::readDelta(MetavoxelData& value, const MetavoxelData& reference); + +Q_DECLARE_METATYPE(MetavoxelData) + /// Holds the state used in streaming metavoxel data. class MetavoxelStreamState { public: @@ -592,7 +608,7 @@ public: const QUrl& getURL() const { return _url; } virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - const glm::vec3& clipMinimum, float clipSize,float& distance) const; + const glm::vec3& clipMinimum, float clipSize, float& distance) const; signals: diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index ce0d01ccf2..7bf10467f6 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -305,3 +305,12 @@ void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& obje setIntersectingMasked(spanner->getBounds(), data); } + +SetDataEdit::SetDataEdit(const glm::vec3& minimum, const MetavoxelData& data) : + minimum(minimum), + data(data) { +} + +void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { + data.set(minimum, this->data); +} diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 25db8e5464..309439812d 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -176,4 +176,21 @@ public: DECLARE_STREAMABLE_METATYPE(SetSpannerEdit) +/// An edit that directly sets part of the metavoxel data. +class SetDataEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM glm::vec3 minimum; + + STREAM MetavoxelData data; + + SetDataEdit(const glm::vec3& minimum = glm::vec3(), const MetavoxelData& data = MetavoxelData()); + + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; +}; + +DECLARE_STREAMABLE_METATYPE(SetDataEdit) + #endif /* defined(__interface__MetavoxelMessages__) */ From 3a44a846ed3daa6f8cd4c2d35044293b3721dd13 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 2 Apr 2014 15:48:53 -0700 Subject: [PATCH 03/37] More set/blend bits. --- .../metavoxels/src/AttributeRegistry.cpp | 28 ++++++++++ libraries/metavoxels/src/AttributeRegistry.h | 12 ++++ libraries/metavoxels/src/MetavoxelData.cpp | 56 +++++++++++++++---- libraries/metavoxels/src/MetavoxelData.h | 8 ++- .../metavoxels/src/MetavoxelMessages.cpp | 7 ++- libraries/metavoxels/src/MetavoxelMessages.h | 4 +- 6 files changed, 96 insertions(+), 19 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index fc448613f9..8914a9e3c9 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -144,6 +144,14 @@ void OwnedAttributeValue::mix(const AttributeValue& first, const AttributeValue& _value = _attribute->mix(first.getValue(), second.getValue(), alpha); } +void OwnedAttributeValue::blend(const AttributeValue& source, const AttributeValue& dest) { + if (_attribute) { + _attribute->destroy(_value); + } + _attribute = source.getAttribute(); + _value = _attribute->blend(source.getValue(), dest.getValue()); +} + OwnedAttributeValue& OwnedAttributeValue::operator=(const AttributeValue& other) { if (_attribute) { _attribute->destroy(_value); @@ -243,6 +251,19 @@ void* QRgbAttribute::mix(void* first, void* second, float alpha) const { glm::mix((float)qAlpha(firstValue), (float)qAlpha(secondValue), alpha))); } +const float EIGHT_BIT_MAXIMUM = 255.0f; + +void* QRgbAttribute::blend(void* source, void* dest) const { + QRgb sourceValue = decodeInline(source); + QRgb destValue = decodeInline(dest); + float alpha = qAlpha(sourceValue) / EIGHT_BIT_MAXIMUM; + return encodeInline(qRgba( + glm::mix((float)qRed(destValue), (float)qRed(sourceValue), alpha), + glm::mix((float)qGreen(destValue), (float)qGreen(sourceValue), alpha), + glm::mix((float)qBlue(destValue), (float)qBlue(sourceValue), alpha), + glm::mix((float)qAlpha(destValue), (float)qAlpha(sourceValue), alpha))); +} + void* QRgbAttribute::createFromScript(const QScriptValue& value, QScriptEngine* engine) const { return encodeInline((QRgb)value.toUInt32()); } @@ -287,6 +308,13 @@ void* PackedNormalAttribute::mix(void* first, void* second, float alpha) const { return encodeInline(packNormal(glm::normalize(glm::mix(firstNormal, secondNormal, alpha)))); } +void* PackedNormalAttribute::blend(void* source, void* dest) const { + QRgb sourceValue = decodeInline(source); + QRgb destValue = decodeInline(dest); + float alpha = qAlpha(sourceValue) / EIGHT_BIT_MAXIMUM; + return encodeInline(packNormal(glm::normalize(glm::mix(unpackNormal(destValue), unpackNormal(sourceValue), alpha)))); +} + const float CHAR_SCALE = 127.0f; const float INVERSE_CHAR_SCALE = 1.0f / CHAR_SCALE; diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index f7d8d955a5..db13ea9f4e 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -158,6 +158,9 @@ public: /// Sets this attribute to a mix of the first and second provided. void mix(const AttributeValue& first, const AttributeValue& second, float alpha); + /// Sets this attribute to a blend of the source and destination. + void blend(const AttributeValue& source, const AttributeValue& dest); + /// Destroys the current value, if any, and copies the specified other value. OwnedAttributeValue& operator=(const AttributeValue& other); @@ -218,6 +221,9 @@ public: /// Mixes the first and the second, returning a new value with the result. virtual void* mix(void* first, void* second, float alpha) const = 0; + /// Blends the source with the destination, returning a new value with the result. + virtual void* blend(void* source, void* dest) const = 0; + virtual void* getDefaultValue() const = 0; virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const { return create(); } @@ -249,6 +255,8 @@ public: virtual void* mix(void* first, void* second, float alpha) const { return create(alpha < 0.5f ? first : second); } + virtual void* blend(void* source, void* dest) const { return create(source); } + virtual void* getDefaultValue() const { return encodeInline(_defaultValue); } protected: @@ -315,6 +323,8 @@ public: virtual void* mix(void* first, void* second, float alpha) const; + virtual void* blend(void* source, void* dest) const; + virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const; virtual void* createFromVariant(const QVariant& value) const; @@ -333,6 +343,8 @@ public: virtual bool merge(void*& parent, void* children[], bool postRead = false) const; virtual void* mix(void* first, void* second, float alpha) const; + + virtual void* blend(void* source, void* dest) const; }; /// Packs a normal into an RGB value. diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index c89967b3a0..efbc0b157d 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -336,17 +336,41 @@ static glm::vec3 getNextMinimum(const glm::vec3& minimum, float nextSize, int in (index & Z_MAXIMUM_FLAG) ? nextSize : 0.0f); } -static void setNode(const AttributePointer& attribute, MetavoxelNode*& node, MetavoxelNode* other) { - if (node) { - node->decrementReferenceCount(attribute); +static void setNode(const AttributeValue& value, MetavoxelNode*& node, MetavoxelNode* other, bool blend) { + if (!blend) { + // if we're not blending, we can just make a shallow copy + if (node) { + node->decrementReferenceCount(value.getAttribute()); + } + (node = other)->incrementReferenceCount(); + return; } - (node = other)->incrementReferenceCount(); + if (node) { + MetavoxelNode* oldNode = node; + node = new MetavoxelNode(value.getAttribute(), oldNode); + oldNode->decrementReferenceCount(value.getAttribute()); + + } else { + node = new MetavoxelNode(value); + } + OwnedAttributeValue oldValue = node->getAttributeValue(value.getAttribute()); + node->blendAttributeValues(other->getAttributeValue(value.getAttribute()), oldValue); + if (other->isLeaf()) { + node->clearChildren(value.getAttribute()); + return; + } + for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + MetavoxelNode* child = node->getChild(i); + setNode(oldValue, child, other->getChild(i), true); + node->setChild(i, child); + } + node->mergeChildren(value.getAttribute()); } static void setNode(const AttributeValue& value, MetavoxelNode*& node, const glm::vec3& minimum, float size, - MetavoxelNode* other, const glm::vec3& otherMinimum, float otherSize) { + MetavoxelNode* other, const glm::vec3& otherMinimum, float otherSize, bool blend) { if (otherSize >= size) { - setNode(value.getAttribute(), node, other); + setNode(value, node, other, blend); return; } if (!node) { @@ -372,21 +396,27 @@ static void setNode(const AttributeValue& value, MetavoxelNode*& node, const glm } MetavoxelNode* nextNode = node->getChild(index); setNode(node->getAttributeValue(value.getAttribute()), nextNode, getNextMinimum(minimum, nextSize, index), - nextSize, other, otherMinimum, otherSize); + nextSize, other, otherMinimum, otherSize, blend); node->setChild(index, nextNode); + node->mergeChildren(value.getAttribute()); } -void MetavoxelData::set(const glm::vec3& minimum, const MetavoxelData& data) { +void MetavoxelData::set(const glm::vec3& minimum, const MetavoxelData& data, bool blend) { // expand to fit the entire data Box bounds = minimum + glm::vec3(data.getSize(), data.getSize(), data.getSize()); while (!getBounds().contains(bounds)) { expand(); } - // set each attribute separately + // set/mix each attribute separately for (QHash::const_iterator it = data._roots.constBegin(); it != data._roots.constEnd(); it++) { - setNode(it.key(), _roots[it.key()], getMinimum(), getSize(), it.value(), minimum, data.getSize()); + MetavoxelNode*& root = _roots[it.key()]; + setNode(it.key(), root, getMinimum(), getSize(), it.value(), minimum, data.getSize(), blend); + if (root->isLeaf() && root->getAttributeValue(it.key()).isDefault()) { + _roots.remove(it.key()); + root->decrementReferenceCount(it.key()); + } } } @@ -659,7 +689,11 @@ MetavoxelNode::MetavoxelNode(const AttributePointer& attribute, const MetavoxelN void MetavoxelNode::setAttributeValue(const AttributeValue& attributeValue) { attributeValue.getAttribute()->destroy(_attributeValue); _attributeValue = attributeValue.copy(); - clearChildren(attributeValue.getAttribute()); +} + +void MetavoxelNode::blendAttributeValues(const AttributeValue& source, const AttributeValue& dest) { + source.getAttribute()->destroy(_attributeValue); + _attributeValue = source.getAttribute()->blend(source.getValue(), dest.getValue()); } AttributeValue MetavoxelNode::getAttributeValue(const AttributePointer& attribute) const { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 4db2e919b4..ed8b1a224c 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -91,7 +91,7 @@ public: const AttributePointer& attribute, float& distance, const MetavoxelLOD& lod = MetavoxelLOD()); /// Sets part of the data. - void set(const glm::vec3& minimum, const MetavoxelData& data); + void set(const glm::vec3& minimum, const MetavoxelData& data, bool blend = false); /// Expands the tree, increasing its capacity in all dimensions. void expand(); @@ -158,6 +158,8 @@ public: void setAttributeValue(const AttributeValue& attributeValue); + void blendAttributeValues(const AttributeValue& source, const AttributeValue& dest); + AttributeValue getAttributeValue(const AttributePointer& attribute) const; void* getAttributeValue() const { return _attributeValue; } @@ -190,13 +192,13 @@ public: void destroy(const AttributePointer& attribute); + void clearChildren(const AttributePointer& attribute); + private: Q_DISABLE_COPY(MetavoxelNode) friend class MetavoxelVisitation; - void clearChildren(const AttributePointer& attribute); - int _referenceCount; void* _attributeValue; MetavoxelNode* _children[CHILD_COUNT]; diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 7bf10467f6..c930688cbd 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -306,11 +306,12 @@ void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& obje setIntersectingMasked(spanner->getBounds(), data); } -SetDataEdit::SetDataEdit(const glm::vec3& minimum, const MetavoxelData& data) : +SetDataEdit::SetDataEdit(const glm::vec3& minimum, const MetavoxelData& data, bool blend) : minimum(minimum), - data(data) { + data(data), + blend(blend) { } void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { - data.set(minimum, this->data); + data.set(minimum, this->data, blend); } diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 309439812d..4f90a52e4c 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -183,10 +183,10 @@ class SetDataEdit : public MetavoxelEdit { public: STREAM glm::vec3 minimum; - STREAM MetavoxelData data; + STREAM bool blend; - SetDataEdit(const glm::vec3& minimum = glm::vec3(), const MetavoxelData& data = MetavoxelData()); + SetDataEdit(const glm::vec3& minimum = glm::vec3(), const MetavoxelData& data = MetavoxelData(), bool blend = false); virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; From 4375fe85f1b504d0b9658bf448b16edd6e13cada Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 2 Apr 2014 18:56:18 -0700 Subject: [PATCH 04/37] Working on voxelizing spanners using a set of six rendered images. --- interface/src/ui/MetavoxelEditor.cpp | 121 +++++++++++++++++++++++++-- interface/src/ui/MetavoxelEditor.h | 6 +- 2 files changed, 115 insertions(+), 12 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 19f5902336..d0a2d40461 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -13,8 +13,12 @@ #include #include #include +#include +#include #include +#include #include +#include #include #include @@ -582,20 +586,18 @@ bool PlaceSpannerTool::eventFilter(QObject* watched, QEvent* event) { void PlaceSpannerTool::place() { AttributePointer attribute = AttributeRegistry::getInstance()->getAttribute(_editor->getSelectedAttribute()); - if (!attribute) { - return; + if (attribute) { + applyEdit(attribute, _editor->getValue().value()); } - SharedObjectPointer spanner = _editor->getValue().value(); - MetavoxelEditMessage message = { createEdit(attribute, spanner) }; - Application::getInstance()->getMetavoxels()->applyEdit(message); } InsertSpannerTool::InsertSpannerTool(MetavoxelEditor* editor) : PlaceSpannerTool(editor, "Insert Spanner", "Insert") { } -QVariant InsertSpannerTool::createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { - return QVariant::fromValue(InsertSpannerEdit(attribute, spanner)); +void InsertSpannerTool::applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { + MetavoxelEditMessage message = { QVariant::fromValue(InsertSpannerEdit(attribute, spanner)) }; + Application::getInstance()->getMetavoxels()->applyEdit(message); } RemoveSpannerTool::RemoveSpannerTool(MetavoxelEditor* editor) : @@ -654,6 +656,107 @@ bool SetSpannerTool::appliesTo(const AttributePointer& attribute) const { return attribute == AttributeRegistry::getInstance()->getSpannersAttribute(); } -QVariant SetSpannerTool::createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { - return QVariant::fromValue(SetSpannerEdit(spanner)); +glm::vec3 DIRECTION_VECTORS[] = { glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f), + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 0.0f, 1.0f) }; + +/// Represents a view from one direction of the spanner to be voxelized. +class DirectionImages { +public: + QImage color; + QVector depth; +}; + +class Voxelizer : public QRunnable { +public: + + Voxelizer(float size, const Box& bounds, const QVector& directionImages); + + virtual void run(); + +private: + + float _size; + Box _bounds; + QVector _directionImages; +}; + +Voxelizer::Voxelizer(float size, const Box& bounds, const QVector& directionImages) : + _size(size), + _bounds(bounds), + _directionImages(directionImages) { +} + +void Voxelizer::run() { + +} + +void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { + Spanner* spannerData = static_cast(spanner.data()); + Box bounds = spannerData->getBounds(); + float longestSide(qMax(bounds.getLongestSide(), spannerData->getPlacementGranularity())); + float size = powf(2.0f, floorf(logf(longestSide) / logf(2.0f))); + Box cellBounds(glm::floor(bounds.minimum / size) * size, glm::ceil(bounds.maximum / size) * size); + + Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->bind(); + + glEnable(GL_SCISSOR_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + + QVector directionImages; + + for (unsigned int i = 0; i < sizeof(DIRECTION_VECTORS) / sizeof(DIRECTION_VECTORS[0]); i++) { + glm::quat rotation = rotationBetween(DIRECTION_VECTORS[i], IDENTITY_FRONT); + glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX); + glm::vec3 maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int j = 0; j < Box::VERTEX_COUNT; j++) { + glm::vec3 rotated = rotation * cellBounds.getVertex(j); + minima = glm::min(minima, rotated); + maxima = glm::max(maxima, rotated); + } + int width = glm::round((maxima.x - minima.x) / spannerData->getVoxelizationGranularity()); + int height = glm::round((maxima.y - minima.y) / spannerData->getVoxelizationGranularity()); + + glViewport(0, 0, width, height); + glScissor(0, 0, width, height); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glLoadIdentity(); + glOrtho(minima.x, maxima.x, minima.y, maxima.y, -minima.z, -maxima.z); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + + spannerData->getRenderer()->render(1.0f, glm::vec3(), 0.0f); + + DirectionImages images = { QImage(width, height, QImage::Format_ARGB32), QVector(width * height) }; + glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, images.color.bits()); + glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, images.depth.data()); + directionImages.append(images); + + glMatrixMode(GL_PROJECTION); + } + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glEnable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + + Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->release(); + + glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); + + // send the images off to the lab for processing + QThreadPool::globalInstance()->start(new Voxelizer(size, cellBounds, directionImages)); } diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 76ef8baf6f..7f3521bd1a 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -157,7 +157,7 @@ public: protected: - virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) = 0; + virtual void applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) = 0; private slots: @@ -174,7 +174,7 @@ public: protected: - virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner); + virtual void applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner); }; /// Allows removing a spanner from the scene. @@ -217,7 +217,7 @@ public: protected: - virtual QVariant createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner); + virtual void applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner); }; #endif /* defined(__interface__MetavoxelEditor__) */ From 407a6ecc700ac02838060385009c3d36553059be Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 3 Apr 2014 11:26:54 -0700 Subject: [PATCH 05/37] More work on voxelizing. --- interface/src/MetavoxelSystem.cpp | 19 ++++++++++++------- interface/src/MetavoxelSystem.h | 4 ++-- interface/src/ui/MetavoxelEditor.cpp | 15 ++++++++++++++- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 042c9329f2..11d6e8de2c 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -69,13 +69,13 @@ SharedObjectPointer MetavoxelSystem::findFirstRaySpannerIntersection( return closestSpanner; } -void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit) { +void MetavoxelSystem::applyEdit(const MetavoxelEditMessage& edit, bool reliable) { foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { if (node->getType() == NodeType::MetavoxelServer) { QMutexLocker locker(&node->getMutex()); MetavoxelClient* client = static_cast(node->getLinkedData()); if (client) { - client->applyEdit(edit); + client->applyEdit(edit, reliable); } } } @@ -267,12 +267,17 @@ void MetavoxelClient::guide(MetavoxelVisitor& visitor) { _data.guide(visitor); } -void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit) { - // apply immediately to local tree - edit.apply(_data, _sequencer.getWeakSharedObjectHash()); +void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) { + if (reliable) { + _sequencer.getReliableOutputChannel()->sendMessage(QVariant::fromValue(edit)); + + } else { + // apply immediately to local tree + edit.apply(_data, _sequencer.getWeakSharedObjectHash()); - // start sending it out - _sequencer.sendHighPriorityMessage(QVariant::fromValue(edit)); + // start sending it out + _sequencer.sendHighPriorityMessage(QVariant::fromValue(edit)); + } } void MetavoxelClient::simulate(float deltaTime) { diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 58f40dad37..ee6f91597e 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -38,7 +38,7 @@ public: SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, float& distance); - void applyEdit(const MetavoxelEditMessage& edit); + Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false); void simulate(float deltaTime); void render(); @@ -98,7 +98,7 @@ public: void guide(MetavoxelVisitor& visitor); - void applyEdit(const MetavoxelEditMessage& edit); + void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false); void simulate(float deltaTime); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index d0a2d40461..1c37ec9078 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -675,6 +675,8 @@ public: private: + void voxelize(const glm::vec3& minimum); + float _size; Box _bounds; QVector _directionImages; @@ -687,7 +689,18 @@ Voxelizer::Voxelizer(float size, const Box& bounds, const QVector Date: Thu, 3 Apr 2014 16:48:56 -0700 Subject: [PATCH 06/37] Some alphabetical cleaning --- interface/src/Application.h | 14 +++++----- interface/src/Menu.h | 56 ++++++++++++++++++------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index fd2d6f2dfa..284e475d2f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -14,14 +14,14 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 56d5e5fd6f..3726bcd9a1 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -219,65 +219,65 @@ private: namespace MenuOption { const QString AboutApp = "About Interface"; const QString AmbientOcclusion = "Ambient Occlusion"; - const QString Avatars = "Avatars"; const QString Atmosphere = "Atmosphere"; - const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; + const QString AudioNoiseReduction = "Audio Noise Reduction"; + const QString AudioToneInjection = "Inject Test Tone"; + const QString Avatars = "Avatars"; const QString Bandwidth = "Bandwidth Display"; const QString BandwidthDetails = "Bandwidth Details"; const QString BuckyBalls = "Bucky Balls"; + const QString Chat = "Chat..."; const QString ChatCircling = "Chat Circling"; - const QString Collisions = "Collisions"; const QString CollideWithAvatars = "Collide With Avatars"; + const QString CollideWithEnvironment = "Collide With World Boundaries"; const QString CollideWithParticles = "Collide With Particles"; const QString CollideWithVoxels = "Collide With Voxels"; - const QString CollideWithEnvironment = "Collide With World Boundaries"; + const QString Collisions = "Collisions"; const QString CullSharedFaces = "Cull Shared Voxel Faces"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; + const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; - const QString FilterSixense = "Smooth Sixense Movement"; - const QString Enable3DTVMode = "Enable 3DTV Mode"; - const QString AudioNoiseReduction = "Audio Noise Reduction"; - const QString AudioToneInjection = "Inject Test Tone"; - const QString EchoServerAudio = "Echo Server Audio"; - const QString EchoLocalAudio = "Echo Local Audio"; - const QString MuteAudio = "Mute Microphone"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; - const QString HeadMouse = "Head Mouse"; - const QString HandsCollideWithSelf = "Collide With Self"; + const QString EchoLocalAudio = "Echo Local Audio"; + const QString EchoServerAudio = "Echo Server Audio"; + const QString Enable3DTVMode = "Enable 3DTV Mode"; const QString Faceshift = "Faceshift"; + const QString FilterSixense = "Smooth Sixense Movement"; const QString FirstPerson = "First Person"; const QString FrameTimer = "Show Timer"; const QString FrustumRenderMode = "Render Mode"; const QString Fullscreen = "Fullscreen"; const QString FullscreenMirror = "Fullscreen Mirror"; const QString GlowMode = "Cycle Glow Mode"; + const QString GoHome = "Go Home"; + const QString GoTo = "Go To..."; const QString GoToDomain = "Go To Domain..."; const QString GoToLocation = "Go To Location..."; - const QString NameLocation = "Name this location"; - const QString GoTo = "Go To..."; + const QString Gravity = "Use Gravity"; + const QString HandsCollideWithSelf = "Collide With Self"; + const QString HeadMouse = "Head Mouse"; const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IncreaseVoxelSize = "Increase Voxel Size"; - const QString GoHome = "Go Home"; - const QString Gravity = "Use Gravity"; + const QString LoadScript = "Open and Run Script File..."; + const QString LoadScriptURL = "Open and Run Script from URL..."; const QString LodTools = "LOD Tools"; const QString Log = "Log"; const QString Login = "Login"; const QString Logout = "Logout"; const QString LookAtVectors = "Look-at Vectors"; const QString MetavoxelEditor = "Metavoxel Editor..."; - const QString Chat = "Chat..."; const QString Metavoxels = "Metavoxels"; const QString Mirror = "Mirror"; const QString MoveWithLean = "Move with Lean"; + const QString MuteAudio = "Mute Microphone"; + const QString NameLocation = "Name this location"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; + const QString OctreeStats = "Voxel and Particle Statistics"; const QString OffAxisProjection = "Off-Axis Projection"; const QString OldVoxelCullingMode = "Old Voxel Culling Mode"; - const QString TurnWithHead = "Turn using Head"; - const QString LoadScript = "Open and Run Script File..."; - const QString LoadScriptURL = "Open and Run Script from URL..."; const QString Oscilloscope = "Audio Oscilloscope"; const QString Pair = "Pair"; const QString Particles = "Particles"; @@ -285,30 +285,30 @@ namespace MenuOption { const QString PipelineWarnings = "Show Render Pipeline Warnings"; const QString PlaySlaps = "Play Slaps"; const QString Preferences = "Preferences..."; + const QString Quit = "Quit"; const QString ReloadAllScripts = "Reload All Scripts"; - const QString RenderSkeletonCollisionShapes = "Skeleton Collision Shapes"; - const QString RenderHeadCollisionShapes = "Head Collision Shapes"; const QString RenderBoundingCollisionShapes = "Bounding Collision Shapes"; + const QString RenderHeadCollisionShapes = "Head Collision Shapes"; + const QString RenderSkeletonCollisionShapes = "Skeleton Collision Shapes"; const QString ResetAvatarSize = "Reset Avatar Size"; const QString RunningScripts = "Running Scripts"; const QString RunTimingTests = "Run Timing Tests"; + const QString SettingsExport = "Export Settings"; const QString SettingsImport = "Import Settings"; const QString Shadows = "Shadows"; - const QString SettingsExport = "Export Settings"; const QString ShowCulledSharedFaces = "Show Culled Shared Voxel Faces"; - const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString Stars = "Stars"; const QString Stats = "Stats"; const QString StopAllScripts = "Stop All Scripts"; + const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString TestPing = "Test Ping"; const QString TransmitterDrive = "Transmitter Drive"; + const QString TurnWithHead = "Turn using Head"; const QString UploadHead = "Upload Head Model"; const QString UploadSkeleton = "Upload Skeleton Model"; const QString Visage = "Visage"; - const QString Quit = "Quit"; - const QString Voxels = "Voxels"; const QString VoxelMode = "Cycle Voxel Mode"; - const QString OctreeStats = "Voxel and Particle Statistics"; + const QString Voxels = "Voxels"; const QString VoxelTextures = "Voxel Textures"; } From d3ce2c7640c468b051c40c9d28a810bcfa0329a3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Apr 2014 16:51:08 -0700 Subject: [PATCH 07/37] Added undo/redo support to the client --- interface/src/Application.h | 4 ++++ interface/src/Menu.cpp | 43 +++++++++++++++++++++++++++++++++++++ interface/src/Menu.h | 8 ++++++- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index 284e475d2f..627d80d8dc 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -176,6 +177,7 @@ public: Visage* getVisage() { return &_visage; } SixenseManager* getSixenseManager() { return &_sixenseManager; } BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; } + QUndoStack* getUndoStack() { return &_undoStack; } /// if you need to access the application settings, use lockSettings()/unlockSettings() QSettings* lockSettings() { _settingsMutex.lock(); return _settings; } @@ -362,6 +364,8 @@ private: QMutex _settingsMutex; QSettings* _settings; + QUndoStack _undoStack; + glm::vec3 _gravity; // Frame Rate Measurement diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5530c57281..89db728465 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -161,6 +161,14 @@ Menu::Menu() : QMenu* editMenu = addMenu("Edit"); + QUndoStack* undoStack = Application::getInstance()->getUndoStack(); + QAction* undoAction = undoStack->createUndoAction(editMenu); + QAction* redoAction = undoStack->createRedoAction(editMenu); + + addActionToQMenuAndActionHash(editMenu, + undoAction); + addActionToQMenuAndActionHash(editMenu, + redoAction); addActionToQMenuAndActionHash(editMenu, MenuOption::Preferences, @@ -620,6 +628,41 @@ QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu, return action; } +QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu, + QAction* action, + const QString& actionName, + const QKeySequence& shortcut, + QAction::MenuRole role, + int menuItemLocation) { + QAction* actionBefore = NULL; + + if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) { + actionBefore = destinationMenu->actions()[menuItemLocation]; + } + + if (!actionName.isEmpty()) { + action->setText(actionName); + } + + if (shortcut != 0) { + action->setShortcut(shortcut); + } + + if (role != QAction::NoRole) { + action->setMenuRole(role); + } + + if (!actionBefore) { + destinationMenu->addAction(action); + } else { + destinationMenu->insertAction(actionBefore, action); + } + + _actionHash.insert(action->text(), action); + + return action; +} + QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu, const QString& actionName, const QKeySequence& shortcut, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3726bcd9a1..7bb0b75675 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -102,7 +102,13 @@ public: const char* member = NULL, QAction::MenuRole role = QAction::NoRole, int menuItemLocation = UNSPECIFIED_POSITION); - + QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu, + QAction* action, + const QString& actionName = QString(), + const QKeySequence& shortcut = 0, + QAction::MenuRole role = QAction::NoRole, + int menuItemLocation = UNSPECIFIED_POSITION); + void removeAction(QMenu* menu, const QString& actionName); bool goToDestination(QString destination); From d706e23012c6d067e161531a7232959cab2b12b7 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 3 Apr 2014 23:47:31 -0700 Subject: [PATCH 08/37] Basic voxelization. --- interface/src/ui/MetavoxelEditor.cpp | 139 ++++++++++++++++++--- libraries/metavoxels/src/MetavoxelData.cpp | 9 +- libraries/metavoxels/src/MetavoxelData.h | 1 + libraries/metavoxels/src/SharedObject.cpp | 7 +- libraries/metavoxels/src/SharedObject.h | 5 +- 5 files changed, 138 insertions(+), 23 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 1c37ec9078..6471dd21b2 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -656,35 +656,45 @@ bool SetSpannerTool::appliesTo(const AttributePointer& attribute) const { return attribute == AttributeRegistry::getInstance()->getSpannersAttribute(); } -glm::vec3 DIRECTION_VECTORS[] = { glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f), - glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 0.0f, 1.0f) }; +glm::quat DIRECTION_ROTATIONS[] = { + rotationBetween(glm::vec3(-1.0f, 0.0f, 0.0f), IDENTITY_FRONT), + rotationBetween(glm::vec3(1.0f, 0.0f, 0.0f), IDENTITY_FRONT), + rotationBetween(glm::vec3(0.0f, -1.0f, 0.0f), IDENTITY_FRONT), + rotationBetween(glm::vec3(0.0f, 1.0f, 0.0f), IDENTITY_FRONT), + rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), IDENTITY_FRONT), + rotationBetween(glm::vec3(0.0f, 0.0f, 1.0f), IDENTITY_FRONT) }; /// Represents a view from one direction of the spanner to be voxelized. class DirectionImages { public: QImage color; QVector depth; + glm::vec3 minima; + glm::vec3 maxima; + glm::vec3 scale; }; class Voxelizer : public QRunnable { public: - Voxelizer(float size, const Box& bounds, const QVector& directionImages); + Voxelizer(float size, const Box& bounds, float granularity, const QVector& directionImages); virtual void run(); private: - void voxelize(const glm::vec3& minimum); + void voxelize(const glm::vec3& center); float _size; Box _bounds; + float _granularity; QVector _directionImages; }; -Voxelizer::Voxelizer(float size, const Box& bounds, const QVector& directionImages) : +Voxelizer::Voxelizer(float size, const Box& bounds, float granularity, const QVector& directionImages) : _size(size), _bounds(bounds), + _granularity(granularity), _directionImages(directionImages) { } @@ -694,13 +704,108 @@ void Voxelizer::run() { for (float x = _bounds.minimum.x + halfSize; x < _bounds.maximum.x; x += _size) { for (float y = _bounds.minimum.y + halfSize; y < _bounds.maximum.y; y += _size) { for (float z = _bounds.minimum.z + halfSize; z < _bounds.maximum.z; z += _size) { - + voxelize(glm::vec3(x, y, z)); } } } } -void Voxelizer::voxelize(const glm::vec3& minimum) { +class VoxelizationVisitor : public MetavoxelVisitor { +public: + + VoxelizationVisitor(const QVector& directionImages, const glm::vec3& center, float granularity); + + virtual int visit(MetavoxelInfo& info); + +private: + + QVector _directionImages; + glm::vec3 _center; + float _granularity; +}; + +VoxelizationVisitor::VoxelizationVisitor(const QVector& directionImages, + const glm::vec3& center, float granularity) : + MetavoxelVisitor(QVector(), QVector() << + AttributeRegistry::getInstance()->getColorAttribute()), + _directionImages(directionImages), + _center(center), + _granularity(granularity) { +} + +bool checkDisjoint(const DirectionImages& images, const glm::vec3& minimum, const glm::vec3& maximum) { + for (int x = qMax(0, (int)minimum.x), xmax = qMin(images.color.width(), (int)maximum.x); x < xmax; x++) { + for (int y = qMax(0, (int)minimum.y), ymax = qMin(images.color.height(), (int)maximum.y); y < ymax; y++) { + float depth = 1.0f - images.depth.at(y * images.color.width() + x); + if (depth - minimum.z >= 0.0f) { + return false; + } + } + } + return true; +} + +int VoxelizationVisitor::visit(MetavoxelInfo& info) { + float halfSize = info.size * 0.5f; + glm::vec3 center = info.minimum + _center + glm::vec3(halfSize, halfSize, halfSize); + if (info.size > _granularity) { + for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) { + glm::vec3 rotated = DIRECTION_ROTATIONS[i] * center; + const DirectionImages& images = _directionImages.at(i); + glm::vec3 relative = (rotated - images.minima) * images.scale; + glm::vec3 extents = images.scale * halfSize; + glm::vec3 minimum = relative - extents; + glm::vec3 maximum = relative + extents; + if (checkDisjoint(images, minimum, maximum)) { + info.outputValues[0] = AttributeValue(_outputs.at(0)); + return STOP_RECURSION; + } + } + return DEFAULT_ORDER; + } + QRgb closestColor; + float closestDistance = FLT_MAX; + for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) { + glm::vec3 rotated = DIRECTION_ROTATIONS[i] * center; + const DirectionImages& images = _directionImages.at(i); + glm::vec3 relative = (rotated - images.minima) * images.scale; + int x = qMax(qMin((int)glm::round(relative.x), images.color.width() - 1), 0); + int y = qMax(qMin((int)glm::round(relative.y), images.color.height() - 1), 0); + float depth = 1.0f - images.depth.at(y * images.color.width() + x); + float distance = depth - relative.z; + if (distance < 0.0f) { + info.outputValues[0] = AttributeValue(_outputs.at(0)); + return STOP_RECURSION; + } + QRgb color = images.color.pixel(x, y); + if (distance < EPSILON) { + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(color)); + return STOP_RECURSION; + } + if (distance < closestDistance) { + closestColor = color; + closestDistance = distance; + } + } + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(closestColor)); + return STOP_RECURSION; +} + +void Voxelizer::voxelize(const glm::vec3& center) { + MetavoxelData data; + data.setSize(_size); + + qDebug() << "Started voxelizing " << center.x << center.y << center.z; + + VoxelizationVisitor visitor(_directionImages, center, _granularity); + data.guide(visitor); + + qDebug() << "Finished voxelizing " << center.x << center.y << center.z; + + MetavoxelEditMessage edit = { QVariant::fromValue(SetDataEdit( + center - glm::vec3(_size, _size, _size) * 0.5f, data, false)) }; + QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "applyEdit", + Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, true)); } void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { @@ -725,12 +830,11 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb QVector directionImages; - for (unsigned int i = 0; i < sizeof(DIRECTION_VECTORS) / sizeof(DIRECTION_VECTORS[0]); i++) { - glm::quat rotation = rotationBetween(DIRECTION_VECTORS[i], IDENTITY_FRONT); + for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) { glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX); glm::vec3 maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX); for (int j = 0; j < Box::VERTEX_COUNT; j++) { - glm::vec3 rotated = rotation * cellBounds.getVertex(j); + glm::vec3 rotated = DIRECTION_ROTATIONS[i] * cellBounds.getVertex(j); minima = glm::min(minima, rotated); maxima = glm::max(maxima, rotated); } @@ -742,16 +846,20 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); - glOrtho(minima.x, maxima.x, minima.y, maxima.y, -minima.z, -maxima.z); + glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + glm::vec3 axis = glm::axis(DIRECTION_ROTATIONS[i]); + glRotatef(glm::degrees(glm::angle(DIRECTION_ROTATIONS[i])), axis.x, axis.y, axis.z); + + Application::getInstance()->setupWorldLight(); spannerData->getRenderer()->render(1.0f, glm::vec3(), 0.0f); - DirectionImages images = { QImage(width, height, QImage::Format_ARGB32), QVector(width * height) }; + DirectionImages images = { QImage(width, height, QImage::Format_ARGB32), + QVector(width * height), minima, maxima, glm::vec3(width / (maxima.x - minima.x), + height / (maxima.y - minima.y), 1.0f / (maxima.z - minima.z)) }; glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, images.color.bits()); glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, images.depth.data()); directionImages.append(images); @@ -771,5 +879,6 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); // send the images off to the lab for processing - QThreadPool::globalInstance()->start(new Voxelizer(size, cellBounds, directionImages)); + QThreadPool::globalInstance()->start(new Voxelizer(size, cellBounds, + spannerData->getVoxelizationGranularity(), directionImages)); } diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index efbc0b157d..f86406a507 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -373,7 +373,12 @@ static void setNode(const AttributeValue& value, MetavoxelNode*& node, const glm setNode(value, node, other, blend); return; } - if (!node) { + if (node) { + MetavoxelNode* oldNode = node; + node = new MetavoxelNode(value.getAttribute(), oldNode); + oldNode->decrementReferenceCount(value.getAttribute()); + + } else { node = new MetavoxelNode(value); } int index = 0; @@ -403,7 +408,7 @@ static void setNode(const AttributeValue& value, MetavoxelNode*& node, const glm void MetavoxelData::set(const glm::vec3& minimum, const MetavoxelData& data, bool blend) { // expand to fit the entire data - Box bounds = minimum + glm::vec3(data.getSize(), data.getSize(), data.getSize()); + Box bounds(minimum, minimum + glm::vec3(data.getSize(), data.getSize(), data.getSize())); while (!getBounds().contains(bounds)) { expand(); } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index ed8b1a224c..4254b3bbb2 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -61,6 +61,7 @@ public: MetavoxelData& operator=(const MetavoxelData& other); + void setSize(float size) { _size = size; } float getSize() const { return _size; } glm::vec3 getMinimum() const { return glm::vec3(_size, _size, _size) * -0.5f; } diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index 36257a740f..64ea48e016 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -20,18 +20,17 @@ REGISTER_META_OBJECT(SharedObject) SharedObject::SharedObject() : _id(++_lastID), - _remoteID(0), - _referenceCount(0) { + _remoteID(0) { _weakHash.insert(_id, this); } void SharedObject::incrementReferenceCount() { - _referenceCount++; + _referenceCount.ref(); } void SharedObject::decrementReferenceCount() { - if (--_referenceCount == 0) { + if (!_referenceCount.deref()) { _weakHash.remove(_id); delete this; } diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 435127fffd..2751a66db3 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -9,6 +9,7 @@ #ifndef __interface__SharedObject__ #define __interface__SharedObject__ +#include #include #include #include @@ -42,7 +43,7 @@ public: void setRemoteID(int remoteID) { _remoteID = remoteID; } - int getReferenceCount() const { return _referenceCount; } + int getReferenceCount() const { return _referenceCount.load(); } void incrementReferenceCount(); void decrementReferenceCount(); @@ -62,7 +63,7 @@ private: int _id; int _remoteID; - int _referenceCount; + QAtomicInt _referenceCount; static int _lastID; static WeakSharedObjectHash _weakHash; From dfaa98cc34f5e1713d5f9b5ddd94d433d2026345 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 3 Apr 2014 23:51:49 -0700 Subject: [PATCH 09/37] Blend when setting. --- interface/src/ui/MetavoxelEditor.cpp | 2 +- libraries/metavoxels/src/MetavoxelData.cpp | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 6471dd21b2..a7d9026582 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -803,7 +803,7 @@ void Voxelizer::voxelize(const glm::vec3& center) { qDebug() << "Finished voxelizing " << center.x << center.y << center.z; MetavoxelEditMessage edit = { QVariant::fromValue(SetDataEdit( - center - glm::vec3(_size, _size, _size) * 0.5f, data, false)) }; + center - glm::vec3(_size, _size, _size) * 0.5f, data, true)) }; QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, true)); } diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index f86406a507..f4d2870ad4 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -355,14 +355,12 @@ static void setNode(const AttributeValue& value, MetavoxelNode*& node, Metavoxel } OwnedAttributeValue oldValue = node->getAttributeValue(value.getAttribute()); node->blendAttributeValues(other->getAttributeValue(value.getAttribute()), oldValue); - if (other->isLeaf()) { - node->clearChildren(value.getAttribute()); - return; - } - for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { - MetavoxelNode* child = node->getChild(i); - setNode(oldValue, child, other->getChild(i), true); - node->setChild(i, child); + if (!other->isLeaf()) { + for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + MetavoxelNode* child = node->getChild(i); + setNode(oldValue, child, other->getChild(i), true); + node->setChild(i, child); + } } node->mergeChildren(value.getAttribute()); } From 38022d2440114ea7acaf9005101d400a3efc3f9d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Apr 2014 00:33:33 -0700 Subject: [PATCH 10/37] Fix for voxelizing models. --- interface/src/Application.cpp | 11 +++++++---- interface/src/Application.h | 4 ++++ interface/src/ui/MetavoxelEditor.cpp | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 18a3a228d6..7d3d5e9c19 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2229,8 +2229,7 @@ void Application::updateShadowMap() { glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z); // store view matrix without translation, which we'll use for precision-sensitive objects - glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); - _viewMatrixTranslation = glm::vec3(); + updateUntranslatedViewMatrix(); _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); _particles.render(); @@ -2315,8 +2314,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); // store view matrix without translation, which we'll use for precision-sensitive objects - glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); - _viewMatrixTranslation = -whichCamera.getPosition(); + updateUntranslatedViewMatrix(-whichCamera.getPosition()); glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); @@ -2447,6 +2445,11 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } } +void Application::updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTranslation) { + glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); + _viewMatrixTranslation = viewMatrixTranslation; +} + void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { glLoadMatrixf((const GLfloat*)&_untranslatedViewMatrix); glTranslatef(translation.x + _viewMatrixTranslation.x, translation.y + _viewMatrixTranslation.y, diff --git a/interface/src/Application.h b/interface/src/Application.h index fd2d6f2dfa..625974d0bd 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -203,6 +203,10 @@ public: void displaySide(Camera& whichCamera, bool selfAvatarOnly = false); + /// Stores the current modelview matrix as the untranslated view matrix to use for transforms and the supplied vector as + /// the view matrix translation. + void updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTranslation = glm::vec3()); + /// Loads a view matrix that incorporates the specified model translation without the precision issues that can /// result from matrix multiplication at high translation magnitudes. void loadTranslatedViewMatrix(const glm::vec3& translation); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index a7d9026582..024dd0c5d1 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -855,6 +855,8 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb Application::getInstance()->setupWorldLight(); + Application::getInstance()->updateUntranslatedViewMatrix(); + spannerData->getRenderer()->render(1.0f, glm::vec3(), 0.0f); DirectionImages images = { QImage(width, height, QImage::Format_ARGB32), From a0c7e4d3cc84c5eefadd15b9192a1149c29a2aeb Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Apr 2014 11:45:03 -0700 Subject: [PATCH 11/37] Working on model rendering modes. --- interface/src/Menu.cpp | 2 +- interface/src/MetavoxelSystem.cpp | 18 +++++++++--------- interface/src/MetavoxelSystem.h | 10 +++++----- interface/src/avatar/Head.cpp | 4 ++-- interface/src/avatar/Head.h | 2 +- interface/src/renderer/Model.cpp | 20 ++++++++++---------- interface/src/renderer/Model.h | 7 +++++-- interface/src/ui/MetavoxelEditor.cpp | 12 ++++++++---- libraries/metavoxels/src/Bitstream.cpp | 6 +++++- libraries/metavoxels/src/MetavoxelData.cpp | 2 +- libraries/metavoxels/src/MetavoxelData.h | 4 +++- 11 files changed, 50 insertions(+), 37 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5530c57281..e324b5dd16 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -183,7 +183,7 @@ Menu::Menu() : #ifdef HAVE_QXMPP _chatAction = addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, - Qt::Key_Return, + 0, this, SLOT(showChat())); diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 11d6e8de2c..ce9c00ad17 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -228,7 +228,7 @@ MetavoxelSystem::RenderVisitor::RenderVisitor() : } bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) { - spanner->getRenderer()->render(1.0f, clipMinimum, clipSize); + spanner->getRenderer()->render(1.0f, SpannerRenderer::DEFAULT_MODE, clipMinimum, clipSize); return true; } @@ -345,9 +345,9 @@ static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { glEnable(plane); } -void ClippedRenderer::render(float alpha, const glm::vec3& clipMinimum, float clipSize) { +void ClippedRenderer::render(float alpha, Mode mode, const glm::vec3& clipMinimum, float clipSize) { if (clipSize == 0.0f) { - renderUnclipped(alpha); + renderUnclipped(alpha, mode); return; } enableClipPlane(GL_CLIP_PLANE0, -1.0f, 0.0f, 0.0f, clipMinimum.x + clipSize); @@ -357,7 +357,7 @@ void ClippedRenderer::render(float alpha, const glm::vec3& clipMinimum, float cl enableClipPlane(GL_CLIP_PLANE4, 0.0f, 0.0f, -1.0f, clipMinimum.z + clipSize); enableClipPlane(GL_CLIP_PLANE5, 0.0f, 0.0f, 1.0f, -clipMinimum.z); - renderUnclipped(alpha); + renderUnclipped(alpha, mode); glDisable(GL_CLIP_PLANE0); glDisable(GL_CLIP_PLANE1); @@ -370,9 +370,9 @@ void ClippedRenderer::render(float alpha, const glm::vec3& clipMinimum, float cl SphereRenderer::SphereRenderer() { } -void SphereRenderer::render(float alpha, const glm::vec3& clipMinimum, float clipSize) { +void SphereRenderer::render(float alpha, Mode mode, const glm::vec3& clipMinimum, float clipSize) { if (clipSize == 0.0f) { - renderUnclipped(alpha); + renderUnclipped(alpha, mode); return; } // slight performance optimization: don't render if clip bounds are entirely within sphere @@ -381,13 +381,13 @@ void SphereRenderer::render(float alpha, const glm::vec3& clipMinimum, float cli for (int i = 0; i < Box::VERTEX_COUNT; i++) { const float CLIP_PROPORTION = 0.95f; if (glm::distance(sphere->getTranslation(), clipBox.getVertex(i)) >= sphere->getScale() * CLIP_PROPORTION) { - ClippedRenderer::render(alpha, clipMinimum, clipSize); + ClippedRenderer::render(alpha, mode, clipMinimum, clipSize); return; } } } -void SphereRenderer::renderUnclipped(float alpha) { +void SphereRenderer::renderUnclipped(float alpha, Mode mode) { Sphere* sphere = static_cast(parent()); const QColor& color = sphere->getColor(); glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF() * alpha); @@ -435,7 +435,7 @@ void StaticModelRenderer::simulate(float deltaTime) { _model->simulate(deltaTime); } -void StaticModelRenderer::renderUnclipped(float alpha) { +void StaticModelRenderer::renderUnclipped(float alpha, Mode mode) { _model->render(alpha); } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index ee6f91597e..7612437bb9 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -147,11 +147,11 @@ class ClippedRenderer : public SpannerRenderer { public: - virtual void render(float alpha, const glm::vec3& clipMinimum, float clipSize); + virtual void render(float alpha, Mode mode, const glm::vec3& clipMinimum, float clipSize); protected: - virtual void renderUnclipped(float alpha) = 0; + virtual void renderUnclipped(float alpha, Mode mode) = 0; }; /// Renders spheres. @@ -162,11 +162,11 @@ public: Q_INVOKABLE SphereRenderer(); - virtual void render(float alpha, const glm::vec3& clipMinimum, float clipSize); + virtual void render(float alpha, Mode mode, const glm::vec3& clipMinimum, float clipSize); protected: - virtual void renderUnclipped(float alpha); + virtual void renderUnclipped(float alpha, Mode mode); }; /// Renders static models. @@ -184,7 +184,7 @@ public: protected: - virtual void renderUnclipped(float alpha); + virtual void renderUnclipped(float alpha, Mode mode); private slots: diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index ffa0975ccb..396f93d821 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -179,8 +179,8 @@ void Head::relaxLean(float deltaTime) { _deltaLeanForward *= relaxationFactor; } -void Head::render(float alpha, bool forShadowMap) { - if (_faceModel.render(alpha, forShadowMap) && _renderLookatVectors) { +void Head::render(float alpha, Model::RenderMode mode) { + if (_faceModel.render(alpha, mode) && _renderLookatVectors) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); } } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 8a03cfc7ad..36ab6a9229 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -37,7 +37,7 @@ public: void init(); void reset(); void simulate(float deltaTime, bool isMine, bool billboard = false); - void render(float alpha, bool forShadowMap); + void render(float alpha, Model::RenderMode mode); void setScale(float scale); void setPosition(glm::vec3 position) { _position = position; } void setGravity(glm::vec3 gravity) { _gravity = gravity; } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 9d2a031a6e..e840de9fbb 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -281,7 +281,7 @@ bool Model::updateGeometry() { return needFullUpdate; } -bool Model::render(float alpha, bool forShadowMap) { +bool Model::render(float alpha, RenderMode mode) { // render the attachments foreach (Model* attachment, _attachments) { attachment->render(alpha); @@ -305,20 +305,20 @@ bool Model::render(float alpha, bool forShadowMap) { glDisable(GL_COLOR_MATERIAL); - glEnable(GL_CULL_FACE); + // glEnable(GL_CULL_FACE); // render opaque meshes with alpha testing glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5f * alpha); - renderMeshes(alpha, forShadowMap, false); + renderMeshes(alpha, mode, false); glDisable(GL_ALPHA_TEST); // render translucent meshes afterwards, with back face culling - renderMeshes(alpha, forShadowMap, true); + renderMeshes(alpha, mode, true); glDisable(GL_CULL_FACE); @@ -1112,7 +1112,7 @@ void Model::deleteGeometry() { } } -void Model::renderMeshes(float alpha, bool forShadowMap, bool translucent) { +void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); @@ -1137,7 +1137,7 @@ void Model::renderMeshes(float alpha, bool forShadowMap, bool translucent) { ProgramObject* program = &_program; ProgramObject* skinProgram = &_skinProgram; SkinLocations* skinLocations = &_skinLocations; - if (forShadowMap) { + if (mode == SHADOW_MAP_MODE) { program = &_shadowProgram; skinProgram = &_skinShadowProgram; skinLocations = &_skinShadowLocations; @@ -1175,7 +1175,7 @@ void Model::renderMeshes(float alpha, bool forShadowMap, bool translucent) { } if (mesh.blendshapes.isEmpty()) { - if (!(mesh.tangents.isEmpty() || forShadowMap)) { + if (!(mesh.tangents.isEmpty() || mode == SHADOW_MAP_MODE)) { activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); activeProgram->enableAttributeArray(tangentLocation); } @@ -1185,7 +1185,7 @@ void Model::renderMeshes(float alpha, bool forShadowMap, bool translucent) { (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); } else { - if (!(mesh.tangents.isEmpty() || forShadowMap)) { + if (!(mesh.tangents.isEmpty() || mode == SHADOW_MAP_MODE)) { activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, 0, 3); activeProgram->enableAttributeArray(tangentLocation); } @@ -1214,7 +1214,7 @@ void Model::renderMeshes(float alpha, bool forShadowMap, bool translucent) { continue; } // apply material properties - if (forShadowMap) { + if (mode == SHADOW_MAP_MODE) { glBindTexture(GL_TEXTURE_2D, 0); } else { @@ -1255,7 +1255,7 @@ void Model::renderMeshes(float alpha, bool forShadowMap, bool translucent) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); } - if (!(mesh.tangents.isEmpty() || forShadowMap)) { + if (!(mesh.tangents.isEmpty() || mode == SHADOW_MAP_MODE)) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 11374a6369..5671e104fc 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -57,7 +57,10 @@ public: void init(); void reset(); virtual void simulate(float deltaTime, bool fullUpdate = true); - bool render(float alpha = 1.0f, bool forShadowMap = false); + + enum RenderMode { DEFAULT_MODE, SHADOW_MAP_MODE, DIFFUSE_MODE, NORMAL_MODE }; + + bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_MODE); /// Sets the URL of the model to render. /// \param fallback the URL of a fallback model to render if the requested model fails to load @@ -254,7 +257,7 @@ private: void applyNextGeometry(); void deleteGeometry(); - void renderMeshes(float alpha, bool forShadowMap, bool translucent); + void renderMeshes(float alpha, RenderMode mode, bool translucent); QVector createJointStates(const FBXGeometry& geometry); QSharedPointer _baseGeometry; ///< reference required to prevent collection of base diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 024dd0c5d1..2bb2b3a7e5 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -569,7 +569,7 @@ void PlaceSpannerTool::render() { } Spanner* spanner = static_cast(_editor->getValue().value().data()); const float SPANNER_ALPHA = 0.25f; - spanner->getRenderer()->render(SPANNER_ALPHA, glm::vec3(), 0.0f); + spanner->getRenderer()->render(SPANNER_ALPHA, SpannerRenderer::DEFAULT_MODE, glm::vec3(), 0.0f); } bool PlaceSpannerTool::appliesTo(const AttributePointer& attribute) const { @@ -773,6 +773,7 @@ int VoxelizationVisitor::visit(MetavoxelInfo& info) { int y = qMax(qMin((int)glm::round(relative.y), images.color.height() - 1), 0); float depth = 1.0f - images.depth.at(y * images.color.width() + x); float distance = depth - relative.z; + float extent = images.scale.z * halfSize; if (distance < 0.0f) { info.outputValues[0] = AttributeValue(_outputs.at(0)); return STOP_RECURSION; @@ -838,8 +839,9 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb minima = glm::min(minima, rotated); maxima = glm::max(maxima, rotated); } - int width = glm::round((maxima.x - minima.x) / spannerData->getVoxelizationGranularity()); - int height = glm::round((maxima.y - minima.y) / spannerData->getVoxelizationGranularity()); + float renderGranularity = spannerData->getVoxelizationGranularity() / 4.0f; + int width = glm::round((maxima.x - minima.x) / renderGranularity); + int height = glm::round((maxima.y - minima.y) / renderGranularity); glViewport(0, 0, width, height); glScissor(0, 0, width, height); @@ -857,7 +859,7 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb Application::getInstance()->updateUntranslatedViewMatrix(); - spannerData->getRenderer()->render(1.0f, glm::vec3(), 0.0f); + spannerData->getRenderer()->render(1.0f, SpannerRenderer::DIFFUSE_MODE, glm::vec3(), 0.0f); DirectionImages images = { QImage(width, height, QImage::Format_ARGB32), QVector(width * height), minima, maxima, glm::vec3(width / (maxima.x - minima.x), @@ -866,6 +868,8 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, images.depth.data()); directionImages.append(images); + images.color.save(QString::number(i) + ".png"); + glMatrixMode(GL_PROJECTION); } glPopMatrix(); diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 077e6c1c69..09e71700be 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -869,7 +869,11 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { *this >> rawObject; } pointer = static_cast(rawObject); - pointer->setRemoteID(id); + if (pointer) { + pointer->setRemoteID(id); + } else { + qDebug() << "Null object" << pointer << reference; + } } object = static_cast(pointer.data()); return *this; diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index f4d2870ad4..e4cce9c735 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -1527,7 +1527,7 @@ void SpannerRenderer::simulate(float deltaTime) { // nothing by default } -void SpannerRenderer::render(float alpha, const glm::vec3& clipMinimum, float clipSize) { +void SpannerRenderer::render(float alpha, Mode mode, const glm::vec3& clipMinimum, float clipSize) { // nothing by default } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 4254b3bbb2..41285af2f5 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -518,11 +518,13 @@ class SpannerRenderer : public QObject { public: + enum Mode { DEFAULT_MODE, DIFFUSE_MODE, NORMAL_MODE }; + Q_INVOKABLE SpannerRenderer(); virtual void init(Spanner* spanner); virtual void simulate(float deltaTime); - virtual void render(float alpha, const glm::vec3& clipMinimum, float clipSize); + virtual void render(float alpha, Mode mode, const glm::vec3& clipMinimum, float clipSize); virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& clipMinimum, float clipSize, float& distance) const; }; From a2b94aa43330c139ff073838b9c90e481014f6d9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Apr 2014 14:22:01 -0700 Subject: [PATCH 12/37] Working on render modes. --- interface/src/MetavoxelSystem.cpp | 13 +++++++++++++ interface/src/avatar/Avatar.cpp | 6 ++++-- interface/src/avatar/MyAvatar.cpp | 6 ++++-- interface/src/renderer/Model.cpp | 20 ++++++++++++-------- interface/src/renderer/Model.h | 4 ++-- interface/src/ui/MetavoxelEditor.cpp | 4 ++-- 6 files changed, 37 insertions(+), 16 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index ce9c00ad17..8fe4b53922 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -436,6 +436,19 @@ void StaticModelRenderer::simulate(float deltaTime) { } void StaticModelRenderer::renderUnclipped(float alpha, Mode mode) { + switch (mode) { + case DIFFUSE_MODE: + _model->render(alpha, Model::DIFFUSE_RENDER_MODE); + break; + + case NORMAL_MODE: + _model->render(alpha, Model::NORMAL_RENDER_MODE); + break; + + default: + _model->render(alpha); + break; + } _model->render(alpha); } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 899514d1c1..d2e6293f3b 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -326,8 +326,10 @@ void Avatar::renderBody(RenderMode renderMode) { renderBillboard(); return; } - _skeletonModel.render(1.0f, renderMode == SHADOW_RENDER_MODE); - getHead()->render(1.0f, renderMode == SHADOW_RENDER_MODE); + Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? + Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + _skeletonModel.render(1.0f, modelRenderMode); + getHead()->render(1.0f, modelRenderMode); getHand()->render(false); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9dcfaa09ba..b63da79c6f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -642,14 +642,16 @@ void MyAvatar::renderBody(RenderMode renderMode) { } // Render the body's voxels and head - _skeletonModel.render(1.0f, renderMode == SHADOW_RENDER_MODE); + Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? + Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; + _skeletonModel.render(1.0f, modelRenderMode); // Render head so long as the camera isn't inside it const float RENDER_HEAD_CUTOFF_DISTANCE = 0.40f; Camera* myCamera = Application::getInstance()->getCamera(); if (renderMode != NORMAL_RENDER_MODE || (glm::length(myCamera->getPosition() - getHead()->calculateAverageEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale)) { - getHead()->render(1.0f, renderMode == SHADOW_RENDER_MODE); + getHead()->render(1.0f, modelRenderMode); } getHand()->render(true); } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index e840de9fbb..6583b436b7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -284,7 +284,7 @@ bool Model::updateGeometry() { bool Model::render(float alpha, RenderMode mode) { // render the attachments foreach (Model* attachment, _attachments) { - attachment->render(alpha); + attachment->render(alpha, mode); } if (_meshStates.isEmpty()) { return false; @@ -305,7 +305,11 @@ bool Model::render(float alpha, RenderMode mode) { glDisable(GL_COLOR_MATERIAL); - // glEnable(GL_CULL_FACE); + if (mode == DIFFUSE_RENDER_MODE || mode == NORMAL_RENDER_MODE) { + glDisable(GL_CULL_FACE); + } else { + glEnable(GL_CULL_FACE); + } // render opaque meshes with alpha testing @@ -316,7 +320,7 @@ bool Model::render(float alpha, RenderMode mode) { glDisable(GL_ALPHA_TEST); - // render translucent meshes afterwards, with back face culling + // render translucent meshes afterwards renderMeshes(alpha, mode, true); @@ -1137,7 +1141,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { ProgramObject* program = &_program; ProgramObject* skinProgram = &_skinProgram; SkinLocations* skinLocations = &_skinLocations; - if (mode == SHADOW_MAP_MODE) { + if (mode == SHADOW_RENDER_MODE) { program = &_shadowProgram; skinProgram = &_skinShadowProgram; skinLocations = &_skinShadowLocations; @@ -1175,7 +1179,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { } if (mesh.blendshapes.isEmpty()) { - if (!(mesh.tangents.isEmpty() || mode == SHADOW_MAP_MODE)) { + if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); activeProgram->enableAttributeArray(tangentLocation); } @@ -1185,7 +1189,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); } else { - if (!(mesh.tangents.isEmpty() || mode == SHADOW_MAP_MODE)) { + if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, 0, 3); activeProgram->enableAttributeArray(tangentLocation); } @@ -1214,7 +1218,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { continue; } // apply material properties - if (mode == SHADOW_MAP_MODE) { + if (mode == SHADOW_RENDER_MODE) { glBindTexture(GL_TEXTURE_2D, 0); } else { @@ -1255,7 +1259,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); } - if (!(mesh.tangents.isEmpty() || mode == SHADOW_MAP_MODE)) { + if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 5671e104fc..134a3e2172 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -58,9 +58,9 @@ public: void reset(); virtual void simulate(float deltaTime, bool fullUpdate = true); - enum RenderMode { DEFAULT_MODE, SHADOW_MAP_MODE, DIFFUSE_MODE, NORMAL_MODE }; + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; - bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_MODE); + bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE); /// Sets the URL of the model to render. /// \param fallback the URL of a fallback model to render if the requested model fails to load diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 2bb2b3a7e5..e12bc334a5 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -774,12 +774,12 @@ int VoxelizationVisitor::visit(MetavoxelInfo& info) { float depth = 1.0f - images.depth.at(y * images.color.width() + x); float distance = depth - relative.z; float extent = images.scale.z * halfSize; - if (distance < 0.0f) { + if (distance < -extent - EPSILON) { info.outputValues[0] = AttributeValue(_outputs.at(0)); return STOP_RECURSION; } QRgb color = images.color.pixel(x, y); - if (distance < EPSILON) { + if (distance < extent + EPSILON) { info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(color)); return STOP_RECURSION; } From d2b0cc43dd1414710aafa23c82c0bde959fde561 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Apr 2014 16:32:14 -0700 Subject: [PATCH 13/37] Extent tweaks. --- interface/src/ui/MetavoxelEditor.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index e12bc334a5..87b04e53d5 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -733,11 +733,11 @@ VoxelizationVisitor::VoxelizationVisitor(const QVector& directi _granularity(granularity) { } -bool checkDisjoint(const DirectionImages& images, const glm::vec3& minimum, const glm::vec3& maximum) { +bool checkDisjoint(const DirectionImages& images, const glm::vec3& minimum, const glm::vec3& maximum, float extent) { for (int x = qMax(0, (int)minimum.x), xmax = qMin(images.color.width(), (int)maximum.x); x < xmax; x++) { for (int y = qMax(0, (int)minimum.y), ymax = qMin(images.color.height(), (int)maximum.y); y < ymax; y++) { float depth = 1.0f - images.depth.at(y * images.color.width() + x); - if (depth - minimum.z >= 0.0f) { + if (depth - minimum.z >= -extent - EPSILON) { return false; } } @@ -748,6 +748,7 @@ bool checkDisjoint(const DirectionImages& images, const glm::vec3& minimum, cons int VoxelizationVisitor::visit(MetavoxelInfo& info) { float halfSize = info.size * 0.5f; glm::vec3 center = info.minimum + _center + glm::vec3(halfSize, halfSize, halfSize); + const float EXTENT_SCALE = 2.0f; if (info.size > _granularity) { for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) { glm::vec3 rotated = DIRECTION_ROTATIONS[i] * center; @@ -756,7 +757,7 @@ int VoxelizationVisitor::visit(MetavoxelInfo& info) { glm::vec3 extents = images.scale * halfSize; glm::vec3 minimum = relative - extents; glm::vec3 maximum = relative + extents; - if (checkDisjoint(images, minimum, maximum)) { + if (checkDisjoint(images, minimum, maximum, extents.z * EXTENT_SCALE)) { info.outputValues[0] = AttributeValue(_outputs.at(0)); return STOP_RECURSION; } @@ -773,7 +774,7 @@ int VoxelizationVisitor::visit(MetavoxelInfo& info) { int y = qMax(qMin((int)glm::round(relative.y), images.color.height() - 1), 0); float depth = 1.0f - images.depth.at(y * images.color.width() + x); float distance = depth - relative.z; - float extent = images.scale.z * halfSize; + float extent = images.scale.z * halfSize * EXTENT_SCALE; if (distance < -extent - EPSILON) { info.outputValues[0] = AttributeValue(_outputs.at(0)); return STOP_RECURSION; From 2d535f3b867dd38952d9b739ed47c70b454cffca Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Apr 2014 16:36:58 -0700 Subject: [PATCH 14/37] Removed debugging code. --- interface/src/ui/MetavoxelEditor.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 87b04e53d5..71539d3a27 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -797,13 +797,9 @@ void Voxelizer::voxelize(const glm::vec3& center) { MetavoxelData data; data.setSize(_size); - qDebug() << "Started voxelizing " << center.x << center.y << center.z; - VoxelizationVisitor visitor(_directionImages, center, _granularity); data.guide(visitor); - qDebug() << "Finished voxelizing " << center.x << center.y << center.z; - MetavoxelEditMessage edit = { QVariant::fromValue(SetDataEdit( center - glm::vec3(_size, _size, _size) * 0.5f, data, true)) }; QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "applyEdit", @@ -869,8 +865,6 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, images.depth.data()); directionImages.append(images); - images.color.save(QString::number(i) + ".png"); - glMatrixMode(GL_PROJECTION); } glPopMatrix(); From 4335ba7b5aa2d5b9b167b05fc9c2ad2b232585db Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 7 Apr 2014 17:01:24 +0200 Subject: [PATCH 15/37] windows default device fix --- interface/src/Audio.cpp | 73 +++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 63c683dbb0..3f48c73867 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -15,6 +15,13 @@ #include #endif +#ifdef WIN32 +#include +#include +#include +#include +#endif + #include #include #include @@ -146,24 +153,54 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { } #endif #ifdef WIN32 - QString deviceName; - if (mode == QAudio::AudioInput) { - WAVEINCAPS wic; - // first use WAVE_MAPPER to get the default devices manufacturer ID - waveInGetDevCaps(WAVE_MAPPER, &wic, sizeof(wic)); - //Use the received manufacturer id to get the device's real name - waveInGetDevCaps(wic.wMid, &wic, sizeof(wic)); - qDebug() << "input device:" << wic.szPname; - deviceName = wic.szPname; - } else { - WAVEOUTCAPS woc; - // first use WAVE_MAPPER to get the default devices manufacturer ID - waveOutGetDevCaps(WAVE_MAPPER, &woc, sizeof(woc)); - //Use the received manufacturer id to get the device's real name - waveOutGetDevCaps(woc.wMid, &woc, sizeof(woc)); - qDebug() << "output device:" << woc.szPname; - deviceName = woc.szPname; - } + QString deviceName; + //Check for Windows Vista or higher, IMMDeviceEnumerator doesn't work below that. + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + if (osvi.dwMajorVersion < 6) {// lower then vista + if (mode == QAudio::AudioInput) { + WAVEINCAPS wic; + // first use WAVE_MAPPER to get the default devices manufacturer ID + waveInGetDevCaps(WAVE_MAPPER, &wic, sizeof(wic)); + //Use the received manufacturer id to get the device's real name + waveInGetDevCaps(wic.wMid, &wic, sizeof(wic)); + qDebug() << "input device:" << wic.szPname; + deviceName = wic.szPname; + } else { + WAVEOUTCAPS woc; + // first use WAVE_MAPPER to get the default devices manufacturer ID + waveOutGetDevCaps(WAVE_MAPPER, &woc, sizeof(woc)); + //Use the received manufacturer id to get the device's real name + waveOutGetDevCaps(woc.wMid, &woc, sizeof(woc)); + qDebug() << "output device:" << woc.szPname; + deviceName = woc.szPname; + } + } else { + HRESULT hr = S_OK; + CoInitialize(NULL); + IMMDeviceEnumerator *pMMDeviceEnumerator = NULL; + CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator); + IMMDevice *pEndpoint; + pMMDeviceEnumerator->GetDefaultAudioEndpoint(mode == QAudio::AudioOutput ? eRender : eCapture, eMultimedia, &pEndpoint); + IPropertyStore *pPropertyStore; + pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore); + pEndpoint->Release(); + pEndpoint = NULL; + PROPVARIANT pv; + PropVariantInit(&pv); + hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); + pPropertyStore->Release(); + pPropertyStore = NULL; + //QAudio devices seems to only take the 31 first characters of the Friendly Device Name. + deviceName = QString::fromWCharArray((wchar_t *)pv.pwszVal).left(31); + qDebug() << (mode == QAudio::AudioOutput ? "output" : "input") << " device:" << deviceName; + PropVariantClear(&pv); + pMMDeviceEnumerator->Release(); + pMMDeviceEnumerator = NULL; + CoUninitialize(); + } qDebug() << "DEBUG [" << deviceName << "] [" << getNamedAudioDeviceForMode(mode, deviceName).deviceName() << "]"; return getNamedAudioDeviceForMode(mode, deviceName); From e9922b6db92337da655290ae9d9f0d98069fa7d7 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 7 Apr 2014 18:50:13 +0200 Subject: [PATCH 16/37] windows default device fix: - fixed tabs>spaces - doesn't require atlbase anymore, so works on visual studio express --- interface/src/Audio.cpp | 80 +++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 3f48c73867..7e7dfd9df1 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -16,7 +16,9 @@ #endif #ifdef WIN32 -#include +#define WIN32_LEAN_AND_MEAN +#include +#include #include #include #include @@ -153,55 +155,55 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { } #endif #ifdef WIN32 - QString deviceName; - //Check for Windows Vista or higher, IMMDeviceEnumerator doesn't work below that. + QString deviceName; + //Check for Windows Vista or higher, IMMDeviceEnumerator doesn't work below that. OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); - if (osvi.dwMajorVersion < 6) {// lower then vista - if (mode == QAudio::AudioInput) { - WAVEINCAPS wic; - // first use WAVE_MAPPER to get the default devices manufacturer ID - waveInGetDevCaps(WAVE_MAPPER, &wic, sizeof(wic)); - //Use the received manufacturer id to get the device's real name - waveInGetDevCaps(wic.wMid, &wic, sizeof(wic)); - qDebug() << "input device:" << wic.szPname; - deviceName = wic.szPname; - } else { - WAVEOUTCAPS woc; - // first use WAVE_MAPPER to get the default devices manufacturer ID - waveOutGetDevCaps(WAVE_MAPPER, &woc, sizeof(woc)); - //Use the received manufacturer id to get the device's real name - waveOutGetDevCaps(woc.wMid, &woc, sizeof(woc)); - qDebug() << "output device:" << woc.szPname; - deviceName = woc.szPname; - } - } else { - HRESULT hr = S_OK; - CoInitialize(NULL); - IMMDeviceEnumerator *pMMDeviceEnumerator = NULL; - CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator); - IMMDevice *pEndpoint; - pMMDeviceEnumerator->GetDefaultAudioEndpoint(mode == QAudio::AudioOutput ? eRender : eCapture, eMultimedia, &pEndpoint); + if (osvi.dwMajorVersion < 6) {// lower then vista + if (mode == QAudio::AudioInput) { + WAVEINCAPS wic; + // first use WAVE_MAPPER to get the default devices manufacturer ID + waveInGetDevCaps(WAVE_MAPPER, &wic, sizeof(wic)); + //Use the received manufacturer id to get the device's real name + waveInGetDevCaps(wic.wMid, &wic, sizeof(wic)); + qDebug() << "input device:" << wic.szPname; + deviceName = wic.szPname; + } else { + WAVEOUTCAPS woc; + // first use WAVE_MAPPER to get the default devices manufacturer ID + waveOutGetDevCaps(WAVE_MAPPER, &woc, sizeof(woc)); + //Use the received manufacturer id to get the device's real name + waveOutGetDevCaps(woc.wMid, &woc, sizeof(woc)); + qDebug() << "output device:" << woc.szPname; + deviceName = woc.szPname; + } + } else { + HRESULT hr = S_OK; + CoInitialize(NULL); + IMMDeviceEnumerator *pMMDeviceEnumerator = NULL; + CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator); + IMMDevice *pEndpoint; + pMMDeviceEnumerator->GetDefaultAudioEndpoint(mode == QAudio::AudioOutput ? eRender : eCapture, eMultimedia, &pEndpoint); IPropertyStore *pPropertyStore; pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore); pEndpoint->Release(); - pEndpoint = NULL; + pEndpoint = NULL; PROPVARIANT pv; - PropVariantInit(&pv); + PropVariantInit(&pv); hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); pPropertyStore->Release(); - pPropertyStore = NULL; - //QAudio devices seems to only take the 31 first characters of the Friendly Device Name. - deviceName = QString::fromWCharArray((wchar_t *)pv.pwszVal).left(31); + pPropertyStore = NULL; + //QAudio devices seems to only take the 31 first characters of the Friendly Device Name. + deviceName = QString::fromWCharArray((wchar_t *)pv.pwszVal).left(31); qDebug() << (mode == QAudio::AudioOutput ? "output" : "input") << " device:" << deviceName; - PropVariantClear(&pv); - pMMDeviceEnumerator->Release(); - pMMDeviceEnumerator = NULL; - CoUninitialize(); - } - qDebug() << "DEBUG [" << deviceName << "] [" << getNamedAudioDeviceForMode(mode, deviceName).deviceName() << "]"; + PropVariantClear(&pv); + pMMDeviceEnumerator->Release(); + pMMDeviceEnumerator = NULL; + CoUninitialize(); + } + qDebug() << "DEBUG [" << deviceName << "] [" << getNamedAudioDeviceForMode(mode, deviceName).deviceName() << "]"; return getNamedAudioDeviceForMode(mode, deviceName); #endif From cec99caa47ff1692dd95a85e716f751620f7bef8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 13:45:30 -0700 Subject: [PATCH 17/37] Added upload progress tracking to AccountManager via JSON --- libraries/shared/src/AccountManager.cpp | 12 +++++++++--- libraries/shared/src/AccountManager.h | 5 ++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index 955ba779d1..841fd9dde0 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -170,12 +170,18 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: if (!callbackParams.isEmpty()) { // if we have information for a callback, insert the callbackParams into our local map _pendingCallbackMap.insert(networkReply, callbackParams); + + if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) { + callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)), + callbackParams.updateSlot.toStdString().c_str()); + } } // if we ended up firing of a request, hook up to it now - connect(networkReply, SIGNAL(finished()), this, SLOT(passSuccessToCallback())); + connect(networkReply, SIGNAL(finished()), + SLOT(passSuccessToCallback())); connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(passErrorToCallback(QNetworkReply::NetworkError))); + SLOT(passErrorToCallback(QNetworkReply::NetworkError))); } } } @@ -194,7 +200,7 @@ void AccountManager::passSuccessToCallback() { // remove the related reply-callback group from the map _pendingCallbackMap.remove(requestReply); - } else { + } else { if (VERBOSE_HTTP_REQUEST_DEBUGGING) { qDebug() << "Received JSON response from data-server that has no matching callback."; qDebug() << jsonResponse; diff --git a/libraries/shared/src/AccountManager.h b/libraries/shared/src/AccountManager.h index bfe84f392e..b410885705 100644 --- a/libraries/shared/src/AccountManager.h +++ b/libraries/shared/src/AccountManager.h @@ -21,7 +21,8 @@ class JSONCallbackParameters { public: JSONCallbackParameters() : jsonCallbackReceiver(NULL), jsonCallbackMethod(), - errorCallbackReceiver(NULL), errorCallbackMethod() {}; + errorCallbackReceiver(NULL), errorCallbackMethod(), + updateReciever(NULL), updateSlot() {}; bool isEmpty() const { return !jsonCallbackReceiver && !errorCallbackReceiver; } @@ -29,6 +30,8 @@ public: QString jsonCallbackMethod; QObject* errorCallbackReceiver; QString errorCallbackMethod; + QObject* updateReciever; + QString updateSlot; }; class AccountManager : public QObject { From b21fe02fa2ae017520d6e4a6e05a5e371286bcaf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 13:46:38 -0700 Subject: [PATCH 18/37] Put ModelUploder on a different thread, not to block the rendering of the main window --- interface/src/Application.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d54cceb245..fb50f647e8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3245,9 +3245,12 @@ void Application::toggleRunningScriptsWidget() void Application::uploadFST(bool isHead) { ModelUploader* uploader = new ModelUploader(isHead); - if (uploader->zip()) { - uploader->send(); - } + QThread* thread = new QThread(); + thread->connect(uploader, SIGNAL(destroyed()), SLOT(quit())); + thread->connect(thread, SIGNAL(finished()), SLOT(deleteLater())); + uploader->connect(thread, SIGNAL(started()), SLOT(send())); + + thread->start(); } void Application::uploadHead() { From e85703d25bf657f3a5d7297a38dfe73a5827be04 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 13:48:28 -0700 Subject: [PATCH 19/37] Added feedback and a better success check --- libraries/shared/src/ModelUploader.cpp | 102 +++++++++++++++++++++---- libraries/shared/src/ModelUploader.h | 25 +++++- 2 files changed, 109 insertions(+), 18 deletions(-) diff --git a/libraries/shared/src/ModelUploader.cpp b/libraries/shared/src/ModelUploader.cpp index 71514c8b0f..2ec199750f 100644 --- a/libraries/shared/src/ModelUploader.cpp +++ b/libraries/shared/src/ModelUploader.cpp @@ -9,13 +9,15 @@ #include #include -#include #include -#include +#include #include -#include -#include #include +#include +#include +#include +#include +#include #include "AccountManager.h" #include "ModelUploader.h" @@ -26,9 +28,12 @@ static const QString FILENAME_FIELD = "filename"; static const QString TEXDIR_FIELD = "texdir"; static const QString LOD_FIELD = "lod"; +static const QString S3_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com"; static const QString MODEL_URL = "/api/v1/models"; static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB +static const int TIMEOUT = 1000; +static const int MAX_CHECK = 30; // Class providing the QObject parent system to QTemporaryDir class TemporaryDir : public QTemporaryDir, public QObject { @@ -45,10 +50,11 @@ ModelUploader::ModelUploader(bool isHead) : _totalSize(0), _isHead(isHead), _readyToSend(false), - _dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType)) + _dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType)), + _numberOfChecks(MAX_CHECK) { _zipDir->setParent(_dataMultiPart); - + connect(&_timer, SIGNAL(timeout()), SLOT(checkS3())); } ModelUploader::~ModelUploader() { @@ -59,8 +65,9 @@ bool ModelUploader::zip() { // File Dialog QString filename = QFileDialog::getOpenFileName(NULL, "Select your .fst file ...", - QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), + QStandardPaths::writableLocation(QStandardPaths::HomeLocation), "*.fst"); + qDebug() << QStandardPaths::writableLocation(QStandardPaths::HomeLocation); if (filename == "") { // If the user canceled we return. return false; @@ -103,6 +110,7 @@ bool ModelUploader::zip() { " name=\"model_name\""); textPart.setBody(line[1].toUtf8()); _dataMultiPart->append(textPart); + _url = S3_URL + ((_isHead)? "/models/heads/" : "/models/skeletons/") + line[1].toUtf8() + ".fst"; } else if (line[0] == FILENAME_FIELD) { QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]); if (!fbx.exists() || !fbx.isFile()) { // Check existence @@ -167,9 +175,9 @@ bool ModelUploader::zip() { return true; } -bool ModelUploader::send() { - if (!_readyToSend) { - return false; +void ModelUploader::send() { + if (!zip()) { + return; } JSONCallbackParameters callbackParams; @@ -177,22 +185,52 @@ bool ModelUploader::send() { callbackParams.jsonCallbackMethod = "uploadSuccess"; callbackParams.errorCallbackReceiver = this; callbackParams.errorCallbackMethod = "uploadFailed"; + callbackParams.updateReciever = this; + callbackParams.updateSlot = SLOT(uploadUpdate(qint64, qint64)); AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, callbackParams, QByteArray(), _dataMultiPart); _zipDir = NULL; _dataMultiPart = NULL; qDebug() << "Sending model..."; + _progressDialog = new QDialog(); + _progressBar = new QProgressBar(_progressDialog); + _progressBar->setRange(0, 100); + _progressBar->setValue(0); - return true; + _progressDialog->setWindowTitle("Uploading model..."); + _progressDialog->setLayout(new QGridLayout(_progressDialog)); + _progressDialog->layout()->addWidget(_progressBar); + + _progressDialog->exec(); + + delete _progressDialog; + _progressDialog = NULL; + _progressBar = NULL; +} + +void ModelUploader::uploadUpdate(qint64 bytesSent, qint64 bytesTotal) { + if (_progressDialog) { + _progressBar->setRange(0, bytesTotal); + _progressBar->setValue(bytesSent); + } } void ModelUploader::uploadSuccess(const QJsonObject& jsonResponse) { - qDebug() << "Model sent with success to the data server."; - qDebug() << "It might take a few minute for it to appear in your model browser."; - deleteLater(); + if (_progressDialog) { + _progressDialog->accept(); + } + QMessageBox::information(NULL, + QString("ModelUploader::uploadSuccess()"), + QString("Your model is being processed by the system."), + QMessageBox::Ok); + qDebug() << "Model sent with success"; + checkS3(); } void ModelUploader::uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString) { + if (_progressDialog) { + _progressDialog->reject(); + } QMessageBox::warning(NULL, QString("ModelUploader::uploadFailed()"), QString("Model could not be sent to the data server."), @@ -201,6 +239,42 @@ void ModelUploader::uploadFailed(QNetworkReply::NetworkError errorCode, const QS deleteLater(); } +void ModelUploader::checkS3() { + qDebug() << "Checking S3 for " << _url; + QNetworkRequest request(_url); + QNetworkReply* reply = _networkAccessManager.head(request); + connect(reply, SIGNAL(finished()), SLOT(processCheck())); +} + +void ModelUploader::processCheck() { + QNetworkReply* reply = static_cast(sender()); + _timer.stop(); + + switch (reply->error()) { + case QNetworkReply::NoError: + QMessageBox::information(NULL, + QString("ModelUploader::processCheck()"), + QString("Your model is now available in the browser."), + QMessageBox::Ok); + deleteLater(); + break; + case QNetworkReply::ContentNotFoundError: + if (--_numberOfChecks) { + _timer.start(TIMEOUT); + break; + } + default: + QMessageBox::warning(NULL, + QString("ModelUploader::processCheck()"), + QString("Could not verify that the model is present on the server."), + QMessageBox::Ok); + deleteLater(); + break; + } + + delete reply; +} + bool ModelUploader::addTextures(const QFileInfo& texdir) { QStringList filter; filter << "*.png" << "*.tif" << "*.jpg" << "*.jpeg"; diff --git a/libraries/shared/src/ModelUploader.h b/libraries/shared/src/ModelUploader.h index f127008f44..066a577e57 100644 --- a/libraries/shared/src/ModelUploader.h +++ b/libraries/shared/src/ModelUploader.h @@ -10,9 +10,14 @@ #ifndef __hifi__ModelUploader__ #define __hifi__ModelUploader__ -class TemporaryDir; -class QHttpMultiPart; +#include + +class QDialog; class QFileInfo; +class QHttpMultiPart; +class QProgressBar; + +class TemporaryDir; class ModelUploader : public QObject { Q_OBJECT @@ -21,14 +26,18 @@ public: ModelUploader(bool isHead); ~ModelUploader(); - bool zip(); - bool send(); +public slots: + void send(); private slots: + void uploadUpdate(qint64 bytesSent, qint64 bytesTotal); void uploadSuccess(const QJsonObject& jsonResponse); void uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString); + void checkS3(); + void processCheck(); private: + QString _url; TemporaryDir* _zipDir; int _lodCount; int _texturesCount; @@ -37,8 +46,16 @@ private: bool _readyToSend; QHttpMultiPart* _dataMultiPart; + QNetworkAccessManager _networkAccessManager; + + int _numberOfChecks; + QTimer _timer; + + QDialog* _progressDialog; + QProgressBar* _progressBar; + bool zip(); bool addTextures(const QFileInfo& texdir); bool compressFile(const QString& inFileName, const QString& outFileName); bool addPart(const QString& path, const QString& name); From 262c6d320640a168894593764d612934e156a969 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 14:35:13 -0700 Subject: [PATCH 20/37] Fixed double JSON callback when http error occurs --- libraries/shared/src/AccountManager.cpp | 25 +++++++++++++++---------- libraries/shared/src/AccountManager.h | 6 ++++-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index 841fd9dde0..fe361ba751 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -179,15 +179,23 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: // if we ended up firing of a request, hook up to it now connect(networkReply, SIGNAL(finished()), - SLOT(passSuccessToCallback())); - connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)), - SLOT(passErrorToCallback(QNetworkReply::NetworkError))); + SLOT(processReply())); } } } -void AccountManager::passSuccessToCallback() { +void AccountManager::processReply() { QNetworkReply* requestReply = reinterpret_cast(sender()); + + if (requestReply->error() == QNetworkReply::NoError) { + passSuccessToCallback(requestReply); + } else { + passErrorToCallback(requestReply); + } + delete requestReply; +} + +void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) { QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll()); JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply); @@ -206,17 +214,15 @@ void AccountManager::passSuccessToCallback() { qDebug() << jsonResponse; } } - delete requestReply; } -void AccountManager::passErrorToCallback(QNetworkReply::NetworkError errorCode) { - QNetworkReply* requestReply = reinterpret_cast(sender()); +void AccountManager::passErrorToCallback(QNetworkReply* requestReply) { JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply); if (callbackParams.errorCallbackReceiver) { // invoke the right method on the callback receiver QMetaObject::invokeMethod(callbackParams.errorCallbackReceiver, qPrintable(callbackParams.errorCallbackMethod), - Q_ARG(QNetworkReply::NetworkError, errorCode), + Q_ARG(QNetworkReply::NetworkError, requestReply->error()), Q_ARG(const QString&, requestReply->errorString())); // remove the related reply-callback group from the map @@ -224,10 +230,9 @@ void AccountManager::passErrorToCallback(QNetworkReply::NetworkError errorCode) } else { if (VERBOSE_HTTP_REQUEST_DEBUGGING) { qDebug() << "Received error response from data-server that has no matching callback."; - qDebug() << "Error" << errorCode << "-" << requestReply->errorString(); + qDebug() << "Error" << requestReply->error() << "-" << requestReply->errorString(); } } - delete requestReply; } bool AccountManager::hasValidAccessToken() { diff --git a/libraries/shared/src/AccountManager.h b/libraries/shared/src/AccountManager.h index b410885705..55a40438e0 100644 --- a/libraries/shared/src/AccountManager.h +++ b/libraries/shared/src/AccountManager.h @@ -73,13 +73,15 @@ signals: void loginComplete(const QUrl& authURL); void logoutComplete(); private slots: - void passSuccessToCallback(); - void passErrorToCallback(QNetworkReply::NetworkError errorCode); + void processReply(); private: AccountManager(); AccountManager(AccountManager const& other); // not implemented void operator=(AccountManager const& other); // not implemented + void passSuccessToCallback(QNetworkReply* reply); + void passErrorToCallback(QNetworkReply* reply); + Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray, From 15e9d45dc3465503364adcaf83dc55738b55ff81 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Apr 2014 15:41:42 -0700 Subject: [PATCH 21/37] Switched from storing Euler angles to using quaternions along with a quaternion editor. Also, use a default step of 0.01 for floats/doubles. --- interface/src/MetavoxelSystem.cpp | 8 +-- interface/src/MetavoxelSystem.h | 2 +- interface/src/renderer/Model.cpp | 5 +- libraries/metavoxels/src/Bitstream.cpp | 9 +++ libraries/metavoxels/src/Bitstream.h | 3 + libraries/metavoxels/src/MetavoxelData.cpp | 2 +- libraries/metavoxels/src/MetavoxelData.h | 10 ++-- libraries/metavoxels/src/MetavoxelUtil.cpp | 69 +++++++++++++++++----- libraries/metavoxels/src/MetavoxelUtil.h | 66 +++++++++++++++++---- 9 files changed, 136 insertions(+), 38 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 8fe4b53922..7eb046756b 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -395,7 +395,7 @@ void SphereRenderer::renderUnclipped(float alpha, Mode mode) { glPushMatrix(); const glm::vec3& translation = sphere->getTranslation(); glTranslatef(translation.x, translation.y, translation.z); - glm::quat rotation = glm::quat(glm::radians(sphere->getRotation())); + glm::quat rotation = sphere->getRotation(); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); @@ -418,7 +418,7 @@ void StaticModelRenderer::init(Spanner* spanner) { applyURL(staticModel->getURL()); connect(spanner, SIGNAL(translationChanged(const glm::vec3&)), SLOT(applyTranslation(const glm::vec3&))); - connect(spanner, SIGNAL(rotationChanged(const glm::vec3&)), SLOT(applyRotation(const glm::vec3&))); + connect(spanner, SIGNAL(rotationChanged(const glm::quat&)), SLOT(applyRotation(const glm::quat&))); connect(spanner, SIGNAL(scaleChanged(float)), SLOT(applyScale(float))); connect(spanner, SIGNAL(urlChanged(const QUrl&)), SLOT(applyURL(const QUrl&))); } @@ -461,8 +461,8 @@ void StaticModelRenderer::applyTranslation(const glm::vec3& translation) { _model->setTranslation(translation); } -void StaticModelRenderer::applyRotation(const glm::vec3& rotation) { - _model->setRotation(glm::quat(glm::radians(rotation))); +void StaticModelRenderer::applyRotation(const glm::quat& rotation) { + _model->setRotation(rotation); } void StaticModelRenderer::applyScale(float scale) { diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 7612437bb9..ecab30d535 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -189,7 +189,7 @@ protected: private slots: void applyTranslation(const glm::vec3& translation); - void applyRotation(const glm::vec3& eulerAngles); // eulerAngles are in degrees + void applyRotation(const glm::quat& rotation); void applyScale(float scale); void applyURL(const QUrl& url); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 6583b436b7..36fbbe3833 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -58,7 +58,10 @@ Model::SkinLocations Model::_skinShadowLocations; void Model::setScale(const glm::vec3& scale) { glm::vec3 deltaScale = _scale - scale; - if (glm::length2(deltaScale) > EPSILON) { + + // decreased epsilon because this wasn't handling scale changes of 0.01 + const float SMALLER_EPSILON = EPSILON * 0.0001f; + if (glm::length2(deltaScale) > SMALLER_EPSILON) { _scale = scale; rebuildShapes(); } diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 09e71700be..3f3d6e5423 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -35,6 +35,7 @@ REGISTER_SIMPLE_TYPE_STREAMER(SharedObjectPointer) // some types don't quite work with our macro static int vec3Streamer = Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); +static int quatStreamer = Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); static int metaObjectStreamer = Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); @@ -352,6 +353,14 @@ Bitstream& Bitstream::operator>>(glm::vec3& value) { return *this >> value.x >> value.y >> value.z; } +Bitstream& Bitstream::operator<<(const glm::quat& value) { + return *this << value.w << value.x << value.y << value.z; +} + +Bitstream& Bitstream::operator>>(glm::quat& value) { + return *this >> value.w >> value.x >> value.y >> value.z; +} + Bitstream& Bitstream::operator<<(const QByteArray& string) { *this << string.size(); return write(string.constData(), string.size() * BITS_IN_BYTE); diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 8f36ce9a08..d7b16fcc4a 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -312,6 +312,9 @@ public: Bitstream& operator<<(const glm::vec3& value); Bitstream& operator>>(glm::vec3& value); + Bitstream& operator<<(const glm::quat& value); + Bitstream& operator>>(glm::quat& value); + Bitstream& operator<<(const QByteArray& string); Bitstream& operator>>(QByteArray& string); diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index e4cce9c735..6ae847cea3 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -1545,7 +1545,7 @@ void Transformable::setTranslation(const glm::vec3& translation) { } } -void Transformable::setRotation(const glm::vec3& rotation) { +void Transformable::setRotation(const glm::quat& rotation) { if (_rotation != rotation) { emit rotationChanged(_rotation = rotation); } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 41285af2f5..7a53598042 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -533,7 +533,7 @@ public: class Transformable : public Spanner { Q_OBJECT Q_PROPERTY(glm::vec3 translation MEMBER _translation WRITE setTranslation NOTIFY translationChanged) - Q_PROPERTY(glm::vec3 rotation MEMBER _rotation WRITE setRotation NOTIFY rotationChanged) + Q_PROPERTY(glm::quat rotation MEMBER _rotation WRITE setRotation NOTIFY rotationChanged) Q_PROPERTY(float scale MEMBER _scale WRITE setScale NOTIFY scaleChanged) public: @@ -543,8 +543,8 @@ public: void setTranslation(const glm::vec3& translation); const glm::vec3& getTranslation() const { return _translation; } - void setRotation(const glm::vec3& rotation); - const glm::vec3& getRotation() const { return _rotation; } + void setRotation(const glm::quat& rotation); + const glm::quat& getRotation() const { return _rotation; } void setScale(float scale); float getScale() const { return _scale; } @@ -552,13 +552,13 @@ public: signals: void translationChanged(const glm::vec3& translation); - void rotationChanged(const glm::vec3& rotation); + void rotationChanged(const glm::quat& rotation); void scaleChanged(float scale); private: glm::vec3 _translation; - glm::vec3 _rotation; // Euler Angles in degrees + glm::quat _rotation; float _scale; }; diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index 7995809f1c..b259c1b513 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -52,6 +52,7 @@ public: DoubleEditor::DoubleEditor(QWidget* parent) : QDoubleSpinBox(parent) { setMinimum(-FLT_MAX); setMaximum(FLT_MAX); + setSingleStep(0.01); } DelegatingItemEditorFactory::DelegatingItemEditorFactory() : @@ -127,6 +128,12 @@ static QItemEditorCreatorBase* createVec3EditorCreator() { return creator; } +static QItemEditorCreatorBase* createQuatEditorCreator() { + QItemEditorCreatorBase* creator = new LazyItemEditorCreator(); + getItemEditorFactory()->registerEditor(qMetaTypeId(), creator); + return creator; +} + static QItemEditorCreatorBase* createParameterizedURLEditorCreator() { QItemEditorCreatorBase* creator = new LazyItemEditorCreator(); getItemEditorFactory()->registerEditor(qMetaTypeId(), creator); @@ -138,6 +145,7 @@ static QItemEditorCreatorBase* qMetaObjectEditorCreator = createQMetaObjectEdito static QItemEditorCreatorBase* qColorEditorCreator = createQColorEditorCreator(); static QItemEditorCreatorBase* qUrlEditorCreator = createQUrlEditorCreator(); static QItemEditorCreatorBase* vec3EditorCreator = createVec3EditorCreator(); +static QItemEditorCreatorBase* quatEditorCreator = createQuatEditorCreator(); static QItemEditorCreatorBase* parameterizedURLEditorCreator = createParameterizedURLEditorCreator(); QByteArray signal(const char* signature) { @@ -380,7 +388,7 @@ void QUrlEditor::updateSettings() { QSettings().setValue("editorURLs", urls); } -Vec3Editor::Vec3Editor(QWidget* parent) : QWidget(parent) { +BaseVec3Editor::BaseVec3Editor(QWidget* parent) : QWidget(parent) { QHBoxLayout* layout = new QHBoxLayout(); layout->setContentsMargins(QMargins()); setLayout(layout); @@ -390,26 +398,59 @@ Vec3Editor::Vec3Editor(QWidget* parent) : QWidget(parent) { layout->addWidget(_z = createComponentBox()); } -void Vec3Editor::setVector(const glm::vec3& vector) { - _vector = vector; - _x->setValue(vector.x); - _y->setValue(vector.y); - _z->setValue(vector.z); -} - -void Vec3Editor::updateVector() { - emit vectorChanged(_vector = glm::vec3(_x->value(), _y->value(), _z->value())); -} - -QDoubleSpinBox* Vec3Editor::createComponentBox() { +QDoubleSpinBox* BaseVec3Editor::createComponentBox() { QDoubleSpinBox* box = new QDoubleSpinBox(); box->setMinimum(-FLT_MAX); box->setMaximum(FLT_MAX); box->setMinimumWidth(50); - connect(box, SIGNAL(valueChanged(double)), SLOT(updateVector())); + connect(box, SIGNAL(valueChanged(double)), SLOT(updateValue())); return box; } +Vec3Editor::Vec3Editor(QWidget* parent) : BaseVec3Editor(parent) { + _x->setSingleStep(0.01); + _y->setSingleStep(0.01); + _z->setSingleStep(0.01); +} + +static void setComponentValue(QDoubleSpinBox* box, double value) { + box->blockSignals(true); + box->setValue(value); + box->blockSignals(false); +} + +void Vec3Editor::setValue(const glm::vec3& value) { + _value = value; + setComponentValue(_x, value.x); + setComponentValue(_y, value.y); + setComponentValue(_z, value.z); +} + +void Vec3Editor::updateValue() { + emit valueChanged(_value = glm::vec3(_x->value(), _y->value(), _z->value())); +} + +QuatEditor::QuatEditor(QWidget* parent) : BaseVec3Editor(parent) { + _x->setRange(-180.0, 180.0); + _y->setRange(-90.0, 90.0); + _z->setRange(-180.0, 180.0); + + _x->setWrapping(true); + _y->setWrapping(true); + _z->setWrapping(true); +} + +void QuatEditor::setValue(const glm::quat& value) { + glm::vec3 eulers = glm::degrees(safeEulerAngles(_value = value)); + setComponentValue(_x, eulers.x); + setComponentValue(_y, eulers.y); + setComponentValue(_z, eulers.z); +} + +void QuatEditor::updateValue() { + emit valueChanged(_value = glm::quat(glm::radians(glm::vec3(_x->value(), _y->value(), _z->value())))); +} + ParameterizedURL::ParameterizedURL(const QUrl& url, const ScriptHash& parameters) : _url(url), _parameters(parameters) { diff --git a/libraries/metavoxels/src/MetavoxelUtil.h b/libraries/metavoxels/src/MetavoxelUtil.h index 9972981bc7..cc6c540151 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.h +++ b/libraries/metavoxels/src/MetavoxelUtil.h @@ -142,10 +142,31 @@ private: QUrl _url; }; -/// Editor for vector values. -class Vec3Editor : public QWidget { +/// Base class for Vec3Editor and QuatEditor. +class BaseVec3Editor : public QWidget { Q_OBJECT - Q_PROPERTY(glm::vec3 vector MEMBER _vector WRITE setVector NOTIFY vectorChanged USER true) + +public: + + BaseVec3Editor(QWidget* parent); + +protected slots: + + virtual void updateValue() = 0; + +protected: + + QDoubleSpinBox* createComponentBox(); + + QDoubleSpinBox* _x; + QDoubleSpinBox* _y; + QDoubleSpinBox* _z; +}; + +/// Editor for vector values. +class Vec3Editor : public BaseVec3Editor { + Q_OBJECT + Q_PROPERTY(glm::vec3 value MEMBER _value WRITE setValue NOTIFY valueChanged USER true) public: @@ -153,24 +174,45 @@ public: signals: - void vectorChanged(const glm::vec3& vector); + void valueChanged(const glm::vec3& vector); public slots: - void setVector(const glm::vec3& vector); + void setValue(const glm::vec3& vector); -private slots: +protected: - void updateVector(); + virtual void updateValue(); private: - QDoubleSpinBox* createComponentBox(); + glm::vec3 _value; +}; + +/// Editor for quaternion values. +class QuatEditor : public BaseVec3Editor { + Q_OBJECT + Q_PROPERTY(glm::quat value MEMBER _value WRITE setValue NOTIFY valueChanged USER true) + +public: - QDoubleSpinBox* _x; - QDoubleSpinBox* _y; - QDoubleSpinBox* _z; - glm::vec3 _vector; + QuatEditor(QWidget* parent); + +signals: + + void valueChanged(const glm::quat& value); + +public slots: + + void setValue(const glm::quat& value); + +protected: + + virtual void updateValue(); + +private: + + glm::quat _value; }; typedef QHash ScriptHash; From 2a58a863fd8271f7952f387f67e47b4dbfe2f128 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Apr 2014 15:48:34 -0700 Subject: [PATCH 22/37] Fix for rotation placement. --- libraries/metavoxels/src/MetavoxelUtil.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelUtil.cpp b/libraries/metavoxels/src/MetavoxelUtil.cpp index b259c1b513..2ec1c3cb57 100644 --- a/libraries/metavoxels/src/MetavoxelUtil.cpp +++ b/libraries/metavoxels/src/MetavoxelUtil.cpp @@ -431,9 +431,9 @@ void Vec3Editor::updateValue() { } QuatEditor::QuatEditor(QWidget* parent) : BaseVec3Editor(parent) { - _x->setRange(-180.0, 180.0); - _y->setRange(-90.0, 90.0); - _z->setRange(-180.0, 180.0); + _x->setRange(-179.0, 180.0); + _y->setRange(-179.0, 180.0); + _z->setRange(-179.0, 180.0); _x->setWrapping(true); _y->setWrapping(true); @@ -441,14 +441,19 @@ QuatEditor::QuatEditor(QWidget* parent) : BaseVec3Editor(parent) { } void QuatEditor::setValue(const glm::quat& value) { - glm::vec3 eulers = glm::degrees(safeEulerAngles(_value = value)); - setComponentValue(_x, eulers.x); - setComponentValue(_y, eulers.y); - setComponentValue(_z, eulers.z); + if (_value != value) { + glm::vec3 eulers = glm::degrees(safeEulerAngles(_value = value)); + setComponentValue(_x, eulers.x); + setComponentValue(_y, eulers.y); + setComponentValue(_z, eulers.z); + } } void QuatEditor::updateValue() { - emit valueChanged(_value = glm::quat(glm::radians(glm::vec3(_x->value(), _y->value(), _z->value())))); + glm::quat value(glm::radians(glm::vec3(_x->value(), _y->value(), _z->value()))); + if (_value != value) { + emit valueChanged(_value = value); + } } ParameterizedURL::ParameterizedURL(const QUrl& url, const ScriptHash& parameters) : From 3be2319081ec99d0df4997cfb95e6eecbb2baa59 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 16:18:23 -0700 Subject: [PATCH 23/37] Removed all the temporaryDir junk --- libraries/shared/src/ModelUploader.cpp | 77 +++++--------------------- libraries/shared/src/ModelUploader.h | 2 - 2 files changed, 14 insertions(+), 65 deletions(-) diff --git a/libraries/shared/src/ModelUploader.cpp b/libraries/shared/src/ModelUploader.cpp index 2ec199750f..cda57aeab9 100644 --- a/libraries/shared/src/ModelUploader.cpp +++ b/libraries/shared/src/ModelUploader.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -35,16 +34,8 @@ static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB static const int TIMEOUT = 1000; static const int MAX_CHECK = 30; -// Class providing the QObject parent system to QTemporaryDir -class TemporaryDir : public QTemporaryDir, public QObject { -public: - virtual ~TemporaryDir() { - // ensuring the entire object gets deleted by the QObject parent. - } -}; ModelUploader::ModelUploader(bool isHead) : - _zipDir(new TemporaryDir()), _lodCount(-1), _texturesCount(-1), _totalSize(0), @@ -53,7 +44,6 @@ ModelUploader::ModelUploader(bool isHead) : _dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType)), _numberOfChecks(MAX_CHECK) { - _zipDir->setParent(_dataMultiPart); connect(&_timer, SIGNAL(timeout()), SLOT(checkS3())); } @@ -86,11 +76,7 @@ bool ModelUploader::zip() { qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); // Compress and copy the fst - if (!compressFile(QFileInfo(fst).filePath(), _zipDir->path() + "/" + QFileInfo(fst).fileName())) { - return false; - } - if (!addPart(_zipDir->path() + "/" + QFileInfo(fst).fileName(), - QString("fst"))) { + if (!addPart(QFileInfo(fst).filePath(), QString("fst"))) { return false; } @@ -122,10 +108,7 @@ bool ModelUploader::zip() { return false; } // Compress and copy - if (!compressFile(fbx.filePath(), _zipDir->path() + "/" + line[1])) { - return false; - } - if (!addPart(_zipDir->path() + "/" + line[1], "fbx")) { + if (!addPart(fbx.filePath(), "fbx")) { return false; } } else if (line[0] == TEXDIR_FIELD) { // Check existence @@ -152,10 +135,7 @@ bool ModelUploader::zip() { return false; } // Compress and copy - if (!compressFile(lod.filePath(), _zipDir->path() + "/" + line[1])) { - return false; - } - if (!addPart(_zipDir->path() + "/" + line[1], QString("lod%1").arg(++_lodCount))) { + if (!addPart(lod.filePath(), QString("lod%1").arg(++_lodCount))) { return false; } } @@ -189,7 +169,6 @@ void ModelUploader::send() { callbackParams.updateSlot = SLOT(uploadUpdate(qint64, qint64)); AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, callbackParams, QByteArray(), _dataMultiPart); - _zipDir = NULL; _dataMultiPart = NULL; qDebug() << "Sending model..."; _progressDialog = new QDialog(); @@ -287,11 +266,7 @@ bool ModelUploader::addTextures(const QFileInfo& texdir) { foreach (QFileInfo info, list) { if (info.isFile()) { // Compress and copy - if (!compressFile(info.filePath(), _zipDir->path() + "/" + info.fileName())) { - return false; - } - if (!addPart(_zipDir->path() + "/" + info.fileName(), - QString("texture%1").arg(++_texturesCount))) { + if (!addPart(info.filePath(), QString("texture%1").arg(++_texturesCount))) { return false; } } else if (info.isDir()) { @@ -304,54 +279,30 @@ bool ModelUploader::addTextures(const QFileInfo& texdir) { return true; } -bool ModelUploader::compressFile(const QString &inFileName, const QString &outFileName) { - QFile inFile(inFileName); - inFile.open(QIODevice::ReadOnly); - QByteArray buffer = inFile.readAll(); - - QFile outFile(outFileName); - if (!outFile.open(QIODevice::WriteOnly)) { - QDir(_zipDir->path()).mkpath(QFileInfo(outFileName).path()); - if (!outFile.open(QIODevice::WriteOnly)) { - QMessageBox::warning(NULL, - QString("ModelUploader::compressFile()"), - QString("Could not compress %1").arg(inFileName), - QMessageBox::Ok); - qDebug() << "[Warning] " << QString("Could not compress %1").arg(inFileName); - return false; - } - } - QDataStream out(&outFile); - out << qCompress(buffer); - - return true; -} - - bool ModelUploader::addPart(const QString &path, const QString& name) { - QFile* file = new QFile(path); - if (!file->open(QIODevice::ReadOnly)) { + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) { QMessageBox::warning(NULL, QString("ModelUploader::addPart()"), QString("Could not open %1").arg(path), QMessageBox::Ok); qDebug() << "[Warning] " << QString("Could not open %1").arg(path); - delete file; return false; } + QByteArray buffer = qCompress(file.readAll()); + buffer.remove(0, 4); QHttpPart part; - part.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" + part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data;" " name=\"" + name.toUtf8() + "\";" - " filename=\"" + QFileInfo(*file).fileName().toUtf8() + "\""); - part.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream"); - part.setBodyDevice(file); + " filename=\"" + QFileInfo(file).fileName().toUtf8() + "\"")); + part.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); + part.setBody(buffer); _dataMultiPart->append(part); - file->setParent(_dataMultiPart); - qDebug() << "File " << QFileInfo(*file).fileName() << " added to model."; - _totalSize += file->size(); + qDebug() << "File " << QFileInfo(file).fileName() << " added to model."; + _totalSize += file.size(); if (_totalSize > MAX_SIZE) { QMessageBox::warning(NULL, QString("ModelUploader::zip()"), diff --git a/libraries/shared/src/ModelUploader.h b/libraries/shared/src/ModelUploader.h index 066a577e57..0e62ab8705 100644 --- a/libraries/shared/src/ModelUploader.h +++ b/libraries/shared/src/ModelUploader.h @@ -38,7 +38,6 @@ private slots: private: QString _url; - TemporaryDir* _zipDir; int _lodCount; int _texturesCount; int _totalSize; @@ -57,7 +56,6 @@ private: bool zip(); bool addTextures(const QFileInfo& texdir); - bool compressFile(const QString& inFileName, const QString& outFileName); bool addPart(const QString& path, const QString& name); }; From d213cd784034285337e137b6575166088ef7a803 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 17:10:15 -0700 Subject: [PATCH 24/37] More work on Undo/Redo --- examples/editVoxels.js | 1 - interface/src/Application.cpp | 1 + interface/src/Menu.cpp | 11 +-- libraries/voxels/src/VoxelTree.h | 7 +- libraries/voxels/src/VoxelTreeCommands.cpp | 64 +++++++++++++++ libraries/voxels/src/VoxelTreeCommands.h | 46 +++++++++++ .../voxels/src/VoxelsScriptingInterface.cpp | 77 +++++++++++++++---- .../voxels/src/VoxelsScriptingInterface.h | 4 +- 8 files changed, 190 insertions(+), 21 deletions(-) create mode 100644 libraries/voxels/src/VoxelTreeCommands.cpp create mode 100644 libraries/voxels/src/VoxelTreeCommands.h diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 4922caf0d8..0f9ed25d2c 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -911,7 +911,6 @@ function mousePressEvent(event) { } voxelDetails = calculateVoxelFromIntersection(intersection,"add"); - Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s, newColor.red, newColor.green, newColor.blue); lastVoxelPosition = { x: voxelDetails.x, y: voxelDetails.y, z: voxelDetails.z }; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d54cceb245..68b2ae9a24 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3274,6 +3274,7 @@ void Application::loadScript(const QString& scriptName) { // we can use the same ones from the application. scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender); scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree()); + scriptEngine->getVoxelsScriptingInterface()->setUndoStack(&_undoStack); scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender); scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree()); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e090f4d046..b9aa0ea91c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -161,14 +161,15 @@ Menu::Menu() : QMenu* editMenu = addMenu("Edit"); + QUndoStack* undoStack = Application::getInstance()->getUndoStack(); QAction* undoAction = undoStack->createUndoAction(editMenu); + undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); + addActionToQMenuAndActionHash(editMenu, undoAction); + QAction* redoAction = undoStack->createRedoAction(editMenu); - - addActionToQMenuAndActionHash(editMenu, - undoAction); - addActionToQMenuAndActionHash(editMenu, - redoAction); + redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); + addActionToQMenuAndActionHash(editMenu, redoAction); addActionToQMenuAndActionHash(editMenu, MenuOption::Preferences, diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 2079ab91b2..3d1b699a45 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -1,4 +1,4 @@ -// + // // VoxelTree.h // hifi // @@ -14,6 +14,7 @@ #include "VoxelTreeElement.h" #include "VoxelEditPacketSender.h" +class QUndoStack; class ReadCodeColorBufferToTreeArgs; class VoxelTree : public Octree { @@ -44,6 +45,8 @@ public: virtual bool handlesEditPacketType(PacketType packetType) const; virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength, const unsigned char* editData, int maxLength, const SharedNodePointer& node); + + void setUndoStack(QUndoStack* undoStack) { _undoStack = undoStack; } private: // helper functions for nudgeSubTree @@ -52,6 +55,8 @@ private: void nudgeLeaf(VoxelTreeElement* element, void* extraData); void chunkifyLeaf(VoxelTreeElement* element); void readCodeColorBufferToTreeRecursion(VoxelTreeElement* node, ReadCodeColorBufferToTreeArgs& args); + + QUndoStack* _undoStack; }; #endif /* defined(__hifi__VoxelTree__) */ diff --git a/libraries/voxels/src/VoxelTreeCommands.cpp b/libraries/voxels/src/VoxelTreeCommands.cpp new file mode 100644 index 0000000000..a557137367 --- /dev/null +++ b/libraries/voxels/src/VoxelTreeCommands.cpp @@ -0,0 +1,64 @@ +// +// VoxelTreeCommands.cpp +// hifi +// +// Created by Clement on 4/4/14. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// + +#include "VoxelTree.h" + +#include "VoxelTreeCommands.h" + +AddVoxelCommand::AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) : +QUndoCommand("Add Voxel", parent), +_tree(tree), +_packetSender(packetSender), +_voxel(voxel) +{ +} + +void AddVoxelCommand::redo() { + if (_tree) { + _tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel); + } +} + +void AddVoxelCommand::undo() { + if (_tree) { + _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); + } +} + +DeleteVoxelCommand::DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) : +QUndoCommand("Delete Voxel", parent), +_tree(tree), +_packetSender(packetSender), +_voxel(voxel) +{ +} + +void DeleteVoxelCommand::redo() { + if (_tree) { + _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); + } +} + +void DeleteVoxelCommand::undo() { + if (_tree) { + _tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel); + } +} \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTreeCommands.h b/libraries/voxels/src/VoxelTreeCommands.h new file mode 100644 index 0000000000..ca7700417c --- /dev/null +++ b/libraries/voxels/src/VoxelTreeCommands.h @@ -0,0 +1,46 @@ +// +// VoxelTreeCommands.h +// hifi +// +// Created by Clement on 4/4/14. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __hifi__VoxelTreeCommands__ +#define __hifi__VoxelTreeCommands__ + +#include +#include + +#include "VoxelDetail.h" +#include "VoxelEditPacketSender.h" + +class VoxelTree; + +class AddVoxelCommand : public QUndoCommand { +public: + AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL); + + virtual void redo(); + virtual void undo(); + +private: + VoxelTree* _tree; + VoxelEditPacketSender* _packetSender; + VoxelDetail _voxel; +}; + +class DeleteVoxelCommand : public QUndoCommand { +public: + DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL); + + virtual void redo(); + virtual void undo(); + +private: + VoxelTree* _tree; + VoxelEditPacketSender* _packetSender; + VoxelDetail _voxel; +}; + +#endif /* defined(__hifi__VoxelTreeCommands__) */ diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index 2aecb2d457..59e4662bed 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -6,6 +6,8 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // +#include "VoxelTreeCommands.h" + #include "VoxelsScriptingInterface.h" void VoxelsScriptingInterface::queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails) { @@ -37,17 +39,24 @@ VoxelDetail VoxelsScriptingInterface::getVoxelAt(float x, float y, float z, floa } void VoxelsScriptingInterface::setVoxelNonDestructive(float x, float y, float z, float scale, - uchar red, uchar green, uchar blue) { + uchar red, uchar green, uchar blue) { // setup a VoxelDetail struct with the data - VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, + VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, scale / (float)TREE_SCALE, red, green, blue}; - // queue the add packet - queueVoxelAdd(PacketTypeVoxelSet, addVoxelDetail); // handle the local tree also... if (_tree) { - _tree->createVoxel(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s, red, green, blue, false); + if (_undoStack) { + AddVoxelCommand* command = new AddVoxelCommand(_tree, + addVoxelDetail, + getVoxelPacketSender()); + _undoStack->push(command); + } else { + // queue the add packet + queueVoxelAdd(PacketTypeVoxelSet, addVoxelDetail); + _tree->createVoxel(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s, red, green, blue, false); + } } } @@ -57,26 +66,68 @@ void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, VoxelDetail addVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, scale / (float)TREE_SCALE, red, green, blue}; - // queue the destructive add - queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail); // handle the local tree also... if (_tree) { - _tree->createVoxel(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s, red, green, blue, true); + if (_undoStack) { + AddVoxelCommand* addCommand = new AddVoxelCommand(_tree, + addVoxelDetail, + getVoxelPacketSender()); + + VoxelTreeElement* deleteVoxelElement = _tree->getVoxelAt(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s); + if (deleteVoxelElement) { + nodeColor color; + memcpy(&color, &deleteVoxelElement->getColor(), sizeof(nodeColor)); + VoxelDetail deleteVoxelDetail = {addVoxelDetail.x, + addVoxelDetail.y, + addVoxelDetail.z, + addVoxelDetail.s, + color[0], + color[1], + color[2]}; + DeleteVoxelCommand* delCommand = new DeleteVoxelCommand(_tree, + deleteVoxelDetail, + getVoxelPacketSender()); + _undoStack->beginMacro(addCommand->text()); + qDebug() << "Macro"; + _undoStack->push(delCommand); + _undoStack->push(addCommand); + _undoStack->endMacro(); + } else { + _undoStack->push(addCommand); + } + } else { + // queue the destructive add + queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail); + _tree->createVoxel(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s, red, green, blue, true); + } } } void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale) { - // setup a VoxelDetail struct with data - VoxelDetail deleteVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, - scale / (float)TREE_SCALE, 0, 0, 0}; + VoxelDetail deleteVoxelDetail = {x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, + scale / (float)TREE_SCALE}; - getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail); // handle the local tree also... if (_tree) { - _tree->deleteVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s); + VoxelTreeElement* deleteVoxelElement = _tree->getVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s); + if (deleteVoxelElement) { + deleteVoxelDetail.red = deleteVoxelElement->getColor()[0]; + deleteVoxelDetail.green = deleteVoxelElement->getColor()[1]; + deleteVoxelDetail.blue = deleteVoxelElement->getColor()[2]; + } + + if (_undoStack) { + DeleteVoxelCommand* command = new DeleteVoxelCommand(_tree, + deleteVoxelDetail, + getVoxelPacketSender()); + _undoStack->push(command); + } else { + getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail); + _tree->deleteVoxelAt(deleteVoxelDetail.x, deleteVoxelDetail.y, deleteVoxelDetail.z, deleteVoxelDetail.s); + } } } diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h index d07d2a785c..339e527ebc 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ b/libraries/voxels/src/VoxelsScriptingInterface.h @@ -22,12 +22,13 @@ class VoxelsScriptingInterface : public OctreeScriptingInterface { Q_OBJECT public: - VoxelsScriptingInterface() : _tree(NULL) {}; + VoxelsScriptingInterface() : _tree(NULL), _undoStack(NULL) {}; VoxelEditPacketSender* getVoxelPacketSender() { return (VoxelEditPacketSender*)getPacketSender(); } virtual NodeType_t getServerNodeType() const { return NodeType::VoxelServer; } virtual OctreeEditPacketSender* createPacketSender() { return new VoxelEditPacketSender(); } void setVoxelTree(VoxelTree* tree) { _tree = tree; } + void setUndoStack(QUndoStack* undoStack) { _undoStack = undoStack; } public slots: @@ -79,6 +80,7 @@ public slots: private: void queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails); VoxelTree* _tree; + QUndoStack* _undoStack; }; #endif /* defined(__hifi__VoxelsScriptingInterface__) */ From 46f0e78039529fa6670a9d00fb0cbf7df1f4dfdf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 17:28:03 -0700 Subject: [PATCH 25/37] Erased deprecated code --- libraries/voxels/src/VoxelTree.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 3d1b699a45..2079ab91b2 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -1,4 +1,4 @@ - // +// // VoxelTree.h // hifi // @@ -14,7 +14,6 @@ #include "VoxelTreeElement.h" #include "VoxelEditPacketSender.h" -class QUndoStack; class ReadCodeColorBufferToTreeArgs; class VoxelTree : public Octree { @@ -45,8 +44,6 @@ public: virtual bool handlesEditPacketType(PacketType packetType) const; virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength, const unsigned char* editData, int maxLength, const SharedNodePointer& node); - - void setUndoStack(QUndoStack* undoStack) { _undoStack = undoStack; } private: // helper functions for nudgeSubTree @@ -55,8 +52,6 @@ private: void nudgeLeaf(VoxelTreeElement* element, void* extraData); void chunkifyLeaf(VoxelTreeElement* element); void readCodeColorBufferToTreeRecursion(VoxelTreeElement* node, ReadCodeColorBufferToTreeArgs& args); - - QUndoStack* _undoStack; }; #endif /* defined(__hifi__VoxelTree__) */ From 5a610090998ced77554c7fbdd506a147f655889f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Apr 2014 10:19:39 -0700 Subject: [PATCH 26/37] Add metavoxel bandwidth to details. --- interface/src/MetavoxelSystem.cpp | 2 ++ interface/src/ui/BandwidthMeter.cpp | 3 ++- interface/src/ui/BandwidthMeter.h | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 7eb046756b..6b4d817f7f 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -295,11 +295,13 @@ void MetavoxelClient::simulate(float deltaTime) { int MetavoxelClient::parseData(const QByteArray& packet) { // process through sequencer QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet)); + Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::METAVOXELS).updateValue(packet.size()); return packet.size(); } void MetavoxelClient::sendData(const QByteArray& data) { NodeList::getInstance()->writeDatagram(data, _node); + Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size()); } void MetavoxelClient::readPacket(Bitstream& in) { diff --git a/interface/src/ui/BandwidthMeter.cpp b/interface/src/ui/BandwidthMeter.cpp index 64ff74b846..962e8a857b 100644 --- a/interface/src/ui/BandwidthMeter.cpp +++ b/interface/src/ui/BandwidthMeter.cpp @@ -42,7 +42,8 @@ namespace { // .cpp-local BandwidthMeter::ChannelInfo BandwidthMeter::_CHANNELS[] = { { "Audio" , "Kbps", 8000.0 / 1024.0, 0x33cc99ff }, { "Avatars" , "Kbps", 8000.0 / 1024.0, 0xffef40c0 }, - { "Voxels" , "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0 } + { "Voxels" , "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0 }, + { "Metavoxels", "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0 } }; BandwidthMeter::BandwidthMeter() : diff --git a/interface/src/ui/BandwidthMeter.h b/interface/src/ui/BandwidthMeter.h index 5879b1546d..c1577da8e4 100644 --- a/interface/src/ui/BandwidthMeter.h +++ b/interface/src/ui/BandwidthMeter.h @@ -30,11 +30,11 @@ public: bool isWithinArea(int x, int y, int screenWidth, int screenHeight); // Number of channels / streams. - static size_t const N_CHANNELS = 3; + static size_t const N_CHANNELS = 4; static size_t const N_STREAMS = N_CHANNELS * 2; // Channel usage. - enum ChannelIndex { AUDIO, AVATARS, VOXELS }; + enum ChannelIndex { AUDIO, AVATARS, VOXELS, METAVOXELS }; // Meta information held for a communication channel (bidirectional). struct ChannelInfo { From ee5ebae89e037f27dcf8cda4d212769d9c3020cc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Apr 2014 10:22:50 -0700 Subject: [PATCH 27/37] Code review --- libraries/voxels/src/VoxelTreeCommands.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/voxels/src/VoxelTreeCommands.cpp b/libraries/voxels/src/VoxelTreeCommands.cpp index a557137367..d919f0e150 100644 --- a/libraries/voxels/src/VoxelTreeCommands.cpp +++ b/libraries/voxels/src/VoxelTreeCommands.cpp @@ -12,10 +12,10 @@ #include "VoxelTreeCommands.h" AddVoxelCommand::AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) : -QUndoCommand("Add Voxel", parent), -_tree(tree), -_packetSender(packetSender), -_voxel(voxel) + QUndoCommand("Add Voxel", parent), + _tree(tree), + _packetSender(packetSender), + _voxel(voxel) { } @@ -38,10 +38,10 @@ void AddVoxelCommand::undo() { } DeleteVoxelCommand::DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) : -QUndoCommand("Delete Voxel", parent), -_tree(tree), -_packetSender(packetSender), -_voxel(voxel) + QUndoCommand("Delete Voxel", parent), + _tree(tree), + _packetSender(packetSender), + _voxel(voxel) { } From e1a1ff39887152e21aea3f394eb64cc51f3d56c0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Apr 2014 10:32:49 -0700 Subject: [PATCH 28/37] Code review --- libraries/shared/src/AccountManager.cpp | 15 ++++++++++++--- libraries/shared/src/AccountManager.h | 5 +---- libraries/shared/src/ModelUploader.cpp | 7 ++++++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index fe361ba751..d284640924 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -34,6 +34,16 @@ Q_DECLARE_METATYPE(JSONCallbackParameters) const QString ACCOUNTS_GROUP = "accounts"; +JSONCallbackParameters::JSONCallbackParameters() : + jsonCallbackReceiver(NULL), + jsonCallbackMethod(), + errorCallbackReceiver(NULL), + errorCallbackMethod(), + updateReciever(NULL), + updateSlot() +{ +} + AccountManager::AccountManager() : _authURL(), _networkAccessManager(NULL), @@ -178,8 +188,7 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: } // if we ended up firing of a request, hook up to it now - connect(networkReply, SIGNAL(finished()), - SLOT(processReply())); + connect(networkReply, SIGNAL(finished()), SLOT(processReply())); } } } @@ -208,7 +217,7 @@ void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) { // remove the related reply-callback group from the map _pendingCallbackMap.remove(requestReply); - } else { + } else { if (VERBOSE_HTTP_REQUEST_DEBUGGING) { qDebug() << "Received JSON response from data-server that has no matching callback."; qDebug() << jsonResponse; diff --git a/libraries/shared/src/AccountManager.h b/libraries/shared/src/AccountManager.h index 55a40438e0..05a2e6a08a 100644 --- a/libraries/shared/src/AccountManager.h +++ b/libraries/shared/src/AccountManager.h @@ -19,10 +19,7 @@ class JSONCallbackParameters { public: - JSONCallbackParameters() : - jsonCallbackReceiver(NULL), jsonCallbackMethod(), - errorCallbackReceiver(NULL), errorCallbackMethod(), - updateReciever(NULL), updateSlot() {}; + JSONCallbackParameters(); bool isEmpty() const { return !jsonCallbackReceiver && !errorCallbackReceiver; } diff --git a/libraries/shared/src/ModelUploader.cpp b/libraries/shared/src/ModelUploader.cpp index cda57aeab9..4386704559 100644 --- a/libraries/shared/src/ModelUploader.cpp +++ b/libraries/shared/src/ModelUploader.cpp @@ -34,6 +34,8 @@ static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB static const int TIMEOUT = 1000; static const int MAX_CHECK = 30; +static const int QCOMPRESS_HEADER_POSITION = 0; +static const int QCOMPRESS_HEADER_SIZE = 4; ModelUploader::ModelUploader(bool isHead) : _lodCount(-1), @@ -290,7 +292,10 @@ bool ModelUploader::addPart(const QString &path, const QString& name) { return false; } QByteArray buffer = qCompress(file.readAll()); - buffer.remove(0, 4); + + // Qt's qCompress() default compression level (-1) is the standard zLib compression. + // Here remove Qt's custom header that prevent the data server from uncompressing the files with zLib. + buffer.remove(QCOMPRESS_HEADER_POSITION, QCOMPRESS_HEADER_SIZE); QHttpPart part; part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data;" From ccd7106527de27fc2597f321793ea00048f7ad58 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Apr 2014 10:54:41 -0700 Subject: [PATCH 29/37] Include "InterfaceConfig" before QOpenGLFramebufferObject to fix Windows build. --- interface/src/ui/MetavoxelEditor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 71539d3a27..ee1b4b0460 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -5,6 +5,9 @@ // Created by Andrzej Kapolka on 1/21/14. // Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + #include #include #include From 22cab29d251842c4e063739a788f9e0fb1a56acc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 8 Apr 2014 11:06:48 -0700 Subject: [PATCH 30/37] Code review --- libraries/voxels/src/VoxelsScriptingInterface.cpp | 6 +++++- libraries/voxels/src/VoxelsScriptingInterface.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index 59e4662bed..61ee4b317d 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -51,6 +51,8 @@ void VoxelsScriptingInterface::setVoxelNonDestructive(float x, float y, float z, AddVoxelCommand* command = new AddVoxelCommand(_tree, addVoxelDetail, getVoxelPacketSender()); + + // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. _undoStack->push(command); } else { // queue the add packet @@ -89,11 +91,12 @@ void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, deleteVoxelDetail, getVoxelPacketSender()); _undoStack->beginMacro(addCommand->text()); - qDebug() << "Macro"; + // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. _undoStack->push(delCommand); _undoStack->push(addCommand); _undoStack->endMacro(); } else { + // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. _undoStack->push(addCommand); } } else { @@ -123,6 +126,7 @@ void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale DeleteVoxelCommand* command = new DeleteVoxelCommand(_tree, deleteVoxelDetail, getVoxelPacketSender()); + // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. _undoStack->push(command); } else { getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail); diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h index 339e527ebc..da51259eeb 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ b/libraries/voxels/src/VoxelsScriptingInterface.h @@ -18,6 +18,8 @@ #include "VoxelEditPacketSender.h" #include "VoxelTree.h" +class QUndoStack; + /// handles scripting of voxel commands from JS passed to assigned clients class VoxelsScriptingInterface : public OctreeScriptingInterface { Q_OBJECT From 6754a6ca69f022ba8558aa5c3d85552abfe02429 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 8 Apr 2014 23:45:27 +0200 Subject: [PATCH 31/37] Fixed some style --- interface/src/Audio.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 7e7dfd9df1..597373ffe8 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -161,7 +161,8 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); - if (osvi.dwMajorVersion < 6) {// lower then vista + const DWORD VISTA_MAJOR_VERSION = 6; + if (osvi.dwMajorVersion < VISTA_MAJOR_VERSION) {// lower then vista if (mode == QAudio::AudioInput) { WAVEINCAPS wic; // first use WAVE_MAPPER to get the default devices manufacturer ID @@ -182,11 +183,11 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { } else { HRESULT hr = S_OK; CoInitialize(NULL); - IMMDeviceEnumerator *pMMDeviceEnumerator = NULL; + IMMDeviceEnumerator* pMMDeviceEnumerator = NULL; CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator); - IMMDevice *pEndpoint; + IMMDevice* pEndpoint; pMMDeviceEnumerator->GetDefaultAudioEndpoint(mode == QAudio::AudioOutput ? eRender : eCapture, eMultimedia, &pEndpoint); - IPropertyStore *pPropertyStore; + IPropertyStore* pPropertyStore; pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore); pEndpoint->Release(); pEndpoint = NULL; @@ -196,7 +197,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. - deviceName = QString::fromWCharArray((wchar_t *)pv.pwszVal).left(31); + 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); pMMDeviceEnumerator->Release(); From 5776514e6a0943c9151d2676fa9e29ac1fa7486f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Apr 2014 14:48:01 -0700 Subject: [PATCH 32/37] Working on pushing the mirror camera back to prevent intersecting the near clip plane. Closes #2617. --- interface/src/Application.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6bc8bb62df..db75034e7f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -528,6 +528,16 @@ void Application::paintGL() { _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale()); _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0)); _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); + + // if the head would intersect the near clip plane, we must push the camera out + glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * + (_myAvatar->getHead()->getPosition() - _myCamera.getTargetPosition()); + const float HEAD_RADIUS = 0.1f; + float pushback = relativePosition.z + _myCamera.getNearClip() + HEAD_RADIUS; + if (pushback > 0.0f) { + _myCamera.setTargetPosition(_myCamera.getTargetPosition() + + _myCamera.getTargetRotation() * glm::vec3(0.0f, 0.0f, pushback)); + } } // Update camera position From add7bb26ed4d731d8167b3c6eed21a358c4c8166 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Apr 2014 14:55:46 -0700 Subject: [PATCH 33/37] Use the head height to determine the pushback amount. --- interface/src/Application.cpp | 4 ++-- interface/src/avatar/Avatar.cpp | 10 +++++----- interface/src/avatar/Avatar.h | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index db75034e7f..0b702c98a0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -532,8 +532,8 @@ void Application::paintGL() { // if the head would intersect the near clip plane, we must push the camera out glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * (_myAvatar->getHead()->getPosition() - _myCamera.getTargetPosition()); - const float HEAD_RADIUS = 0.1f; - float pushback = relativePosition.z + _myCamera.getNearClip() + HEAD_RADIUS; + const float HEAD_EXPANSION = 1.1f; + float pushback = relativePosition.z + _myCamera.getNearClip() + _myAvatar->getHeadHeight() * HEAD_EXPANSION; if (pushback > 0.0f) { _myCamera.setTargetPosition(_myCamera.getTargetPosition() + _myCamera.getTargetRotation() * glm::vec3(0.0f, 0.0f, pushback)); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 05f74755df..86378c6cdf 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -524,6 +524,11 @@ void Avatar::updateShapePositions() { headModel.updateShapePositions(); } +float Avatar::getHeadHeight() const { + Extents extents = getHead()->getFaceModel().getBindExtents(); + return extents.maximum.y - extents.minimum.y; +} + bool Avatar::findCollisions(const QVector& shapes, CollisionList& collisions) { // TODO: Andrew to fix: also collide against _skeleton //bool collided = _skeletonModel.findCollisions(shapes, collisions); @@ -750,11 +755,6 @@ float Avatar::getSkeletonHeight() const { return extents.maximum.y - extents.minimum.y; } -float Avatar::getHeadHeight() const { - Extents extents = getHead()->getFaceModel().getBindExtents(); - return extents.maximum.y - extents.minimum.y; -} - bool Avatar::collisionWouldMoveAvatar(CollisionInfo& collision) const { if (!collision._data || collision._type != MODEL_COLLISION) { return false; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index f57982b514..fca7173add 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -151,6 +151,8 @@ public: virtual float getBoundingRadius() const; void updateShapePositions(); + float getHeadHeight() const; + public slots: void updateCollisionFlags(); @@ -179,7 +181,6 @@ protected: void setScale(float scale); float getSkeletonHeight() const; - float getHeadHeight() const; float getPelvisFloatingHeight() const; float getPelvisToHeadLength() const; From faf8c353588b0e6fe238f34c8633fcf762414a35 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Apr 2014 15:01:56 -0700 Subject: [PATCH 34/37] Head height's kind of screwy; let's use the eye position. --- interface/src/Application.cpp | 9 +++++---- interface/src/avatar/Avatar.cpp | 10 +++++----- interface/src/avatar/Avatar.h | 3 +-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0b702c98a0..87cdaf8038 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -524,16 +524,17 @@ void Application::paintGL() { } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness(0.0f); - float headHeight = _myAvatar->getHead()->calculateAverageEyePosition().y - _myAvatar->getPosition().y; + glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition(); + float headHeight = eyePosition.y - _myAvatar->getPosition().y; _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale()); _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0)); _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); // if the head would intersect the near clip plane, we must push the camera out glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * - (_myAvatar->getHead()->getPosition() - _myCamera.getTargetPosition()); - const float HEAD_EXPANSION = 1.1f; - float pushback = relativePosition.z + _myCamera.getNearClip() + _myAvatar->getHeadHeight() * HEAD_EXPANSION; + (eyePosition - _myCamera.getTargetPosition()); + const float PUSHBACK_RADIUS = 0.01f; + float pushback = relativePosition.z + _myCamera.getNearClip() + _myAvatar->getScale() * PUSHBACK_RADIUS; if (pushback > 0.0f) { _myCamera.setTargetPosition(_myCamera.getTargetPosition() + _myCamera.getTargetRotation() * glm::vec3(0.0f, 0.0f, pushback)); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 86378c6cdf..05f74755df 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -524,11 +524,6 @@ void Avatar::updateShapePositions() { headModel.updateShapePositions(); } -float Avatar::getHeadHeight() const { - Extents extents = getHead()->getFaceModel().getBindExtents(); - return extents.maximum.y - extents.minimum.y; -} - bool Avatar::findCollisions(const QVector& shapes, CollisionList& collisions) { // TODO: Andrew to fix: also collide against _skeleton //bool collided = _skeletonModel.findCollisions(shapes, collisions); @@ -755,6 +750,11 @@ float Avatar::getSkeletonHeight() const { return extents.maximum.y - extents.minimum.y; } +float Avatar::getHeadHeight() const { + Extents extents = getHead()->getFaceModel().getBindExtents(); + return extents.maximum.y - extents.minimum.y; +} + bool Avatar::collisionWouldMoveAvatar(CollisionInfo& collision) const { if (!collision._data || collision._type != MODEL_COLLISION) { return false; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index fca7173add..f57982b514 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -151,8 +151,6 @@ public: virtual float getBoundingRadius() const; void updateShapePositions(); - float getHeadHeight() const; - public slots: void updateCollisionFlags(); @@ -181,6 +179,7 @@ protected: void setScale(float scale); float getSkeletonHeight() const; + float getHeadHeight() const; float getPelvisFloatingHeight() const; float getPelvisToHeadLength() const; From 083e9076a96ff7e3f8276a24144ddf6a3b2803b3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Apr 2014 15:17:05 -0700 Subject: [PATCH 35/37] Missed a spot. --- interface/src/Application.cpp | 3 ++- interface/src/Camera.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 87cdaf8038..a30ed648d8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -534,7 +534,8 @@ void Application::paintGL() { glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * (eyePosition - _myCamera.getTargetPosition()); const float PUSHBACK_RADIUS = 0.01f; - float pushback = relativePosition.z + _myCamera.getNearClip() + _myAvatar->getScale() * PUSHBACK_RADIUS; + float pushback = relativePosition.z + _myCamera.getNearClip() + + _myAvatar->getScale() * PUSHBACK_RADIUS - _myCamera.getDistance(); if (pushback > 0.0f) { _myCamera.setTargetPosition(_myCamera.getTargetPosition() + _myCamera.getTargetRotation() * glm::vec3(0.0f, 0.0f, pushback)); diff --git a/interface/src/Camera.h b/interface/src/Camera.h index 9973fd246e..3fd0efd50a 100644 --- a/interface/src/Camera.h +++ b/interface/src/Camera.h @@ -54,6 +54,7 @@ public: const glm::quat& getRotation() const { return _rotation; } CameraMode getMode() const { return _mode; } float getModeShiftPeriod() const { return _modeShiftPeriod; } + float getDistance() const { return _distance; } const glm::vec3& getTargetPosition() const { return _targetPosition; } const glm::quat& getTargetRotation() const { return _targetRotation; } float getFieldOfView() const { return _fieldOfView; } From 597d750af906117ca2cb71a1b8fb4675a5cad3d4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Apr 2014 15:25:10 -0700 Subject: [PATCH 36/37] Better radius. --- 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 a30ed648d8..45ae36a23b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -533,7 +533,7 @@ void Application::paintGL() { // if the head would intersect the near clip plane, we must push the camera out glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * (eyePosition - _myCamera.getTargetPosition()); - const float PUSHBACK_RADIUS = 0.01f; + const float PUSHBACK_RADIUS = 0.2f; float pushback = relativePosition.z + _myCamera.getNearClip() + _myAvatar->getScale() * PUSHBACK_RADIUS - _myCamera.getDistance(); if (pushback > 0.0f) { From 94a7ded212fd1b3cf857ab9bc3cac56afae6ef33 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Apr 2014 15:36:21 -0700 Subject: [PATCH 37/37] Slip in a fix for Windows build warnings on mtc-generated code. --- tools/mtc/src/main.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tools/mtc/src/main.cpp b/tools/mtc/src/main.cpp index 9c77851961..b7e2929d49 100644 --- a/tools/mtc/src/main.cpp +++ b/tools/mtc/src/main.cpp @@ -143,13 +143,15 @@ void generateOutput (QTextStream& out, const QList& streamables) { out << " }\n"; out << " index = nextIndex;\n"; } - out << " switch (index) {\n"; - for (int i = 0; i < str.fields.size(); i++) { - out << " case " << i << ":\n"; - out << " this->" << str.fields.at(i).name << " = value.value<" << str.fields.at(i).type << ">();\n"; - out << " break;\n"; + if (!str.fields.isEmpty()) { + out << " switch (index) {\n"; + for (int i = 0; i < str.fields.size(); i++) { + out << " case " << i << ":\n"; + out << " this->" << str.fields.at(i).name << " = value.value<" << str.fields.at(i).type << ">();\n"; + out << " break;\n"; + } + out << " }\n"; } - out << " }\n"; out << "}\n"; out << "QVariant " << name << "::getField(int index) const {\n"; @@ -162,12 +164,14 @@ void generateOutput (QTextStream& out, const QList& streamables) { out << " }\n"; out << " index = nextIndex;\n"; } - out << " switch (index) {\n"; - for (int i = 0; i < str.fields.size(); i++) { - out << " case " << i << ":\n"; - out << " return QVariant::fromValue(this->" << str.fields.at(i).name << ");\n"; + if (!str.fields.isEmpty()) { + out << " switch (index) {\n"; + for (int i = 0; i < str.fields.size(); i++) { + out << " case " << i << ":\n"; + out << " return QVariant::fromValue(this->" << str.fields.at(i).name << ");\n"; + } + out << " }\n"; } - out << " }\n"; out << " return QVariant();\n"; out << "}\n";