From 53e6a77fcc613cfde2042686b646338f1db587f4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 20 Jan 2017 15:00:56 -0800 Subject: [PATCH 01/22] cleanup EncodeBitstreamParams to use nodeData when possible --- .../src/octree/OctreeSendThread.cpp | 9 +- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/EntityTreeElement.cpp | 54 ++-- libraries/entities/src/LightEntityItem.cpp | 2 +- libraries/entities/src/LineEntityItem.cpp | 2 +- libraries/entities/src/LineEntityItem.h | 2 +- libraries/entities/src/ModelEntityItem.cpp | 2 +- libraries/entities/src/ModelEntityItem.h | 2 +- .../entities/src/ParticleEffectEntityItem.cpp | 2 +- libraries/entities/src/PolyLineEntityItem.cpp | 2 +- libraries/entities/src/PolyLineEntityItem.h | 2 +- libraries/entities/src/PolyVoxEntityItem.cpp | 2 +- libraries/entities/src/PolyVoxEntityItem.h | 2 +- libraries/entities/src/ShapeEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.h | 2 +- libraries/entities/src/WebEntityItem.cpp | 2 +- libraries/entities/src/WebEntityItem.h | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 2 +- libraries/entities/src/ZoneEntityItem.h | 2 +- libraries/octree/src/Octree.cpp | 230 ++++++------------ libraries/octree/src/Octree.h | 18 +- libraries/octree/src/OctreePersistThread.h | 2 +- 23 files changed, 129 insertions(+), 220 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 7922da8af4..7db06f12c0 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -443,13 +443,8 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); EncodeBitstreamParams params(INT_MAX, WANT_EXISTS_BITS, DONT_CHOP, - viewFrustumChanged, - boundaryLevelAdjust, octreeSizeScale, - nodeData->getLastTimeBagEmpty(), - isFullScene, &nodeData->stats, _myServer->getJurisdiction(), - &nodeData->extraEncodeData, - nodeData->getUsesFrustum(), - nodeData); + viewFrustumChanged, boundaryLevelAdjust, octreeSizeScale, + isFullScene, _myServer->getJurisdiction(), nodeData); nodeData->copyCurrentViewFrustum(params.viewFrustum); if (viewFrustumChanged) { nodeData->copyLastKnownViewFrustum(params.lastViewFrustum); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 163b4d9e45..878058ad13 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -125,7 +125,7 @@ public: void markAsChangedOnServer() { _changedOnServer = usecTimestampNow(); } quint64 getLastChangedOnServer() const { return _changedOnServer; } - // TODO: eventually only include properties changed since the params.lastQuerySent time + // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; virtual OctreeElement::AppendState appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 755c19e625..98287541e3 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -51,7 +51,10 @@ void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) cons qCDebug(entities) << "EntityTreeElement::debugExtraEncodeData()... "; qCDebug(entities) << " element:" << _cube; - OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData; + auto entityNodeData = static_cast(params.nodeData); + assert(entityNodeData); + + OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes if (extraEncodeData->contains(this)) { @@ -65,7 +68,11 @@ void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) cons void EntityTreeElement::initializeExtraEncodeData(EncodeBitstreamParams& params) { - OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData; + auto entityNodeData = static_cast(params.nodeData); + assert(entityNodeData); + + OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; + assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes // Check to see if this element yet has encode data... if it doesn't create it if (!extraEncodeData->contains(this)) { @@ -93,7 +100,11 @@ void EntityTreeElement::initializeExtraEncodeData(EncodeBitstreamParams& params) } bool EntityTreeElement::shouldIncludeChildData(int childIndex, EncodeBitstreamParams& params) const { - OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData; + + auto entityNodeData = static_cast(params.nodeData); + assert(entityNodeData); + + OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes if (extraEncodeData->contains(this)) { @@ -122,7 +133,10 @@ bool EntityTreeElement::shouldRecurseChildTree(int childIndex, EncodeBitstreamPa } bool EntityTreeElement::alreadyFullyEncoded(EncodeBitstreamParams& params) const { - OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData; + auto entityNodeData = static_cast(params.nodeData); + assert(entityNodeData); + + OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes if (extraEncodeData->contains(this)) { @@ -137,8 +151,12 @@ bool EntityTreeElement::alreadyFullyEncoded(EncodeBitstreamParams& params) const } void EntityTreeElement::updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const { - OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData; + auto entityNodeData = static_cast(params.nodeData); + assert(entityNodeData); + + OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes + if (extraEncodeData->contains(this)) { EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData = std::static_pointer_cast((*extraEncodeData)[this]); @@ -161,7 +179,10 @@ void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params) con qCDebug(entities) << "EntityTreeElement::elementEncodeComplete() element:" << _cube; } - OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData; + auto entityNodeData = static_cast(params.nodeData); + assert(entityNodeData); + + OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes assert(extraEncodeData->contains(this)); @@ -236,8 +257,12 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData OctreeElement::AppendState appendElementState = OctreeElement::COMPLETED; // assume the best... + auto entityNodeData = static_cast(params.nodeData); + Q_ASSERT_X(entityNodeData, "EntityTreeElement::appendElementData", "expected params.nodeData not to be null"); + // first, check the params.extraEncodeData to see if there's any partial re-encode data for this element - OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData; + OctreeElementExtraEncodeData* extraEncodeData = &entityNodeData->extraEncodeData; + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData = NULL; bool hadElementExtraData = false; if (extraEncodeData && extraEncodeData->contains(this)) { @@ -285,20 +310,17 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData // need to handle the case where our sibling elements need encoding but we don't. if (!entityTreeElementExtraEncodeData->elementCompleted) { - QJsonObject jsonFilters; - auto entityNodeData = static_cast(params.nodeData); - if (entityNodeData) { - // we have an EntityNodeData instance - // so we should assume that means we might have JSON filters to check - jsonFilters = entityNodeData->getJSONParameters(); - } + // we have an EntityNodeData instance + // so we should assume that means we might have JSON filters to check + auto jsonFilters = entityNodeData->getJSONParameters(); + for (uint16_t i = 0; i < _entityItems.size(); i++) { EntityItemPointer entity = _entityItems[i]; bool includeThisEntity = true; - if (!params.forceSendScene && entity->getLastChangedOnServer() < params.lastQuerySent) { + if (!params.forceSendScene && entity->getLastChangedOnServer() < entityNodeData->getLastTimeBagEmpty()) { includeThisEntity = false; } @@ -330,7 +352,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData // we only check the bounds against our frustum and LOD if the query has asked us to check against the frustum // which can sometimes not be the case when JSON filters are sent - if (params.usesFrustum && (includeThisEntity || params.recurseEverything)) { + if (entityNodeData->getUsesFrustum() && (includeThisEntity || params.recurseEverything)) { // we want to use the maximum possible box for this, so that we don't have to worry about the nuance of // simulation changing what's visible. consider the case where the entity contains an angular velocity diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index e09822f028..bc8e55e118 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -174,7 +174,7 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, } -// TODO: eventually only include properties changed since the params.lastQuerySent time +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags LightEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_IS_SPOTLIGHT; diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index 8ace665616..80e3f65fb3 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -126,7 +126,7 @@ int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, } -// TODO: eventually only include properties changed since the params.lastQuerySent time +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags LineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_COLOR; diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index 8629c94eb4..ff64c7c17e 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -26,7 +26,7 @@ class LineEntityItem : public EntityItem { virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.lastQuerySent time + // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 911ff224b2..51d9c2ad25 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -160,7 +160,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, return bytesRead; } -// TODO: eventually only include properties changed since the params.lastQuerySent time +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index e1cb5cd92c..5076a43892 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -29,7 +29,7 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.lastQuerySent time + // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 140522b00e..fc2d128bd1 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -469,7 +469,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch } -// TODO: eventually only include properties changed since the params.lastQuerySent time +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 7abafad627..473d9c1131 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -170,7 +170,7 @@ int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da } -// TODO: eventually only include properties changed since the params.lastQuerySent time +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags PolyLineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_COLOR; diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 5f9f9124cf..3b3cf6e6ba 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -26,7 +26,7 @@ class PolyLineEntityItem : public EntityItem { virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.lastQuerySent time + // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index 90344d6c4b..dc794f1dcc 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -179,7 +179,7 @@ int PolyVoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* dat } -// TODO: eventually only include properties changed since the params.lastQuerySent time +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags PolyVoxEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_VOXEL_VOLUME_SIZE; diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 311a002a4a..db30e54b61 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -26,7 +26,7 @@ class PolyVoxEntityItem : public EntityItem { virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.lastQuerySent time + // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 345d9e54ab..018d8c568a 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -137,7 +137,7 @@ int ShapeEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, } -// TODO: eventually only include properties changed since the params.lastQuerySent time +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags ShapeEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_SHAPE; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index fbb0bdc9cf..366fdc7aa2 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -99,7 +99,7 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, } -// TODO: eventually only include properties changed since the params.lastQuerySent time +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_TEXT; diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 633aa96bfa..c706423cbd 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -30,7 +30,7 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.lastQuerySent time + // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 182d58ba36..40da2a0af2 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -84,7 +84,7 @@ int WebEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, i } -// TODO: eventually only include properties changed since the params.lastQuerySent time +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags WebEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_SOURCE_URL; diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 19a7b577fe..483c2bbc8a 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -29,7 +29,7 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.lastQuerySent time + // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 37b3be99a3..6d1facc979 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -137,7 +137,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, } -// TODO: eventually only include properties changed since the params.lastQuerySent time +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 2bef95e452..6a6326d067 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -30,7 +30,7 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - // TODO: eventually only include properties changed since the params.lastQuerySent time + // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 58910c66bd..dfc6195f95 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -43,14 +43,15 @@ #include #include +#include "Octree.h" #include "OctreeConstants.h" #include "OctreeElementBag.h" -#include "Octree.h" -#include "OctreeUtils.h" #include "OctreeLogging.h" +#include "OctreeQueryNode.h" +#include "OctreeUtils.h" -QVector PERSIST_EXTENSIONS = {"svo", "json", "json.gz"}; +QVector PERSIST_EXTENSIONS = {"json", "json.gz"}; Octree::Octree(bool shouldReaverage) : _rootElement(NULL), @@ -898,8 +899,16 @@ int Octree::encodeTreeBitstream(OctreeElementPointer element, return bytesWritten; } + // you can't call this without a valid nodeData + auto octreeQueryNode = static_cast(params.nodeData); + if (!octreeQueryNode) { + qCDebug(octree, "WARNING! encodeTreeBitstream() called with nodeData=NULL"); + params.stopReason = EncodeBitstreamParams::NULL_NODE_DATA; + return bytesWritten; + } + // If we're at a element that is out of view, then we can return, because no nodes below us will be in view! - if (params.usesFrustum && !params.recurseEverything && !element->isInView(params.viewFrustum)) { + if (octreeQueryNode->getUsesFrustum() && !params.recurseEverything && !element->isInView(params.viewFrustum)) { params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW; return bytesWritten; } @@ -935,9 +944,7 @@ int Octree::encodeTreeBitstream(OctreeElementPointer element, // record some stats, this is the one element that we won't record below in the recursion function, so we need to // track it here - if (params.stats) { - params.stats->traversed(element); - } + octreeQueryNode->stats.traversed(element); ViewFrustum::intersection parentLocationThisView = ViewFrustum::INTERSECT; // assume parent is in view, but not fully @@ -993,6 +1000,15 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, return bytesAtThisLevel; } + // you can't call this without a valid nodeData + auto octreeQueryNode = static_cast(params.nodeData); + if (!octreeQueryNode) { + qCDebug(octree, "WARNING! encodeTreeBitstream() called with nodeData=NULL"); + params.stopReason = EncodeBitstreamParams::NULL_NODE_DATA; + return bytesAtThisLevel; + } + + // Keep track of how deep we've encoded. currentEncodeLevel++; @@ -1015,15 +1031,13 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } ViewFrustum::intersection nodeLocationThisView = ViewFrustum::INSIDE; // assume we're inside - if (params.usesFrustum && !params.recurseEverything) { + if (octreeQueryNode->getUsesFrustum() && !params.recurseEverything) { float boundaryDistance = boundaryDistanceForRenderLevel(element->getLevel() + params.boundaryLevelAdjust, params.octreeElementSizeScale); // If we're too far away for our render level, then just return if (element->distanceToCamera(params.viewFrustum) >= boundaryDistance) { - if (params.stats) { - params.stats->skippedDistance(element); - } + octreeQueryNode->stats.skippedDistance(element); params.stopReason = EncodeBitstreamParams::LOD_SKIP; return bytesAtThisLevel; } @@ -1039,9 +1053,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // we're out of view if (nodeLocationThisView == ViewFrustum::OUTSIDE) { - if (params.stats) { - params.stats->skippedOutOfView(element); - } + octreeQueryNode->stats.skippedOutOfView(element); params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW; return bytesAtThisLevel; } @@ -1066,7 +1078,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // as "was in view"... if (wasInView) { float boundaryDistance = boundaryDistanceForRenderLevel(element->getLevel() + params.boundaryLevelAdjust, - params.octreeElementSizeScale); + params.octreeElementSizeScale); if (element->distanceToCamera(params.lastViewFrustum) >= boundaryDistance) { // This would have been invisible... but now should be visible (we wouldn't be here otherwise)... wasInView = false; @@ -1077,22 +1089,20 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // If we were previously in the view, then we normally will return out of here and stop recursing. But // if we're in deltaView mode, and this element has changed since it was last sent, then we do // need to send it. - if (wasInView && !(params.deltaView && element->hasChangedSince(params.lastQuerySent - CHANGE_FUDGE))) { - if (params.stats) { - params.stats->skippedWasInView(element); - } + if (wasInView && !(params.deltaView && element->hasChangedSince(octreeQueryNode->getLastTimeBagEmpty() - CHANGE_FUDGE))) { + octreeQueryNode->stats.skippedWasInView(element); params.stopReason = EncodeBitstreamParams::WAS_IN_VIEW; return bytesAtThisLevel; } } - // If we're not in delta sending mode, and we weren't asked to do a force send, and the octree element hasn't changed, + // If we're not in delta sending mode, and we weren't asked to do a force send, and the voxel hasn't changed, // then we can also bail early and save bits if (!params.forceSendScene && !params.deltaView && - !element->hasChangedSince(params.lastQuerySent - CHANGE_FUDGE)) { - if (params.stats) { - params.stats->skippedNoChange(element); - } + !element->hasChangedSince(octreeQueryNode->getLastTimeBagEmpty() - CHANGE_FUDGE)) { + + octreeQueryNode->stats.skippedNoChange(element); + params.stopReason = EncodeBitstreamParams::NO_CHANGE; return bytesAtThisLevel; } @@ -1164,8 +1174,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // track stats // must check childElement here, because it could be we got here with no childElement - if (params.stats && childElement) { - params.stats->traversed(childElement); + if (childElement) { + octreeQueryNode->stats.traversed(childElement); } } @@ -1176,7 +1186,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, int originalIndex = indexOfChildren[i]; bool childIsInView = (childElement && - (params.recurseEverything || !params.usesFrustum || + (params.recurseEverything || !octreeQueryNode->getUsesFrustum() || (nodeLocationThisView == ViewFrustum::INSIDE) || // parent was fully in view, we can assume ALL children are (nodeLocationThisView == ViewFrustum::INTERSECT && childElement->isInView(params.viewFrustum)) // the parent intersects and the child is in view @@ -1184,20 +1194,18 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, if (!childIsInView) { // must check childElement here, because it could be we got here because there was no childElement - if (params.stats && childElement) { - params.stats->skippedOutOfView(childElement); + if (childElement) { + octreeQueryNode->stats.skippedOutOfView(childElement); } } else { // Before we consider this further, let's see if it's in our LOD scope... - float boundaryDistance = params.recurseEverything || !params.usesFrustum ? 1 : + float boundaryDistance = params.recurseEverything || !octreeQueryNode->getUsesFrustum() ? 1 : boundaryDistanceForRenderLevel(childElement->getLevel() + params.boundaryLevelAdjust, params.octreeElementSizeScale); if (!(distancesToChildren[i] < boundaryDistance)) { // don't need to check childElement here, because we can't get here with no childElement - if (params.stats) { - params.stats->skippedDistance(childElement); - } + octreeQueryNode->stats.skippedDistance(childElement); } else { inViewCount++; @@ -1211,20 +1219,18 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, bool childIsOccluded = false; // assume it's not occluded - bool shouldRender = params.recurseEverything || !params.usesFrustum || + bool shouldRender = params.recurseEverything || !octreeQueryNode->getUsesFrustum() || childElement->calculateShouldRender(params.viewFrustum, params.octreeElementSizeScale, params.boundaryLevelAdjust); // track some stats - if (params.stats) { - // don't need to check childElement here, because we can't get here with no childElement - if (!shouldRender && childElement->isLeaf()) { - params.stats->skippedDistance(childElement); - } - // don't need to check childElement here, because we can't get here with no childElement - if (childIsOccluded) { - params.stats->skippedOccluded(childElement); - } + // don't need to check childElement here, because we can't get here with no childElement + if (!shouldRender && childElement->isLeaf()) { + octreeQueryNode->stats.skippedDistance(childElement); + } + // don't need to check childElement here, because we can't get here with no childElement + if (childIsOccluded) { + octreeQueryNode->stats.skippedOccluded(childElement); } // track children with actual color, only if the child wasn't previously in view! @@ -1247,19 +1253,17 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // need to send it. if (!childWasInView || (params.deltaView && - childElement->hasChangedSince(params.lastQuerySent - CHANGE_FUDGE))){ + childElement->hasChangedSince(octreeQueryNode->getLastTimeBagEmpty() - CHANGE_FUDGE))){ childrenDataBits += (1 << (7 - originalIndex)); inViewWithColorCount++; } else { // otherwise just track stats of the items we discarded // don't need to check childElement here, because we can't get here with no childElement - if (params.stats) { - if (childWasInView) { - params.stats->skippedWasInView(childElement); - } else { - params.stats->skippedNoChange(childElement); - } + if (childWasInView) { + octreeQueryNode->stats.skippedWasInView(childElement); + } else { + octreeQueryNode->stats.skippedNoChange(childElement); } } } @@ -1277,9 +1281,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, assert(continueThisLevel); // since we used reserved bits, this really shouldn't fail bytesAtThisLevel += sizeof(childrenDataBits); // keep track of byte count - if (params.stats) { - params.stats->colorBitsWritten(); // really data bits not just color bits - } + + octreeQueryNode->stats.colorBitsWritten(); // really data bits not just color bits // NOW might be a good time to give our tree subclass and this element a chance to set up and check any extra encode data element->initializeExtraEncodeData(params); @@ -1349,8 +1352,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child // don't need to check childElement here, because we can't get here with no childElement - if (params.stats && (childAppendState != OctreeElement::NONE)) { - params.stats->colorSent(childElement); + if (childAppendState != OctreeElement::NONE) { + octreeQueryNode->stats.colorSent(childElement); } } } @@ -1377,9 +1380,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, continueThisLevel = packetData->appendBitMask(childrenExistInTreeBits); if (continueThisLevel) { bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count - if (params.stats) { - params.stats->existsBitsWritten(); - } + + octreeQueryNode->stats.existsBitsWritten(); } else { qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to append childrenExistInTreeBits"; qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; @@ -1392,9 +1394,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, continueThisLevel = packetData->appendBitMask(childrenExistInPacketBits); if (continueThisLevel) { bytesAtThisLevel += sizeof(childrenExistInPacketBits); // keep track of byte count - if (params.stats) { - params.stats->existsInPacketBitsWritten(); - } + + octreeQueryNode->stats.existsInPacketBitsWritten(); } else { qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to append childrenExistInPacketBits"; qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; @@ -1451,7 +1452,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // called databits), then we wouldn't send the children. So those types of Octree's should tell us to keep // recursing, by returning TRUE in recurseChildrenWithData(). - if (params.recurseEverything || !params.usesFrustum + if (params.recurseEverything || !octreeQueryNode->getUsesFrustum() || recurseChildrenWithData() || !oneAtBit(childrenDataBits, originalIndex)) { // Allow the datatype a chance to determine if it really wants to recurse this tree. Usually this @@ -1502,8 +1503,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } // If this is the last of the child exists bits, then we're actually be rolling out the entire tree - if (params.stats && childrenExistInPacketBits == 0) { - params.stats->childBitsRemoved(params.includeExistsBits); + if (childrenExistInPacketBits == 0) { + octreeQueryNode->stats.childBitsRemoved(params.includeExistsBits); } if (!continueThisLevel) { @@ -1558,9 +1559,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, if (continueThisLevel) { bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child - if (params.stats) { - params.stats->colorSent(element); - } + octreeQueryNode->stats.colorSent(element); } if (!continueThisLevel) { @@ -1595,9 +1594,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, bag.insert(element); // don't need to check element here, because we can't get here with no element - if (params.stats) { - params.stats->didntFit(element); - } + octreeQueryNode->stats.didntFit(element); params.stopReason = EncodeBitstreamParams::DIDNT_FIT; bytesAtThisLevel = 0; // didn't fit @@ -1876,9 +1873,7 @@ bool Octree::writeToFile(const char* fileName, OctreeElementPointer element, QSt const char* cFileName = byteArray.constData(); bool success = false; - if (persistAsFileType == "svo") { - success = writeToSVOFile(fileName, element); - } else if (persistAsFileType == "json") { + if (persistAsFileType == "json") { success = writeToJSONFile(cFileName, element); } else if (persistAsFileType == "json.gz") { success = writeToJSONFile(cFileName, element, true); @@ -1936,95 +1931,6 @@ bool Octree::writeToJSONFile(const char* fileName, OctreeElementPointer element, return success; } -bool Octree::writeToSVOFile(const char* fileName, OctreeElementPointer element) { - qWarning() << "SVO file format deprecated. Support for reading SVO files is no longer support and will be removed soon."; - bool success = false; - - std::ofstream file(fileName, std::ios::out|std::ios::binary); - - if(file.is_open()) { - qCDebug(octree, "Saving binary SVO to file %s...", fileName); - - PacketType expectedPacketType = expectedDataPacketType(); - int expectedIntType = (int) expectedPacketType; - PacketVersion expectedVersion = versionForPacketType(expectedPacketType); - bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion); - - // before reading the file, check to see if this version of the Octree supports file versions - if (getWantSVOfileVersions()) { - // if so, read the first byte of the file and see if it matches the expected version code - file.write(reinterpret_cast(&expectedIntType), sizeof(expectedIntType)); - file.write(&expectedVersion, sizeof(expectedVersion)); - qCDebug(octree) << "SVO file type: " << expectedPacketType << " version: " << (int)expectedVersion; - - hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion); - } - if (hasBufferBreaks) { - qCDebug(octree) << " this version includes buffer breaks"; - } else { - qCDebug(octree) << " this version does not include buffer breaks"; - } - - - OctreeElementBag elementBag; - OctreeElementExtraEncodeData extraEncodeData; - // If we were given a specific element, start from there, otherwise start from root - if (element) { - elementBag.insert(element); - } else { - elementBag.insert(_rootElement); - } - - OctreePacketData packetData; - int bytesWritten = 0; - bool lastPacketWritten = false; - - while (OctreeElementPointer subTree = elementBag.extract()) { - EncodeBitstreamParams params(INT_MAX, NO_EXISTS_BITS); - params.recurseEverything = true; - withReadLock([&] { - params.extraEncodeData = &extraEncodeData; - bytesWritten = encodeTreeBitstream(subTree, &packetData, elementBag, params); - }); - - // if the subTree couldn't fit, and so we should reset the packet and reinsert the element in our bag and try again - if (bytesWritten == 0 && (params.stopReason == EncodeBitstreamParams::DIDNT_FIT)) { - if (packetData.hasContent()) { - // if this type of SVO file should have buffer breaks, then we will write a buffer size before each - // buffer to allow the reader to read this file in chunks. - if (hasBufferBreaks) { - quint16 bufferSize = packetData.getFinalizedSize(); - file.write((const char*)&bufferSize, sizeof(bufferSize)); - } - file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize()); - lastPacketWritten = true; - } - packetData.reset(); // is there a better way to do this? could we fit more? - elementBag.insert(subTree); - } else { - lastPacketWritten = false; - } - } - - if (!lastPacketWritten) { - // if this type of SVO file should have buffer breaks, then we will write a buffer size before each - // buffer to allow the reader to read this file in chunks. - if (hasBufferBreaks) { - quint16 bufferSize = packetData.getFinalizedSize(); - file.write((const char*)&bufferSize, sizeof(bufferSize)); - } - file.write((const char*)packetData.getFinalizedData(), packetData.getFinalizedSize()); - } - - releaseSceneEncodeData(&extraEncodeData); - - success = true; - } - file.close(); - - return success; -} - unsigned long Octree::getOctreeElementsCount() { unsigned long nodeCount = 0; recurseTreeWithOperation(countOctreeElementsOperation, &nodeCount); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 7b2f303c0d..caae31eaa5 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -59,9 +59,7 @@ const bool DONT_COLLAPSE = false; const int DONT_CHOP = 0; const int NO_BOUNDARY_ADJUST = 0; const int LOW_RES_MOVING_ADJUST = 1; -const quint64 IGNORE_LAST_SENT = 0; -#define IGNORE_SCENE_STATS NULL #define IGNORE_COVERAGE_MAP NULL #define IGNORE_JURISDICTION_MAP NULL @@ -69,7 +67,6 @@ class EncodeBitstreamParams { public: ViewFrustum viewFrustum; ViewFrustum lastViewFrustum; - quint64 lastQuerySent; int maxEncodeLevel; int maxLevelReached; bool includeExistsBits; @@ -79,10 +76,7 @@ public: int boundaryLevelAdjust; float octreeElementSizeScale; bool forceSendScene; - OctreeSceneStats* stats; JurisdictionMap* jurisdictionMap; - OctreeElementExtraEncodeData* extraEncodeData; - bool usesFrustum; NodeData* nodeData; // output hints from the encode process @@ -90,6 +84,7 @@ public: UNKNOWN, DIDNT_FIT, NULL_NODE, + NULL_NODE_DATA, TOO_DEEP, OUT_OF_JURISDICTION, LOD_SKIP, @@ -107,14 +102,9 @@ public: bool useDeltaView = false, int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, - quint64 lastQuerySent = IGNORE_LAST_SENT, bool forceSendScene = true, - OctreeSceneStats* stats = IGNORE_SCENE_STATS, JurisdictionMap* jurisdictionMap = IGNORE_JURISDICTION_MAP, - OctreeElementExtraEncodeData* extraEncodeData = nullptr, - bool usesFrustum = true, NodeData* nodeData = nullptr) : - lastQuerySent(lastQuerySent), maxEncodeLevel(maxEncodeLevel), maxLevelReached(0), includeExistsBits(includeExistsBits), @@ -123,10 +113,7 @@ public: boundaryLevelAdjust(boundaryLevelAdjust), octreeElementSizeScale(octreeElementSizeScale), forceSendScene(forceSendScene), - stats(stats), jurisdictionMap(jurisdictionMap), - extraEncodeData(extraEncodeData), - usesFrustum(usesFrustum), nodeData(nodeData), stopReason(UNKNOWN) { @@ -306,9 +293,8 @@ public: void loadOctreeFile(const char* fileName); // Octree exporters - bool writeToFile(const char* filename, OctreeElementPointer element = NULL, QString persistAsFileType = "svo"); + bool writeToFile(const char* filename, OctreeElementPointer element = NULL, QString persistAsFileType = "json.gz"); bool writeToJSONFile(const char* filename, OctreeElementPointer element = NULL, bool doGzip = false); - bool writeToSVOFile(const char* filename, OctreeElementPointer element = NULL); virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, bool skipThoseWithBadParents) = 0; diff --git a/libraries/octree/src/OctreePersistThread.h b/libraries/octree/src/OctreePersistThread.h index f8215fb34a..927304e862 100644 --- a/libraries/octree/src/OctreePersistThread.h +++ b/libraries/octree/src/OctreePersistThread.h @@ -35,7 +35,7 @@ public: OctreePersistThread(OctreePointer tree, const QString& filename, const QString& backupDirectory, int persistInterval = DEFAULT_PERSIST_INTERVAL, bool wantBackup = false, - const QJsonObject& settings = QJsonObject(), bool debugTimestampNow = false, QString persistAsFileType="svo"); + const QJsonObject& settings = QJsonObject(), bool debugTimestampNow = false, QString persistAsFileType="json.gz"); bool isInitialLoadComplete() const { return _initialLoadComplete; } quint64 getLoadElapsedTime() const { return _loadTimeUSecs; } From 6f2f1d6452e002caff0aa6c9310896685ed3767e Mon Sep 17 00:00:00 2001 From: humbletim Date: Wed, 29 Mar 2017 19:42:19 -0400 Subject: [PATCH 02/22] call finished() when cached resource has already failed to load --- libraries/networking/src/ResourceCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 0396e0ed94..4031ff8bf7 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -191,7 +191,7 @@ ScriptableResource* ResourceCache::prefetch(const QUrl& url, void* extra) { result->setObjectName(url.toString()); result->_resource = resource; - if (resource->isLoaded()) { + if (resource->isLoaded() || resource->_failedToLoad) { result->finished(!resource->_failedToLoad); } else { result->_progressConnection = connect( From 2775b17a657a19353281e58fdcffe39260e665cc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 4 Apr 2017 14:02:58 -0700 Subject: [PATCH 03/22] unravel one loop of spaghetti --- interface/src/avatar/AvatarManager.cpp | 37 +++++++------------------- interface/src/avatar/AvatarManager.h | 26 +++++++++--------- 2 files changed, 24 insertions(+), 39 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 48914908c6..03d7dd1c6c 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -68,7 +68,7 @@ void AvatarManager::registerMetaTypes(QScriptEngine* engine) { } AvatarManager::AvatarManager(QObject* parent) : - _avatarFades(), + _avatarsToFade(), _myAvatar(std::make_shared(std::make_shared())) { // register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar @@ -151,7 +151,7 @@ float AvatarManager::getAvatarSimulationRate(const QUuid& sessionID, const QStri void AvatarManager::updateOtherAvatars(float deltaTime) { // lock the hash for read to check the size QReadLocker lock(&_hashLock); - if (_avatarHash.size() < 2 && _avatarFades.isEmpty()) { + if (_avatarHash.size() < 2 && _avatarsToFade.isEmpty()) { return; } lock.unlock(); @@ -277,22 +277,22 @@ void AvatarManager::postUpdate(float deltaTime) { } void AvatarManager::simulateAvatarFades(float deltaTime) { - QVector::iterator fadingIterator = _avatarFades.begin(); + QVector::iterator fadingIterator = _avatarsToFade.begin(); const float SHRINK_RATE = 0.15f; const float MIN_FADE_SCALE = MIN_AVATAR_SCALE; render::ScenePointer scene = qApp->getMain3DScene(); render::Transaction transaction; - while (fadingIterator != _avatarFades.end()) { + while (fadingIterator != _avatarsToFade.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); avatar->animateScaleChanges(deltaTime); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, transaction); - // only remove from _avatarFades if we're sure its motionState has been removed from PhysicsEngine + // only remove from _avatarsToFade if we're sure its motionState has been removed from PhysicsEngine if (_motionStatesToRemoveFromPhysics.empty()) { - fadingIterator = _avatarFades.erase(fadingIterator); + fadingIterator = _avatarsToFade.erase(fadingIterator); } else { ++fadingIterator; } @@ -306,26 +306,9 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { } AvatarSharedPointer AvatarManager::newSharedAvatar() { - return std::make_shared(std::make_shared()); -} - -AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { - auto newAvatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer); - auto rawRenderableAvatar = std::static_pointer_cast(newAvatar); - - rawRenderableAvatar->addToScene(rawRenderableAvatar); - - return newAvatar; -} - -// virtual -void AvatarManager::removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason) { - QWriteLocker locker(&_hashLock); - - auto removedAvatar = _avatarHash.take(sessionUUID); - if (removedAvatar) { - handleRemovedAvatar(removedAvatar, removalReason); - } + std::shared_ptr avatar = std::make_shared(std::make_shared()); + avatar->addToScene(avatar); + return avatar; } void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { @@ -353,7 +336,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar DependencyManager::get()->removeFromIgnoreMuteSets(avatar->getSessionUUID()); DependencyManager::get()->avatarDisconnected(avatar->getSessionUUID()); } - _avatarFades.push_back(removedAvatar); + _avatarsToFade.push_back(removedAvatar); } void AvatarManager::clearOtherAvatars() { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index b94f9e6a96..228fe7e92f 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -91,21 +91,27 @@ public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } void updateAvatarRenderStatus(bool shouldRenderAvatars); -private slots: - virtual void removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason = KillAvatarReason::NoReason) override; - private: explicit AvatarManager(QObject* parent = 0); explicit AvatarManager(const AvatarManager& other); void simulateAvatarFades(float deltaTime); - // virtual overrides - virtual AvatarSharedPointer newSharedAvatar() override; - virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) override; - virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override; + AvatarSharedPointer newSharedAvatar() override; + void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override; + + /* TODO: maintain these lists + QVector _avatarsToRemoveFromScene; + QVector _avatarsToAddToScene; + QVector _avatarsToRemoveFromPhysicsEngine; + QVector _avatarsToAddToPhysicsEngine; + */ + QVector _avatarsToFade; + + SetOfAvatarMotionStates _motionStatesThatMightUpdate; + VectorOfMotionStates _motionStatesToRemoveFromPhysics; + SetOfMotionStates _motionStatesToAddToPhysics; - QVector _avatarFades; std::shared_ptr _myAvatar; quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate. @@ -115,10 +121,6 @@ private: std::list> _collisionInjectors; - SetOfAvatarMotionStates _motionStatesThatMightUpdate; - SetOfMotionStates _motionStatesToAddToPhysics; - VectorOfMotionStates _motionStatesToRemoveFromPhysics; - RateCounter<> _myAvatarSendRate; int _numAvatarsUpdated { 0 }; int _numAvatarsNotUpdated { 0 }; From 40e223cb82e4e1bed70c6bad719170a75d19d9ec Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 4 Apr 2017 15:10:02 -0700 Subject: [PATCH 04/22] cleanup unused return values and redundant variables --- interface/src/avatar/Avatar.cpp | 8 ++------ interface/src/avatar/Avatar.h | 3 +-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b6ec45b308..a8fc4840fe 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -476,7 +476,7 @@ static TextRenderer3D* textRenderer(TextRendererType type) { return displayNameRenderer; } -bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr scene, render::Transaction& transaction) { +void Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr scene, render::Transaction& transaction) { auto avatarPayload = new render::Payload(self); auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload); _renderItemID = scene->allocateID(); @@ -486,9 +486,6 @@ bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr for (auto& attachmentModel : _attachmentModels) { attachmentModel->addToScene(scene, transaction); } - - _inScene = true; - return true; } void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr scene, render::Transaction& transaction) { @@ -498,7 +495,6 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptrremoveFromScene(scene, transaction); } - _inScene = false; } void Avatar::updateRenderItem(render::Transaction& transaction) { @@ -1435,7 +1431,7 @@ void Avatar::addToScene(AvatarSharedPointer myHandle) { } } void Avatar::ensureInScene(AvatarSharedPointer self) { - if (!_inScene) { + if (!render::Item::isValidID(_renderItemID)) { addToScene(self); } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 7fadf96e11..ae98c525c8 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -81,7 +81,7 @@ public: virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition); - bool addToScene(AvatarSharedPointer self, std::shared_ptr scene, + void addToScene(AvatarSharedPointer self, std::shared_ptr scene, render::Transaction& transaction); void removeFromScene(AvatarSharedPointer self, std::shared_ptr scene, @@ -310,7 +310,6 @@ private: int _nameRectGeometryID { 0 }; bool _initialized; bool _isLookAtTarget { false }; - bool _inScene { false }; bool _isAnimatingScale { false }; float getBoundingRadius() const; From 662c34c266c230619c5272b11866d830dbc7bb0a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 6 Apr 2017 09:40:24 -0700 Subject: [PATCH 05/22] fix avatar scale animation and avatar render debug --- interface/src/avatar/Avatar.cpp | 9 +- interface/src/avatar/Avatar.h | 1 + interface/src/avatar/AvatarManager.cpp | 111 ++++++++++++++++-------- interface/src/avatar/AvatarManager.h | 10 +-- interface/src/avatar/MyAvatar.cpp | 3 +- libraries/avatars/src/AvatarData.cpp | 1 + libraries/avatars/src/AvatarHashMap.cpp | 41 +++++---- libraries/avatars/src/AvatarHashMap.h | 11 +-- 8 files changed, 117 insertions(+), 70 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a8fc4840fe..988d34e554 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -192,6 +192,7 @@ void Avatar::animateScaleChanges(float deltaTime) { _isAnimatingScale = false; } setScale(glm::vec3(animatedScale)); // avatar scale is uniform + _hasNewJointData = true; // TODO: rebuilding the shape constantly is somehwat expensive. // We should only rebuild after significant change. @@ -200,8 +201,12 @@ void Avatar::animateScaleChanges(float deltaTime) { } void Avatar::setTargetScale(float targetScale) { - AvatarData::setTargetScale(targetScale); - _isAnimatingScale = true; + float newValue = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); + if (_targetScale != newValue) { + _targetScale = newValue; + _scaleChanged = usecTimestampNow(); + _isAnimatingScale = true; + } } void Avatar::updateAvatarEntities() { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index ae98c525c8..c4084fce9a 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -285,6 +285,7 @@ protected: void addToScene(AvatarSharedPointer self); void ensureInScene(AvatarSharedPointer self); + bool isInScene() const { return render::Item::isValidID(_renderItemID); } // Some rate tracking support RateCounter<> _simulationRate; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 03d7dd1c6c..0d9cd13d24 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -100,15 +100,16 @@ void AvatarManager::init() { _avatarHash.insert(MY_AVATAR_KEY, _myAvatar); } + _shouldRender = DependencyManager::get()->shouldRenderAvatars(); connect(DependencyManager::get().data(), &SceneScriptingInterface::shouldRenderAvatarsChanged, this, &AvatarManager::updateAvatarRenderStatus, Qt::QueuedConnection); - render::ScenePointer scene = qApp->getMain3DScene(); - render::Transaction transaction; - if (DependencyManager::get()->shouldRenderAvatars()) { + if (_shouldRender) { + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; _myAvatar->addToScene(_myAvatar, scene, transaction); + scene->enqueueTransaction(transaction); } - scene->enqueueTransaction(transaction); } void AvatarManager::updateMyAvatar(float deltaTime) { @@ -181,30 +182,24 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { // DO NOT update or fade out uninitialized Avatars return true; // ignore it } - if (avatar->shouldDie()) { - removeAvatar(avatar->getID()); - return true; // ignore it - } - if (avatar->isDead()) { - return true; // ignore it - } - return false; }); - render::Transaction transaction; uint64_t startTime = usecTimestampNow(); const uint64_t UPDATE_BUDGET = 2000; // usec uint64_t updateExpiry = startTime + UPDATE_BUDGET; - int numAvatarsUpdated = 0; int numAVatarsNotUpdated = 0; + + render::Transaction transaction; while (!sortedAvatars.empty()) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); // for ALL avatars... - avatar->ensureInScene(avatar); + if (_shouldRender) { + avatar->ensureInScene(avatar); + } if (!avatar->getMotionState()) { ShapeInfo shapeInfo; avatar->computeShapeInfo(shapeInfo); @@ -218,6 +213,10 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } } avatar->animateScaleChanges(deltaTime); + if (avatar->shouldDie()) { + avatar->die(); + removeAvatar(avatar->getID()); + } const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY; uint64_t now = usecTimestampNow(); @@ -259,10 +258,21 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { sortedAvatars.pop(); } + if (_shouldRender) { + QVector::iterator itr = _avatarsToFade.begin(); + while (itr != _avatarsToFade.end() && usecTimestampNow() > updateExpiry) { + auto avatar = std::static_pointer_cast(*itr); + avatar->animateScaleChanges(deltaTime); + avatar->simulate(deltaTime, true); + avatar->updateRenderItem(transaction); + ++itr; + } + qApp->getMain3DScene()->enqueueTransaction(transaction); + } + _avatarSimulationTime = (float)(usecTimestampNow() - startTime) / (float)USECS_PER_MSEC; _numAvatarsUpdated = numAvatarsUpdated; _numAvatarsNotUpdated = numAVatarsNotUpdated; - qApp->getMain3DScene()->enqueueTransaction(transaction); simulateAvatarFades(deltaTime); } @@ -277,38 +287,68 @@ void AvatarManager::postUpdate(float deltaTime) { } void AvatarManager::simulateAvatarFades(float deltaTime) { - QVector::iterator fadingIterator = _avatarsToFade.begin(); + QVector::iterator itr = _avatarsToFade.begin(); const float SHRINK_RATE = 0.15f; const float MIN_FADE_SCALE = MIN_AVATAR_SCALE; - render::ScenePointer scene = qApp->getMain3DScene(); - render::Transaction transaction; - while (fadingIterator != _avatarsToFade.end()) { - auto avatar = std::static_pointer_cast(*fadingIterator); + while (itr != _avatarsToFade.end()) { + auto avatar = std::static_pointer_cast(*itr); avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); avatar->animateScaleChanges(deltaTime); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { - avatar->removeFromScene(*fadingIterator, scene, transaction); + // fading to zero is such a rare event we push unique transaction for each one + removeAvatar(avatar->getID()); + if (avatar->isInScene()) { + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; + avatar->removeFromScene(*itr, scene, transaction); + scene->enqueueTransaction(transaction); + } + // only remove from _avatarsToFade if we're sure its motionState has been removed from PhysicsEngine if (_motionStatesToRemoveFromPhysics.empty()) { - fadingIterator = _avatarsToFade.erase(fadingIterator); + itr = _avatarsToFade.erase(itr); } else { - ++fadingIterator; + ++itr; } } else { const bool inView = true; // HACK avatar->simulate(deltaTime, inView); - ++fadingIterator; + ++itr; } } - scene->enqueueTransaction(transaction); } AvatarSharedPointer AvatarManager::newSharedAvatar() { - std::shared_ptr avatar = std::make_shared(std::make_shared()); - avatar->addToScene(avatar); - return avatar; + return std::make_shared(std::make_shared()); +} + +void AvatarManager::processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode) { + PerformanceTimer perfTimer("receiveAvatar"); + // enumerate over all of the avatars in this packet + // only add them if mixerWeakPointer points to something (meaning that mixer is still around) + while (message->getBytesLeftToRead()) { + AvatarSharedPointer avatarData = parseAvatarData(message, sendingNode); + if (avatarData) { + auto avatar = std::static_pointer_cast(avatarData); + if (avatar->isInScene()) { + if (!_shouldRender) { + // rare transition so we process pending changes immediately + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; + avatar->removeFromScene(avatar, scene, transaction); + scene->enqueueTransaction(transaction); + } + } else if (_shouldRender) { + // very rare transition so we process pending changes immediately + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; + avatar->addToScene(avatar, scene, transaction); + scene->enqueueTransaction(transaction); + } + } + } } void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { @@ -458,26 +498,23 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { - if (DependencyManager::get()->shouldRenderAvatars()) { + _shouldRender = shouldRenderAvatars; + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; + if (_shouldRender) { for (auto avatarData : _avatarHash) { auto avatar = std::static_pointer_cast(avatarData); - render::ScenePointer scene = qApp->getMain3DScene(); - render::Transaction transaction; avatar->addToScene(avatar, scene, transaction); - scene->enqueueTransaction(transaction); } } else { for (auto avatarData : _avatarHash) { auto avatar = std::static_pointer_cast(avatarData); - render::ScenePointer scene = qApp->getMain3DScene(); - render::Transaction transaction; avatar->removeFromScene(avatar, scene, transaction); - scene->enqueueTransaction(transaction); } } + scene->enqueueTransaction(transaction); } - AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) const { if (sessionID == AVATAR_SELF_ID || sessionID == _myAvatar->getSessionUUID()) { return _myAvatar; diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 228fe7e92f..3f053f43a6 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -91,6 +91,9 @@ public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } void updateAvatarRenderStatus(bool shouldRenderAvatars); +protected slots: + void processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode) override; + private: explicit AvatarManager(QObject* parent = 0); explicit AvatarManager(const AvatarManager& other); @@ -100,12 +103,6 @@ private: AvatarSharedPointer newSharedAvatar() override; void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override; - /* TODO: maintain these lists - QVector _avatarsToRemoveFromScene; - QVector _avatarsToAddToScene; - QVector _avatarsToRemoveFromPhysicsEngine; - QVector _avatarsToAddToPhysicsEngine; - */ QVector _avatarsToFade; SetOfAvatarMotionStates _motionStatesThatMightUpdate; @@ -125,6 +122,7 @@ private: int _numAvatarsUpdated { 0 }; int _numAvatarsNotUpdated { 0 }; float _avatarSimulationTime { 0.0f }; + bool _shouldRender { true }; }; Q_DECLARE_METATYPE(AvatarManager::LocalLight) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d1edf9d44e..2a616a7a2a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -54,6 +54,7 @@ #include "DebugDraw.h" #include "EntityEditPacketSender.h" #include "MovingEntitiesOperator.h" +#include "SceneScriptingInterface.h" using namespace std; @@ -1634,7 +1635,7 @@ void MyAvatar::postUpdate(float deltaTime) { Avatar::postUpdate(deltaTime); render::ScenePointer scene = qApp->getMain3DScene(); - if (_skeletonModel->initWhenReady(scene)) { + if (DependencyManager::get()->shouldRenderAvatars() && _skeletonModel->initWhenReady(scene)) { initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a1ea103edb..23aa0cd811 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -123,6 +123,7 @@ void AvatarData::setTargetScale(float targetScale) { if (_targetScale != newValue) { _targetScale = newValue; _scaleChanged = usecTimestampNow(); + _avatarScaleChanged = _scaleChanged; } } diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 48e5d673c9..8708030190 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -80,13 +80,10 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { QWriteLocker locker(&_hashLock); - auto avatar = _avatarHash.value(sessionUUID); - if (!avatar) { avatar = addAvatar(sessionUUID, mixerWeakPointer); } - return avatar; } @@ -103,27 +100,33 @@ void AvatarHashMap::processAvatarDataPacket(QSharedPointer mess // enumerate over all of the avatars in this packet // only add them if mixerWeakPointer points to something (meaning that mixer is still around) while (message->getBytesLeftToRead()) { - QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + parseAvatarData(message, sendingNode); + } +} - int positionBeforeRead = message->getPosition(); +AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer message, SharedNodePointer sendingNode) { + QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - QByteArray byteArray = message->readWithoutCopy(message->getBytesLeftToRead()); + int positionBeforeRead = message->getPosition(); - // make sure this isn't our own avatar data or for a previously ignored node - auto nodeList = DependencyManager::get(); + QByteArray byteArray = message->readWithoutCopy(message->getBytesLeftToRead()); - if (sessionUUID != _lastOwnerSessionUUID && (!nodeList->isIgnoringNode(sessionUUID) || nodeList->getRequestsDomainListData())) { - auto avatar = newOrExistingAvatar(sessionUUID, sendingNode); + // make sure this isn't our own avatar data or for a previously ignored node + auto nodeList = DependencyManager::get(); - // have the matching (or new) avatar parse the data from the packet - int bytesRead = avatar->parseDataFromBuffer(byteArray); - message->seek(positionBeforeRead + bytesRead); - } else { - // create a dummy AvatarData class to throw this data on the ground - AvatarData dummyData; - int bytesRead = dummyData.parseDataFromBuffer(byteArray); - message->seek(positionBeforeRead + bytesRead); - } + if (sessionUUID != _lastOwnerSessionUUID && (!nodeList->isIgnoringNode(sessionUUID) || nodeList->getRequestsDomainListData())) { + auto avatar = newOrExistingAvatar(sessionUUID, sendingNode); + + // have the matching (or new) avatar parse the data from the packet + int bytesRead = avatar->parseDataFromBuffer(byteArray); + message->seek(positionBeforeRead + bytesRead); + return avatar; + } else { + // create a dummy AvatarData class to throw this data on the ground + AvatarData dummyData; + int bytesRead = dummyData.parseDataFromBuffer(byteArray); + message->seek(positionBeforeRead + bytesRead); + return std::make_shared(); } } diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index 104ac83261..346cd36b60 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -49,11 +49,11 @@ signals: public slots: bool isAvatarInRange(const glm::vec3 & position, const float range); - -private slots: + +protected slots: void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID); - - void processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode); + + virtual void processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode); void processAvatarIdentityPacket(QSharedPointer message, SharedNodePointer sendingNode); void processKillAvatar(QSharedPointer message, SharedNodePointer sendingNode); void processExitingSpaceBubble(QSharedPointer message, SharedNodePointer sendingNode); @@ -61,12 +61,13 @@ private slots: protected: AvatarHashMap(); + virtual AvatarSharedPointer parseAvatarData(QSharedPointer message, SharedNodePointer sendingNode); virtual AvatarSharedPointer newSharedAvatar(); virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer); AvatarSharedPointer newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer); virtual AvatarSharedPointer findAvatar(const QUuid& sessionUUID) const; // uses a QReadLocker on the hashLock virtual void removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason = KillAvatarReason::NoReason); - + virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason); AvatarHash _avatarHash; From 2f18e51f6ba20740c4ab0e56755a39214540db8e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 6 Apr 2017 10:52:48 -0700 Subject: [PATCH 06/22] lock mutex around fading avatar list --- interface/src/avatar/AvatarManager.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 0d9cd13d24..7f4bc1c953 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -259,13 +259,16 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } if (_shouldRender) { - QVector::iterator itr = _avatarsToFade.begin(); - while (itr != _avatarsToFade.end() && usecTimestampNow() > updateExpiry) { - auto avatar = std::static_pointer_cast(*itr); - avatar->animateScaleChanges(deltaTime); - avatar->simulate(deltaTime, true); - avatar->updateRenderItem(transaction); - ++itr; + if (!_avatarsToFade.empty()) { + QReadLocker lock(&_hashLock); + QVector::iterator itr = _avatarsToFade.begin(); + while (itr != _avatarsToFade.end() && usecTimestampNow() > updateExpiry) { + auto avatar = std::static_pointer_cast(*itr); + avatar->animateScaleChanges(deltaTime); + avatar->simulate(deltaTime, true); + avatar->updateRenderItem(transaction); + ++itr; + } } qApp->getMain3DScene()->enqueueTransaction(transaction); } @@ -287,18 +290,21 @@ void AvatarManager::postUpdate(float deltaTime) { } void AvatarManager::simulateAvatarFades(float deltaTime) { - QVector::iterator itr = _avatarsToFade.begin(); + if (_avatarsToFade.empty()) { + return; + } const float SHRINK_RATE = 0.15f; const float MIN_FADE_SCALE = MIN_AVATAR_SCALE; + QReadLocker locker(&_hashLock); + QVector::iterator itr = _avatarsToFade.begin(); while (itr != _avatarsToFade.end()) { auto avatar = std::static_pointer_cast(*itr); avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); avatar->animateScaleChanges(deltaTime); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { // fading to zero is such a rare event we push unique transaction for each one - removeAvatar(avatar->getID()); if (avatar->isInScene()) { render::ScenePointer scene = qApp->getMain3DScene(); render::Transaction transaction; From 6d627aa9bc44916a647c4c6baea4777fb5d3c197 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 6 Apr 2017 11:19:58 -0700 Subject: [PATCH 07/22] don't remove other avatars on sign-out --- interface/src/avatar/AvatarManager.cpp | 30 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 7f4bc1c953..73e247bdd1 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -386,22 +386,32 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar } void AvatarManager::clearOtherAvatars() { - // clear any avatars that came from an avatar-mixer - QWriteLocker locker(&_hashLock); + // Remove other avatars from the world but don't actually remove them from _avatarHash + // each will either be removed on timeout or will re-added to the world on receipt of update. + render::ScenePointer scene = qApp->getMain3DScene(); + render::PendingChanges pendingChanges; + QReadLocker locker(&_hashLock); AvatarHash::iterator avatarIterator = _avatarHash.begin(); while (avatarIterator != _avatarHash.end()) { auto avatar = std::static_pointer_cast(avatarIterator.value()); - if (avatar == _myAvatar || !avatar->isInitialized()) { - // don't remove myAvatar or uninitialized avatars from the list - ++avatarIterator; - } else { - auto removedAvatar = avatarIterator.value(); - avatarIterator = _avatarHash.erase(avatarIterator); - - handleRemovedAvatar(removedAvatar); + if (avatar != _myAvatar) { + //auto removedAvatar = avatarIterator.value(); + //avatarIterator = _avatarHash.erase(avatarIterator); + //handleRemovedAvatar(removedAvatar); + if (avatar->isInScene()) { + avatar->removeFromScene(avatar, scene, pendingChanges); + } + AvatarMotionState* motionState = avatar->getMotionState(); + if (motionState) { + _motionStatesThatMightUpdate.remove(motionState); + _motionStatesToAddToPhysics.remove(motionState); + _motionStatesToRemoveFromPhysics.push_back(motionState); + } } + ++avatarIterator; } + scene->enqueuePendingChanges(pendingChanges); _myAvatar->clearLookAtTargetAvatar(); } From 1fb88a03152d72aa507f025abfe92a4669cb0fc9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 6 Apr 2017 12:59:25 -0700 Subject: [PATCH 08/22] add a helpful comment --- interface/src/avatar/Avatar.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 988d34e554..6ad389ccf6 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -192,6 +192,8 @@ void Avatar::animateScaleChanges(float deltaTime) { _isAnimatingScale = false; } setScale(glm::vec3(animatedScale)); // avatar scale is uniform + + // flag the joints as having changed for force update to RenderItem _hasNewJointData = true; // TODO: rebuilding the shape constantly is somehwat expensive. From 8773497f7e157052a943243178f2cf6ed578101d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 6 Apr 2017 12:59:39 -0700 Subject: [PATCH 09/22] remvoe commented out cruft --- interface/src/avatar/AvatarManager.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 73e247bdd1..15d1c60b5d 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -396,9 +396,6 @@ void AvatarManager::clearOtherAvatars() { while (avatarIterator != _avatarHash.end()) { auto avatar = std::static_pointer_cast(avatarIterator.value()); if (avatar != _myAvatar) { - //auto removedAvatar = avatarIterator.value(); - //avatarIterator = _avatarHash.erase(avatarIterator); - //handleRemovedAvatar(removedAvatar); if (avatar->isInScene()) { avatar->removeFromScene(avatar, scene, pendingChanges); } From 92495d9622e9a9f787a130f05d29a3b471978c98 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 6 Apr 2017 15:22:04 -0700 Subject: [PATCH 10/22] delete in proper order on shutdown --- interface/src/Application.cpp | 3 +- interface/src/avatar/AvatarManager.cpp | 50 ++++++++++++++++---------- interface/src/avatar/AvatarManager.h | 2 +- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 342d325f58..87fcc77704 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1800,10 +1800,11 @@ Application::~Application() { _physicsEngine->setCharacterController(nullptr); // remove avatars from physics engine - DependencyManager::get()->clearAllAvatars(); + DependencyManager::get()->clearOtherAvatars(); VectorOfMotionStates motionStates; DependencyManager::get()->getObjectsToRemoveFromPhysics(motionStates); _physicsEngine->removeObjects(motionStates); + DependencyManager::get()->deleteAllAvatars(); DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 15d1c60b5d..f1170a7085 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -309,7 +309,9 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { render::ScenePointer scene = qApp->getMain3DScene(); render::Transaction transaction; avatar->removeFromScene(*itr, scene, transaction); - scene->enqueueTransaction(transaction); + if (scene) { + scene->enqueueTransaction(transaction); + } } // only remove from _avatarsToFade if we're sure its motionState has been removed from PhysicsEngine @@ -340,18 +342,22 @@ void AvatarManager::processAvatarDataPacket(QSharedPointer mess auto avatar = std::static_pointer_cast(avatarData); if (avatar->isInScene()) { if (!_shouldRender) { - // rare transition so we process pending changes immediately + // rare transition so we process the transaction immediately render::ScenePointer scene = qApp->getMain3DScene(); - render::Transaction transaction; - avatar->removeFromScene(avatar, scene, transaction); - scene->enqueueTransaction(transaction); + if (scene) { + render::Transaction transaction; + avatar->removeFromScene(avatar, scene, transaction); + scene->enqueueTransaction(transaction); + } } } else if (_shouldRender) { - // very rare transition so we process pending changes immediately + // very rare transition so we process the transaction immediately render::ScenePointer scene = qApp->getMain3DScene(); - render::Transaction transaction; - avatar->addToScene(avatar, scene, transaction); - scene->enqueueTransaction(transaction); + if (scene) { + render::Transaction transaction; + avatar->addToScene(avatar, scene, transaction); + scene->enqueueTransaction(transaction); + } } } } @@ -389,7 +395,7 @@ void AvatarManager::clearOtherAvatars() { // Remove other avatars from the world but don't actually remove them from _avatarHash // each will either be removed on timeout or will re-added to the world on receipt of update. render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; + render::Transaction transaction; QReadLocker locker(&_hashLock); AvatarHash::iterator avatarIterator = _avatarHash.begin(); @@ -397,7 +403,7 @@ void AvatarManager::clearOtherAvatars() { auto avatar = std::static_pointer_cast(avatarIterator.value()); if (avatar != _myAvatar) { if (avatar->isInScene()) { - avatar->removeFromScene(avatar, scene, pendingChanges); + avatar->removeFromScene(avatar, scene, transaction); } AvatarMotionState* motionState = avatar->getMotionState(); if (motionState) { @@ -408,16 +414,20 @@ void AvatarManager::clearOtherAvatars() { } ++avatarIterator; } - scene->enqueuePendingChanges(pendingChanges); + if (scene) { + scene->enqueueTransaction(transaction); + } _myAvatar->clearLookAtTargetAvatar(); } -void AvatarManager::clearAllAvatars() { - clearOtherAvatars(); - - QWriteLocker locker(&_hashLock); - - handleRemovedAvatar(_myAvatar); +void AvatarManager::deleteAllAvatars() { + QReadLocker locker(&_hashLock); + AvatarHash::iterator avatarIterator = _avatarHash.begin(); + while (avatarIterator != _avatarHash.end()) { + auto avatar = std::static_pointer_cast(avatarIterator.value()); + avatarIterator = _avatarHash.erase(avatarIterator); + avatar->die(); + } } void AvatarManager::setLocalLights(const QVector& localLights) { @@ -525,7 +535,9 @@ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { avatar->removeFromScene(avatar, scene, transaction); } } - scene->enqueueTransaction(transaction); + if (scene) { + scene->enqueueTransaction(transaction); + } } AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) const { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 3f053f43a6..c8229115bd 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -53,7 +53,7 @@ public: void postUpdate(float deltaTime); void clearOtherAvatars(); - void clearAllAvatars(); + void deleteAllAvatars(); bool shouldShowReceiveStats() const { return _shouldShowReceiveStats; } From 8d00f0ab8f62e2a041bf63fd64607f19d0611f47 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 7 Apr 2017 15:59:01 -0700 Subject: [PATCH 11/22] allow obj reader to either combine meshes or keep parts separate --- libraries/fbx/src/OBJReader.cpp | 14 ++++++++++---- libraries/fbx/src/OBJReader.h | 11 +++++++---- .../src/model-networking/ModelCache.cpp | 3 ++- tools/vhacd-util/src/VHACDUtil.cpp | 3 ++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index c99b847722..7b46556530 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -302,7 +302,8 @@ QNetworkReply* OBJReader::request(QUrl& url, bool isTest) { } -bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess) { +bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, + float& scaleGuess, bool combineParts) { FaceGroup faces; FBXMesh& mesh = geometry.meshes[0]; mesh.parts.append(FBXMeshPart()); @@ -348,6 +349,9 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi } QByteArray groupName = tokenizer.getDatum(); currentGroup = groupName; + if (!combineParts) { + currentMaterialName = QString("part-") + QString::number(_partCounter++); + } } else if (token == "mtllib" && !_url.isEmpty()) { if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; @@ -361,7 +365,9 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi } QString nextName = tokenizer.getDatum(); if (nextName != currentMaterialName) { - currentMaterialName = nextName; + if (combineParts) { + currentMaterialName = nextName; + } #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader new current material:" << currentMaterialName; #endif @@ -419,7 +425,7 @@ done: } -FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, const QUrl& url) { +FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url) { PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr); QBuffer buffer { &model }; buffer.open(QIODevice::ReadOnly); @@ -438,7 +444,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, try { // call parseOBJGroup as long as it's returning true. Each successful call will // add a new meshPart to the geometry's single mesh. - while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess)) {} + while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess, combineParts)) {} FBXMesh& mesh = geometry.meshes[0]; mesh.meshIndex = 0; diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index b4a48c570e..4be5705f9a 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -22,7 +22,7 @@ public: glm::vec3 getVec3(); glm::vec2 getVec2(); float getFloat() { return std::stof((nextToken() != OBJTokenizer::DATUM_TOKEN) ? nullptr : getDatum().data()); } - + private: QIODevice* _device; QByteArray _datum; @@ -73,15 +73,18 @@ public: QHash materials; QNetworkReply* request(QUrl& url, bool isTest); - FBXGeometry* readOBJ(QByteArray& model, const QVariantHash& mapping, const QUrl& url = QUrl()); - + FBXGeometry* readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl()); + private: QUrl _url; QHash librariesSeen; - bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess); + bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, + float& scaleGuess, bool combineParts); void parseMaterialLibrary(QIODevice* device); bool isValidTexture(const QByteArray &filename); // true if the file exists. TODO?: check content-type header and that it is a supported format. + + int _partCounter { 0 }; }; // What are these utilities doing here? One is used by fbx loading code in VHACD Utils, and the other a general debugging utility. diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 142ea74af4..7e1de5055d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -178,7 +178,8 @@ void GeometryReader::run() { throw QString("empty geometry, possibly due to an unsupported FBX version"); } } else if (_url.path().toLower().endsWith(".obj")) { - fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _url)); + bool combineParts = false; + fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, combineParts, _url)); } else { throw QString("unsupported format"); } diff --git a/tools/vhacd-util/src/VHACDUtil.cpp b/tools/vhacd-util/src/VHACDUtil.cpp index 30d0b5e772..0b12cb64ed 100644 --- a/tools/vhacd-util/src/VHACDUtil.cpp +++ b/tools/vhacd-util/src/VHACDUtil.cpp @@ -43,7 +43,8 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) { QByteArray fbxContents = fbx.readAll(); FBXGeometry* geom; if (filename.toLower().endsWith(".obj")) { - geom = OBJReader().readOBJ(fbxContents, QVariantHash()); + bool combineParts = false; + geom = OBJReader().readOBJ(fbxContents, QVariantHash(), combineParts); } else if (filename.toLower().endsWith(".fbx")) { geom = readFBX(fbxContents, QVariantHash(), filename); } else { From 7628916db682376b3be21714ffb2d95f185cceb9 Mon Sep 17 00:00:00 2001 From: Vladyslav Stelmakhovskyi Date: Sun, 9 Apr 2017 20:09:15 +0200 Subject: [PATCH 12/22] Check if dialog was opened from StackView and then pop or just go to home menu --- interface/resources/qml/dialogs/TabletLoginDialog.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/dialogs/TabletLoginDialog.qml b/interface/resources/qml/dialogs/TabletLoginDialog.qml index 78e5edebb5..a37f5be595 100644 --- a/interface/resources/qml/dialogs/TabletLoginDialog.qml +++ b/interface/resources/qml/dialogs/TabletLoginDialog.qml @@ -66,7 +66,11 @@ TabletModalWindow { HifiConstants { id: hifi } onCanceled: { - loginDialogRoot.Stack.view.pop() + if (loginDialogRoot.Stack.view !== null) { + loginDialogRoot.Stack.view.pop() + } else { + Tablet.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen(); + } } LoginDialog { From a1cab2c0d1cb5ea083cbcbdb42c4bb255d9f9748 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 9 Apr 2017 17:23:56 -0700 Subject: [PATCH 13/22] working toward fixing compound hulls --- .../src/model-networking/ModelCache.cpp | 22 +++++++++++-------- .../src/model-networking/ModelCache.h | 2 +- libraries/networking/src/ResourceCache.h | 4 ++-- tools/vhacd-util/src/VHACDUtilApp.cpp | 3 +++ 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 7e1de5055d..399084b42a 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -32,6 +32,7 @@ class GeometryExtra { public: const QVariantHash& mapping; const QUrl& textureBaseUrl; + bool combineParts; }; QUrl resolveTextureBaseUrl(const QUrl& url, const QUrl& textureBaseUrl) { @@ -89,7 +90,7 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) { } auto modelCache = DependencyManager::get(); - GeometryExtra extra{ mapping, _textureBaseUrl }; + GeometryExtra extra{ mapping, _textureBaseUrl, false }; // XXX // Get the raw GeometryResource _geometryResource = modelCache->getResource(url, QUrl(), &extra).staticCast(); @@ -129,8 +130,8 @@ void GeometryMappingResource::onGeometryMappingLoaded(bool success) { class GeometryReader : public QRunnable { public: GeometryReader(QWeakPointer& resource, const QUrl& url, const QVariantHash& mapping, - const QByteArray& data) : - _resource(resource), _url(url), _mapping(mapping), _data(data) { + const QByteArray& data, bool combineParts) : + _resource(resource), _url(url), _mapping(mapping), _data(data), _combineParts(combineParts) { DependencyManager::get()->incrementStat("PendingProcessing"); } @@ -142,6 +143,7 @@ private: QUrl _url; QVariantHash _mapping; QByteArray _data; + bool _combineParts; }; void GeometryReader::run() { @@ -210,8 +212,8 @@ void GeometryReader::run() { class GeometryDefinitionResource : public GeometryResource { Q_OBJECT public: - GeometryDefinitionResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) : - GeometryResource(url, resolveTextureBaseUrl(url, textureBaseUrl)), _mapping(mapping) {} + GeometryDefinitionResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl, bool combineParts) : + GeometryResource(url, resolveTextureBaseUrl(url, textureBaseUrl)), _mapping(mapping), _combineParts(combineParts) {} QString getType() const override { return "GeometryDefinition"; } @@ -222,10 +224,11 @@ protected: private: QVariantHash _mapping; + bool _combineParts; }; void GeometryDefinitionResource::downloadFinished(const QByteArray& data) { - QThreadPool::globalInstance()->start(new GeometryReader(_self, _url, _mapping, data)); + QThreadPool::globalInstance()->start(new GeometryReader(_self, _url, _mapping, data, _combineParts)); } void GeometryDefinitionResource::setGeometryDefinition(FBXGeometry::Pointer fbxGeometry) { @@ -266,7 +269,7 @@ ModelCache::ModelCache() { } QSharedPointer ModelCache::createResource(const QUrl& url, const QSharedPointer& fallback, - const void* extra) { + const void* extra) { Resource* resource = nullptr; if (url.path().toLower().endsWith(".fst")) { resource = new GeometryMappingResource(url); @@ -274,14 +277,15 @@ QSharedPointer ModelCache::createResource(const QUrl& url, const QShar const GeometryExtra* geometryExtra = static_cast(extra); auto mapping = geometryExtra ? geometryExtra->mapping : QVariantHash(); auto textureBaseUrl = geometryExtra ? geometryExtra->textureBaseUrl : QUrl(); - resource = new GeometryDefinitionResource(url, mapping, textureBaseUrl); + bool combineParts = geometryExtra ? geometryExtra->combineParts : false; + resource = new GeometryDefinitionResource(url, mapping, textureBaseUrl, combineParts); } return QSharedPointer(resource, &Resource::deleter); } GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) { - GeometryExtra geometryExtra = { mapping, textureBaseUrl }; + GeometryExtra geometryExtra = { mapping, textureBaseUrl, false }; // XXX GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra).staticCast(); if (resource) { if (resource->isLoaded() && resource->shouldSetTextures()) { diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 2cd96a84c7..3952924b27 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -142,7 +142,7 @@ protected: friend class GeometryMappingResource; virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, - const void* extra) override; + const void* extra) override; private: ModelCache(); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 8f1f1baed2..53ccd2c386 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -295,8 +295,8 @@ protected: /// Creates a new resource. virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, - const void* extra) = 0; - + const void* extra) = 0; + void addUnusedResource(const QSharedPointer& resource); void removeUnusedResource(const QSharedPointer& resource); diff --git a/tools/vhacd-util/src/VHACDUtilApp.cpp b/tools/vhacd-util/src/VHACDUtilApp.cpp index cae184a49c..4d48bdf2bf 100644 --- a/tools/vhacd-util/src/VHACDUtilApp.cpp +++ b/tools/vhacd-util/src/VHACDUtilApp.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include "VHACDUtilApp.h" #include "VHACDUtil.h" @@ -98,6 +99,8 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) : { vhacd::VHACDUtil vUtil; + DependencyManager::set(); + // parse command-line QCommandLineParser parser; parser.setApplicationDescription("High Fidelity Object Decomposer"); From 393b24452d73b17850a0246774a9778b9e868043 Mon Sep 17 00:00:00 2001 From: Vladyslav Stelmakhovskyi Date: Mon, 10 Apr 2017 17:07:59 +0200 Subject: [PATCH 14/22] Added hover to Snaps and Places --- interface/resources/qml/hifi/TabletTextButton.qml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/TabletTextButton.qml b/interface/resources/qml/hifi/TabletTextButton.qml index 12e53eb217..e5ff1d381d 100644 --- a/interface/resources/qml/hifi/TabletTextButton.qml +++ b/interface/resources/qml/hifi/TabletTextButton.qml @@ -16,6 +16,7 @@ Rectangle { property alias text: label.text property alias pixelSize: label.font.pixelSize; property bool selected: false + property bool hovered: false property int spacing: 2 property var action: function () {} property string highlightColor: hifi.colors.blueHighlight; @@ -37,14 +38,14 @@ Rectangle { Rectangle { id: indicator width: parent.width - height: 3 + height: selected ? 3 : 1 anchors { left: parent.left right: parent.right bottom: parent.bottom } color: hifi.colors.blueHighlight - visible: parent.selected + visible: parent.selected || hovered } MouseArea { @@ -53,6 +54,8 @@ Rectangle { acceptedButtons: Qt.LeftButton; onClicked: action(parent); hoverEnabled: true; + onEntered: hovered = true + onExited: hovered = false } } From 554b23357c4c76b3c1402eb3afe04114cc60bbab Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 10 Apr 2017 10:14:36 -0700 Subject: [PATCH 15/22] add combineParts flag to getGeometryResource. append ?collsion-hull to urls that are used as compound collision hulls --- .../src/RenderableModelEntityItem.cpp | 9 +++++---- .../src/model-networking/ModelCache.cpp | 12 ++++++------ .../src/model-networking/ModelCache.h | 4 +++- libraries/render-utils/src/Model.cpp | 2 +- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 91a4fc2ff9..3f2f4308b3 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -611,7 +611,7 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) { ModelEntityItem::setShapeType(type); if (getShapeType() == SHAPE_TYPE_COMPOUND) { if (!_compoundShapeResource && !getCompoundShapeURL().isEmpty()) { - _compoundShapeResource = DependencyManager::get()->getGeometryResource(getCompoundShapeURL()); + _compoundShapeResource = DependencyManager::get()->getGeometryResource(getCompoundShapeURL(), false); } } else if (_compoundShapeResource && !getCompoundShapeURL().isEmpty()) { // the compoundURL has been set but the shapeType does not agree @@ -621,7 +621,8 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) { void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { auto currentCompoundShapeURL = getCompoundShapeURL(); - ModelEntityItem::setCompoundShapeURL(url); + QString hullURL = url + "?collision-hull"; + ModelEntityItem::setCompoundShapeURL(hullURL); if (getCompoundShapeURL() != currentCompoundShapeURL || !_model) { EntityTreePointer tree = getTree(); @@ -629,7 +630,7 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID())); } if (getShapeType() == SHAPE_TYPE_COMPOUND) { - _compoundShapeResource = DependencyManager::get()->getGeometryResource(url); + _compoundShapeResource = DependencyManager::get()->getGeometryResource(hullURL, false); } } } @@ -661,7 +662,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { } return true; } else if (!getCompoundShapeURL().isEmpty()) { - _compoundShapeResource = DependencyManager::get()->getGeometryResource(getCompoundShapeURL()); + _compoundShapeResource = DependencyManager::get()->getGeometryResource(getCompoundShapeURL(), false); } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 399084b42a..b701c9ae3b 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -90,7 +90,7 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) { } auto modelCache = DependencyManager::get(); - GeometryExtra extra{ mapping, _textureBaseUrl, false }; // XXX + GeometryExtra extra{ mapping, _textureBaseUrl, false }; // Get the raw GeometryResource _geometryResource = modelCache->getResource(url, QUrl(), &extra).staticCast(); @@ -180,8 +180,7 @@ void GeometryReader::run() { throw QString("empty geometry, possibly due to an unsupported FBX version"); } } else if (_url.path().toLower().endsWith(".obj")) { - bool combineParts = false; - fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, combineParts, _url)); + fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _combineParts, _url)); } else { throw QString("unsupported format"); } @@ -277,15 +276,16 @@ QSharedPointer ModelCache::createResource(const QUrl& url, const QShar const GeometryExtra* geometryExtra = static_cast(extra); auto mapping = geometryExtra ? geometryExtra->mapping : QVariantHash(); auto textureBaseUrl = geometryExtra ? geometryExtra->textureBaseUrl : QUrl(); - bool combineParts = geometryExtra ? geometryExtra->combineParts : false; + bool combineParts = geometryExtra ? geometryExtra->combineParts : true; resource = new GeometryDefinitionResource(url, mapping, textureBaseUrl, combineParts); } return QSharedPointer(resource, &Resource::deleter); } -GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) { - GeometryExtra geometryExtra = { mapping, textureBaseUrl, false }; // XXX +GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, bool combineParts, + const QVariantHash& mapping, const QUrl& textureBaseUrl) { + GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts }; GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra).staticCast(); if (resource) { if (resource->isLoaded() && resource->shouldSetTextures()) { diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 3952924b27..b48249ec42 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -136,7 +136,9 @@ class ModelCache : public ResourceCache, public Dependency { public: GeometryResource::Pointer getGeometryResource(const QUrl& url, - const QVariantHash& mapping = QVariantHash(), const QUrl& textureBaseUrl = QUrl()); + bool combineParts, + const QVariantHash& mapping = QVariantHash(), + const QUrl& textureBaseUrl = QUrl()); protected: friend class GeometryMappingResource; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index c274d69af6..f452f7c37e 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -811,7 +811,7 @@ void Model::setURL(const QUrl& url) { invalidCalculatedMeshBoxes(); deleteGeometry(); - auto resource = DependencyManager::get()->getGeometryResource(url); + auto resource = DependencyManager::get()->getGeometryResource(url, true); resource->setLoadPriority(this, _loadingPriority); _renderWatcher.setResource(resource); onInvalidate(); From 717436e0fded47ab9e0172393e8aa5e5dc5a3c1e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 10 Apr 2017 10:54:30 -0700 Subject: [PATCH 16/22] use QUrl rather than just munging the url with a string-append --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 3f2f4308b3..0ff68b4e6a 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -621,8 +622,11 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) { void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { auto currentCompoundShapeURL = getCompoundShapeURL(); - QString hullURL = url + "?collision-hull"; - ModelEntityItem::setCompoundShapeURL(hullURL); + QUrl hullURL(url); + QUrlQuery queryArgs(hullURL); + queryArgs.addQueryItem("collision-hull", ""); + hullURL.setQuery(queryArgs); + ModelEntityItem::setCompoundShapeURL(hullURL.toString()); if (getCompoundShapeURL() != currentCompoundShapeURL || !_model) { EntityTreePointer tree = getTree(); From b57bf956e20e92b4f2494639883c989d59c3bf4b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Apr 2017 11:23:43 -0700 Subject: [PATCH 17/22] make server plugins a dependency of AC too --- .../macros/SetupHifiClientServerPlugin.cmake | 98 ++++++++++--------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/cmake/macros/SetupHifiClientServerPlugin.cmake b/cmake/macros/SetupHifiClientServerPlugin.cmake index 0ce7796756..37b000efb5 100644 --- a/cmake/macros/SetupHifiClientServerPlugin.cmake +++ b/cmake/macros/SetupHifiClientServerPlugin.cmake @@ -6,56 +6,60 @@ # See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN) - set(${TARGET_NAME}_SHARED 1) - setup_hifi_library(${ARGV}) - if (NOT DEFINED SERVER_ONLY) - add_dependencies(interface ${TARGET_NAME}) - endif() - set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Plugins") + set(${TARGET_NAME}_SHARED 1) + setup_hifi_library(${ARGV}) - if (APPLE) - set(CLIENT_PLUGIN_PATH "${INTERFACE_BUNDLE_NAME}.app/Contents/PlugIns") - set(SERVER_PLUGIN_PATH "plugins") - else() - set(CLIENT_PLUGIN_PATH "plugins") - set(SERVER_PLUGIN_PATH "plugins") - endif() + if (NOT DEFINED SERVER_ONLY) + add_dependencies(interface ${TARGET_NAME}) + endif() - if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_GENERATOR STREQUAL "Unix Makefiles") - set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/${CLIENT_PLUGIN_PATH}/") - set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/${SERVER_PLUGIN_PATH}/") - elseif (APPLE) - set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/$/${CLIENT_PLUGIN_PATH}/") - set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/$/${SERVER_PLUGIN_PATH}/") - else() - set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/$/${CLIENT_PLUGIN_PATH}/") - set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/$/${SERVER_PLUGIN_PATH}/") - endif() + add_dependencies(assignment-client ${TARGET_NAME}) - # create the destination for the client plugin binaries - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E make_directory - ${CLIENT_PLUGIN_FULL_PATH} - ) - # copy the client plugin binaries - add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy - "$" - ${CLIENT_PLUGIN_FULL_PATH} - ) + set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Plugins") - # create the destination for the server plugin binaries - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E make_directory - ${SERVER_PLUGIN_FULL_PATH} - ) - # copy the server plugin binaries - add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy - "$" - ${SERVER_PLUGIN_FULL_PATH} - ) + if (APPLE) + set(CLIENT_PLUGIN_PATH "${INTERFACE_BUNDLE_NAME}.app/Contents/PlugIns") + set(SERVER_PLUGIN_PATH "plugins") + else() + set(CLIENT_PLUGIN_PATH "plugins") + set(SERVER_PLUGIN_PATH "plugins") + endif() + + if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_GENERATOR STREQUAL "Unix Makefiles") + set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/${CLIENT_PLUGIN_PATH}/") + set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/${SERVER_PLUGIN_PATH}/") + elseif (APPLE) + set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/$/${CLIENT_PLUGIN_PATH}/") + set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/$/${SERVER_PLUGIN_PATH}/") + else() + set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/$/${CLIENT_PLUGIN_PATH}/") + set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/$/${SERVER_PLUGIN_PATH}/") + endif() + + # create the destination for the client plugin binaries + add_custom_command( + TARGET ${TARGET_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E make_directory + ${CLIENT_PLUGIN_FULL_PATH} + ) + # copy the client plugin binaries + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy + "$" + ${CLIENT_PLUGIN_FULL_PATH} + ) + + # create the destination for the server plugin binaries + add_custom_command( + TARGET ${TARGET_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E make_directory + ${SERVER_PLUGIN_FULL_PATH} + ) + # copy the server plugin binaries + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy + "$" + ${SERVER_PLUGIN_FULL_PATH} + ) endmacro() From 5fc4bbc260404ca45d394711c9d39134b70ad711 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 10 Apr 2017 12:26:34 -0700 Subject: [PATCH 18/22] re-enable the info button for user images on nearby tab --- interface/resources/qml/hifi/NameCard.qml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 6be85f2ea6..554df82d9e 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -81,6 +81,25 @@ Item { anchors.fill: parent; visible: userImage.status != Image.Ready; } + StateImage { + id: infoHoverImage; + visible: false; + imageURL: "../../images/info-icon-2-state.svg"; + size: 32; + buttonState: 1; + anchors.centerIn: parent; + } + MouseArea { + anchors.fill: parent + enabled: (selected || isMyCard) && activeTab == "nearbyTab"; + hoverEnabled: enabled + onClicked: { + userInfoViewer.url = defaultBaseUrl + "/users/" + userName; + userInfoViewer.visible = true; + } + onEntered: infoHoverImage.visible = true; + onExited: infoHoverImage.visible = false; + } } // Colored border around avatarImage From 6bd841857f6a00d6decc924493dc0939624d7eb7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 10 Apr 2017 13:50:36 -0700 Subject: [PATCH 19/22] added a comment --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 0ff68b4e6a..d30baaa6eb 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -621,6 +621,10 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) { } void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { + // because the caching system only allows one Geometry per url, and because this url might also be used + // as a visual model, we need to change this url in some way. We add a "collision-hull" query-arg so it + // will end up in a different hash-key in ResourceCache. TODO: It would be better to use the same URL and + // parse it twice. auto currentCompoundShapeURL = getCompoundShapeURL(); QUrl hullURL(url); QUrlQuery queryArgs(hullURL); From 8a3a52cbcf3b922a26944df6da87bb0dedb23b53 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 10 Apr 2017 13:54:24 -0700 Subject: [PATCH 20/22] make getCollisionGeometryResource a separate call from getGeometryResource rather than passing a bool --- .../src/RenderableModelEntityItem.cpp | 7 ++++--- .../src/model-networking/ModelCache.cpp | 16 +++++++++++++++- .../src/model-networking/ModelCache.h | 5 ++++- libraries/render-utils/src/Model.cpp | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index d30baaa6eb..cb950e244a 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -612,7 +612,7 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) { ModelEntityItem::setShapeType(type); if (getShapeType() == SHAPE_TYPE_COMPOUND) { if (!_compoundShapeResource && !getCompoundShapeURL().isEmpty()) { - _compoundShapeResource = DependencyManager::get()->getGeometryResource(getCompoundShapeURL(), false); + _compoundShapeResource = DependencyManager::get()->getCollisionGeometryResource(getCompoundShapeURL()); } } else if (_compoundShapeResource && !getCompoundShapeURL().isEmpty()) { // the compoundURL has been set but the shapeType does not agree @@ -638,7 +638,7 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID())); } if (getShapeType() == SHAPE_TYPE_COMPOUND) { - _compoundShapeResource = DependencyManager::get()->getGeometryResource(hullURL, false); + _compoundShapeResource = DependencyManager::get()->getCollisionGeometryResource(hullURL); } } } @@ -670,7 +670,8 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { } return true; } else if (!getCompoundShapeURL().isEmpty()) { - _compoundShapeResource = DependencyManager::get()->getGeometryResource(getCompoundShapeURL(), false); + _compoundShapeResource = + DependencyManager::get()->getCollisionGeometryResource(getCompoundShapeURL()); } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index b701c9ae3b..d9c5294be2 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -283,8 +283,22 @@ QSharedPointer ModelCache::createResource(const QUrl& url, const QShar return QSharedPointer(resource, &Resource::deleter); } -GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, bool combineParts, +GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) { + bool combineParts = true; + GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts }; + GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra).staticCast(); + if (resource) { + if (resource->isLoaded() && resource->shouldSetTextures()) { + resource->setTextures(); + } + } + return resource; +} + +GeometryResource::Pointer ModelCache::getCollisionGeometryResource(const QUrl& url, + const QVariantHash& mapping, const QUrl& textureBaseUrl) { + bool combineParts = false; GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts }; GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra).staticCast(); if (resource) { diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index b48249ec42..967897477d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -136,10 +136,13 @@ class ModelCache : public ResourceCache, public Dependency { public: GeometryResource::Pointer getGeometryResource(const QUrl& url, - bool combineParts, const QVariantHash& mapping = QVariantHash(), const QUrl& textureBaseUrl = QUrl()); + GeometryResource::Pointer getCollisionGeometryResource(const QUrl& url, + const QVariantHash& mapping = QVariantHash(), + const QUrl& textureBaseUrl = QUrl()); + protected: friend class GeometryMappingResource; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index f452f7c37e..c274d69af6 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -811,7 +811,7 @@ void Model::setURL(const QUrl& url) { invalidCalculatedMeshBoxes(); deleteGeometry(); - auto resource = DependencyManager::get()->getGeometryResource(url, true); + auto resource = DependencyManager::get()->getGeometryResource(url); resource->setLoadPriority(this, _loadingPriority); _renderWatcher.setResource(resource); onInvalidate(); From e86db2622436889fec71dc0848753f843581cc6a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Apr 2017 14:31:02 -0700 Subject: [PATCH 21/22] Revert "fix relative/absolute path handling for external FBX textures" --- libraries/animation/src/AnimationCache.cpp | 2 +- libraries/fbx/src/FBXReader.cpp | 69 ++++++------------- libraries/fbx/src/FBXReader.h | 12 ++-- libraries/fbx/src/FBXReader_Material.cpp | 9 ++- libraries/fbx/src/FBXReader_Mesh.cpp | 2 +- .../src/model-networking/ModelCache.cpp | 2 +- 6 files changed, 39 insertions(+), 57 deletions(-) diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index 23c9d1d0b5..6594482085 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -74,7 +74,7 @@ void AnimationReader::run() { // Parse the FBX directly from the QNetworkReply FBXGeometry::Pointer fbxgeo; if (_url.path().toLower().endsWith(".fbx")) { - fbxgeo.reset(readFBX(_data, QVariantHash(), _url)); + fbxgeo.reset(readFBX(_data, QVariantHash(), _url.path())); } else { QString errorStr("usupported format"); emit onError(299, errorStr); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index bcd2be3384..64ee0bc869 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -376,10 +376,10 @@ public: }; bool checkMaterialsHaveTextures(const QHash& materials, - const QHash& textureFilepaths, const QMultiMap& _connectionChildMap) { + const QHash& textureFilenames, const QMultiMap& _connectionChildMap) { foreach (const QString& materialID, materials.keys()) { foreach (const QString& childID, _connectionChildMap.values(materialID)) { - if (textureFilepaths.contains(childID)) { + if (textureFilenames.contains(childID)) { return true; } } @@ -443,48 +443,21 @@ FBXLight extractLight(const FBXNode& object) { return light; } -QByteArray fixedTextureFilepath(QByteArray fbxRelativeFilepath, QUrl url) { - // first setup a QFileInfo for the passed relative filepath, with backslashes replaced by forward slashes - auto fileInfo = QFileInfo { fbxRelativeFilepath.replace("\\", "/") }; +QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) { + QString path = QFileInfo(url).path(); + QByteArray filename = filepath; + QFileInfo checkFile(path + "/" + filepath); -#ifndef Q_OS_WIN - // it turns out that absolute windows paths starting with drive letters look like relative paths to QFileInfo on UNIX - // so we add a check for that here to work around it - bool isRelative = fbxRelativeFilepath[1] != ':' && fileInfo.isRelative(); -#else - bool isRelative = fileInfo.isRelative(); -#endif - - if (isRelative) { - // the RelativeFilename pulled from the FBX is already correctly relative - // so simply return this as the filepath to use - return fbxRelativeFilepath; - } else { - // the RelativeFilename pulled from the FBX is an absolute path - - // use the URL to figure out where the FBX is being loaded from - auto filename = fileInfo.fileName(); - - if (url.isLocalFile()) { - // the FBX is being loaded from the local filesystem - - if (fileInfo.exists() && fileInfo.isFile()) { - // found a file at the absolute path in the FBX, return that path - return fbxRelativeFilepath; - } else { - // didn't find a file at the absolute path, assume it is right beside the FBX - // return just the filename as the relative path - return filename.toUtf8(); - } - } else { - // this is a remote file, meaning we can't really do anything with the absolute path to the texture - // so assume it will be right beside the fbx - return filename.toUtf8(); - } + // check if the file exists at the RelativeFilename + if (!(checkFile.exists() && checkFile.isFile())) { + // if not, assume it is in the fbx directory + filename = filename.mid(filename.lastIndexOf('/') + 1); } + + return filename; } -FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QUrl& url) { +FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) { const FBXNode& node = _fbxNode; QMap meshes; QHash modelIDsToNames; @@ -860,9 +833,11 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QU const int MODEL_UV_SCALING_MIN_SIZE = 2; const int CROPPING_MIN_SIZE = 4; if (subobject.name == "RelativeFilename" && subobject.properties.length() >= RELATIVE_FILENAME_MIN_SIZE) { - auto filepath = fixedTextureFilepath(subobject.properties.at(0).toByteArray(), url); - + QByteArray filename = subobject.properties.at(0).toByteArray(); + QByteArray filepath = filename.replace('\\', '/'); + filename = fileOnUrl(filepath, url); _textureFilepaths.insert(getID(object.properties), filepath); + _textureFilenames.insert(getID(object.properties), filename); } else if (subobject.name == "TextureName" && subobject.properties.length() >= TEXTURE_NAME_MIN_SIZE) { // trim the name from the timestamp QString name = QString(subobject.properties.at(0).toByteArray()); @@ -955,7 +930,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QU QByteArray content; foreach (const FBXNode& subobject, object.children) { if (subobject.name == "RelativeFilename") { - filepath = subobject.properties.at(0).toByteArray(); + filepath= subobject.properties.at(0).toByteArray(); filepath = filepath.replace('\\', '/'); } else if (subobject.name == "Content" && !subobject.properties.isEmpty()) { @@ -1527,7 +1502,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QU geometry.materials = _fbxMaterials; // see if any materials have texture children - bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilepaths, _connectionChildMap); + bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilenames, _connectionChildMap); for (QMap::iterator it = meshes.begin(); it != meshes.end(); it++) { ExtractedMesh& extracted = it.value(); @@ -1572,7 +1547,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QU materialIndex++; - } else if (_textureFilepaths.contains(childID)) { + } else if (_textureFilenames.contains(childID)) { FBXTexture texture = getTexture(childID); for (int j = 0; j < extracted.partMaterialTextures.size(); j++) { int partTexture = extracted.partMaterialTextures.at(j).second; @@ -1843,13 +1818,13 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QU return geometryPtr; } -FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QUrl& url, bool loadLightmaps, float lightmapLevel) { +FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { QBuffer buffer(const_cast(&model)); buffer.open(QIODevice::ReadOnly); return readFBX(&buffer, mapping, url, loadLightmaps, lightmapLevel); } -FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QUrl& url, bool loadLightmaps, float lightmapLevel) { +FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { FBXReader reader; reader._fbxNode = FBXReader::parseFBX(device); reader._loadLightmaps = loadLightmaps; diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index dd746322e9..f73088e7a1 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -268,7 +268,7 @@ class FBXGeometry { public: using Pointer = std::shared_ptr; - QUrl originalURL; + QString originalURL; QString author; QString applicationName; ///< the name of the application that generated the model @@ -330,11 +330,11 @@ Q_DECLARE_METATYPE(FBXGeometry::Pointer) /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QUrl& url = QUrl(), bool loadLightmaps = true, float lightmapLevel = 1.0f); +FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QUrl& url = QUrl(), bool loadLightmaps = true, float lightmapLevel = 1.0f); +FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); class TextureParam { public: @@ -402,17 +402,19 @@ public: FBXNode _fbxNode; static FBXNode parseFBX(QIODevice* device); - FBXGeometry* extractFBXGeometry(const QVariantHash& mapping, const QUrl& url); + FBXGeometry* extractFBXGeometry(const QVariantHash& mapping, const QString& url); ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex); QHash meshes; - static void buildModelMesh(FBXMesh& extractedMesh, const QUrl& url); + static void buildModelMesh(FBXMesh& extractedMesh, const QString& url); FBXTexture getTexture(const QString& textureID); QHash _textureNames; // Hashes the original RelativeFilename of textures QHash _textureFilepaths; + // Hashes the place to look for textures, in case they are not inlined + QHash _textureFilenames; // Hashes texture content by filepath, in case they are inlined QHash _textureContent; QHash _textureParams; diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index 2f63d894fd..ca2ec557b4 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -85,7 +85,12 @@ FBXTexture FBXReader::getTexture(const QString& textureID) { FBXTexture texture; const QByteArray& filepath = _textureFilepaths.value(textureID); texture.content = _textureContent.value(filepath); - texture.filename = filepath; + + if (texture.content.isEmpty()) { // the content is not inlined + texture.filename = _textureFilenames.value(textureID); + } else { // use supplied filepath for inlined content + texture.filename = filepath; + } texture.name = _textureNames.value(textureID); texture.transform.setIdentity(); @@ -150,7 +155,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { // FBX files generated by 3DSMax have an intermediate texture parent, apparently foreach(const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) { - if (_textureFilepaths.contains(childTextureID)) { + if (_textureFilenames.contains(childTextureID)) { diffuseTexture = getTexture(diffuseTextureID); } } diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index a6d70408ae..4e153dfe3a 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -388,7 +388,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn return data.extracted; } -void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QUrl& url) { +void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("buildModelMesh failed -- .*"); unsigned int totalSourceIndices = 0; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 142ea74af4..dd3193073d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -173,7 +173,7 @@ void GeometryReader::run() { FBXGeometry::Pointer fbxGeometry; if (_url.path().toLower().endsWith(".fbx")) { - fbxGeometry.reset(readFBX(_data, _mapping, _url)); + fbxGeometry.reset(readFBX(_data, _mapping, _url.path())); if (fbxGeometry->meshes.size() == 0 && fbxGeometry->joints.size() == 0) { throw QString("empty geometry, possibly due to an unsupported FBX version"); } From eb281389f5ceb715f77acfaaa0b5cbd83394c8b7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 10 Apr 2017 14:46:31 -0700 Subject: [PATCH 22/22] fix includeActions so places show up in All --- interface/resources/qml/hifi/tablet/TabletAddressDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 39892f27a4..356ff92664 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -255,7 +255,7 @@ StackView { TabletTextButton { id: allTab; text: "ALL"; - property string includeActions: 'snapshot, concurrency'; + property string includeActions: 'snapshot,concurrency'; selected: allTab === selectedTab; action: tabSelect; }