From 44860a5f5a5acb1951c3ced95224dbf36a053981 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Mar 2014 12:01:37 -0700 Subject: [PATCH 01/46] put servers alphabetically first in node list --- domain-server/resources/web/js/tables.js | 25 +++++++++++++++++++++--- domain-server/src/DomainServer.cpp | 11 +++++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/domain-server/resources/web/js/tables.js b/domain-server/resources/web/js/tables.js index 18e67ac6e7..3f7b2b7b28 100644 --- a/domain-server/resources/web/js/tables.js +++ b/domain-server/resources/web/js/tables.js @@ -2,16 +2,35 @@ $(document).ready(function(){ // setup a function to grab the assignments function getNodesAndAssignments() { $.getJSON("nodes.json", function(json){ + + json.nodes.sort(function(a, b){ + if (a.type === b.type) { + return 0; + } + + if (a.type === "agent" && b.type !== "agent") { + return 1; + } + + if (a.type > b.type) { + return 1; + } + + if (a.type < b.type) { + return -1; + } + }); + nodesTableBody = ""; - $.each(json.nodes, function (uuid, data) { + $.each(json.nodes, function(index, data) { nodesTableBody += ""; nodesTableBody += "" + data.type + ""; - nodesTableBody += "" + uuid + ""; + nodesTableBody += "" + data.uuid + ""; nodesTableBody += "" + (data.pool ? data.pool : "") + ""; nodesTableBody += "" + data.public.ip + ":" + data.public.port + ""; nodesTableBody += "" + data.local.ip + ":" + data.local.port + ""; - nodesTableBody += ""; + nodesTableBody += ""; nodesTableBody += ""; }); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 035e6c9a20..d18f12ec7f 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -622,6 +622,7 @@ QJsonObject DomainServer::jsonForSocket(const HifiSockAddr& socket) { return socketJSON; } +const char JSON_KEY_UUID[] = "uuid"; const char JSON_KEY_TYPE[] = "type"; const char JSON_KEY_PUBLIC_SOCKET[] = "public"; const char JSON_KEY_LOCAL_SOCKET[] = "local"; @@ -635,6 +636,9 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { nodeTypeName = nodeTypeName.toLower(); nodeTypeName.replace(' ', '-'); + // add the node UUID + nodeJson[JSON_KEY_UUID] = uuidStringWithoutCurlyBraces(node->getUUID()); + // add the node type nodeJson[JSON_KEY_TYPE] = nodeTypeName; @@ -707,18 +711,17 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } else if (url.path() == QString("%1.json").arg(URI_NODES)) { // setup the JSON QJsonObject rootJSON; - QJsonObject nodesJSON; + QJsonArray nodesJSONArray; // enumerate the NodeList to find the assigned nodes NodeList* nodeList = NodeList::getInstance(); foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { // add the node using the UUID as the key - QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID()); - nodesJSON[uuidString] = jsonObjectForNode(node); + nodesJSONArray.append(jsonObjectForNode(node)); } - rootJSON["nodes"] = nodesJSON; + rootJSON["nodes"] = nodesJSONArray; // print out the created JSON QJsonDocument nodesDocument(rootJSON); From 7f6dc7ac2fbc98562ae3f301deed701db5d4742a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 2 Apr 2014 09:56:30 -0700 Subject: [PATCH 02/46] 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 03/46] 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 04/46] 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 05/46] 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 06/46] 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 07/46] 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 08/46] 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 09/46] 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 10/46] 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 11/46] 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 f6c98a1cc23107f2fa0c416510c1b0afde4d6e78 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 4 Apr 2014 10:40:55 -0700 Subject: [PATCH 12/46] fix bug in gun.js: unplayed target delete sound --- examples/gun.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/gun.js b/examples/gun.js index e358e6b391..3edb823bd1 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -176,7 +176,6 @@ function particleCollisionWithParticle(particle1, particle2) { print("hit, msecs = " + msecs); Particles.deleteParticle(particle1); Particles.deleteParticle(particle2); - audioOptions.position = newPosition; audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); Audio.playSound(targetHitSound, audioOptions); } From 5e2b8bb2c3296095278bd59c74443368ff350ae6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 4 Apr 2014 10:43:06 -0700 Subject: [PATCH 13/46] connect SIGNAL to SIGNAL to avoid forwarding slot --- interface/src/Application.cpp | 4 ++-- libraries/particles/src/ParticlesScriptingInterface.h | 11 ----------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21fefac6f1..7ba3e5c631 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1567,12 +1567,12 @@ void Application::init() { connect(&_particleCollisionSystem, SIGNAL(particleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)), ScriptEngine::getParticlesScriptingInterface(), - SLOT(forwardParticleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&))); + SIGNAL(particleCollisionWithVoxels(const ParticleID&, const VoxelDetail&, const glm::vec3&))); connect(&_particleCollisionSystem, SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)), ScriptEngine::getParticlesScriptingInterface(), - SLOT(forwardParticleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&))); + SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&))); _audio.init(_glWidget); diff --git a/libraries/particles/src/ParticlesScriptingInterface.h b/libraries/particles/src/ParticlesScriptingInterface.h index af5f76a6af..24bbad9e3e 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.h +++ b/libraries/particles/src/ParticlesScriptingInterface.h @@ -27,17 +27,6 @@ public: void setParticleTree(ParticleTree* particleTree) { _particleTree = particleTree; } ParticleTree* getParticleTree(ParticleTree*) { return _particleTree; } -private slots: - /// inbound slots for external collision systems - void forwardParticleCollisionWithVoxel(const ParticleID& particleID, - const VoxelDetail& voxel, const glm::vec3& penetration) { - emit particleCollisionWithVoxel(particleID, voxel, penetration); - } - - void forwardParticleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB, const glm::vec3& penetration) { - emit particleCollisionWithParticle(idA, idB, penetration); - } - public slots: /// adds a particle with the specific properties ParticleID addParticle(const ParticleProperties& properties); From a0c7e4d3cc84c5eefadd15b9192a1149c29a2aeb Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Apr 2014 11:45:03 -0700 Subject: [PATCH 14/46] 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 15/46] 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 16/46] 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 17/46] 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 18/46] 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 5adcf6875241fd7c58ec309f026e8b866fd87a8a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Apr 2014 09:08:51 -0700 Subject: [PATCH 19/46] sort nodes on DS page by their uptime --- domain-server/resources/web/index.shtml | 1 + domain-server/resources/web/js/tables.js | 16 ++++++++++++++-- domain-server/src/DomainServer.cpp | 4 ++++ libraries/shared/src/Node.cpp | 3 ++- libraries/shared/src/Node.h | 6 +++--- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/domain-server/resources/web/index.shtml b/domain-server/resources/web/index.shtml index bba4dc4d22..afd0af1679 100644 --- a/domain-server/resources/web/index.shtml +++ b/domain-server/resources/web/index.shtml @@ -12,6 +12,7 @@ Pool Public Local + Uptime (s) Kill? diff --git a/domain-server/resources/web/js/tables.js b/domain-server/resources/web/js/tables.js index 3f7b2b7b28..a4884486c3 100644 --- a/domain-server/resources/web/js/tables.js +++ b/domain-server/resources/web/js/tables.js @@ -5,13 +5,21 @@ $(document).ready(function(){ json.nodes.sort(function(a, b){ if (a.type === b.type) { - return 0; + if (a.wake_timestamp < b.wake_timestamp) { + return 1; + } else if (a.wake_timestamp > b.wake_timestamp) { + return -1; + } else { + return 0; + } } if (a.type === "agent" && b.type !== "agent") { return 1; + } else if (b.type === "agent" && a.type !== "agent") { + return -1; } - + if (a.type > b.type) { return 1; } @@ -30,6 +38,10 @@ $(document).ready(function(){ nodesTableBody += "" + (data.pool ? data.pool : "") + ""; nodesTableBody += "" + data.public.ip + ":" + data.public.port + ""; nodesTableBody += "" + data.local.ip + ":" + data.local.port + ""; + + var uptimeSeconds = (Date.now() - data.wake_timestamp) / 1000; + nodesTableBody += "" + uptimeSeconds.toLocaleString() + ""; + nodesTableBody += ""; nodesTableBody += ""; }); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d18f12ec7f..8d1ee9d3dd 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -627,6 +627,7 @@ const char JSON_KEY_TYPE[] = "type"; const char JSON_KEY_PUBLIC_SOCKET[] = "public"; const char JSON_KEY_LOCAL_SOCKET[] = "local"; const char JSON_KEY_POOL[] = "pool"; +const char JSON_KEY_WAKE_TIMESTAMP[] = "wake_timestamp"; QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { QJsonObject nodeJson; @@ -646,6 +647,9 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { nodeJson[JSON_KEY_PUBLIC_SOCKET] = jsonForSocket(node->getPublicSocket()); nodeJson[JSON_KEY_LOCAL_SOCKET] = jsonForSocket(node->getLocalSocket()); + // add the node uptime in our list + nodeJson[JSON_KEY_WAKE_TIMESTAMP] = QString::number(node->getWakeTimestamp()); + // if the node has pool information, add it SharedAssignmentPointer matchingAssignment = _staticAssignmentHash.value(node->getUUID()); if (matchingAssignment) { diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index a4491fb707..1e78bc3feb 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -19,6 +19,7 @@ #include "SharedUtil.h" #include +#include #include const QString UNKNOWN_NodeType_t_NAME = "Unknown"; @@ -47,7 +48,7 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { Node::Node(const QUuid& uuid, char type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) : _type(type), _uuid(uuid), - _wakeMicrostamp(usecTimestampNow()), + _wakeTimestamp(QDateTime::currentMSecsSinceEpoch()), _lastHeardMicrostamp(usecTimestampNow()), _publicSocket(publicSocket), _localSocket(localSocket), diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index 79d75629a6..5d30d6f7b0 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -60,8 +60,8 @@ public: const QUuid& getUUID() const { return _uuid; } void setUUID(const QUuid& uuid) { _uuid = uuid; } - quint64 getWakeMicrostamp() const { return _wakeMicrostamp; } - void setWakeMicrostamp(quint64 wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; } + quint64 getWakeTimestamp() const { return _wakeTimestamp; } + void setWakeTimestamp(quint64 wakeTimestamp) { _wakeTimestamp = wakeTimestamp; } quint64 getLastHeardMicrostamp() const { return _lastHeardMicrostamp; } void setLastHeardMicrostamp(quint64 lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; } @@ -109,7 +109,7 @@ private: NodeType_t _type; QUuid _uuid; - quint64 _wakeMicrostamp; + quint64 _wakeTimestamp; quint64 _lastHeardMicrostamp; HifiSockAddr _publicSocket; HifiSockAddr _localSocket; From e9922b6db92337da655290ae9d9f0d98069fa7d7 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 7 Apr 2014 18:50:13 +0200 Subject: [PATCH 20/46] 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 d902580d6faff2d6ca460a93ff850df4e4f2e5d5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 7 Apr 2014 10:03:10 -0700 Subject: [PATCH 21/46] Add Collision metatype to JS script system --- examples/collidingParticles.js | 10 +++-- examples/globalCollisionsExample.js | 10 +++-- examples/gun.js | 16 +++---- examples/paintGun.js | 5 ++- examples/spaceInvadersExample.js | 5 ++- interface/src/Application.cpp | 8 ++-- .../particles/src/ParticleCollisionSystem.cpp | 42 ++++++++++++------- .../particles/src/ParticleCollisionSystem.h | 8 ++-- .../src/ParticlesScriptingInterface.h | 6 ++- libraries/shared/src/RegisteredMetaTypes.cpp | 13 ++++++ libraries/shared/src/RegisteredMetaTypes.h | 5 +++ 11 files changed, 82 insertions(+), 46 deletions(-) diff --git a/examples/collidingParticles.js b/examples/collidingParticles.js index 2d2cf4fecc..95520df757 100644 --- a/examples/collidingParticles.js +++ b/examples/collidingParticles.js @@ -30,9 +30,10 @@ var gravity = { var damping = 0.1; var scriptA = " " + - " function collisionWithParticle(other, penetration) { " + + " function collisionWithParticle(other, collision) { " + " print('collisionWithParticle(other.getID()=' + other.getID() + ')...'); " + - " Vec3.print('penetration=', penetration); " + + " Vec3.print('penetration=', collision.penetration); " + + " Vec3.print('contactPoint=', collision.contactPoint); " + " print('myID=' + Particle.getID() + '\\n'); " + " var colorBlack = { red: 0, green: 0, blue: 0 };" + " var otherColor = other.getColor();" + @@ -46,9 +47,10 @@ var scriptA = " " + " "; var scriptB = " " + - " function collisionWithParticle(other, penetration) { " + + " function collisionWithParticle(other, collision) { " + " print('collisionWithParticle(other.getID()=' + other.getID() + ')...'); " + - " Vec3.print('penetration=', penetration); " + + " Vec3.print('penetration=', collision.penetration); " + + " Vec3.print('contactPoint=', collision.contactPoint); " + " print('myID=' + Particle.getID() + '\\n'); " + " Particle.setScript('Particle.setShouldDie(true);'); " + " } " + diff --git a/examples/globalCollisionsExample.js b/examples/globalCollisionsExample.js index 266823f564..7abf707cbf 100644 --- a/examples/globalCollisionsExample.js +++ b/examples/globalCollisionsExample.js @@ -12,18 +12,20 @@ print("hello..."); -function particleCollisionWithVoxel(particle, voxel, penetration) { +function particleCollisionWithVoxel(particle, voxel, collision) { print("particleCollisionWithVoxel().."); print(" particle.getID()=" + particle.id); print(" voxel color...=" + voxel.red + ", " + voxel.green + ", " + voxel.blue); - Vec3.print('penetration=', penetration); + Vec3.print('penetration=', collision.penetration); + Vec3.print('contactPoint=', collision.contactPoint); } -function particleCollisionWithParticle(particleA, particleB, penetration) { +function particleCollisionWithParticle(particleA, particleB, collision) { print("particleCollisionWithParticle().."); print(" particleA.getID()=" + particleA.id); print(" particleB.getID()=" + particleB.id); - Vec3.print('penetration=', penetration); + Vec3.print('penetration=', collision.penetration); + Vec3.print('contactPoint=', collision.contactPoint); } Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel); diff --git a/examples/gun.js b/examples/gun.js index 3edb823bd1..7bdde19d94 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -145,24 +145,21 @@ function shootTarget() { -function particleCollisionWithVoxel(particle, voxel, penetration) { +function particleCollisionWithVoxel(particle, voxel, collision) { var HOLE_SIZE = 0.125; var particleProperties = Particles.getParticleProperties(particle); var position = particleProperties.position; Particles.deleteParticle(particle); // Make a hole in this voxel - Vec3.print("penetration", penetration); - Vec3.print("position", position); - var pointOfEntry = Vec3.subtract(position, penetration); - Vec3.print("pointOfEntry", pointOfEntry); - Voxels.eraseVoxel(pointOfEntry.x, pointOfEntry.y, pointOfEntry.z, HOLE_SIZE); + Vec3.print("penetration", collision.penetration); + Vec3.print("contactPoint", collision.contactPoint); + Voxels.eraseVoxel(contactPoint.x, contactPoint.y, contactPoint.z, HOLE_SIZE); Voxels.eraseVoxel(position.x, position.y, position.z, HOLE_SIZE); - //audioOptions.position = position; audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); Audio.playSound(impactSound, audioOptions); } -function particleCollisionWithParticle(particle1, particle2) { +function particleCollisionWithParticle(particle1, particle2, collision) { score++; if (showScore) { Overlays.editOverlay(text, { text: "Score: " + score } ); @@ -174,8 +171,11 @@ function particleCollisionWithParticle(particle1, particle2) { var endTime = new Date(); var msecs = endTime.valueOf() - shotTime.valueOf(); print("hit, msecs = " + msecs); + Vec3.print("penetration = ", collision.penetration); + Vec3.print("contactPoint = ", collision.contactPoint); Particles.deleteParticle(particle1); Particles.deleteParticle(particle2); + // play the sound near the camera so the shooter can hear it audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); Audio.playSound(targetHitSound, audioOptions); } diff --git a/examples/paintGun.js b/examples/paintGun.js index 6b6e78b43e..0b30d99fb5 100644 --- a/examples/paintGun.js +++ b/examples/paintGun.js @@ -62,9 +62,10 @@ function checkController(deltaTime) { // This is the script for the particles that this gun shoots. var script = - " function collisionWithVoxel(voxel, penetration) { " + + " function collisionWithVoxel(voxel, collision) { " + " print('collisionWithVoxel(voxel)... '); " + - " Vec3.print('penetration=', penetration); " + + " Vec3.print('penetration=', collision.penetration); " + + " Vec3.print('contactPoint=', collision.contactPoint); " + " print('myID=' + Particle.getID() + '\\n'); " + " var voxelColor = { red: voxel.red, green: voxel.green, blue: voxel.blue };" + " var voxelAt = { x: voxel.x, y: voxel.y, z: voxel.z };" + diff --git a/examples/spaceInvadersExample.js b/examples/spaceInvadersExample.js index 61ff93fc8f..df985e2e18 100644 --- a/examples/spaceInvadersExample.js +++ b/examples/spaceInvadersExample.js @@ -392,9 +392,10 @@ function deleteIfInvader(possibleInvaderParticle) { } } -function particleCollisionWithParticle(particleA, particleB, penetration) { +function particleCollisionWithParticle(particleA, particleB, collision) { print("particleCollisionWithParticle() a.id="+particleA.id + " b.id=" + particleB.id); - Vec3.print('particleCollisionWithParticle() penetration=', penetration); + Vec3.print('particleCollisionWithParticle() penetration=', collision.penetration); + Vec3.print('particleCollisionWithParticle() contactPoint=', collision.contactPoint); if (missileFired) { myMissile = Particles.identifyParticle(myMissile); if (myMissile.id == particleA.id) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7ba3e5c631..48aab620a5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1565,14 +1565,14 @@ void Application::init() { // connect the _particleCollisionSystem to our script engine's ParticleScriptingInterface connect(&_particleCollisionSystem, - SIGNAL(particleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)), + SIGNAL(particleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const CollisionInfo&)), ScriptEngine::getParticlesScriptingInterface(), - SIGNAL(particleCollisionWithVoxels(const ParticleID&, const VoxelDetail&, const glm::vec3&))); + SIGNAL(particleCollisionWithVoxels(const ParticleID&, const VoxelDetail&, const CollisionInfo&))); connect(&_particleCollisionSystem, - SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)), + SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const CollisionInfo&)), ScriptEngine::getParticlesScriptingInterface(), - SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&))); + SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const CollisionInfo&))); _audio.init(_glWidget); diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index c827e28c78..028cf80df9 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -72,17 +72,17 @@ void ParticleCollisionSystem::checkParticle(Particle* particle) { } void ParticleCollisionSystem::emitGlobalParticleCollisionWithVoxel(Particle* particle, - VoxelDetail* voxelDetails, const glm::vec3& penetration) { + VoxelDetail* voxelDetails, const CollisionInfo& collision) { ParticleID particleID = particle->getParticleID(); - emit particleCollisionWithVoxel(particleID, *voxelDetails, penetration); + emit particleCollisionWithVoxel(particleID, *voxelDetails, collision); } void ParticleCollisionSystem::emitGlobalParticleCollisionWithParticle(Particle* particleA, - Particle* particleB, const glm::vec3& penetration) { + Particle* particleB, const CollisionInfo& collision) { ParticleID idA = particleA->getParticleID(); ParticleID idB = particleB->getParticleID(); - emit particleCollisionWithParticle(idA, idB, penetration); + emit particleCollisionWithParticle(idA, idB, collision); } void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) { @@ -100,11 +100,17 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) { // let the particles run their collision scripts if they have them particle->collisionWithVoxel(voxelDetails, collisionInfo._penetration); - // let the global script run their collision scripts for particles if they have them - emitGlobalParticleCollisionWithVoxel(particle, voxelDetails, collisionInfo._penetration); - + // findSpherePenetration() only computes the penetration but we also want some other collision info + // so we compute it ourselves here. Note that we must multiply scale by TREE_SCALE when feeding + // the results to systems outside of this octree reference frame. updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY); + collisionInfo._contactPoint = (float)TREE_SCALE * (particle->getPosition() + particle->getRadius() * glm::normalize(collisionInfo._penetration)); + // let the global script run their collision scripts for particles if they have them + emitGlobalParticleCollisionWithVoxel(particle, voxelDetails, collisionInfo); + + // we must scale back down to the octree reference frame before updating the particle properties collisionInfo._penetration /= (float)(TREE_SCALE); + collisionInfo._contactPoint /= (float)(TREE_SCALE); particle->applyHardCollision(collisionInfo); queueParticlePropertiesUpdate(particle); @@ -121,8 +127,7 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA) glm::vec3 penetration; Particle* particleB; if (_particles->findSpherePenetration(center, radius, penetration, (void**)&particleB, Octree::NoLock)) { - // NOTE: 'penetration' is the depth that 'particleA' overlaps 'particleB'. - // That is, it points from A into B. + // NOTE: 'penetration' is the depth that 'particleA' overlaps 'particleB'. It points from A into B. // Even if the particles overlap... when the particles are already moving appart // we don't want to count this as a collision. @@ -130,7 +135,12 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA) if (glm::dot(relativeVelocity, penetration) > 0.0f) { particleA->collisionWithParticle(particleB, penetration); particleB->collisionWithParticle(particleA, penetration * -1.0f); // the penetration is reversed - emitGlobalParticleCollisionWithParticle(particleA, particleB, penetration); + + CollisionInfo collision; + collision._penetration = penetration; + // for now the contactPoint is the average between the the two paricle centers + collision._contactPoint = (0.5f * (float)TREE_SCALE) * (particleA->getPosition() + particleB->getPosition()); + emitGlobalParticleCollisionWithParticle(particleA, particleB, collision); glm::vec3 axis = glm::normalize(penetration); glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis; @@ -142,25 +152,25 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA) float massB = (particleB->getInHand()) ? MAX_MASS : particleB->getMass(); float totalMass = massA + massB; - // handle A particle + // handle particle A particleA->setVelocity(particleA->getVelocity() - axialVelocity * (2.0f * massB / totalMass)); particleA->setPosition(particleA->getPosition() - 0.5f * penetration); ParticleProperties propertiesA; - ParticleID particleAid(particleA->getID()); + ParticleID idA(particleA->getID()); propertiesA.copyFromParticle(*particleA); propertiesA.setVelocity(particleA->getVelocity() * (float)TREE_SCALE); propertiesA.setPosition(particleA->getPosition() * (float)TREE_SCALE); - _packetSender->queueParticleEditMessage(PacketTypeParticleAddOrEdit, particleAid, propertiesA); + _packetSender->queueParticleEditMessage(PacketTypeParticleAddOrEdit, idA, propertiesA); - // handle B particle + // handle particle B particleB->setVelocity(particleB->getVelocity() + axialVelocity * (2.0f * massA / totalMass)); particleA->setPosition(particleB->getPosition() + 0.5f * penetration); ParticleProperties propertiesB; - ParticleID particleBid(particleB->getID()); + ParticleID idB(particleB->getID()); propertiesB.copyFromParticle(*particleB); propertiesB.setVelocity(particleB->getVelocity() * (float)TREE_SCALE); propertiesB.setPosition(particleB->getPosition() * (float)TREE_SCALE); - _packetSender->queueParticleEditMessage(PacketTypeParticleAddOrEdit, particleBid, propertiesB); + _packetSender->queueParticleEditMessage(PacketTypeParticleAddOrEdit, idB, propertiesB); _packetSender->releaseQueuedMessages(); diff --git a/libraries/particles/src/ParticleCollisionSystem.h b/libraries/particles/src/ParticleCollisionSystem.h index 1b30fd31ac..c6ab97c02b 100644 --- a/libraries/particles/src/ParticleCollisionSystem.h +++ b/libraries/particles/src/ParticleCollisionSystem.h @@ -53,13 +53,13 @@ public: void updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency); signals: - void particleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel, const glm::vec3& penetration); - void particleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB, const glm::vec3& penetration); + void particleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel, const CollisionInfo& penetration); + void particleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB, const CollisionInfo& penetration); private: static bool updateOperation(OctreeElement* element, void* extraData); - void emitGlobalParticleCollisionWithVoxel(Particle* particle, VoxelDetail* voxelDetails, const glm::vec3& penetration); - void emitGlobalParticleCollisionWithParticle(Particle* particleA, Particle* particleB, const glm::vec3& penetration); + void emitGlobalParticleCollisionWithVoxel(Particle* particle, VoxelDetail* voxelDetails, const CollisionInfo& penetration); + void emitGlobalParticleCollisionWithParticle(Particle* particleA, Particle* particleB, const CollisionInfo& penetration); ParticleEditPacketSender* _packetSender; ParticleTree* _particles; diff --git a/libraries/particles/src/ParticlesScriptingInterface.h b/libraries/particles/src/ParticlesScriptingInterface.h index 24bbad9e3e..8de44e20bb 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.h +++ b/libraries/particles/src/ParticlesScriptingInterface.h @@ -11,6 +11,8 @@ #include +#include + #include #include "ParticleEditPacketSender.h" @@ -55,8 +57,8 @@ public slots: QVector findParticles(const glm::vec3& center, float radius) const; signals: - void particleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel, const glm::vec3& penetration); - void particleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB, const glm::vec3& penetration); + void particleCollisionWithVoxel(const ParticleID& particleID, const VoxelDetail& voxel, const CollisionInfo& collision); + void particleCollisionWithParticle(const ParticleID& idA, const ParticleID& idB, const CollisionInfo& collision); private: void queueParticleMessage(PacketType packetType, ParticleID particleID, const ParticleProperties& properties); diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index d106977ae0..af074c59bc 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -16,6 +16,7 @@ static int vec2MetaTypeId = qRegisterMetaType(); static int quatMetaTypeId = qRegisterMetaType(); static int xColorMetaTypeId = qRegisterMetaType(); static int pickRayMetaTypeId = qRegisterMetaType(); +static int collisionMetaTypeId = qRegisterMetaType(); void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue); @@ -24,6 +25,7 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue); qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue); + qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); } QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4) { @@ -122,3 +124,14 @@ void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) { } } +QScriptValue collisionToScriptValue(QScriptEngine* engine, const CollisionInfo& collision) { + QScriptValue obj = engine->newObject(); + obj.setProperty("penetration", vec3toScriptValue(engine, collision._penetration)); + obj.setProperty("contactPoint", vec3toScriptValue(engine, collision._contactPoint)); + return obj; +} + +void collisionFromScriptValue(const QScriptValue &object, CollisionInfo& collision) { + // TODO: implement this when we know what it means to accept collision events from JS +} + diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index ea65e45c95..0e7732c057 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -15,6 +15,7 @@ #include +#include "CollisionInfo.h" #include "SharedUtil.h" Q_DECLARE_METATYPE(glm::vec4) @@ -50,4 +51,8 @@ Q_DECLARE_METATYPE(PickRay) QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); +Q_DECLARE_METATYPE(CollisionInfo) +QScriptValue collisionToScriptValue(QScriptEngine* engine, const CollisionInfo& collision); +void collisionFromScriptValue(const QScriptValue &object, CollisionInfo& collision); + #endif From cec99caa47ff1692dd95a85e716f751620f7bef8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 13:45:30 -0700 Subject: [PATCH 22/46] 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 23/46] 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 24/46] 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 0011276b0bc1e6aab7b8854d39acae874a19261d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Apr 2014 14:19:17 -0700 Subject: [PATCH 25/46] Added back the download stats, which got lost in a merge. --- interface/src/ui/Stats.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 1722732e76..dbcbb3d8bb 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -20,6 +20,8 @@ #include "Menu.h" #include "Util.h" +using namespace std; + const int STATS_PELS_PER_LINE = 20; const int STATS_GENERAL_MIN_WIDTH = 165; @@ -287,7 +289,7 @@ void Stats::display( MyAvatar* myAvatar = Application::getInstance()->getAvatar(); glm::vec3 avatarPos = myAvatar->getPosition(); - lines = _expanded ? 4 : 3; + lines = _expanded ? 5 : 3; drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; @@ -318,6 +320,16 @@ void Stats::display( verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarMixerStats, color); + + stringstream downloads; + downloads << "Downloads: "; + foreach (Resource* resource, ResourceCache::getLoadingRequests()) { + downloads << (int)(resource->getProgress() * 100.0f) << "% "; + } + downloads << "(" << ResourceCache::getPendingRequestCount() << " pending)"; + + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, downloads.str().c_str(), color); } verticalOffset = 0; From 262c6d320640a168894593764d612934e156a969 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 14:35:13 -0700 Subject: [PATCH 26/46] 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 56b0583600bb21ff12c4180cc58c72d780283b22 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 14:42:35 -0700 Subject: [PATCH 27/46] Fix for editVoxels/inspect conflict --- examples/editVoxels.js | 46 ++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 4922caf0d8..1dc8c189f3 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -32,6 +32,7 @@ var MIN_PASTE_VOXEL_SCALE = .256; var zFightingSizeAdjust = 0.002; // used to adjust preview voxels to prevent z fighting var previewLineWidth = 1.5; +var inspectJsIsRunning = false; var isAdding = false; var isExtruding = false; var extrudeDirection = { x: 0, y: 0, z: 0 }; @@ -62,9 +63,9 @@ var whichColor = -1; // Starting color is 'Copy' mode // Create sounds for adding, deleting, recoloring voxels var addSound1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+2.raw"); -var addSound2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+3.raw"); -var addSound3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+4.raw"); +var addSound2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+4.raw"); +var addSound3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+3.raw"); var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+delete+2.raw"); var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+edit+2.raw"); var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/toggle+switch+-+medium.raw"); @@ -727,6 +728,9 @@ function trackKeyPressEvent(event) { trackAsEyedropper = true; moveTools(); } + if (event.text == "ALT") { + inspectJsIsRunning = true; + } showPreviewGuides(); } @@ -739,6 +743,10 @@ function trackKeyReleaseEvent(event) { showPreviewGuides(); Audio.playSound(clickSound, audioOptions); } + + if (event.text == "ALT") { + inspectJsIsRunning = false; + } if (editToolsOn) { if (event.text == "ESC") { @@ -777,11 +785,13 @@ function trackKeyReleaseEvent(event) { } function mousePressEvent(event) { - // if our tools are off, then don't do anything if (!editToolsOn) { return; } + if (inspectJsIsRunning) { + return; + } var clickedOnSomething = false; var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); @@ -1061,7 +1071,9 @@ function mouseMoveEvent(event) { if (!editToolsOn) { return; } - + if (inspectJsIsRunning) { + return; + } if (isMovingSlider) { thumbX = (event.x - thumbClickOffsetX) - sliderX; @@ -1121,7 +1133,10 @@ function mouseReleaseEvent(event) { if (!editToolsOn) { return; } - + if (inspectJsIsRunning) { + return; + } + if (isMovingSlider) { isMovingSlider = false; } @@ -1214,24 +1229,6 @@ function moveTools() { } -function touchBeginEvent(event) { - if (!editToolsOn) { - return; - } -} - -function touchUpdateEvent(event) { - if (!editToolsOn) { - return; - } -} - -function touchEndEvent(event) { - if (!editToolsOn) { - return; - } -} - var lastFingerAddVoxel = { x: -1, y: -1, z: -1}; // off of the build-able area var lastFingerDeleteVoxel = { x: -1, y: -1, z: -1}; // off of the build-able area @@ -1332,9 +1329,6 @@ Controller.mouseReleaseEvent.connect(mouseReleaseEvent); Controller.mouseMoveEvent.connect(mouseMoveEvent); Controller.keyPressEvent.connect(keyPressEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent); -Controller.touchBeginEvent.connect(touchBeginEvent); -Controller.touchUpdateEvent.connect(touchUpdateEvent); -Controller.touchEndEvent.connect(touchEndEvent); Controller.captureKeyEvents({ text: "+" }); Controller.captureKeyEvents({ text: "-" }); From 15e9d45dc3465503364adcaf83dc55738b55ff81 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Apr 2014 15:41:42 -0700 Subject: [PATCH 28/46] 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 29/46] 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 30/46] 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 bf0eb69e2c9733b500ecff3d8d03a706e58b98e5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 7 Apr 2014 16:28:55 -0700 Subject: [PATCH 31/46] fix for sometimes slow avatar --- interface/src/avatar/Avatar.cpp | 4 ++-- interface/src/avatar/Avatar.h | 1 - interface/src/avatar/MyAvatar.cpp | 18 ++++++++---------- interface/src/avatar/MyAvatar.h | 1 - 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 899514d1c1..75b9db1581 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -46,7 +46,6 @@ Avatar::Avatar() : _mode(AVATAR_MODE_STANDING), _velocity(0.0f, 0.0f, 0.0f), _thrust(0.0f, 0.0f, 0.0f), - _speed(0.0f), _leanScale(0.5f), _scale(1.0f), _worldUpDirection(DEFAULT_UP_DIRECTION), @@ -137,7 +136,8 @@ void Avatar::simulate(float deltaTime) { } // use speed and angular velocity to determine walking vs. standing - if (_speed + fabs(_bodyYawDelta) > 0.2) { + float speed = glm::length(_velocity); + if (speed + fabs(_bodyYawDelta) > 0.2) { _mode = AVATAR_MODE_WALKING; } else { _mode = AVATAR_MODE_INTERACTING; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index f6d5669859..a6cefedef8 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -160,7 +160,6 @@ protected: AvatarMode _mode; glm::vec3 _velocity; glm::vec3 _thrust; - float _speed; float _leanScale; float _scale; glm::vec3 _worldUpDirection; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1ff93794c5..05636166e2 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -169,9 +169,6 @@ void MyAvatar::simulate(float deltaTime) { // Collect thrust forces from keyboard and devices updateThrust(deltaTime); - // calculate speed - _speed = glm::length(_velocity); - // update the movement of the hand and process handshaking with other avatars... updateHandMovementAndTouching(deltaTime); @@ -203,9 +200,9 @@ void MyAvatar::simulate(float deltaTime) { if (fabs(_bodyRollDelta) < MINIMUM_ROTATION_RATE) { _bodyRollDelta = 0.f; } if (fabs(_bodyPitchDelta) < MINIMUM_ROTATION_RATE) { _bodyPitchDelta = 0.f; } - const float MAX_STATIC_FRICTION_VELOCITY = 0.5f; + const float MAX_STATIC_FRICTION_SPEED = 0.5f; const float STATIC_FRICTION_STRENGTH = _scale * 20.f; - applyStaticFriction(deltaTime, _velocity, MAX_STATIC_FRICTION_VELOCITY, STATIC_FRICTION_STRENGTH); + applyStaticFriction(deltaTime, _velocity, MAX_STATIC_FRICTION_SPEED, STATIC_FRICTION_STRENGTH); // Damp avatar velocity const float LINEAR_DAMPING_STRENGTH = 0.5f; @@ -230,7 +227,8 @@ void MyAvatar::simulate(float deltaTime) { const float WALKING_SPEED_THRESHOLD = 0.2f; // use speed and angular velocity to determine walking vs. standing - if (_speed + fabs(_bodyYawDelta) > WALKING_SPEED_THRESHOLD) { + float speed = glm::length(_velocity); + if (speed + fabs(_bodyYawDelta) > WALKING_SPEED_THRESHOLD) { _mode = AVATAR_MODE_WALKING; } else { _mode = AVATAR_MODE_INTERACTING; @@ -238,7 +236,7 @@ void MyAvatar::simulate(float deltaTime) { // update moving flag based on speed const float MOVING_SPEED_THRESHOLD = 0.01f; - _moving = _speed > MOVING_SPEED_THRESHOLD; + _moving = speed > MOVING_SPEED_THRESHOLD; // If a move target is set, update position explicitly const float MOVE_FINISHED_TOLERANCE = 0.1f; @@ -681,7 +679,6 @@ void MyAvatar::updateThrust(float deltaTime) { if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) { const float THRUST_INCREASE_RATE = 1.05f; const float MAX_THRUST_MULTIPLIER = 75.0f; - //printf("m = %.3f\n", _thrustMultiplier); _thrustMultiplier *= 1.f + deltaTime * THRUST_INCREASE_RATE; if (_thrustMultiplier > MAX_THRUST_MULTIPLIER) { _thrustMultiplier = MAX_THRUST_MULTIPLIER; @@ -703,11 +700,12 @@ void MyAvatar::updateThrust(float deltaTime) { if ((glm::length(_thrust) == 0.0f) && _isThrustOn && (glm::length(_velocity) > MIN_SPEED_BRAKE_VELOCITY)) { _speedBrakes = true; } + _isThrustOn = (glm::length(_thrust) > EPSILON); - if (_speedBrakes && (glm::length(_velocity) < MIN_SPEED_BRAKE_VELOCITY)) { + if (_isThrustOn || (_speedBrakes && (glm::length(_velocity) < MIN_SPEED_BRAKE_VELOCITY))) { _speedBrakes = false; } - _isThrustOn = (glm::length(_thrust) > EPSILON); + } void MyAvatar::updateHandMovementAndTouching(float deltaTime) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 5c940f0f50..2125b126b3 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -50,7 +50,6 @@ public: void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } // getters - float getSpeed() const { return _speed; } AvatarMode getMode() const { return _mode; } float getLeanScale() const { return _leanScale; } float getElapsedTimeStopped() const { return _elapsedTimeStopped; } From d213cd784034285337e137b6575166088ef7a803 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Apr 2014 17:10:15 -0700 Subject: [PATCH 32/46] 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 33/46] 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 fa05a482707a049c53ac554aede2b7190579b87c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Apr 2014 17:55:36 -0700 Subject: [PATCH 34/46] Provide a means of supplying the joint mappings in the FST file so that agent scripts can address joints by name. Closes #2526. --- examples/crazylegs.js | 7 +++-- interface/src/avatar/Avatar.cpp | 4 +++ interface/src/avatar/Avatar.h | 2 ++ libraries/avatars/src/AvatarData.cpp | 46 ++++++++++++++++++++++++++++ libraries/avatars/src/AvatarData.h | 12 ++++++-- 5 files changed, 67 insertions(+), 4 deletions(-) diff --git a/examples/crazylegs.js b/examples/crazylegs.js index 099387e000..19a171dbdf 100644 --- a/examples/crazylegs.js +++ b/examples/crazylegs.js @@ -12,9 +12,12 @@ var AMPLITUDE = 45.0; var cumulativeTime = 0.0; -print("Joint List:"); +print("# Joint list start"); var jointList = MyAvatar.getJointNames(); -print(jointList); +for (var i = 0; i < jointList.length; i++) { + print("jointIndex = " + jointList[i] + " = " + i); +} +print("# Joint list end"); Script.update.connect(function(deltaTime) { cumulativeTime += deltaTime; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 899514d1c1..7a55d4d534 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -331,6 +331,10 @@ void Avatar::renderBody(RenderMode renderMode) { getHand()->render(false); } +void Avatar::updateJointMappings() { + // no-op; joint mappings come from skeleton model +} + void Avatar::renderBillboard() { if (_billboard.isEmpty()) { return; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index f6d5669859..e0d46c8624 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -187,6 +187,8 @@ protected: void renderDisplayName(); virtual void renderBody(RenderMode renderMode); + virtual void updateJointMappings(); + private: bool _initialized; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 930e3f7350..e84636b5a4 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -639,6 +639,8 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { _skeletonModelURL = skeletonModelURL.isEmpty() ? DEFAULT_BODY_MODEL_URL : skeletonModelURL; qDebug() << "Changing skeleton model for avatar to" << _skeletonModelURL.toString(); + + updateJointMappings(); } void AvatarData::setDisplayName(const QString& displayName) { @@ -673,6 +675,40 @@ void AvatarData::setBillboardFromURL(const QString &billboardURL) { void AvatarData::setBillboardFromNetworkReply() { QNetworkReply* networkReply = reinterpret_cast(sender()); setBillboard(networkReply->readAll()); + networkReply->deleteLater(); +} + +void AvatarData::setJointMappingsFromNetworkReply() { + QNetworkReply* networkReply = static_cast(sender()); + + QByteArray line; + while (!(line = networkReply->readLine()).isEmpty()) { + if (!(line = line.trimmed()).startsWith("jointIndex")) { + continue; + } + int jointNameIndex = line.indexOf('=') + 1; + if (jointNameIndex == 0) { + continue; + } + int secondSeparatorIndex = line.indexOf('=', jointNameIndex); + if (secondSeparatorIndex == -1) { + continue; + } + QString jointName = line.mid(jointNameIndex, secondSeparatorIndex - jointNameIndex).trimmed(); + bool ok; + int jointIndex = line.mid(secondSeparatorIndex + 1).trimmed().toInt(&ok); + if (ok) { + while (_jointNames.size() < jointIndex + 1) { + _jointNames.append(QString()); + } + _jointNames[jointIndex] = jointName; + } + } + for (int i = 0; i < _jointNames.size(); i++) { + _jointIndices.insert(_jointNames.at(i), i + 1); + } + + networkReply->deleteLater(); } void AvatarData::setClampedTargetScale(float targetScale) { @@ -705,3 +741,13 @@ void AvatarData::sendBillboardPacket() { NodeList::getInstance()->broadcastToNodes(billboardPacket, NodeSet() << NodeType::AvatarMixer); } } + +void AvatarData::updateJointMappings() { + _jointIndices.clear(); + _jointNames.clear(); + + if (networkAccessManager && _skeletonModelURL.fileName().toLower().endsWith(".fst")) { + QNetworkReply* networkReply = networkAccessManager->get(QNetworkRequest(_skeletonModelURL)); + connect(networkReply, SIGNAL(finished()), this, SLOT(setJointMappingsFromNetworkReply())); + } +} diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 221bbd0428..cf645855e8 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -30,6 +30,7 @@ typedef unsigned long long quint64; #include #include +#include #include #include #include @@ -160,9 +161,9 @@ public: Q_INVOKABLE glm::quat getJointRotation(const QString& name) const; /// Returns the index of the joint with the specified name, or -1 if not found/unknown. - Q_INVOKABLE virtual int getJointIndex(const QString& name) const { return -1; } + Q_INVOKABLE virtual int getJointIndex(const QString& name) const { return _jointIndices.value(name) - 1; } - Q_INVOKABLE virtual QStringList getJointNames() const { return QStringList(); } + Q_INVOKABLE virtual QStringList getJointNames() const { return _jointNames; } // key state void setKeyState(KeyState s) { _keyState = s; } @@ -217,6 +218,7 @@ public slots: void sendIdentityPacket(); void sendBillboardPacket(); void setBillboardFromNetworkReply(); + void setJointMappingsFromNetworkReply(); protected: glm::vec3 _position; glm::vec3 _handPosition; @@ -258,10 +260,16 @@ protected: QByteArray _billboard; QString _billboardURL; + QHash _jointIndices; ///< 1-based, since zero is returned for missing keys + QStringList _jointNames; ///< in order of depth-first traversal + static QNetworkAccessManager* networkAccessManager; quint64 _errorLogExpiry; ///< time in future when to log an error + /// Loads the joint indices, names from the FST file (if any) + virtual void updateJointMappings(); + private: // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&); From 5a610090998ced77554c7fbdd506a147f655889f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 8 Apr 2014 10:19:39 -0700 Subject: [PATCH 35/46] 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 36/46] 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 37/46] 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 38/46] 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 39/46] 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 40/46] 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 41/46] 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 42/46] 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 43/46] 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 44/46] 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 45/46] 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 46/46] 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";