From 37541e4ed2ce178508db014664139d650e78b324 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 10 Feb 2017 14:29:29 -0800 Subject: [PATCH 01/64] Start capping the time budget for draw opaque --- .../render-utils/src/RenderDeferredTask.cpp | 3 +- libraries/render/src/render/DrawTask.cpp | 105 ++++++++++++++++++ libraries/render/src/render/DrawTask.h | 2 +- 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 55a9c8b9e4..82db502af1 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -295,7 +295,8 @@ void DrawStateSortDeferred::run(const SceneContextPointer& sceneContext, const R batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); if (_stateSort) { - renderStateSortShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); + // renderStateSortShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); + renderStateSortShapesCapped(sceneContext, renderContext, _shapePlumber, inItems, 2.0, _maxDrawn); } else { renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); } diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 2829c6f8e7..d6f09f735c 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -123,6 +123,111 @@ void render::renderStateSortShapes(const SceneContextPointer& sceneContext, cons } } + +void render::renderStateSortShapesCapped(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, double mstimeBudget, int maxDrawnItems) { + + auto& scene = sceneContext->_scene; + RenderArgs* args = renderContext->args; + auto now = usecTimestampNow(); + + int numItemsToDraw = (int)inItems.size(); + if (maxDrawnItems != -1) { + numItemsToDraw = glm::min(numItemsToDraw, maxDrawnItems); + } + + using SortedPipelines = std::vector; + using SortedShapes = std::unordered_map, render::ShapeKey::Hash, render::ShapeKey::KeyEqual>; + SortedPipelines sortedPipelines; + SortedShapes sortedShapes; + std::vector ownPipelineBucket; + + { + PROFILE_RANGE(render_detail, "sort"); + + for (auto i = 0; i < numItemsToDraw; ++i) { + auto item = scene->getItem(inItems[i].id); + + { + assert(item.getKey().isShape()); + const auto key = item.getShapeKey(); + if (key.isValid() && !key.hasOwnPipeline()) { + auto& bucket = sortedShapes[key]; + if (bucket.empty()) { + sortedPipelines.push_back(key); + } + bucket.push_back(item); + } else if (key.hasOwnPipeline()) { + ownPipelineBucket.push_back(item); + } else { + qCDebug(renderlogging) << "Item could not be rendered with invalid key" << key; + } + } + } + } + + { + PROFILE_RANGE(render_detail, "render"); + + // Then render + quint64 usecHalfBudget = 1000 * 0.5 * mstimeBudget; + quint64 usecBudget = 1000 * mstimeBudget; + + int numDrawCalls = 0; + int numDrawcallsChecks = 128; + int numChecks = 0; + int numChecksBudget = 4; + + for (auto& pipelineKey : sortedPipelines) { + auto& bucket = sortedShapes[pipelineKey]; + args->_pipeline = shapeContext->pickPipeline(args, pipelineKey); + if (!args->_pipeline) { + continue; + } + for (auto& item : bucket) { + item.render(args); + + numDrawCalls++; + if ((numDrawCalls % numDrawcallsChecks) == 0) { + auto newNow = usecTimestampNow(); + if ((newNow - now) > usecHalfBudget) { + if ((newNow - now) > usecBudget) { + return; + } + + usecHalfBudget += (usecHalfBudget / 2); + numDrawcallsChecks / 2; + numChecks++; + if (numChecks > numChecksBudget) { + return; + } + } + } + } + } + args->_pipeline = nullptr; + for (auto& item : ownPipelineBucket) { + item.render(args); + + numDrawCalls++; + if ((numDrawCalls % numDrawcallsChecks) == 0) { + auto newNow = usecTimestampNow(); + if ((newNow - now) > usecHalfBudget) { + if ((newNow - now) > usecBudget) { + return; + } + + usecHalfBudget += (usecHalfBudget / 2); + numDrawcallsChecks / 2; + numChecks++; + if (numChecks > numChecksBudget) { + return; + } + } + } + } + } +} + void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inLights) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 27f07921c3..042a927caf 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -19,7 +19,7 @@ namespace render { void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems = -1); void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); void renderStateSortShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); - +void renderStateSortShapesCapped(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, double mstimeBudget, int maxDrawnItems = -1); class DrawLightConfig : public Job::Config { From 9261e81ba2f4004fad6b613e54ee29acaf6ee8ce Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 10 Feb 2017 17:47:56 -0800 Subject: [PATCH 02/64] Cleaning up the interface --- .../render-utils/src/RenderDeferredTask.cpp | 2 +- libraries/render-utils/src/RenderDeferredTask.h | 5 ++++- scripts/developer/utilities/render/culling.qml | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 82db502af1..24e284a416 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -296,7 +296,7 @@ void DrawStateSortDeferred::run(const SceneContextPointer& sceneContext, const R if (_stateSort) { // renderStateSortShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); - renderStateSortShapesCapped(sceneContext, renderContext, _shapePlumber, inItems, 2.0, _maxDrawn); + renderStateSortShapesCapped(sceneContext, renderContext, _shapePlumber, inItems, _maxTimeBudget, _maxDrawn); } else { renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); } diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 8a95447e67..2d9a7d4888 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -85,6 +85,7 @@ class DrawStateSortConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged) Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) + Q_PROPERTY(float maxTimeBudget MEMBER maxTimeBudget NOTIFY dirty) Q_PROPERTY(bool stateSort MEMBER stateSort NOTIFY dirty) public: @@ -92,6 +93,7 @@ public: void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); } int maxDrawn{ -1 }; + float maxTimeBudget { 8.0f }; // 8ms maximum bool stateSort{ true }; signals: @@ -111,12 +113,13 @@ public: DrawStateSortDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} - void configure(const Config& config) { _maxDrawn = config.maxDrawn; _stateSort = config.stateSort; } + void configure(const Config& config) { _maxDrawn = config.maxDrawn; _maxTimeBudget = config.maxTimeBudget; _stateSort = config.stateSort; } void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: render::ShapePlumberPointer _shapePlumber; int _maxDrawn; // initialized by Config + float _maxTimeBudget; //ms time budget bool _stateSort; }; diff --git a/scripts/developer/utilities/render/culling.qml b/scripts/developer/utilities/render/culling.qml index e3f5e67bbe..4157b5e4dd 100644 --- a/scripts/developer/utilities/render/culling.qml +++ b/scripts/developer/utilities/render/culling.qml @@ -95,6 +95,7 @@ Column { GroupBox { title: "Render Items" + Column{ Column{ Repeater { @@ -110,5 +111,20 @@ Column { } } } + + Column{ + Repeater { + model: [ "Draw Opaque [ms]:DrawOpaqueDeferred" ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: false + config: Render.getConfig(modelData.split(":")[1]) + property: "maxTimeBudget" + max: 10.0 + min: 0.0 + } + } + } + } } } From 127a014b4694fdbd8dac2d16799249b82d49a203 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 15 Feb 2017 15:21:08 -0800 Subject: [PATCH 03/64] Clear caches on domain switch --- interface/src/Application.cpp | 7 +++++++ libraries/networking/src/ResourceCache.cpp | 6 +++--- libraries/networking/src/ResourceCache.h | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 488e97b5e6..1b83419db7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5152,6 +5152,7 @@ void Application::updateWindowTitle() const { #endif _window->setWindowTitle(title); } + void Application::clearDomainOctreeDetails() { // if we're about to quit, we really don't need to do any of these things... @@ -5181,6 +5182,12 @@ void Application::clearDomainOctreeDetails() { skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT); _recentlyClearedDomain = true; + + DependencyManager::get()->clearOtherAvatars(); + DependencyManager::get()->clearUnusedResources(); + DependencyManager::get()->clearUnusedResources(); + DependencyManager::get()->clearUnusedResources(); + DependencyManager::get()->clearUnusedResources(); } void Application::domainChanged(const QString& domainHostname) { diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index d95c6f140f..0396e0ed94 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -221,7 +221,7 @@ ResourceCache::ResourceCache(QObject* parent) : QObject(parent) { } ResourceCache::~ResourceCache() { - clearUnusedResource(); + clearUnusedResources(); } void ResourceCache::clearATPAssets() { @@ -265,7 +265,7 @@ void ResourceCache::clearATPAssets() { void ResourceCache::refreshAll() { // Clear all unused resources so we don't have to reload them - clearUnusedResource(); + clearUnusedResources(); resetResourceCounters(); QHash> resources; @@ -418,7 +418,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { } } -void ResourceCache::clearUnusedResource() { +void ResourceCache::clearUnusedResources() { // the unused resources may themselves reference resources that will be added to the unused // list on destruction, so keep clearing until there are no references left QWriteLocker locker(&_unusedResourcesLock); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index a369416ebe..8f1f1baed2 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -249,6 +249,7 @@ public: void refreshAll(); void refresh(const QUrl& url); + void clearUnusedResources(); signals: void dirty(); @@ -298,7 +299,7 @@ protected: void addUnusedResource(const QSharedPointer& resource); void removeUnusedResource(const QSharedPointer& resource); - + /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading /// \return true if the resource began loading, otherwise false if the resource is in the pending queue static bool attemptRequest(QSharedPointer resource); @@ -309,7 +310,6 @@ private: friend class Resource; void reserveUnusedResource(qint64 resourceSize); - void clearUnusedResource(); void resetResourceCounters(); void removeResource(const QUrl& url, qint64 size = 0); From 55611d2373f6fd4fa7f1e1ced5687ac634529c3a Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 21 Feb 2017 14:56:07 -0800 Subject: [PATCH 04/64] Backing up to master --- .../render-utils/src/RenderDeferredTask.cpp | 3 +- .../render-utils/src/RenderDeferredTask.h | 5 +- libraries/render/src/render/DrawTask.cpp | 105 ------------------ libraries/render/src/render/DrawTask.h | 1 - .../developer/utilities/render/culling.qml | 16 --- 5 files changed, 2 insertions(+), 128 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 24e284a416..55a9c8b9e4 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -295,8 +295,7 @@ void DrawStateSortDeferred::run(const SceneContextPointer& sceneContext, const R batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); if (_stateSort) { - // renderStateSortShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); - renderStateSortShapesCapped(sceneContext, renderContext, _shapePlumber, inItems, _maxTimeBudget, _maxDrawn); + renderStateSortShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); } else { renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); } diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 2d9a7d4888..8a95447e67 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -85,7 +85,6 @@ class DrawStateSortConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged) Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) - Q_PROPERTY(float maxTimeBudget MEMBER maxTimeBudget NOTIFY dirty) Q_PROPERTY(bool stateSort MEMBER stateSort NOTIFY dirty) public: @@ -93,7 +92,6 @@ public: void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); } int maxDrawn{ -1 }; - float maxTimeBudget { 8.0f }; // 8ms maximum bool stateSort{ true }; signals: @@ -113,13 +111,12 @@ public: DrawStateSortDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} - void configure(const Config& config) { _maxDrawn = config.maxDrawn; _maxTimeBudget = config.maxTimeBudget; _stateSort = config.stateSort; } + void configure(const Config& config) { _maxDrawn = config.maxDrawn; _stateSort = config.stateSort; } void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: render::ShapePlumberPointer _shapePlumber; int _maxDrawn; // initialized by Config - float _maxTimeBudget; //ms time budget bool _stateSort; }; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index d6f09f735c..2829c6f8e7 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -123,111 +123,6 @@ void render::renderStateSortShapes(const SceneContextPointer& sceneContext, cons } } - -void render::renderStateSortShapesCapped(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, double mstimeBudget, int maxDrawnItems) { - - auto& scene = sceneContext->_scene; - RenderArgs* args = renderContext->args; - auto now = usecTimestampNow(); - - int numItemsToDraw = (int)inItems.size(); - if (maxDrawnItems != -1) { - numItemsToDraw = glm::min(numItemsToDraw, maxDrawnItems); - } - - using SortedPipelines = std::vector; - using SortedShapes = std::unordered_map, render::ShapeKey::Hash, render::ShapeKey::KeyEqual>; - SortedPipelines sortedPipelines; - SortedShapes sortedShapes; - std::vector ownPipelineBucket; - - { - PROFILE_RANGE(render_detail, "sort"); - - for (auto i = 0; i < numItemsToDraw; ++i) { - auto item = scene->getItem(inItems[i].id); - - { - assert(item.getKey().isShape()); - const auto key = item.getShapeKey(); - if (key.isValid() && !key.hasOwnPipeline()) { - auto& bucket = sortedShapes[key]; - if (bucket.empty()) { - sortedPipelines.push_back(key); - } - bucket.push_back(item); - } else if (key.hasOwnPipeline()) { - ownPipelineBucket.push_back(item); - } else { - qCDebug(renderlogging) << "Item could not be rendered with invalid key" << key; - } - } - } - } - - { - PROFILE_RANGE(render_detail, "render"); - - // Then render - quint64 usecHalfBudget = 1000 * 0.5 * mstimeBudget; - quint64 usecBudget = 1000 * mstimeBudget; - - int numDrawCalls = 0; - int numDrawcallsChecks = 128; - int numChecks = 0; - int numChecksBudget = 4; - - for (auto& pipelineKey : sortedPipelines) { - auto& bucket = sortedShapes[pipelineKey]; - args->_pipeline = shapeContext->pickPipeline(args, pipelineKey); - if (!args->_pipeline) { - continue; - } - for (auto& item : bucket) { - item.render(args); - - numDrawCalls++; - if ((numDrawCalls % numDrawcallsChecks) == 0) { - auto newNow = usecTimestampNow(); - if ((newNow - now) > usecHalfBudget) { - if ((newNow - now) > usecBudget) { - return; - } - - usecHalfBudget += (usecHalfBudget / 2); - numDrawcallsChecks / 2; - numChecks++; - if (numChecks > numChecksBudget) { - return; - } - } - } - } - } - args->_pipeline = nullptr; - for (auto& item : ownPipelineBucket) { - item.render(args); - - numDrawCalls++; - if ((numDrawCalls % numDrawcallsChecks) == 0) { - auto newNow = usecTimestampNow(); - if ((newNow - now) > usecHalfBudget) { - if ((newNow - now) > usecBudget) { - return; - } - - usecHalfBudget += (usecHalfBudget / 2); - numDrawcallsChecks / 2; - numChecks++; - if (numChecks > numChecksBudget) { - return; - } - } - } - } - } -} - void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inLights) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 042a927caf..890001ded0 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -19,7 +19,6 @@ namespace render { void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems = -1); void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); void renderStateSortShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); -void renderStateSortShapesCapped(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, double mstimeBudget, int maxDrawnItems = -1); class DrawLightConfig : public Job::Config { diff --git a/scripts/developer/utilities/render/culling.qml b/scripts/developer/utilities/render/culling.qml index 4157b5e4dd..e3f5e67bbe 100644 --- a/scripts/developer/utilities/render/culling.qml +++ b/scripts/developer/utilities/render/culling.qml @@ -95,7 +95,6 @@ Column { GroupBox { title: "Render Items" - Column{ Column{ Repeater { @@ -111,20 +110,5 @@ Column { } } } - - Column{ - Repeater { - model: [ "Draw Opaque [ms]:DrawOpaqueDeferred" ] - ConfigSlider { - label: qsTr(modelData.split(":")[0]) - integral: false - config: Render.getConfig(modelData.split(":")[1]) - property: "maxTimeBudget" - max: 10.0 - min: 0.0 - } - } - } - } } } From 3cd422e5081b69e206975ac2f3effc5ea54419b4 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 21 Feb 2017 15:02:12 -0800 Subject: [PATCH 05/64] Last clean up --- libraries/render/src/render/DrawTask.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 890001ded0..6e0e5ba10b 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -20,7 +20,6 @@ void renderItems(const SceneContextPointer& sceneContext, const RenderContextPoi void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); void renderStateSortShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); - class DrawLightConfig : public Job::Config { Q_OBJECT Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged) From 6d7fab40530c781ffed6f6b6506352c678435033 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 21 Feb 2017 16:59:08 -0800 Subject: [PATCH 06/64] Agent Avatars sending loudness in AvatarData --- assignment-client/src/Agent.cpp | 53 +++++++++++++++++++++++++-------- assignment-client/src/Agent.h | 1 + 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index bea677aeb6..cd8c8189b2 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -88,9 +88,9 @@ void Agent::playAvatarSound(SharedSoundPointer sound) { QMetaObject::invokeMethod(this, "playAvatarSound", Q_ARG(SharedSoundPointer, sound)); return; } else { - // TODO: seems to add occasional artifact in tests. I believe it is + // TODO: seems to add occasional artifact in tests. I believe it is // correct to do this, but need to figure out for sure, so commenting this - // out until I verify. + // out until I verify. // _numAvatarSoundSentBytes = 0; setAvatarSound(sound); } @@ -105,7 +105,7 @@ void Agent::handleOctreePacket(QSharedPointer message, SharedNo if (message->getSize() > statsMessageLength) { // pull out the piggybacked packet and create a new QSharedPointer for it int piggyBackedSizeWithHeader = message->getSize() - statsMessageLength; - + auto buffer = std::unique_ptr(new char[piggyBackedSizeWithHeader]); memcpy(buffer.get(), message->getRawMessage() + statsMessageLength, piggyBackedSizeWithHeader); @@ -284,7 +284,7 @@ void Agent::selectAudioFormat(const QString& selectedCodecName) { for (auto& plugin : codecPlugins) { if (_selectedCodecName == plugin->getName()) { _codec = plugin; - _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO); + _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO); _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, AudioConstants::MONO); qDebug() << "Selected Codec Plugin:" << _codec.get(); break; @@ -424,16 +424,16 @@ void Agent::executeScript() { entityScriptingInterface->setEntityTree(_entityViewer.getTree()); DependencyManager::set(_entityViewer.getTree()); - + // 100Hz timer for audio AvatarAudioTimer* audioTimerWorker = new AvatarAudioTimer(); audioTimerWorker->moveToThread(&_avatarAudioTimerThread); connect(audioTimerWorker, &AvatarAudioTimer::avatarTick, this, &Agent::processAgentAvatarAudio); connect(this, &Agent::startAvatarAudioTimer, audioTimerWorker, &AvatarAudioTimer::start); connect(this, &Agent::stopAvatarAudioTimer, audioTimerWorker, &AvatarAudioTimer::stop); - connect(&_avatarAudioTimerThread, &QThread::finished, audioTimerWorker, &QObject::deleteLater); + connect(&_avatarAudioTimerThread, &QThread::finished, audioTimerWorker, &QObject::deleteLater); _avatarAudioTimerThread.start(); - + // 60Hz timer for avatar QObject::connect(_scriptEngine.get(), &ScriptEngine::update, this, &Agent::processAgentAvatar); _scriptEngine->run(); @@ -448,14 +448,14 @@ QUuid Agent::getSessionUUID() const { return DependencyManager::get()->getSessionUUID(); } -void Agent::setIsListeningToAudioStream(bool isListeningToAudioStream) { +void Agent::setIsListeningToAudioStream(bool isListeningToAudioStream) { // this must happen on Agent's main thread if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setIsListeningToAudioStream", Q_ARG(bool, isListeningToAudioStream)); return; } if (_isListeningToAudioStream) { - // have to tell just the audio mixer to KillAvatar. + // have to tell just the audio mixer to KillAvatar. auto nodeList = DependencyManager::get(); nodeList->eachMatchingNode( @@ -471,7 +471,7 @@ void Agent::setIsListeningToAudioStream(bool isListeningToAudioStream) { }); } - _isListeningToAudioStream = isListeningToAudioStream; + _isListeningToAudioStream = isListeningToAudioStream; } void Agent::setIsAvatar(bool isAvatar) { @@ -552,6 +552,7 @@ void Agent::processAgentAvatar() { nodeList->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); } } + void Agent::encodeFrameOfZeros(QByteArray& encodedZeros) { _flushEncoder = false; static const QByteArray zeros(AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL, 0); @@ -562,6 +563,23 @@ void Agent::encodeFrameOfZeros(QByteArray& encodedZeros) { } } +void Agent::computeLoudness(QByteArray* decodedBuffer) { + float loudness = 0.0f; + auto scriptedAvatar = DependencyManager::get(); + if (decodedBuffer) { + auto soundData = reinterpret_cast(decodedBuffer->constData()); + auto numFrames = decodedBuffer->size() / sizeof(int16_t); + // now iterate and come up with average + if (numFrames > 0) { + for(int i = 0; i < numFrames; i++) { + loudness += (float) std::abs(soundData[i]); + } + loudness /= numFrames; + } + } + scriptedAvatar->setAudioLoudness(loudness); +} + void Agent::processAgentAvatarAudio() { auto recordingInterface = DependencyManager::get(); bool isPlayingRecording = recordingInterface->isPlaying(); @@ -611,6 +629,9 @@ void Agent::processAgentAvatarAudio() { audioPacket->seek(sizeof(quint16)); if (silentFrame) { + // no matter what, the loudness should be set to 0 + computeLoudness(nullptr); + if (!_isListeningToAudioStream) { // if we have a silent frame and we're not listening then just send nothing and break out of here return; @@ -618,7 +639,7 @@ void Agent::processAgentAvatarAudio() { // write the codec audioPacket->writeString(_selectedCodecName); - + // write the number of silent samples so the audio-mixer can uphold timing audioPacket->writePrimitive(numAvailableSamples); @@ -628,8 +649,9 @@ void Agent::processAgentAvatarAudio() { audioPacket->writePrimitive(headOrientation); audioPacket->writePrimitive(scriptedAvatar->getPosition()); audioPacket->writePrimitive(glm::vec3(0)); + } else if (nextSoundOutput) { - + // write the codec audioPacket->writeString(_selectedCodecName); @@ -646,6 +668,8 @@ void Agent::processAgentAvatarAudio() { QByteArray encodedBuffer; if (_flushEncoder) { encodeFrameOfZeros(encodedBuffer); + // loudness is 0 + computeLoudness(nullptr); } else { QByteArray decodedBuffer(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); if (_encoder) { @@ -654,10 +678,15 @@ void Agent::processAgentAvatarAudio() { } else { encodedBuffer = decodedBuffer; } + computeLoudness(&decodedBuffer); } audioPacket->write(encodedBuffer.constData(), encodedBuffer.size()); } + // we should never have both nextSoundOutput being null and silentFrame being false, but lets + // assert on it in case things above change in a bad way + assert(nextSoundOutput || silentFrame); + // write audio packet to AudioMixer nodes auto nodeList = DependencyManager::get(); nodeList->eachNode([this, &nodeList, &audioPacket](const SharedNodePointer& node) { diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index c9b1707101..7f04b4746f 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -82,6 +82,7 @@ private: void negotiateAudioFormat(); void selectAudioFormat(const QString& selectedCodecName); void encodeFrameOfZeros(QByteArray& encodedZeros); + void computeLoudness(QByteArray* decodedBuffer); std::unique_ptr _scriptEngine; EntityEditPacketSender _entityEditSender; From a00216cb4f43d967ac49f6e05a528eab00a44b5b Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 21 Feb 2017 18:20:55 -0800 Subject: [PATCH 07/64] debugging the emissive issue for verlay in front --- .../render-utils/src/RenderPipelines.cpp | 7 +- .../render-utils/src/overlay3D_model.slf | 134 ++++++++++++++++++ .../src/overlay3D_translucent.slf | 2 + 3 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 libraries/render-utils/src/overlay3D_model.slf diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index c5a6c4b6ca..53fc9153e8 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -50,6 +50,7 @@ #include "overlay3D_vert.h" #include "overlay3D_frag.h" +#include "overlay3D_model_frag.h" #include "overlay3D_translucent_frag.h" #include "overlay3D_unlit_frag.h" #include "overlay3D_translucent_unlit_frag.h" @@ -70,17 +71,19 @@ void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch); void initOverlay3DPipelines(ShapePlumber& plumber) { auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert)); - auto pixel = gpu::Shader::createPixel(std::string(overlay3D_frag)); + auto pixel = gpu::Shader::createPixel(std::string(overlay3D_model_frag)); auto pixelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_translucent_frag)); auto pixelUnlit = gpu::Shader::createPixel(std::string(overlay3D_unlit_frag)); auto pixelTranslucentUnlit = gpu::Shader::createPixel(std::string(overlay3D_translucent_unlit_frag)); + auto pixelMaterial = gpu::Shader::createPixel(std::string(overlay3D_model_frag)); auto opaqueProgram = gpu::Shader::createProgram(vertex, pixel); auto translucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucent); auto unlitOpaqueProgram = gpu::Shader::createProgram(vertex, pixelUnlit); auto unlitTranslucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucentUnlit); + auto opaqueMaterialProgram = gpu::Shader::createProgram(vertex, pixelMaterial); - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 16; i++) { bool isCulled = (i & 1); bool isBiased = (i & 2); bool isOpaque = (i & 4); diff --git a/libraries/render-utils/src/overlay3D_model.slf b/libraries/render-utils/src/overlay3D_model.slf new file mode 100644 index 0000000000..dcc5eac58c --- /dev/null +++ b/libraries/render-utils/src/overlay3D_model.slf @@ -0,0 +1,134 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// overlay3D.slf +// fragment shader +// +// Created by Sam Gateau on 6/16/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +<@include model/Light.slh@> +<$declareLightBuffer()$> +<$declareLightAmbientBuffer()$> + +<@include LightingModel.slh@> + +<@include LightDirectional.slh@> +<$declareLightingDirectional()$> + +<@include model/Material.slh@> + +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> + +vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness, float opacity) { + + // Need the light now + Light light = getLight(); + vec3 lightDirection = getLightDirection(light); + vec3 lightIrradiance = getLightIrradiance(light); + + LightAmbient ambient = getLightAmbient(); + + TransformCamera cam = getTransformCamera(); + vec3 fragNormal; + <$transformEyeToWorldDir(cam, normal, fragNormal)$> + vec3 fragEyeVectorView = normalize(-position); + vec3 fragEyeDir; + <$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$> + + vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(ambient); + + // Directional + vec3 directionalDiffuse; + vec3 directionalSpecular; + evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation); + color += directionalDiffuse * isDiffuseEnabled() * isDirectionalEnabled(); + color += directionalSpecular * isSpecularEnabled() * isDirectionalEnabled(); + + return vec4(color, opacity); +} + + +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec4 _position; +in vec3 _normal; +in vec3 _color; +in float _alpha; + +out vec4 _fragColor; + +void main(void) { + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float metallic = getMaterialMetallic(mat); + vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value + if (metallic <= 0.5) { + metallic = 0.0; + } else { + fresnel = albedo; + metallic = 1.0; + } + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + + vec3 fragPosition = _position.xyz; + vec3 fragNormal = normalize(_normal); + + TransformCamera cam = getTransformCamera(); + + vec4 color = evalGlobalColor(occlusionTex, + fragPosition, + fragNormal, + albedo, + metallic, + fresnel, + roughness, + opacity); + + color.rgb += emissive; + + // Apply standard tone mapping + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); + + /*_fragColor = vec4(evalGlobalLightingAlphaBlended( + cam._viewInverse, + 1.0, + occlusionTex, + fragPosition, + fragNormal, + albedo, + fresnel, + metallic, + emissive, + roughness, opacity), + opacity); + + // Apply standard tone mapping + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w);*/ +} \ No newline at end of file diff --git a/libraries/render-utils/src/overlay3D_translucent.slf b/libraries/render-utils/src/overlay3D_translucent.slf index 9bdac2d21f..0343567127 100644 --- a/libraries/render-utils/src/overlay3D_translucent.slf +++ b/libraries/render-utils/src/overlay3D_translucent.slf @@ -82,6 +82,8 @@ void main(void) { fragRoughness, fragOpacity); + color.xyz += vec3(1.0, 0.0, 0.0) * fragOpacity; + // Apply standard tone mapping _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); } From 397eb89c143d2e746ca6e5ecd3980c210ea95e04 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 22 Feb 2017 08:38:49 -0800 Subject: [PATCH 08/64] compiler warning - odd --- assignment-client/src/Agent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index cd8c8189b2..2f91571d8b 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -568,7 +568,7 @@ void Agent::computeLoudness(QByteArray* decodedBuffer) { auto scriptedAvatar = DependencyManager::get(); if (decodedBuffer) { auto soundData = reinterpret_cast(decodedBuffer->constData()); - auto numFrames = decodedBuffer->size() / sizeof(int16_t); + int numFrames = decodedBuffer->size() / sizeof(int16_t); // now iterate and come up with average if (numFrames > 0) { for(int i = 0; i < numFrames; i++) { From c7b164d8f26d1bb45666f1c1ad96c354b648b4ae Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 22 Feb 2017 18:21:18 -0800 Subject: [PATCH 09/64] Adding differenciation for the Material shapeKey bit --- .../render-utils/src/MeshPartPayload.cpp | 4 ++ .../render-utils/src/RenderPipelines.cpp | 66 ++++++++++--------- libraries/render/src/render/ShapePipeline.h | 9 ++- 3 files changed, 46 insertions(+), 33 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 4cb4e2a316..5b3d285b47 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -97,6 +97,8 @@ ShapeKey MeshPartPayload::getShapeKey() const { } ShapeKey::Builder builder; + builder.withMaterial(); + if (drawMaterialKey.isTranslucent()) { builder.withTranslucent(); } @@ -478,6 +480,8 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { } ShapeKey::Builder builder; + builder.withMaterial(); + if (isTranslucent || _fadeState != FADE_COMPLETE) { builder.withTranslucent(); } diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 53fc9153e8..19284814fc 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -106,6 +106,7 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { } ShapeKey::Filter::Builder builder; + isCulled ? builder.withCullFace() : builder.withoutCullFace(); isBiased ? builder.withDepthBias() : builder.withoutDepthBias(); isOpaque ? builder.withOpaque() : builder.withTranslucent(); @@ -113,6 +114,7 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto simpleProgram = isOpaque ? opaqueProgram : translucentProgram; auto unlitProgram = isOpaque ? unlitOpaqueProgram : unlitTranslucentProgram; plumber.addPipeline(builder.withoutUnlit().build(), simpleProgram, state, &lightBatchSetter); + plumber.addPipeline(builder.withMaterial().build(), opaqueMaterialProgram, state, &lightBatchSetter); plumber.addPipeline(builder.withUnlit().build(), unlitProgram, state, &batchSetter); } } @@ -147,78 +149,78 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { // TODO: Refactor this to use a filter // Opaques addPipeline( - Key::Builder(), + Key::Builder().withMaterial(), modelVertex, modelPixel); addPipeline( - Key::Builder().withUnlit(), + Key::Builder().withMaterial().withUnlit(), modelVertex, modelUnlitPixel); addPipeline( - Key::Builder().withTangents(), + Key::Builder().withMaterial().withTangents(), modelNormalMapVertex, modelNormalMapPixel); addPipeline( - Key::Builder().withSpecular(), + Key::Builder().withMaterial().withSpecular(), modelVertex, modelSpecularMapPixel); addPipeline( - Key::Builder().withTangents().withSpecular(), + Key::Builder().withMaterial().withTangents().withSpecular(), modelNormalMapVertex, modelNormalSpecularMapPixel); // Translucents addPipeline( - Key::Builder().withTranslucent(), + Key::Builder().withMaterial().withTranslucent(), modelVertex, modelTranslucentPixel); addPipeline( - Key::Builder().withTranslucent().withUnlit(), + Key::Builder().withMaterial().withTranslucent().withUnlit(), modelVertex, modelTranslucentUnlitPixel); addPipeline( - Key::Builder().withTranslucent().withTangents(), + Key::Builder().withMaterial().withTranslucent().withTangents(), modelNormalMapVertex, modelTranslucentPixel); addPipeline( - Key::Builder().withTranslucent().withSpecular(), + Key::Builder().withMaterial().withTranslucent().withSpecular(), modelVertex, modelTranslucentPixel); addPipeline( - Key::Builder().withTranslucent().withTangents().withSpecular(), + Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular(), modelNormalMapVertex, modelTranslucentPixel); addPipeline( // FIXME: Ignore lightmap for translucents meshpart - Key::Builder().withTranslucent().withLightmap(), + Key::Builder().withMaterial().withTranslucent().withLightmap(), modelVertex, modelTranslucentPixel); // Lightmapped addPipeline( - Key::Builder().withLightmap(), + Key::Builder().withMaterial().withLightmap(), modelLightmapVertex, modelLightmapPixel); addPipeline( - Key::Builder().withLightmap().withTangents(), + Key::Builder().withMaterial().withLightmap().withTangents(), modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); addPipeline( - Key::Builder().withLightmap().withSpecular(), + Key::Builder().withMaterial().withLightmap().withSpecular(), modelLightmapVertex, modelLightmapSpecularMapPixel); addPipeline( - Key::Builder().withLightmap().withTangents().withSpecular(), + Key::Builder().withMaterial().withLightmap().withTangents().withSpecular(), modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); // Skinned addPipeline( - Key::Builder().withSkinned(), + Key::Builder().withMaterial().withSkinned(), skinModelVertex, modelPixel); addPipeline( - Key::Builder().withSkinned().withTangents(), + Key::Builder().withMaterial().withSkinned().withTangents(), skinModelNormalMapVertex, modelNormalMapPixel); addPipeline( - Key::Builder().withSkinned().withSpecular(), + Key::Builder().withMaterial().withSkinned().withSpecular(), skinModelVertex, modelSpecularMapPixel); addPipeline( - Key::Builder().withSkinned().withTangents().withSpecular(), + Key::Builder().withMaterial().withSkinned().withTangents().withSpecular(), skinModelNormalMapVertex, modelNormalSpecularMapPixel); // Skinned and Translucent addPipeline( - Key::Builder().withSkinned().withTranslucent(), + Key::Builder().withMaterial().withSkinned().withTranslucent(), skinModelVertex, modelTranslucentPixel); addPipeline( - Key::Builder().withSkinned().withTranslucent().withTangents(), + Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents(), skinModelNormalMapVertex, modelTranslucentPixel); addPipeline( - Key::Builder().withSkinned().withTranslucent().withSpecular(), + Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular(), skinModelVertex, modelTranslucentPixel); addPipeline( - Key::Builder().withSkinned().withTranslucent().withTangents().withSpecular(), + Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(), skinModelNormalMapVertex, modelTranslucentPixel); // Depth-only addPipeline( @@ -247,32 +249,32 @@ void initForwardPipelines(render::ShapePlumber& plumber) { auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); // Opaques addPipeline( - Key::Builder(), + Key::Builder().withMaterial(), modelVertex, modelPixel); addPipeline( - Key::Builder().withUnlit(), + Key::Builder().withMaterial().withUnlit(), modelVertex, modelUnlitPixel); addPipeline( - Key::Builder().withTangents(), + Key::Builder().withMaterial().withTangents(), modelNormalMapVertex, modelNormalMapPixel); addPipeline( - Key::Builder().withSpecular(), + Key::Builder().withMaterial().withSpecular(), modelVertex, modelSpecularMapPixel); addPipeline( - Key::Builder().withTangents().withSpecular(), + Key::Builder().withMaterial().withTangents().withSpecular(), modelNormalMapVertex, modelNormalSpecularMapPixel); // Skinned addPipeline( - Key::Builder().withSkinned(), + Key::Builder().withMaterial().withSkinned(), skinModelVertex, modelPixel); addPipeline( - Key::Builder().withSkinned().withTangents(), + Key::Builder().withMaterial().withSkinned().withTangents(), skinModelNormalMapVertex, modelNormalMapPixel); addPipeline( - Key::Builder().withSkinned().withSpecular(), + Key::Builder().withMaterial().withSkinned().withSpecular(), skinModelVertex, modelSpecularMapPixel); addPipeline( - Key::Builder().withSkinned().withTangents().withSpecular(), + Key::Builder().withMaterial().withSkinned().withTangents().withSpecular(), skinModelNormalMapVertex, modelNormalSpecularMapPixel); } diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index e7a14d2f2b..e55c1d4bc4 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -22,7 +22,8 @@ namespace render { class ShapeKey { public: enum FlagBit { - TRANSLUCENT = 0, + MATERIAL = 0, + TRANSLUCENT, LIGHTMAP, TANGENTS, SPECULAR, @@ -53,6 +54,7 @@ public: ShapeKey build() const { return ShapeKey{_flags}; } + Builder& withMaterial() { _flags.set(MATERIAL); return (*this); } Builder& withTranslucent() { _flags.set(TRANSLUCENT); return (*this); } Builder& withLightmap() { _flags.set(LIGHTMAP); return (*this); } Builder& withTangents() { _flags.set(TANGENTS); return (*this); } @@ -89,6 +91,9 @@ public: Filter build() const { return Filter(_flags, _mask); } + Builder& withMaterial() { _flags.set(MATERIAL); _mask.set(MATERIAL); return (*this); } + Builder& withoutMaterial() { _flags.reset(MATERIAL); _mask.set(MATERIAL); return (*this); } + Builder& withTranslucent() { _flags.set(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); } Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); } @@ -134,6 +139,7 @@ public: Flags _mask{0}; }; + bool useMaterial() const { return _flags[MATERIAL]; } bool hasLightmap() const { return _flags[LIGHTMAP]; } bool hasTangents() const { return _flags[TANGENTS]; } bool hasSpecular() const { return _flags[SPECULAR]; } @@ -170,6 +176,7 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& key) { debug << "[ShapeKey: OWN_PIPELINE]"; } else { debug << "[ShapeKey:" + << "useMaterial:" << key.useMaterial() << "hasLightmap:" << key.hasLightmap() << "hasTangents:" << key.hasTangents() << "hasSpecular:" << key.hasSpecular() From 6d59144a4f6be81935376fb8893a1d1c04ea6363 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 23 Feb 2017 17:42:02 -0800 Subject: [PATCH 10/64] Trying to fix the emissive for overlay in front ? --- interface/src/ui/overlays/OverlaysPayload.cpp | 6 +++++- libraries/render-utils/src/RenderPipelines.cpp | 9 +++++---- libraries/render-utils/src/overlay3D_model.slf | 5 +++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 277a86e93f..4aa3edbe6c 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -62,7 +62,11 @@ namespace render { if (overlay->is3D()) { auto overlay3D = std::dynamic_pointer_cast(overlay); if (overlay3D->isAA()) - return (overlay3D->getDrawInFront() ? LAYER_3D_FRONT : LAYER_3D); + if (overlay3D->getDrawInFront()) { + return LAYER_3D_FRONT; + } else { + return LAYER_3D; + } else return LAYER_NO_AA; } else { diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 19284814fc..cbbd1cd193 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -71,6 +71,7 @@ void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch); void initOverlay3DPipelines(ShapePlumber& plumber) { auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert)); + auto vertexModel = gpu::Shader::createVertex(std::string(model_vert)); auto pixel = gpu::Shader::createPixel(std::string(overlay3D_model_frag)); auto pixelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_translucent_frag)); auto pixelUnlit = gpu::Shader::createPixel(std::string(overlay3D_unlit_frag)); @@ -81,7 +82,7 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto translucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucent); auto unlitOpaqueProgram = gpu::Shader::createProgram(vertex, pixelUnlit); auto unlitTranslucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucentUnlit); - auto opaqueMaterialProgram = gpu::Shader::createProgram(vertex, pixelMaterial); + auto opaqueMaterialProgram = gpu::Shader::createProgram(vertexModel, pixelMaterial); for (int i = 0; i < 16; i++) { bool isCulled = (i & 1); @@ -113,9 +114,9 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto simpleProgram = isOpaque ? opaqueProgram : translucentProgram; auto unlitProgram = isOpaque ? unlitOpaqueProgram : unlitTranslucentProgram; - plumber.addPipeline(builder.withoutUnlit().build(), simpleProgram, state, &lightBatchSetter); - plumber.addPipeline(builder.withMaterial().build(), opaqueMaterialProgram, state, &lightBatchSetter); - plumber.addPipeline(builder.withUnlit().build(), unlitProgram, state, &batchSetter); + plumber.addPipeline(builder.withoutUnlit().withoutMaterial().build(), simpleProgram, state, &lightBatchSetter); + plumber.addPipeline(builder.withMaterial().withoutUnlit().build(), opaqueMaterialProgram, state, &lightBatchSetter); + plumber.addPipeline(builder.withUnlit().withoutMaterial().build(), unlitProgram, state, &batchSetter); } } diff --git a/libraries/render-utils/src/overlay3D_model.slf b/libraries/render-utils/src/overlay3D_model.slf index dcc5eac58c..cd4179b112 100644 --- a/libraries/render-utils/src/overlay3D_model.slf +++ b/libraries/render-utils/src/overlay3D_model.slf @@ -112,9 +112,10 @@ void main(void) { opacity); color.rgb += emissive; - + color.rgb = vec3(0.5, 0.5, 1.0); // Apply standard tone mapping - _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), 0.9); + //_fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); /*_fragColor = vec4(evalGlobalLightingAlphaBlended( cam._viewInverse, From d9a716bf3de4bc95ddd0d98f5ecd0e5a3487cc10 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 24 Feb 2017 18:42:52 +1300 Subject: [PATCH 11/64] If someone else is grabbing entity you want to grab show their grab beam --- .../system/controllers/handControllerGrab.js | 62 ++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index ea76490b7b..5064705f78 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -419,10 +419,10 @@ function entityIsGrabbedByOther(entityID) { } if (tag.slice(0, 5) == "grab-") { // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. - return true; + return tag.slice(5, 42); } } - return false; + return null; } function propsArePhysical(props) { @@ -790,10 +790,10 @@ function MyController(hand) { // for visualizations this.overlayLine = null; - - // for lights - this.overlayLine = null; this.searchSphere = null; + this.otherGrabbingLine = null; + + this.otherGrabbingUUID = null; this.waitForTriggerRelease = false; @@ -1050,6 +1050,29 @@ function MyController(hand) { } }; + this.otherGrabbingLineOn = function(avatarPosition, entityPosition, color) { + if (this.otherGrabbingLine === null) { + var lineProperties = { + lineWidth: 5, + start: avatarPosition, + end: entityPosition, + color: color, + glow: 1.0, + ignoreRayIntersection: true, + drawInFront: true, + visible: true, + alpha: 1 + }; + this.otherGrabbingLine = Overlays.addOverlay("line3d", lineProperties); + } else { + Overlays.editOverlay(this.otherGrabbingLine, { + start: avatarPosition, + end: entityPosition, + color: color + }); + } + }; + this.evalLightWorldTransform = function(modelPos, modelRot) { var MODEL_LIGHT_POSITION = { @@ -1093,14 +1116,20 @@ function MyController(hand) { } }; - this.turnOffVisualizations = function() { + this.otherGrabbingLineOff = function() { + if (this.otherGrabbingLine !== null) { + Overlays.deleteOverlay(this.otherGrabbingLine); + } + this.otherGrabbingLine = null; + }; + this.turnOffVisualizations = function() { this.overlayLineOff(); this.grabPointSphereOff(); this.lineOff(); this.searchSphereOff(); + this.otherGrabbingLineOff(); restore2DMode(); - }; this.triggerPress = function(value) { @@ -1504,7 +1533,8 @@ function MyController(hand) { return false; } - if (entityIsGrabbedByOther(entityID)) { + this.otherGrabbingUUID = entityIsGrabbedByOther(entityID); + if (this.otherGrabbingUUID !== null) { // don't distance grab something that is already grabbed. if (debug) { print("distance grab is skipping '" + props.name + "': already grabbed by another."); @@ -1683,6 +1713,7 @@ function MyController(hand) { } else { // potentialFarTriggerEntity = entity; } + this.otherGrabbingLineOff(); } else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) { if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) { this.grabbedEntity = entity; @@ -1692,7 +1723,21 @@ function MyController(hand) { } else { // potentialFarGrabEntity = entity; } + this.otherGrabbingLineOff(); + } else if (this.otherGrabbingUUID !== null) { + if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) { + var avatar = AvatarList.getAvatar(this.otherGrabbingUUID); + var IN_FRONT_OF_AVATAR = { x: 0, y: 0, z: 0.2 }; + var startPosition = Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.rotation, IN_FRONT_OF_AVATAR)); + this.otherGrabbingLineOn(startPosition, rayPickInfo.properties.position, COLORS_GRAB_DISTANCE_HOLD); + } else { + this.otherGrabbingLineOff(); + } + } else { + this.otherGrabbingLineOff(); } + } else { + this.otherGrabbingLineOff(); } this.updateEquipHaptics(potentialEquipHotspot, handPosition); @@ -2268,6 +2313,7 @@ function MyController(hand) { this.lineOff(); this.overlayLineOff(); this.searchSphereOff(); + this.otherGrabbingLineOff(); this.dropGestureReset(); this.clearEquipHaptics(); From 67031850aab6e723a230b8d06507c90b6a9790f1 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 24 Feb 2017 00:05:54 -0800 Subject: [PATCH 12/64] Deep dive into the shape key and filters and the PLumber construction --- libraries/render-utils/src/RenderPipelines.cpp | 4 ++-- libraries/render/src/render/ShapePipeline.cpp | 4 ++++ libraries/render/src/render/ShapePipeline.h | 7 ------- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index cbbd1cd193..59d8baacf8 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -84,7 +84,7 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto unlitTranslucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucentUnlit); auto opaqueMaterialProgram = gpu::Shader::createProgram(vertexModel, pixelMaterial); - for (int i = 0; i < 16; i++) { + for (int i = 0; i < 8; i++) { bool isCulled = (i & 1); bool isBiased = (i & 2); bool isOpaque = (i & 4); @@ -115,7 +115,7 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto simpleProgram = isOpaque ? opaqueProgram : translucentProgram; auto unlitProgram = isOpaque ? unlitOpaqueProgram : unlitTranslucentProgram; plumber.addPipeline(builder.withoutUnlit().withoutMaterial().build(), simpleProgram, state, &lightBatchSetter); - plumber.addPipeline(builder.withMaterial().withoutUnlit().build(), opaqueMaterialProgram, state, &lightBatchSetter); + plumber.addPipeline(builder.withoutUnlit().withMaterial().build(), opaqueMaterialProgram, state, &lightBatchSetter); plumber.addPipeline(builder.withUnlit().withoutMaterial().build(), unlitProgram, state, &batchSetter); } } diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 48e8ee43d5..cec1971165 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -39,6 +39,10 @@ void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit } } else { // Add the brand new pipeline and cache its location in the lib + auto precedent = _pipelineMap.find(key); + if (precedent != _pipelineMap.end()) { + qCDebug(renderlogging) << "Key already assigned: " << key; + } _pipelineMap.insert(PipelineMap::value_type(key, pipeline)); } } diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index e55c1d4bc4..c7e494ee4c 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -29,7 +29,6 @@ public: SPECULAR, UNLIT, SKINNED, - STEREO, DEPTH_ONLY, DEPTH_BIAS, WIREFRAME, @@ -61,7 +60,6 @@ public: Builder& withSpecular() { _flags.set(SPECULAR); return (*this); } Builder& withUnlit() { _flags.set(UNLIT); return (*this); } Builder& withSkinned() { _flags.set(SKINNED); return (*this); } - Builder& withStereo() { _flags.set(STEREO); return (*this); } Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); } Builder& withDepthBias() { _flags.set(DEPTH_BIAS); return (*this); } Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } @@ -112,9 +110,6 @@ public: Builder& withSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); } Builder& withoutSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); } - Builder& withStereo() { _flags.set(STEREO); _mask.set(STEREO); return (*this); } - Builder& withoutStereo() { _flags.reset(STEREO); _mask.set(STEREO); return (*this); } - Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } Builder& withoutDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } @@ -146,7 +141,6 @@ public: bool isUnlit() const { return _flags[UNLIT]; } bool isTranslucent() const { return _flags[TRANSLUCENT]; } bool isSkinned() const { return _flags[SKINNED]; } - bool isStereo() const { return _flags[STEREO]; } bool isDepthOnly() const { return _flags[DEPTH_ONLY]; } bool isDepthBiased() const { return _flags[DEPTH_BIAS]; } bool isWireFrame() const { return _flags[WIREFRAME]; } @@ -183,7 +177,6 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& key) { << "isUnlit:" << key.isUnlit() << "isTranslucent:" << key.isTranslucent() << "isSkinned:" << key.isSkinned() - << "isStereo:" << key.isStereo() << "isDepthOnly:" << key.isDepthOnly() << "isDepthBiased:" << key.isDepthBiased() << "isWireFrame:" << key.isWireFrame() From e1aad8bd63950baa11b5e520924d07a633f1af49 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 24 Feb 2017 00:35:10 -0800 Subject: [PATCH 13/64] Deep dive into the shape key and filters and the PLumber construction --- .../src/model-networking/TextureCache.cpp | 8 ------- .../src/model-networking/TextureCache.h | 4 ---- libraries/render-utils/src/DeferredBuffer.slh | 21 ------------------- libraries/render-utils/src/GeometryCache.cpp | 15 ------------- .../render-utils/src/RenderPipelines.cpp | 7 ++----- libraries/render/src/render/ShapePipeline.cpp | 5 ----- libraries/render/src/render/ShapePipeline.h | 3 --- 7 files changed, 2 insertions(+), 61 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index f371207981..8a4e85cfe6 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -154,14 +154,6 @@ const gpu::TexturePointer& TextureCache::getBlackTexture() { return _blackTexture; } - -const gpu::TexturePointer& TextureCache::getNormalFittingTexture() { - if (!_normalFittingTexture) { - _normalFittingTexture = getImageTexture(PathUtils::resourcesPath() + "images/normalFittingScale.dds"); - } - return _normalFittingTexture; -} - /// Extra data for creating textures. class TextureExtra { public: diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index cb509490c6..77311afae6 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -124,9 +124,6 @@ public: /// Returns the a black texture (useful for a default). const gpu::TexturePointer& getBlackTexture(); - // Returns a map used to compress the normals through a fitting scale algorithm - const gpu::TexturePointer& getNormalFittingTexture(); - /// Returns a texture version of an image file static gpu::TexturePointer getImageTexture(const QString& path, Type type = Type::DEFAULT_TEXTURE, QVariantMap options = QVariantMap()); @@ -151,7 +148,6 @@ private: gpu::TexturePointer _grayTexture; gpu::TexturePointer _blueTexture; gpu::TexturePointer _blackTexture; - gpu::TexturePointer _normalFittingTexture; }; #endif // hifi_TextureCache_h diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index a4b69bd70e..a13c2ec5d1 100644 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -65,25 +65,4 @@ float packUnlit() { return FRAG_PACK_UNLIT; } - - <@endif@> diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index c277b9be64..e0dee7b953 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -414,8 +414,6 @@ _nextID(0) { // Set the defaults needed for a simple program batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, DependencyManager::get()->getWhiteTexture()); - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, - DependencyManager::get()->getNormalFittingTexture()); } ); GeometryCache::_simpleTransparentPipeline = @@ -424,8 +422,6 @@ _nextID(0) { // Set the defaults needed for a simple program batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, DependencyManager::get()->getWhiteTexture()); - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, - DependencyManager::get()->getNormalFittingTexture()); } ); GeometryCache::_simpleWirePipeline = @@ -1770,7 +1766,6 @@ static void buildWebShader(const std::string& vertShaderText, const std::string& shaderPointerOut = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::MAP::NORMAL_FITTING)); gpu::Shader::makeProgram(*shaderPointerOut, slotBindings); auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_NONE); @@ -1784,9 +1779,6 @@ static void buildWebShader(const std::string& vertShaderText, const std::string& void GeometryCache::bindOpaqueWebBrowserProgram(gpu::Batch& batch, bool isAA) { batch.setPipeline(getOpaqueWebBrowserProgram(isAA)); - // Set a default normal map - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, - DependencyManager::get()->getNormalFittingTexture()); } gpu::PipelinePointer GeometryCache::getOpaqueWebBrowserProgram(bool isAA) { @@ -1802,9 +1794,6 @@ gpu::PipelinePointer GeometryCache::getOpaqueWebBrowserProgram(bool isAA) { void GeometryCache::bindTransparentWebBrowserProgram(gpu::Batch& batch, bool isAA) { batch.setPipeline(getTransparentWebBrowserProgram(isAA)); - // Set a default normal map - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, - DependencyManager::get()->getNormalFittingTexture()); } gpu::PipelinePointer GeometryCache::getTransparentWebBrowserProgram(bool isAA) { @@ -1827,9 +1816,6 @@ void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool tra batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, DependencyManager::get()->getWhiteTexture()); } - // Set a default normal map - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, - DependencyManager::get()->getNormalFittingTexture()); } gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transparent, bool culled, bool unlit, bool depthBiased) { @@ -1846,7 +1832,6 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp _unlitShader = gpu::Shader::createProgram(VS, PSUnlit); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::MAP::NORMAL_FITTING)); gpu::Shader::makeProgram(*_simpleShader, slotBindings); gpu::Shader::makeProgram(*_unlitShader, slotBindings); }); diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 59d8baacf8..158daad54c 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -114,9 +114,9 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto simpleProgram = isOpaque ? opaqueProgram : translucentProgram; auto unlitProgram = isOpaque ? unlitOpaqueProgram : unlitTranslucentProgram; - plumber.addPipeline(builder.withoutUnlit().withoutMaterial().build(), simpleProgram, state, &lightBatchSetter); plumber.addPipeline(builder.withoutUnlit().withMaterial().build(), opaqueMaterialProgram, state, &lightBatchSetter); - plumber.addPipeline(builder.withUnlit().withoutMaterial().build(), unlitProgram, state, &batchSetter); + plumber.addPipeline(builder.withoutUnlit().build(), simpleProgram, state, &lightBatchSetter); + plumber.addPipeline(builder.withUnlit().build(), unlitProgram, state, &batchSetter); } } @@ -325,9 +325,6 @@ void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { // Set a default albedo map batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, DependencyManager::get()->getWhiteTexture()); - // Set a default normal map - batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, - DependencyManager::get()->getNormalFittingTexture()); // Set a default material if (pipeline.locations->materialBufferUnit >= 0) { diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index cec1971165..1c8e73f5d7 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -69,16 +69,11 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::BUFFER::LIGHT)); slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER)); slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Slot::NORMAL_FITTING)); gpu::Shader::makeProgram(*program, slotBindings); auto locations = std::make_shared(); - locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); - if (program->getTextures().findLocation("normalFittingMap") > -1) { - locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); - } locations->albedoTextureUnit = program->getTextures().findLocation("albedoMap"); locations->roughnessTextureUnit = program->getTextures().findLocation("roughnessMap"); locations->normalTextureUnit = program->getTextures().findLocation("normalMap"); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index c7e494ee4c..1e0f1cad76 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -213,8 +213,6 @@ public: OCCLUSION, SCATTERING, LIGHT_AMBIENT, - - NORMAL_FITTING = 10, }; }; @@ -226,7 +224,6 @@ public: int metallicTextureUnit; int emissiveTextureUnit; int occlusionTextureUnit; - int normalFittingMapUnit; int lightingModelBufferUnit; int skinClusterBufferUnit; int materialBufferUnit; From 5257194c4825406920c9aa614a7d7e9e5f2a703f Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 24 Feb 2017 01:11:59 -0800 Subject: [PATCH 14/64] SImplify the overlay PLumber --- libraries/render-utils/src/RenderPipelines.cpp | 7 ++++--- libraries/render-utils/src/overlay3D_model.slf | 4 ++-- libraries/render-utils/src/overlay3D_translucent.slf | 3 ++- libraries/render/src/render/ShapePipeline.h | 1 + 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 158daad54c..508b035a5a 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -114,9 +114,10 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto simpleProgram = isOpaque ? opaqueProgram : translucentProgram; auto unlitProgram = isOpaque ? unlitOpaqueProgram : unlitTranslucentProgram; - plumber.addPipeline(builder.withoutUnlit().withMaterial().build(), opaqueMaterialProgram, state, &lightBatchSetter); - plumber.addPipeline(builder.withoutUnlit().build(), simpleProgram, state, &lightBatchSetter); - plumber.addPipeline(builder.withUnlit().build(), unlitProgram, state, &batchSetter); + + plumber.addPipeline(builder.withoutUnlit().withMaterial().build().key(), opaqueMaterialProgram, state, &lightBatchSetter); + plumber.addPipeline(builder.withoutUnlit().withoutMaterial().build().key(), simpleProgram, state, &lightBatchSetter); + plumber.addPipeline(builder.withUnlit().withoutMaterial().build().key(), unlitProgram, state, &batchSetter); } } diff --git a/libraries/render-utils/src/overlay3D_model.slf b/libraries/render-utils/src/overlay3D_model.slf index cd4179b112..979a6f2201 100644 --- a/libraries/render-utils/src/overlay3D_model.slf +++ b/libraries/render-utils/src/overlay3D_model.slf @@ -112,9 +112,9 @@ void main(void) { opacity); color.rgb += emissive; - color.rgb = vec3(0.5, 0.5, 1.0); + // color.rgb = vec3(0.5, 0.5, 1.0); // Apply standard tone mapping - _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), 0.9); + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), 1.0); //_fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); /*_fragColor = vec4(evalGlobalLightingAlphaBlended( diff --git a/libraries/render-utils/src/overlay3D_translucent.slf b/libraries/render-utils/src/overlay3D_translucent.slf index 0343567127..9f00cdf982 100644 --- a/libraries/render-utils/src/overlay3D_translucent.slf +++ b/libraries/render-utils/src/overlay3D_translucent.slf @@ -82,7 +82,8 @@ void main(void) { fragRoughness, fragOpacity); - color.xyz += vec3(1.0, 0.0, 0.0) * fragOpacity; + color.xyz += vec3(0.0, 1.0, 0.0) * fragOpacity; + color.w = 1.0; // Apply standard tone mapping _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 1e0f1cad76..0c77a15184 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -128,6 +128,7 @@ public: Flags _mask{0}; }; Filter(const Filter::Builder& builder) : Filter(builder._flags, builder._mask) {} + ShapeKey key() const { return ShapeKey(_flags); } protected: friend class ShapePlumber; Flags _flags{0}; From a98824f48300179684c5e3817545cbf67de1bfc6 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 25 Feb 2017 08:13:15 +1300 Subject: [PATCH 15/64] Code review --- scripts/system/controllers/handControllerGrab.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 5064705f78..fe0fe19ae3 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -417,9 +417,11 @@ function entityIsGrabbedByOther(entityID) { // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. continue; } - if (tag.slice(0, 5) == "grab-") { + var GRAB_PREFIX_LENGTH = 5; + var UUID_LENGTH = 38; + if (tag.slice(0, GRAB_PREFIX_LENGTH) == "grab-") { // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. - return tag.slice(5, 42); + return tag.slice(GRAB_PREFIX_LENGTH, GRAB_PREFIX_LENGTH + UUID_LENGTH - 1); } } return null; From 1b501487fd9eb019cd2894aeb8caba9c49ab623e Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 24 Feb 2017 16:03:28 -0800 Subject: [PATCH 16/64] simple shader checks --- libraries/render-utils/src/overlay3D_model.slf | 6 ++---- scripts/system/pal.js | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/overlay3D_model.slf b/libraries/render-utils/src/overlay3D_model.slf index 979a6f2201..75198cdfe4 100644 --- a/libraries/render-utils/src/overlay3D_model.slf +++ b/libraries/render-utils/src/overlay3D_model.slf @@ -112,10 +112,8 @@ void main(void) { opacity); color.rgb += emissive; - // color.rgb = vec3(0.5, 0.5, 1.0); - // Apply standard tone mapping - _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), 1.0); - //_fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); + + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); /*_fragColor = vec4(evalGlobalLightingAlphaBlended( cam._viewInverse, diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 36ecc1f084..962923eeef 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -175,7 +175,8 @@ function HighlightedEntity(id, entityProperties) { }, lineWidth: 1.0, ignoreRayIntersection: true, - drawInFront: false // Arguable. For now, let's not distract with mysterious wires around the scene. + //drawInFront: false // Arguable. For now, let's not distract with mysterious wires around the scene. + drawInFront: true // Arguable. For now, let's not distract with mysterious wires around the scene. }); HighlightedEntity.overlays.push(this); } From 9ffdc03dc9eae75a71df822d1ce6f0cc8ef67d1c Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 24 Feb 2017 18:25:24 -0800 Subject: [PATCH 17/64] setting the shaeKeys for the overly properly because most of them are CustomPipleline --- interface/src/ui/overlays/Circle3DOverlay.cpp | 2 +- interface/src/ui/overlays/Cube3DOverlay.cpp | 2 +- interface/src/ui/overlays/Image3DOverlay.cpp | 2 +- interface/src/ui/overlays/Shape3DOverlay.cpp | 2 +- interface/src/ui/overlays/Sphere3DOverlay.cpp | 2 +- interface/src/ui/overlays/Text3DOverlay.cpp | 2 +- interface/src/ui/overlays/Web3DOverlay.cpp | 2 +- libraries/render-utils/src/MeshPartPayload.h | 3 ++- libraries/render-utils/src/overlay3D_model.slf | 7 +++++-- libraries/render-utils/src/overlay3D_translucent.slf | 4 ++-- 10 files changed, 16 insertions(+), 12 deletions(-) diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index ae0173f054..b51f83ec87 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -263,7 +263,7 @@ void Circle3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Circle3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder().withoutCullFace().withUnlit(); + auto builder = render::ShapeKey::Builder().withoutCullFace().withUnlit().withOwnPipeline(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index 8af4c1d908..3cb3c6115d 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -116,7 +116,7 @@ void Cube3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Cube3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder(); + auto builder = render::ShapeKey::Builder().withOwnPipeline(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 45d63d9cf1..2350ec36ab 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -116,7 +116,7 @@ void Image3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Image3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias(); + auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias().withOwnPipeline(); if (_emissive) { builder.withUnlit(); } diff --git a/interface/src/ui/overlays/Shape3DOverlay.cpp b/interface/src/ui/overlays/Shape3DOverlay.cpp index 2556bc84aa..d64f6db9df 100644 --- a/interface/src/ui/overlays/Shape3DOverlay.cpp +++ b/interface/src/ui/overlays/Shape3DOverlay.cpp @@ -61,7 +61,7 @@ void Shape3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Shape3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder(); + auto builder = render::ShapeKey::Builder().withOwnPipeline(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/interface/src/ui/overlays/Sphere3DOverlay.cpp b/interface/src/ui/overlays/Sphere3DOverlay.cpp index 07c2861f16..0c3dd48094 100644 --- a/interface/src/ui/overlays/Sphere3DOverlay.cpp +++ b/interface/src/ui/overlays/Sphere3DOverlay.cpp @@ -58,7 +58,7 @@ void Sphere3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Sphere3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder(); + auto builder = render::ShapeKey::Builder().withOwnPipeline(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 2e2d586abc..41dabe83fd 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -132,7 +132,7 @@ void Text3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Text3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder(); + auto builder = render::ShapeKey::Builder().withOwnPipeline(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index bfc37ccf60..96051beb2b 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -275,7 +275,7 @@ void Web3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Web3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias(); + auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias().withOwnPipeline(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index c585c95025..fa8742c40c 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -118,7 +118,8 @@ public: private: mutable quint64 _fadeStartTime { 0 }; - mutable uint8_t _fadeState { FADE_WAITING_TO_START }; + //mutable uint8_t _fadeState { FADE_WAITING_TO_START }; + mutable uint8_t _fadeState { FADE_COMPLETE }; }; namespace render { diff --git a/libraries/render-utils/src/overlay3D_model.slf b/libraries/render-utils/src/overlay3D_model.slf index 75198cdfe4..6c21f95a91 100644 --- a/libraries/render-utils/src/overlay3D_model.slf +++ b/libraries/render-utils/src/overlay3D_model.slf @@ -112,8 +112,11 @@ void main(void) { opacity); color.rgb += emissive; - - _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); + color.rgb += vec3(1, 0.0, 0.0); + // Apply standard tone mapping + // _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), 1.0); + _fragColor = vec4(albedo, 0.5); + //_fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); /*_fragColor = vec4(evalGlobalLightingAlphaBlended( cam._viewInverse, diff --git a/libraries/render-utils/src/overlay3D_translucent.slf b/libraries/render-utils/src/overlay3D_translucent.slf index 9f00cdf982..3604fd88c5 100644 --- a/libraries/render-utils/src/overlay3D_translucent.slf +++ b/libraries/render-utils/src/overlay3D_translucent.slf @@ -82,8 +82,8 @@ void main(void) { fragRoughness, fragOpacity); - color.xyz += vec3(0.0, 1.0, 0.0) * fragOpacity; - color.w = 1.0; + // color.xyz += vec3(0.0, 1.0, 0.0) * fragOpacity; + // color.w = 1.0; // Apply standard tone mapping _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); From a53d5e8fbddd2ea03d30528fea17e6914e0b9b83 Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 25 Feb 2017 13:00:37 -0800 Subject: [PATCH 18/64] adjusted the PLumber shape keys to coever non material shapes in main pass --- interface/src/ui/overlays/Circle3DOverlay.cpp | 2 +- interface/src/ui/overlays/Cube3DOverlay.cpp | 2 +- interface/src/ui/overlays/Image3DOverlay.cpp | 2 +- interface/src/ui/overlays/Shape3DOverlay.cpp | 2 +- interface/src/ui/overlays/Sphere3DOverlay.cpp | 2 +- interface/src/ui/overlays/Text3DOverlay.cpp | 2 +- interface/src/ui/overlays/Web3DOverlay.cpp | 2 +- libraries/render-utils/src/MeshPartPayload.h | 4 ++-- libraries/render-utils/src/RenderDeferredTask.cpp | 6 ++---- libraries/render-utils/src/RenderPipelines.cpp | 9 +++++++++ libraries/render-utils/src/overlay3D_model.slf | 6 +++--- libraries/render-utils/src/overlay3D_translucent.slf | 3 --- 12 files changed, 23 insertions(+), 19 deletions(-) diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index b51f83ec87..ae0173f054 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -263,7 +263,7 @@ void Circle3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Circle3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder().withoutCullFace().withUnlit().withOwnPipeline(); + auto builder = render::ShapeKey::Builder().withoutCullFace().withUnlit(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index 3cb3c6115d..8af4c1d908 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -116,7 +116,7 @@ void Cube3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Cube3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder().withOwnPipeline(); + auto builder = render::ShapeKey::Builder(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 2350ec36ab..45d63d9cf1 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -116,7 +116,7 @@ void Image3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Image3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias().withOwnPipeline(); + auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias(); if (_emissive) { builder.withUnlit(); } diff --git a/interface/src/ui/overlays/Shape3DOverlay.cpp b/interface/src/ui/overlays/Shape3DOverlay.cpp index d64f6db9df..2556bc84aa 100644 --- a/interface/src/ui/overlays/Shape3DOverlay.cpp +++ b/interface/src/ui/overlays/Shape3DOverlay.cpp @@ -61,7 +61,7 @@ void Shape3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Shape3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder().withOwnPipeline(); + auto builder = render::ShapeKey::Builder(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/interface/src/ui/overlays/Sphere3DOverlay.cpp b/interface/src/ui/overlays/Sphere3DOverlay.cpp index 0c3dd48094..07c2861f16 100644 --- a/interface/src/ui/overlays/Sphere3DOverlay.cpp +++ b/interface/src/ui/overlays/Sphere3DOverlay.cpp @@ -58,7 +58,7 @@ void Sphere3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Sphere3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder().withOwnPipeline(); + auto builder = render::ShapeKey::Builder(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 41dabe83fd..2e2d586abc 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -132,7 +132,7 @@ void Text3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Text3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder().withOwnPipeline(); + auto builder = render::ShapeKey::Builder(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 96051beb2b..bfc37ccf60 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -275,7 +275,7 @@ void Web3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Web3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias().withOwnPipeline(); + auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index fa8742c40c..9d021f4f34 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -118,8 +118,8 @@ public: private: mutable quint64 _fadeStartTime { 0 }; - //mutable uint8_t _fadeState { FADE_WAITING_TO_START }; - mutable uint8_t _fadeState { FADE_COMPLETE }; + mutable uint8_t _fadeState { FADE_WAITING_TO_START }; + // mutable uint8_t _fadeState { FADE_COMPLETE }; }; namespace render { diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 55a9c8b9e4..5d03cac58f 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -75,7 +75,6 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { // GPU jobs: Start preparing the primary, deferred and lighting buffer const auto primaryFramebuffer = addJob("PreparePrimaryBuffer"); - // const auto fullFrameRangeTimer = addJob("BeginRangeTimer"); const auto opaqueRangeTimer = addJob("BeginOpaqueRangeTimer", "DrawOpaques"); const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).hasVarying(); @@ -167,6 +166,8 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { // Bounds do not draw on stencil buffer, so they must come last addJob("DrawMetaBounds", metas); + addJob("DrawOverlaysOpaques", overlayOpaques); + addJob("DrawOverlaysTransparents", overlayTransparents); // Debugging Deferred buffer job const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); @@ -207,9 +208,6 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { // Blit! addJob("Blit", primaryFramebuffer); - - // addJob("RangeTimer", fullFrameRangeTimer); - } void BeginGPURangeTimer::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, gpu::RangeTimerPointer& timer) { diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 508b035a5a..93bc7b77df 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -156,6 +156,9 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withMaterial().withUnlit(), modelVertex, modelUnlitPixel); + addPipeline( + Key::Builder().withUnlit(), + modelVertex, modelUnlitPixel); addPipeline( Key::Builder().withMaterial().withTangents(), modelNormalMapVertex, modelNormalMapPixel); @@ -169,9 +172,15 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withMaterial().withTranslucent(), modelVertex, modelTranslucentPixel); + addPipeline( + Key::Builder().withTranslucent(), + modelVertex, modelTranslucentPixel); addPipeline( Key::Builder().withMaterial().withTranslucent().withUnlit(), modelVertex, modelTranslucentUnlitPixel); + addPipeline( + Key::Builder().withTranslucent().withUnlit(), + modelVertex, modelTranslucentUnlitPixel); addPipeline( Key::Builder().withMaterial().withTranslucent().withTangents(), modelNormalMapVertex, modelTranslucentPixel); diff --git a/libraries/render-utils/src/overlay3D_model.slf b/libraries/render-utils/src/overlay3D_model.slf index 6c21f95a91..42c08d21bc 100644 --- a/libraries/render-utils/src/overlay3D_model.slf +++ b/libraries/render-utils/src/overlay3D_model.slf @@ -114,9 +114,9 @@ void main(void) { color.rgb += emissive; color.rgb += vec3(1, 0.0, 0.0); // Apply standard tone mapping - // _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), 1.0); - _fragColor = vec4(albedo, 0.5); - //_fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), 1.0); + //_fragColor = vec4(albedo, 0.5); + // _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); /*_fragColor = vec4(evalGlobalLightingAlphaBlended( cam._viewInverse, diff --git a/libraries/render-utils/src/overlay3D_translucent.slf b/libraries/render-utils/src/overlay3D_translucent.slf index 3604fd88c5..9bdac2d21f 100644 --- a/libraries/render-utils/src/overlay3D_translucent.slf +++ b/libraries/render-utils/src/overlay3D_translucent.slf @@ -82,9 +82,6 @@ void main(void) { fragRoughness, fragOpacity); - // color.xyz += vec3(0.0, 1.0, 0.0) * fragOpacity; - // color.w = 1.0; - // Apply standard tone mapping _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); } From 709c2e4240b038ecc109b4e189957569d8876a5c Mon Sep 17 00:00:00 2001 From: sam Date: Mon, 27 Feb 2017 02:52:00 -0800 Subject: [PATCH 19/64] Fixing the emissive on overlayfor models --- .../render-utils/src/RenderDeferredTask.cpp | 19 +++-- .../render-utils/src/RenderPipelines.cpp | 12 ++- .../render-utils/src/overlay3D_model.slf | 70 +++------------- .../src/overlay3D_model_translucent.slf | 83 +++++++++++++++++++ .../utilities/render/deferredLighting.qml | 24 +++++- 5 files changed, 135 insertions(+), 73 deletions(-) create mode 100644 libraries/render-utils/src/overlay3D_model_translucent.slf diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 5d03cac58f..676d176cca 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -153,22 +153,25 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { const auto toneMappingInputs = render::Varying(ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer)); addJob("ToneMapping", toneMappingInputs); + { // DEbug the bounds of the rendered items, still look at the zbuffer + addJob("DrawMetaBounds", metas); + addJob("DrawOpaqueBounds", opaques); + addJob("DrawTransparentBounds", transparents); + } + // Overlays const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).hasVarying(); const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).hasVarying(); addJob("DrawOverlay3DOpaque", overlayOpaquesInputs, true); addJob("DrawOverlay3DTransparent", overlayTransparentsInputs, false); + { // DEbug the bounds of the rendered OVERLAY items, still look at the zbuffer + addJob("DrawOverlayOpaqueBounds", overlayOpaques); + addJob("DrawOverlayTransparentBounds", overlayTransparents); + } - // Debugging stages + // Debugging stages { - - - // Bounds do not draw on stencil buffer, so they must come last - addJob("DrawMetaBounds", metas); - addJob("DrawOverlaysOpaques", overlayOpaques); - addJob("DrawOverlaysTransparents", overlayTransparents); - // Debugging Deferred buffer job const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); addJob("DebugDeferredBuffer", debugFramebuffers); diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 93bc7b77df..d753c679c6 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -51,6 +51,7 @@ #include "overlay3D_vert.h" #include "overlay3D_frag.h" #include "overlay3D_model_frag.h" +#include "overlay3D_model_translucent_frag.h" #include "overlay3D_translucent_frag.h" #include "overlay3D_unlit_frag.h" #include "overlay3D_translucent_unlit_frag.h" @@ -72,17 +73,19 @@ void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch); void initOverlay3DPipelines(ShapePlumber& plumber) { auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert)); auto vertexModel = gpu::Shader::createVertex(std::string(model_vert)); - auto pixel = gpu::Shader::createPixel(std::string(overlay3D_model_frag)); + auto pixel = gpu::Shader::createPixel(std::string(overlay3D_frag)); auto pixelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_translucent_frag)); auto pixelUnlit = gpu::Shader::createPixel(std::string(overlay3D_unlit_frag)); auto pixelTranslucentUnlit = gpu::Shader::createPixel(std::string(overlay3D_translucent_unlit_frag)); - auto pixelMaterial = gpu::Shader::createPixel(std::string(overlay3D_model_frag)); + auto pixelModel = gpu::Shader::createPixel(std::string(overlay3D_model_frag)); + auto pixelModelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_model_translucent_frag)); auto opaqueProgram = gpu::Shader::createProgram(vertex, pixel); auto translucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucent); auto unlitOpaqueProgram = gpu::Shader::createProgram(vertex, pixelUnlit); auto unlitTranslucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucentUnlit); - auto opaqueMaterialProgram = gpu::Shader::createProgram(vertexModel, pixelMaterial); + auto materialOpaqueProgram = gpu::Shader::createProgram(vertexModel, pixelModel); + auto materialTranslucentProgram = gpu::Shader::createProgram(vertexModel, pixelModelTranslucent); for (int i = 0; i < 8; i++) { bool isCulled = (i & 1); @@ -114,8 +117,9 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto simpleProgram = isOpaque ? opaqueProgram : translucentProgram; auto unlitProgram = isOpaque ? unlitOpaqueProgram : unlitTranslucentProgram; + auto materialProgram = isOpaque ? materialOpaqueProgram : materialTranslucentProgram; - plumber.addPipeline(builder.withoutUnlit().withMaterial().build().key(), opaqueMaterialProgram, state, &lightBatchSetter); + plumber.addPipeline(builder.withMaterial().build().key(), materialProgram, state, &lightBatchSetter); plumber.addPipeline(builder.withoutUnlit().withoutMaterial().build().key(), simpleProgram, state, &lightBatchSetter); plumber.addPipeline(builder.withUnlit().withoutMaterial().build().key(), unlitProgram, state, &batchSetter); } diff --git a/libraries/render-utils/src/overlay3D_model.slf b/libraries/render-utils/src/overlay3D_model.slf index 42c08d21bc..bb0d84a513 100644 --- a/libraries/render-utils/src/overlay3D_model.slf +++ b/libraries/render-utils/src/overlay3D_model.slf @@ -11,15 +11,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - -<@include model/Light.slh@> -<$declareLightBuffer()$> -<$declareLightAmbientBuffer()$> - -<@include LightingModel.slh@> - -<@include LightDirectional.slh@> -<$declareLightingDirectional()$> +<@include DeferredGlobalLight.slh@> +<$declareEvalSkyboxGlobalColor()$> <@include model/Material.slh@> @@ -29,35 +22,6 @@ <@include MaterialTextures.slh@> <$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> -vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness, float opacity) { - - // Need the light now - Light light = getLight(); - vec3 lightDirection = getLightDirection(light); - vec3 lightIrradiance = getLightIrradiance(light); - - LightAmbient ambient = getLightAmbient(); - - TransformCamera cam = getTransformCamera(); - vec3 fragNormal; - <$transformEyeToWorldDir(cam, normal, fragNormal)$> - vec3 fragEyeVectorView = normalize(-position); - vec3 fragEyeDir; - <$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$> - - vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(ambient); - - // Directional - vec3 directionalDiffuse; - vec3 directionalSpecular; - evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation); - color += directionalDiffuse * isDiffuseEnabled() * isDirectionalEnabled(); - color += directionalSpecular * isSpecularEnabled() * isDirectionalEnabled(); - - return vec4(color, opacity); -} - - in vec2 _texCoord0; in vec2 _texCoord1; in vec4 _position; @@ -98,27 +62,13 @@ void main(void) { vec3 fragPosition = _position.xyz; - vec3 fragNormal = normalize(_normal); + //vec3 fragNormal = normalize(_normal); TransformCamera cam = getTransformCamera(); + vec3 fragNormal; + <$transformEyeToWorldDir(cam, _normal, fragNormal)$>; - vec4 color = evalGlobalColor(occlusionTex, - fragPosition, - fragNormal, - albedo, - metallic, - fresnel, - roughness, - opacity); - - color.rgb += emissive; - color.rgb += vec3(1, 0.0, 0.0); - // Apply standard tone mapping - _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), 1.0); - //_fragColor = vec4(albedo, 0.5); - // _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); - - /*_fragColor = vec4(evalGlobalLightingAlphaBlended( + vec4 color = vec4(evalSkyboxGlobalColor( cam._viewInverse, 1.0, occlusionTex, @@ -127,10 +77,12 @@ void main(void) { albedo, fresnel, metallic, - emissive, - roughness, opacity), + roughness), opacity); + // And emissive + color.rgb += emissive * isEmissiveEnabled(); + // Apply standard tone mapping - _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w);*/ + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); } \ No newline at end of file diff --git a/libraries/render-utils/src/overlay3D_model_translucent.slf b/libraries/render-utils/src/overlay3D_model_translucent.slf new file mode 100644 index 0000000000..748eea329c --- /dev/null +++ b/libraries/render-utils/src/overlay3D_model_translucent.slf @@ -0,0 +1,83 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// overlay3D_model_transparent.slf +// +// Created by Sam Gateau on 2/27/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include DeferredGlobalLight.slh@> +<$declareEvalGlobalLightingAlphaBlended()$> + +<@include model/Material.slh@> + +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> + +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec4 _position; +in vec3 _normal; +in vec3 _color; +in float _alpha; + +out vec4 _fragColor; + +void main(void) { + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float metallic = getMaterialMetallic(mat); + vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value + if (metallic <= 0.5) { + metallic = 0.0; + } else { + fresnel = albedo; + metallic = 1.0; + } + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + + vec3 fragPosition = _position.xyz; + + TransformCamera cam = getTransformCamera(); + vec3 fragNormal; + <$transformEyeToWorldDir(cam, _normal, fragNormal)$> + + vec4 color = vec4(evalGlobalLightingAlphaBlended( + cam._viewInverse, + 1.0, + occlusionTex, + fragPosition, + fragNormal, + albedo, + fresnel, + metallic, + emissive, + roughness, opacity), + opacity); + + // Apply standard tone mapping + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); +} \ No newline at end of file diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 0ac4cbc5b5..99a9f258e3 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -159,13 +159,33 @@ Column { } } - Row { + Column { id: metas CheckBox { - text: "Draw Meta Bounds" + text: "Metas" checked: Render.getConfig("DrawMetaBounds")["enabled"] onCheckedChanged: { Render.getConfig("DrawMetaBounds")["enabled"] = checked } } + CheckBox { + text: "Opaques" + checked: Render.getConfig("DrawOpaqueBounds")["enabled"] + onCheckedChanged: { Render.getConfig("DrawOpaqueBounds")["enabled"] = checked } + } + CheckBox { + text: "Transparents" + checked: Render.getConfig("DrawTransparentBounds")["enabled"] + onCheckedChanged: { Render.getConfig("DrawTransparentBounds")["enabled"] = checked } + } + CheckBox { + text: "Overlay Opaques" + checked: Render.getConfig("DrawOverlayOpaqueBounds")["enabled"] + onCheckedChanged: { Render.getConfig("DrawOverlayOpaqueBounds")["enabled"] = checked } + } + CheckBox { + text: "Overlay Transparents" + checked: Render.getConfig("DrawOverlayTransparentBounds")["enabled"] + onCheckedChanged: { Render.getConfig("DrawOverlayTransparentBounds")["enabled"] = checked } + } } } From f4a3627b767294133ef060ad5e74630721d29093 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 28 Feb 2017 09:47:36 +1300 Subject: [PATCH 20/64] Make other avatar's grab beam start at more natural position --- scripts/system/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index fe0fe19ae3..1ab06927ac 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1729,7 +1729,7 @@ function MyController(hand) { } else if (this.otherGrabbingUUID !== null) { if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) { var avatar = AvatarList.getAvatar(this.otherGrabbingUUID); - var IN_FRONT_OF_AVATAR = { x: 0, y: 0, z: 0.2 }; + var IN_FRONT_OF_AVATAR = { x: 0, y: 0.2, z: 0.4 }; // Up from hips and in front of avatar. var startPosition = Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.rotation, IN_FRONT_OF_AVATAR)); this.otherGrabbingLineOn(startPosition, rayPickInfo.properties.position, COLORS_GRAB_DISTANCE_HOLD); } else { From 08cae1d3f23c74b34a4bcb9349b0a8b68a3fc61e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 28 Feb 2017 10:02:06 +1300 Subject: [PATCH 21/64] Make other avatar's grab beam finish at entity's centroid --- scripts/system/controllers/handControllerGrab.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 1ab06927ac..cdfb33ee06 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1731,7 +1731,11 @@ function MyController(hand) { var avatar = AvatarList.getAvatar(this.otherGrabbingUUID); var IN_FRONT_OF_AVATAR = { x: 0, y: 0.2, z: 0.4 }; // Up from hips and in front of avatar. var startPosition = Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.rotation, IN_FRONT_OF_AVATAR)); - this.otherGrabbingLineOn(startPosition, rayPickInfo.properties.position, COLORS_GRAB_DISTANCE_HOLD); + var finishPisition = Vec3.sum(rayPickInfo.properties.position, // Entity's centroid. + Vec3.multiplyQbyV(rayPickInfo.properties.rotation , + Vec3.multiplyVbyV(rayPickInfo.properties.dimensions, + Vec3.subtract(DEFAULT_REGISTRATION_POINT, rayPickInfo.properties.registrationPoint)))); + this.otherGrabbingLineOn(startPosition, finishPisition, COLORS_GRAB_DISTANCE_HOLD); } else { this.otherGrabbingLineOff(); } From 6fcc096bcf57cd2d3429906e3ceec3e16dd5e140 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 28 Feb 2017 10:14:38 +1300 Subject: [PATCH 22/64] Fix JavaScript error --- scripts/system/controllers/handControllerGrab.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index cdfb33ee06..3df7b91b6a 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -413,13 +413,13 @@ function entityIsGrabbedByOther(entityID) { var actionID = actionIDs[actionIndex]; var actionArguments = Entities.getActionArguments(entityID, actionID); var tag = actionArguments.tag; - if (tag == getTag()) { + if (tag === getTag()) { // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. continue; } var GRAB_PREFIX_LENGTH = 5; var UUID_LENGTH = 38; - if (tag.slice(0, GRAB_PREFIX_LENGTH) == "grab-") { + if (tag && tag.slice(0, GRAB_PREFIX_LENGTH) == "grab-") { // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. return tag.slice(GRAB_PREFIX_LENGTH, GRAB_PREFIX_LENGTH + UUID_LENGTH - 1); } From 2635657456a097bfc99d28eb44711f3b7a6b0797 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 28 Feb 2017 13:24:25 -0700 Subject: [PATCH 23/64] zappoman's feedback, plus added const corrrectness to computeLoudness --- assignment-client/src/Agent.cpp | 4 +++- assignment-client/src/Agent.h | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 5211c3beaa..9c830ef391 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -380,6 +380,8 @@ void Agent::executeScript() { audioTransform.setTranslation(scriptedAvatar->getPosition()); audioTransform.setRotation(headOrientation); + computeLoudness(&audio); + QByteArray encodedBuffer; if (_encoder) { _encoder->encode(audio, encodedBuffer); @@ -571,7 +573,7 @@ void Agent::encodeFrameOfZeros(QByteArray& encodedZeros) { } } -void Agent::computeLoudness(QByteArray* decodedBuffer) { +void Agent::computeLoudness(const QByteArray* decodedBuffer) { float loudness = 0.0f; auto scriptedAvatar = DependencyManager::get(); if (decodedBuffer) { diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 7f04b4746f..ce7393011f 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -68,10 +68,10 @@ private slots: void handleAudioPacket(QSharedPointer message); void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); - void handleSelectedAudioFormat(QSharedPointer message); + void handleSelectedAudioFormat(QSharedPointer message); void nodeActivated(SharedNodePointer activatedNode); - + void processAgentAvatar(); void processAgentAvatarAudio(); @@ -82,7 +82,7 @@ private: void negotiateAudioFormat(); void selectAudioFormat(const QString& selectedCodecName); void encodeFrameOfZeros(QByteArray& encodedZeros); - void computeLoudness(QByteArray* decodedBuffer); + void computeLoudness(const QByteArray* decodedBuffer); std::unique_ptr _scriptEngine; EntityEditPacketSender _entityEditSender; @@ -104,10 +104,10 @@ private: bool _isAvatar = false; QTimer* _avatarIdentityTimer = nullptr; QHash _outgoingScriptAudioSequenceNumbers; - + CodecPluginPointer _codec; QString _selectedCodecName; - Encoder* _encoder { nullptr }; + Encoder* _encoder { nullptr }; QThread _avatarAudioTimerThread; bool _flushEncoder { false }; }; From 6ac85aee7e22f1fd29b0ae257f9b0a033d0213f4 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 28 Feb 2017 18:12:35 -0800 Subject: [PATCH 24/64] Adding support for the unliti materials too for overlay's --- .../render-utils/src/RenderPipelines.cpp | 8 ++++ .../src/overlay3D_model_translucent_unlit.slf | 43 ++++++++++++++++++ .../src/overlay3D_model_unlit.slf | 44 +++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 libraries/render-utils/src/overlay3D_model_translucent_unlit.slf create mode 100644 libraries/render-utils/src/overlay3D_model_unlit.slf diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index d753c679c6..3b279ff6d9 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -55,6 +55,8 @@ #include "overlay3D_translucent_frag.h" #include "overlay3D_unlit_frag.h" #include "overlay3D_translucent_unlit_frag.h" +#include "overlay3D_model_unlit_frag.h" +#include "overlay3D_model_translucent_unlit_frag.h" using namespace render; @@ -79,6 +81,8 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto pixelTranslucentUnlit = gpu::Shader::createPixel(std::string(overlay3D_translucent_unlit_frag)); auto pixelModel = gpu::Shader::createPixel(std::string(overlay3D_model_frag)); auto pixelModelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_model_translucent_frag)); + auto pixelModelUnlit = gpu::Shader::createPixel(std::string(overlay3D_model_unlit_frag)); + auto pixelModelTranslucentUnlit = gpu::Shader::createPixel(std::string(overlay3D_model_translucent_unlit_frag)); auto opaqueProgram = gpu::Shader::createProgram(vertex, pixel); auto translucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucent); @@ -86,6 +90,8 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto unlitTranslucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucentUnlit); auto materialOpaqueProgram = gpu::Shader::createProgram(vertexModel, pixelModel); auto materialTranslucentProgram = gpu::Shader::createProgram(vertexModel, pixelModelTranslucent); + auto materialUnlitOpaqueProgram = gpu::Shader::createProgram(vertexModel, pixelModel); + auto materialUnlitTranslucentProgram = gpu::Shader::createProgram(vertexModel, pixelModelTranslucent); for (int i = 0; i < 8; i++) { bool isCulled = (i & 1); @@ -118,8 +124,10 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { auto simpleProgram = isOpaque ? opaqueProgram : translucentProgram; auto unlitProgram = isOpaque ? unlitOpaqueProgram : unlitTranslucentProgram; auto materialProgram = isOpaque ? materialOpaqueProgram : materialTranslucentProgram; + auto materialUnlitProgram = isOpaque ? materialUnlitOpaqueProgram : materialUnlitTranslucentProgram; plumber.addPipeline(builder.withMaterial().build().key(), materialProgram, state, &lightBatchSetter); + plumber.addPipeline(builder.withMaterial().withUnlit().build().key(), materialUnlitProgram, state, &batchSetter); plumber.addPipeline(builder.withoutUnlit().withoutMaterial().build().key(), simpleProgram, state, &lightBatchSetter); plumber.addPipeline(builder.withUnlit().withoutMaterial().build().key(), unlitProgram, state, &batchSetter); } diff --git a/libraries/render-utils/src/overlay3D_model_translucent_unlit.slf b/libraries/render-utils/src/overlay3D_model_translucent_unlit.slf new file mode 100644 index 0000000000..3dd8138272 --- /dev/null +++ b/libraries/render-utils/src/overlay3D_model_translucent_unlit.slf @@ -0,0 +1,43 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// overlay3D-model_transparent_unlit.slf +// fragment shader +// +// Created by Sam Gateau on 2/28/2017. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include LightingModel.slh@> +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO)$> + +in vec2 _texCoord0; +in vec3 _normal; +in vec3 _color; +in float _alpha; + +out vec4 _fragColor; + +void main(void) { + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + vec4 color = vec4(albedo * isUnlitEnabled(), opacity); + + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); +} \ No newline at end of file diff --git a/libraries/render-utils/src/overlay3D_model_unlit.slf b/libraries/render-utils/src/overlay3D_model_unlit.slf new file mode 100644 index 0000000000..80c2bb971e --- /dev/null +++ b/libraries/render-utils/src/overlay3D_model_unlit.slf @@ -0,0 +1,44 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// overlay3D-model_unlit.slf +// fragment shader +// +// Created by Sam Gateau on 2/28/2017. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include LightingModel.slh@> +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO)$> + +in vec2 _texCoord0; +in vec3 _normal; +in vec3 _color; +in float _alpha; + +out vec4 _fragColor; + +void main(void) { + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + vec4 color = vec4(albedo * isUnlitEnabled(), opacity); + + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); +} From 01abb4bdb61ed9e6eff63da995cd74400f4cbad1 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 24 Feb 2017 15:34:20 -0800 Subject: [PATCH 25/64] Exposed DebugDraw interface to Java Script --- libraries/script-engine/src/Quat.h | 10 ++++ libraries/script-engine/src/ScriptEngine.cpp | 3 + libraries/script-engine/src/Vec3.h | 9 +++ libraries/shared/src/DebugDraw.cpp | 8 +-- libraries/shared/src/DebugDraw.h | 63 ++++++++++++++++---- tools/jsdoc/plugins/hifi.js | 1 + 6 files changed, 80 insertions(+), 14 deletions(-) diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index bb81f24586..b51f1cb47e 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -19,6 +19,16 @@ #include #include +/**jsdoc + * A Quaternion + * + * @typedef Quat + * @property {float} x imaginary component i. + * @property {float} y imaginary component j. + * @property {float} z imaginary component k. + * @property {float} w real component. + */ + /// Scriptable interface a Quaternion helper class object. Used exclusively in the JavaScript API class Quat : public QObject { Q_OBJECT diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 83f2f5ccc0..2147374367 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -630,6 +631,8 @@ void ScriptEngine::init() { registerGlobalObject("Tablet", DependencyManager::get().data()); registerGlobalObject("Assets", &_assetScriptingInterface); registerGlobalObject("Resources", DependencyManager::get().data()); + + registerGlobalObject("DebugDraw", &DebugDraw::getInstance()); } void ScriptEngine::registerValue(const QString& valueName, QScriptValue value) { diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h index 5f524eaf74..b3a3dc3035 100644 --- a/libraries/script-engine/src/Vec3.h +++ b/libraries/script-engine/src/Vec3.h @@ -37,6 +37,15 @@ * @property {float} z Z-coordinate of the vector. */ +/**jsdoc + * A 4-dimensional vector. + * + * @typedef Vec4 + * @property {float} x X-coordinate of the vector. + * @property {float} y Y-coordinate of the vector. + * @property {float} z Z-coordinate of the vector. + * @property {float} w W-coordinate of the vector. + */ /// Scriptable interface a Vec3ernion helper class object. Used exclusively in the JavaScript API class Vec3 : public QObject { diff --git a/libraries/shared/src/DebugDraw.cpp b/libraries/shared/src/DebugDraw.cpp index 04759e6187..549dbb7293 100644 --- a/libraries/shared/src/DebugDraw.cpp +++ b/libraries/shared/src/DebugDraw.cpp @@ -28,19 +28,19 @@ void DebugDraw::drawRay(const glm::vec3& start, const glm::vec3& end, const glm: _rays.push_back(Ray(start, end, color)); } -void DebugDraw::addMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) { +void DebugDraw::addMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) { _markers[key] = MarkerInfo(rotation, position, color); } -void DebugDraw::removeMarker(const std::string& key) { +void DebugDraw::removeMarker(const QString& key) { _markers.erase(key); } -void DebugDraw::addMyAvatarMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) { +void DebugDraw::addMyAvatarMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) { _myAvatarMarkers[key] = MarkerInfo(rotation, position, color); } -void DebugDraw::removeMyAvatarMarker(const std::string& key) { +void DebugDraw::removeMyAvatarMarker(const QString& key) { _myAvatarMarkers.erase(key); } diff --git a/libraries/shared/src/DebugDraw.h b/libraries/shared/src/DebugDraw.h index f77e281e06..ac7e8b3cbc 100644 --- a/libraries/shared/src/DebugDraw.h +++ b/libraries/shared/src/DebugDraw.h @@ -17,26 +17,69 @@ #include #include -class DebugDraw { +#include +#include + +/**jsdoc + * Helper functions to render ephemeral debug markers and lines. + * DebugDraw markers and lines are only visible locally, they are not visible by other users. + * @namespace DebugDraw + */ +class DebugDraw : public QObject { + Q_OBJECT public: static DebugDraw& getInstance(); DebugDraw(); ~DebugDraw(); - // world space line, drawn only once - void drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color); + /**jsdoc + * Draws a line in world space, but it will only be visible for a single frame. + * @function DebugDraw.drawRay + * @param {Vec3} start - start position of line in world space. + * @param {Vec3} end - end position of line in world space. + * @param {Vec4} color - color of line, each component should be in the zero to one range. x = red, y = blue, z = green, w = alpha. + */ + Q_INVOKABLE void drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color); - // world space maker, marker drawn every frame until it is removed. - void addMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color); - void removeMarker(const std::string& key); + /**jsdoc + * Adds a debug marker to the world. This marker will be drawn every frame until it is removed with DebugDraw.removeMarker. + * This can be called repeatedly to change the position of the marker. + * @function DebugDraw.addMarker + * @param {string} key - name to uniquely identify this marker, later used for DebugDraw.removeMarker. + * @param {Quat} rotation - start position of line in world space. + * @param {Vec3} position - position of the marker in world space. + * @param {Vec4} color - color of the marker. + */ + Q_INVOKABLE void addMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color); - // myAvatar relative marker, maker is drawn every frame until it is removed. - void addMyAvatarMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color); - void removeMyAvatarMarker(const std::string& key); + /**jsdoc + * Removes debug marker from the world. Once a marker is removed, it will no longer be visible. + * @function DebugDraw.removeMarker + * @param {string} key - name of marker to remove. + */ + Q_INVOKABLE void removeMarker(const QString& key); + + /**jsdoc + * Adds a debug marker to the world, this marker will be drawn every frame until it is removed with DebugDraw.removeMyAvatarMarker. + * This can be called repeatedly to change the position of the marker. + * @function DebugDraw.addMyAvatarMarker + * @param {string} key - name to uniquely identify this marker, later used for DebugDraw.removeMyAvatarMarker. + * @param {Quat} rotation - start position of line in avatar space. + * @param {Vec3} position - position of the marker in avatar space. + * @param {Vec4} color - color of the marker. + */ + Q_INVOKABLE void addMyAvatarMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color); + + /**jsdoc + * Removes debug marker from the world. Once a marker is removed, it will no longer be visible + * @function DebugDraw.removeMyAvatarMarker + * @param {string} key - name of marker to remove. + */ + Q_INVOKABLE void removeMyAvatarMarker(const QString& key); using MarkerInfo = std::tuple; - using MarkerMap = std::unordered_map; + using MarkerMap = std::map; using Ray = std::tuple; using Rays = std::vector; diff --git a/tools/jsdoc/plugins/hifi.js b/tools/jsdoc/plugins/hifi.js index 8a6d2bf0f2..8be15c4103 100644 --- a/tools/jsdoc/plugins/hifi.js +++ b/tools/jsdoc/plugins/hifi.js @@ -21,6 +21,7 @@ exports.handlers = { '../../libraries/networking/src', '../../libraries/animation/src', '../../libraries/entities/src', + '../../libraries/shared/src' ]; var exts = ['.h', '.cpp']; From f41845710042c935d078ef0d04111ca99480053b Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 24 Feb 2017 15:50:41 -0800 Subject: [PATCH 26/64] Index finger touch support for the tablet-ui. --- .../system/controllers/handControllerGrab.js | 215 ++++++++++++++---- 1 file changed, 169 insertions(+), 46 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index d313d1cfa1..5f854cd5ab 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -28,7 +28,7 @@ Script.include("/~/system/libraries/controllers.js"); // var WANT_DEBUG = false; -var WANT_DEBUG_STATE = false; +var WANT_DEBUG_STATE = true; var WANT_DEBUG_SEARCH_NAME = null; var FORCE_IGNORE_IK = false; @@ -46,6 +46,8 @@ var BUMPER_ON_VALUE = 0.5; var THUMB_ON_VALUE = 0.5; +var USE_FINGER_AS_STYLUS = true; + var HAPTIC_PULSE_STRENGTH = 1.0; var HAPTIC_PULSE_DURATION = 13.0; var HAPTIC_TEXTURE_STRENGTH = 0.1; @@ -74,6 +76,10 @@ var WEB_TOUCH_Y_OFFSET = 0.05; // how far forward (or back with a negative numbe var WEB_TOUCH_TOO_CLOSE = 0.03; // if the stylus is pushed far though the web surface, don't consider it touching var WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE = 0.01; +var FINGER_TOUCH_Y_OFFSET = -0.02; +var FINGER_TOUCH_MIN = -0.01 - FINGER_TOUCH_Y_OFFSET; +var FINGER_TOUCH_MAX = 0.01 - FINGER_TOUCH_Y_OFFSET; + // // distant manipulation // @@ -252,20 +258,51 @@ CONTROLLER_STATE_MACHINE[STATE_FAR_TRIGGER] = { updateMethod: "farTrigger" }; CONTROLLER_STATE_MACHINE[STATE_ENTITY_STYLUS_TOUCHING] = { - name: "entityTouching", + name: "entityStylusTouching", + enterMethod: "entityTouchingEnter", + exitMethod: "entityTouchingExit", + updateMethod: "entityTouching" +}; +CONTROLLER_STATE_MACHINE[STATE_ENTITY_LASER_TOUCHING] = { + name: "entityLaserTouching", enterMethod: "entityTouchingEnter", exitMethod: "entityTouchingExit", updateMethod: "entityTouching" }; -CONTROLLER_STATE_MACHINE[STATE_ENTITY_LASER_TOUCHING] = CONTROLLER_STATE_MACHINE[STATE_ENTITY_STYLUS_TOUCHING]; CONTROLLER_STATE_MACHINE[STATE_OVERLAY_STYLUS_TOUCHING] = { - name: "overlayTouching", + name: "overlayStylusTouching", + enterMethod: "overlayTouchingEnter", + exitMethod: "overlayTouchingExit", + updateMethod: "overlayTouching" +}; +CONTROLLER_STATE_MACHINE[STATE_OVERLAY_LASER_TOUCHING] = { + name: "overlayLaserTouching", enterMethod: "overlayTouchingEnter", exitMethod: "overlayTouchingExit", updateMethod: "overlayTouching" }; -CONTROLLER_STATE_MACHINE[STATE_OVERLAY_LASER_TOUCHING] = CONTROLLER_STATE_MACHINE[STATE_OVERLAY_STYLUS_TOUCHING]; +function getFingerWorldLocation(hand) { + var fingerJointName = (hand === RIGHT_HAND) ? "RightHandIndex4" : "LeftHandIndex4"; + + var fingerJointIndex = MyAvatar.getJointIndex(fingerJointName); + var fingerPosition = MyAvatar.getAbsoluteJointTranslationInObjectFrame(fingerJointIndex); + var fingerRotation = MyAvatar.getAbsoluteJointRotationInObjectFrame(fingerJointIndex); + var worldFingerRotation = Quat.multiply(MyAvatar.orientation, fingerRotation); + var worldFingerPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, fingerPosition)); + + // local y offset. + var localYOffset = Vec3.multiplyQbyV(worldFingerRotation, {x: 0, y: FINGER_TOUCH_Y_OFFSET, z: 0}); + + var offsetWorldFingerPosition = Vec3.sum(worldFingerPosition, localYOffset); + + return { + position: offsetWorldFingerPosition, + orientation: worldFingerRotation, + rotation: worldFingerRotation, + valid: true + }; +} function distanceBetweenPointAndEntityBoundingBox(point, entityProps) { var entityXform = new Xform(entityProps.rotation, entityProps.position); @@ -347,6 +384,7 @@ function handLaserIntersectItem(position, rotation, start) { direction: rayDirection, length: PICK_MAX_DISTANCE }; + return intersectionInfo; } else { // entity has been destroyed? or is no longer in cache @@ -816,6 +854,8 @@ function MyController(hand) { this.tabletStabbedPos2D = null; this.tabletStabbedPos3D = null; + this.useFingerInsteadOfStylus = false; + var _this = this; var suppressedIn2D = [STATE_OFF, STATE_SEARCHING]; @@ -829,10 +869,17 @@ function MyController(hand) { this.updateSmoothedTrigger(); this.maybeScaleMyAvatar(); + if (USE_FINGER_AS_STYLUS && MyAvatar.getJointIndex("LeftHandIndex4") !== -1) { + this.useFingerInsteadOfStylus = true; + } else { + this.useFingerInsteadOfStylus = false; + } + if (this.ignoreInput()) { // Most hand input is disabled, because we are interacting with the 2d hud. // However, we still should check for collisions of the stylus with the web overlay. + var controllerLocation = getControllerWorldLocation(this.handToController(), true); this.processStylus(controllerLocation.position); @@ -1174,30 +1221,54 @@ function MyController(hand) { }; this.processStylus = function(worldHandPosition) { - // see if the hand is near a tablet or web-entity - var candidateEntities = Entities.findEntities(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE); - entityPropertiesCache.addEntities(candidateEntities); - var nearWeb = false; - for (var i = 0; i < candidateEntities.length; i++) { - var props = entityPropertiesCache.getProps(candidateEntities[i]); - if (props && (props.type == "Web" || this.isTablet(candidateEntities[i]))) { - nearWeb = true; - break; + + var performRayTest = false; + if (this.useFingerInsteadOfStylus) { + this.hideStylus(); + performRayTest = true; + } else { + var i; + + // see if the hand is near a tablet or web-entity + var candidateEntities = Entities.findEntities(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE); + entityPropertiesCache.addEntities(candidateEntities); + for (i = 0; i < candidateEntities.length; i++) { + var props = entityPropertiesCache.getProps(candidateEntities[i]); + if (props && (props.type == "Web" || this.isTablet(candidateEntities[i]))) { + performRayTest = true; + break; + } + } + + if (!performRayTest) { + var candidateOverlays = Overlays.findOverlays(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE); + for (i = 0; i < candidateOverlays.length; i++) { + if (this.isTablet(candidateOverlays[i])) { + performRayTest = true; + break; + } + } + } + + if (performRayTest) { + this.showStylus(); + } else { + this.hideStylus(); } } - var candidateOverlays = Overlays.findOverlays(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE); - for (var j = 0; j < candidateOverlays.length; j++) { - if (this.isTablet(candidateOverlays[j])) { - nearWeb = true; + if (performRayTest) { + var rayPickInfo = this.calcRayPickInfo(this.hand, this.useFingerInsteadOfStylus); + var max, min; + if (this.useFingerInsteadOfStylus) { + max = FINGER_TOUCH_MAX; + min = FINGER_TOUCH_MIN; + } else { + max = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET; + min = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE; } - } - if (nearWeb) { - this.showStylus(); - var rayPickInfo = this.calcRayPickInfo(this.hand); - if (rayPickInfo.distance < WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET && - rayPickInfo.distance > WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE) { + if (rayPickInfo.distance < max && rayPickInfo.distance > min) { this.handleStylusOnHomeButton(rayPickInfo); if (this.handleStylusOnWebEntity(rayPickInfo)) { return; @@ -1206,10 +1277,8 @@ function MyController(hand) { return; } } else { - this.homeButtonTouched = false; - } - } else { - this.hideStylus(); + this.homeButtonTouched = false; + } } }; @@ -1324,10 +1393,17 @@ function MyController(hand) { // Performs ray pick test from the hand controller into the world // @param {number} which hand to use, RIGHT_HAND or LEFT_HAND + // @param {bool} if true use the world position/orientation of the index finger to cast the ray from. // @returns {object} returns object with two keys entityID and distance // - this.calcRayPickInfo = function(hand) { - var controllerLocation = getControllerWorldLocation(this.handToController(), true); + this.calcRayPickInfo = function(hand, useFingerInsteadOfController) { + + var controllerLocation; + if (useFingerInsteadOfController) { + controllerLocation = getFingerWorldLocation(hand); + } else { + controllerLocation = getControllerWorldLocation(this.handToController(), true); + } var worldHandPosition = controllerLocation.position; var worldHandRotation = controllerLocation.orientation; @@ -2783,8 +2859,13 @@ function MyController(hand) { this.entityTouchingEnter = function() { // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, - getControllerWorldLocation(this.handToController(), true)); + var controllerLocation; + if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) { + controllerLocation = getFingerWorldLocation(this.hand); + } else { + controllerLocation = getControllerWorldLocation(this.handToController(), true); + } + var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, controllerLocation); if (intersectInfo) { var pointerEvent = { type: "Press", @@ -2820,8 +2901,13 @@ function MyController(hand) { this.entityTouchingExit = function() { // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, - getControllerWorldLocation(this.handToController(), true)); + var controllerLocation; + if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) { + controllerLocation = getFingerWorldLocation(this.hand); + } else { + controllerLocation = getControllerWorldLocation(this.handToController(), true); + } + var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, controllerLocation); if (intersectInfo) { var pointerEvent; if (this.deadspotExpired) { @@ -2861,12 +2947,26 @@ function MyController(hand) { } // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, - getControllerWorldLocation(this.handToController(), true)); + var controllerLocation; + if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) { + controllerLocation = getFingerWorldLocation(this.hand); + } else { + controllerLocation = getControllerWorldLocation(this.handToController(), true); + } + var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, controllerLocation); if (intersectInfo) { + var max, min; + if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) { + max = FINGER_TOUCH_MAX; + min = FINGER_TOUCH_MIN; + } else { + max = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET; + min = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE; + } + if (this.state == STATE_ENTITY_STYLUS_TOUCHING && - intersectInfo.distance > WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET) { + intersectInfo.distance > max) { this.setState(STATE_OFF, "pulled away from web entity"); return; } @@ -2909,8 +3009,13 @@ function MyController(hand) { this.overlayTouchingEnter = function () { // Test for intersection between controller laser and Web overlay plane. - var intersectInfo = - handLaserIntersectOverlay(this.grabbedOverlay, getControllerWorldLocation(this.handToController(), true)); + var controllerLocation; + if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) { + controllerLocation = getFingerWorldLocation(this.hand); + } else { + controllerLocation = getControllerWorldLocation(this.handToController(), true); + } + var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation); if (intersectInfo) { var pointerEvent = { type: "Press", @@ -2945,8 +3050,13 @@ function MyController(hand) { this.overlayTouchingExit = function () { // Test for intersection between controller laser and Web overlay plane. - var intersectInfo = - handLaserIntersectOverlay(this.grabbedOverlay, getControllerWorldLocation(this.handToController(), true)); + var controllerLocation; + if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) { + controllerLocation = getFingerWorldLocation(this.hand); + } else { + controllerLocation = getControllerWorldLocation(this.handToController(), true); + } + var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation); if (intersectInfo) { var pointerEvent; @@ -3003,12 +3113,25 @@ function MyController(hand) { } // Test for intersection between controller laser and Web overlay plane. - var intersectInfo = - handLaserIntersectOverlay(this.grabbedOverlay, getControllerWorldLocation(this.handToController(), true)); + var controllerLocation; + if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) { + controllerLocation = getFingerWorldLocation(this.hand); + } else { + controllerLocation = getControllerWorldLocation(this.handToController(), true); + } + var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation); if (intersectInfo) { - if (this.state == STATE_OVERLAY_STYLUS_TOUCHING && - intersectInfo.distance > WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET + WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE) { + var max, min; + if (this.useFingerInsteadOfStylus && this.state === STATE_OVERLAY_STYLUS_TOUCHING) { + max = FINGER_TOUCH_MAX; + min = FINGER_TOUCH_MIN; + } else { + max = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET + WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE; + min = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE; + } + + if (this.state == STATE_OVERLAY_STYLUS_TOUCHING && intersectInfo.distance > max) { this.grabbedThingID = null; this.setState(STATE_OFF, "pulled away from overlay"); return; @@ -3019,7 +3142,7 @@ function MyController(hand) { if (this.state == STATE_OVERLAY_STYLUS_TOUCHING && !this.tabletStabbed && - intersectInfo.distance < WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE) { + intersectInfo.distance < min) { // they've stabbed the tablet, don't send events until they pull back this.tabletStabbed = true; this.tabletStabbedPos2D = pos2D; From d142c3d69bfd851b57f6901bf24440b3c0ec4697 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 1 Mar 2017 13:29:24 -0800 Subject: [PATCH 27/64] eslint fix --- scripts/system/controllers/handControllerGrab.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 5f854cd5ab..dbc2bebd31 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -2956,13 +2956,11 @@ function MyController(hand) { var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, controllerLocation); if (intersectInfo) { - var max, min; + var max; if (this.useFingerInsteadOfStylus && this.state === STATE_ENTITY_STYLUS_TOUCHING) { max = FINGER_TOUCH_MAX; - min = FINGER_TOUCH_MIN; } else { max = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET; - min = WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_TOO_CLOSE; } if (this.state == STATE_ENTITY_STYLUS_TOUCHING && From 465a9e2008f18e893b27e33e87e4c58c5c475bd2 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 1 Mar 2017 14:31:04 -0800 Subject: [PATCH 28/64] Responsiveness improvement to tablet PointerEvents sent from handControllerGrab.js to the Qml window are now direct connections, instead of queued. This should reduce latency of laser and finger pressed onto the tablet. --- interface/src/ui/overlays/Web3DOverlay.cpp | 33 ++++++++++++++-------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index bfc37ccf60..7b9e075d64 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -198,18 +198,27 @@ void Web3DOverlay::render(RenderArgs* args) { _webSurface->getRootItem()->setProperty("scriptURL", _scriptURL); currentContext->makeCurrent(currentSurface); + auto selfOverlayID = getOverlayID(); + std::weak_ptr weakSelf = std::dynamic_pointer_cast(qApp->getOverlays().getOverlay(selfOverlayID)); auto forwardPointerEvent = [=](OverlayID overlayID, const PointerEvent& event) { - if (overlayID == getOverlayID()) { - handlePointerEvent(event); + auto self = weakSelf.lock(); + if (!self) { + return; + } + if (overlayID == selfOverlayID) { + self->handlePointerEvent(event); } }; - _mousePressConnection = connect(&(qApp->getOverlays()), &Overlays::mousePressOnOverlay, forwardPointerEvent); - _mouseReleaseConnection = connect(&(qApp->getOverlays()), &Overlays::mouseReleaseOnOverlay, forwardPointerEvent); - _mouseMoveConnection = connect(&(qApp->getOverlays()), &Overlays::mouseMoveOnOverlay, forwardPointerEvent); - _hoverLeaveConnection = connect(&(qApp->getOverlays()), &Overlays::hoverLeaveOverlay, - [=](OverlayID overlayID, const PointerEvent& event) { - if (this->_pressed && this->getOverlayID() == overlayID) { + _mousePressConnection = connect(&(qApp->getOverlays()), &Overlays::mousePressOnOverlay, this, forwardPointerEvent, Qt::DirectConnection); + _mouseReleaseConnection = connect(&(qApp->getOverlays()), &Overlays::mouseReleaseOnOverlay, this, forwardPointerEvent, Qt::DirectConnection); + _mouseMoveConnection = connect(&(qApp->getOverlays()), &Overlays::mouseMoveOnOverlay, this, forwardPointerEvent, Qt::DirectConnection); + _hoverLeaveConnection = connect(&(qApp->getOverlays()), &Overlays::hoverLeaveOverlay, this, [=](OverlayID overlayID, const PointerEvent& event) { + auto self = weakSelf.lock(); + if (!self) { + return; + } + if (self->_pressed && overlayID == selfOverlayID) { // If the user mouses off the overlay while the button is down, simulate a touch end. QTouchEvent::TouchPoint point; point.setId(event.getID()); @@ -222,12 +231,12 @@ void Web3DOverlay::render(RenderArgs* args) { touchPoints.push_back(point); QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr, Qt::NoModifier, Qt::TouchPointReleased, touchPoints); - touchEvent->setWindow(_webSurface->getWindow()); + touchEvent->setWindow(self->_webSurface->getWindow()); touchEvent->setDevice(&_touchDevice); - touchEvent->setTarget(_webSurface->getRootItem()); - QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent); + touchEvent->setTarget(self->_webSurface->getRootItem()); + QCoreApplication::postEvent(self->_webSurface->getWindow(), touchEvent); } - }); + }, Qt::DirectConnection); _emitScriptEventConnection = connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent); _webEventReceivedConnection = connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived); From 81451191c1fef266e2b78b9549b1bb855710caea Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 1 Mar 2017 18:06:03 -0700 Subject: [PATCH 29/64] no need to get the ScriptableAvatar from DependencyManager every time --- assignment-client/src/Agent.cpp | 14 ++++++-------- assignment-client/src/Agent.h | 3 ++- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 9c830ef391..d20ef2e687 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -43,7 +43,6 @@ #include #include // TODO: consider moving to scriptengine.h -#include "avatars/ScriptableAvatar.h" #include "entities/AssignmentParentFinder.h" #include "RecordingScriptingInterface.h" #include "AbstractAudioInterface.h" @@ -380,7 +379,7 @@ void Agent::executeScript() { audioTransform.setTranslation(scriptedAvatar->getPosition()); audioTransform.setRotation(headOrientation); - computeLoudness(&audio); + computeLoudness(&audio, scriptedAvatar); QByteArray encodedBuffer; if (_encoder) { @@ -573,9 +572,8 @@ void Agent::encodeFrameOfZeros(QByteArray& encodedZeros) { } } -void Agent::computeLoudness(const QByteArray* decodedBuffer) { +void Agent::computeLoudness(const QByteArray* decodedBuffer, QSharedPointer scriptableAvatar) { float loudness = 0.0f; - auto scriptedAvatar = DependencyManager::get(); if (decodedBuffer) { auto soundData = reinterpret_cast(decodedBuffer->constData()); int numFrames = decodedBuffer->size() / sizeof(int16_t); @@ -587,7 +585,7 @@ void Agent::computeLoudness(const QByteArray* decodedBuffer) { loudness /= numFrames; } } - scriptedAvatar->setAudioLoudness(loudness); + scriptableAvatar->setAudioLoudness(loudness); } void Agent::processAgentAvatarAudio() { @@ -640,7 +638,7 @@ void Agent::processAgentAvatarAudio() { if (silentFrame) { // no matter what, the loudness should be set to 0 - computeLoudness(nullptr); + computeLoudness(nullptr, scriptedAvatar); if (!_isListeningToAudioStream) { // if we have a silent frame and we're not listening then just send nothing and break out of here @@ -679,7 +677,7 @@ void Agent::processAgentAvatarAudio() { if (_flushEncoder) { encodeFrameOfZeros(encodedBuffer); // loudness is 0 - computeLoudness(nullptr); + computeLoudness(nullptr, scriptedAvatar); } else { QByteArray decodedBuffer(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); if (_encoder) { @@ -688,7 +686,7 @@ void Agent::processAgentAvatarAudio() { } else { encodedBuffer = decodedBuffer; } - computeLoudness(&decodedBuffer); + computeLoudness(&decodedBuffer, scriptedAvatar); } audioPacket->write(encodedBuffer.constData(), encodedBuffer.size()); } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index ce7393011f..0ce7b71d5d 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -30,6 +30,7 @@ #include #include "MixedAudioStream.h" +#include "avatars/ScriptableAvatar.h" class Agent : public ThreadedAssignment { Q_OBJECT @@ -82,7 +83,7 @@ private: void negotiateAudioFormat(); void selectAudioFormat(const QString& selectedCodecName); void encodeFrameOfZeros(QByteArray& encodedZeros); - void computeLoudness(const QByteArray* decodedBuffer); + void computeLoudness(const QByteArray* decodedBuffer, QSharedPointer); std::unique_ptr _scriptEngine; EntityEditPacketSender _entityEditSender; From 4f03c06a948ce37283f07247e73ffc793fa24f2e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 1 Mar 2017 18:07:53 -0800 Subject: [PATCH 30/64] Added General Preference to control stylus vs finger usage By default the finger is preferred over the stylus. --- interface/src/Application.cpp | 6 ++++++ interface/src/Application.h | 3 +++ interface/src/ui/PreferencesDialog.cpp | 6 ++++++ scripts/system/controllers/handControllerGrab.js | 7 +++++-- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d48fe19a99..d37c1a259e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -549,6 +549,7 @@ const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f; const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true; const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false; const bool DEFAULT_TABLET_VISIBLE_TO_OTHERS = false; +const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = true; Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) : QApplication(argc, argv), @@ -572,6 +573,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _desktopTabletBecomesToolbarSetting("desktopTabletBecomesToolbar", DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR), _hmdTabletBecomesToolbarSetting("hmdTabletBecomesToolbar", DEFAULT_HMD_TABLET_BECOMES_TOOLBAR), _tabletVisibleToOthersSetting("tabletVisibleToOthers", DEFAULT_TABLET_VISIBLE_TO_OTHERS), + _preferAvatarFingerOverStylusSetting("preferAvatarFingerOverStylus", DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS), _constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true), _scaleMirror(1.0f), _rotateMirror(0.0f), @@ -2362,6 +2364,10 @@ void Application::setTabletVisibleToOthersSetting(bool value) { updateSystemTabletMode(); } +void Application::setPreferAvatarFingerOverStylus(bool value) { + _preferAvatarFingerOverStylusSetting.set(value); +} + void Application::setSettingConstrainToolbarPosition(bool setting) { _constrainToolbarPosition.set(setting); DependencyManager::get()->setConstrainToolbarToCenterX(setting); diff --git a/interface/src/Application.h b/interface/src/Application.h index 13c1458aee..ec6d9b19f7 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -220,6 +220,8 @@ public: void setHmdTabletBecomesToolbarSetting(bool value); bool getTabletVisibleToOthersSetting() { return _tabletVisibleToOthersSetting.get(); } void setTabletVisibleToOthersSetting(bool value); + bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); } + void setPreferAvatarFingerOverStylus(bool value); float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); } void setSettingConstrainToolbarPosition(bool setting); @@ -565,6 +567,7 @@ private: Setting::Handle _desktopTabletBecomesToolbarSetting; Setting::Handle _hmdTabletBecomesToolbarSetting; Setting::Handle _tabletVisibleToOthersSetting; + Setting::Handle _preferAvatarFingerOverStylusSetting; Setting::Handle _constrainToolbarPosition; float _scaleMirror; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index d291510556..c2caf91045 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -107,6 +107,12 @@ void setupPreferences() { auto setter = [](bool value) { qApp->setTabletVisibleToOthersSetting(value); }; preferences->addPreference(new CheckPreference(UI_CATEGORY, "Tablet Is Visible To Others", getter, setter)); } + { + auto getter = []()->bool { return qApp->getPreferAvatarFingerOverStylus(); }; + auto setter = [](bool value) { qApp->setPreferAvatarFingerOverStylus(value); }; + preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Avatar Finger Over Stylus", getter, setter)); + } + // Snapshots static const QString SNAPSHOTS { "Snapshots" }; { diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index dbc2bebd31..e52c3344e6 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -46,8 +46,6 @@ var BUMPER_ON_VALUE = 0.5; var THUMB_ON_VALUE = 0.5; -var USE_FINGER_AS_STYLUS = true; - var HAPTIC_PULSE_STRENGTH = 1.0; var HAPTIC_PULSE_DURATION = 13.0; var HAPTIC_TEXTURE_STRENGTH = 0.1; @@ -869,6 +867,11 @@ function MyController(hand) { this.updateSmoothedTrigger(); this.maybeScaleMyAvatar(); + var DEFAULT_USE_FINGER_AS_STYLUS = true; + var USE_FINGER_AS_STYLUS = Settings.getValue("preferAvatarFingerOverStylus"); + if (USE_FINGER_AS_STYLUS === "") { + USE_FINGER_AS_STYLUS = DEFAULT_USE_FINGER_AS_STYLUS; + } if (USE_FINGER_AS_STYLUS && MyAvatar.getJointIndex("LeftHandIndex4") !== -1) { this.useFingerInsteadOfStylus = true; } else { From 29f263a29668e5901865c8d60aadf772183b4026 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 2 Mar 2017 12:43:41 -0700 Subject: [PATCH 31/64] oh man, this was hard to find --- assignment-client/src/Agent.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d20ef2e687..be23dcfa25 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -637,8 +637,6 @@ void Agent::processAgentAvatarAudio() { audioPacket->seek(sizeof(quint16)); if (silentFrame) { - // no matter what, the loudness should be set to 0 - computeLoudness(nullptr, scriptedAvatar); if (!_isListeningToAudioStream) { // if we have a silent frame and we're not listening then just send nothing and break out of here @@ -658,6 +656,8 @@ void Agent::processAgentAvatarAudio() { audioPacket->writePrimitive(scriptedAvatar->getPosition()); audioPacket->writePrimitive(glm::vec3(0)); + // no matter what, the loudness should be set to 0 + computeLoudness(nullptr, scriptedAvatar); } else if (nextSoundOutput) { // write the codec From 644e29a43d63bf8029e4f71bf4d6d576d693eaab Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 2 Mar 2017 14:15:05 -0800 Subject: [PATCH 32/64] disable WANT_STATE_DEBUG in handControllerGrab.js --- scripts/system/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index e52c3344e6..33254e9da2 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -28,7 +28,7 @@ Script.include("/~/system/libraries/controllers.js"); // var WANT_DEBUG = false; -var WANT_DEBUG_STATE = true; +var WANT_DEBUG_STATE = false; var WANT_DEBUG_SEARCH_NAME = null; var FORCE_IGNORE_IK = false; From bc256f3e8f01ce07b5740f00099e7dac59c1b4ef Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 2 Mar 2017 14:42:06 -0800 Subject: [PATCH 33/64] Fix for multi-threaded access to maps in DebugDraw. --- libraries/shared/src/DebugDraw.cpp | 30 ++++++++++++++++++++++++++++++ libraries/shared/src/DebugDraw.h | 10 ++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/DebugDraw.cpp b/libraries/shared/src/DebugDraw.cpp index 549dbb7293..f17671da4d 100644 --- a/libraries/shared/src/DebugDraw.cpp +++ b/libraries/shared/src/DebugDraw.cpp @@ -10,6 +10,8 @@ #include "DebugDraw.h" #include "SharedUtil.h" +using Lock = std::unique_lock; + DebugDraw& DebugDraw::getInstance() { static DebugDraw* instance = globalInstance("com.highfidelity.DebugDraw"); return *instance; @@ -25,22 +27,50 @@ DebugDraw::~DebugDraw() { // world space line, drawn only once void DebugDraw::drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color) { + Lock lock(_mapMutex); _rays.push_back(Ray(start, end, color)); } void DebugDraw::addMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) { + Lock lock(_mapMutex); _markers[key] = MarkerInfo(rotation, position, color); } void DebugDraw::removeMarker(const QString& key) { + Lock lock(_mapMutex); _markers.erase(key); } void DebugDraw::addMyAvatarMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) { + Lock lock(_mapMutex); _myAvatarMarkers[key] = MarkerInfo(rotation, position, color); } void DebugDraw::removeMyAvatarMarker(const QString& key) { + Lock lock(_mapMutex); _myAvatarMarkers.erase(key); } +// +// accessors used by renderer +// + +DebugDraw::MarkerMap DebugDraw::getMarkerMap() const { + Lock lock(_mapMutex); + return _markers; +} + +DebugDraw::MarkerMap DebugDraw::getMyAvatarMarkerMap() const { + Lock lock(_mapMutex); + return _myAvatarMarkers; +} + +DebugDraw::Rays DebugDraw::getRays() const { + Lock lock(_mapMutex); + return _rays; +} + +void DebugDraw::clearRays() { + Lock lock(_mapMutex); + _rays.clear(); +} diff --git a/libraries/shared/src/DebugDraw.h b/libraries/shared/src/DebugDraw.h index ac7e8b3cbc..64327585fb 100644 --- a/libraries/shared/src/DebugDraw.h +++ b/libraries/shared/src/DebugDraw.h @@ -10,6 +10,7 @@ #ifndef hifi_DebugDraw_h #define hifi_DebugDraw_h +#include #include #include #include @@ -87,16 +88,17 @@ public: // accessors used by renderer // - const MarkerMap& getMarkerMap() const { return _markers; } - const MarkerMap& getMyAvatarMarkerMap() const { return _myAvatarMarkers; } + MarkerMap getMarkerMap() const; + MarkerMap getMyAvatarMarkerMap() const; void updateMyAvatarPos(const glm::vec3& pos) { _myAvatarPos = pos; } const glm::vec3& getMyAvatarPos() const { return _myAvatarPos; } void updateMyAvatarRot(const glm::quat& rot) { _myAvatarRot = rot; } const glm::quat& getMyAvatarRot() const { return _myAvatarRot; } - const Rays getRays() const { return _rays; } - void clearRays() { _rays.clear(); } + Rays getRays() const; + void clearRays(); protected: + mutable std::mutex _mapMutex; MarkerMap _markers; MarkerMap _myAvatarMarkers; glm::quat _myAvatarRot; From e56f02d94f8c499acb50b099830d4dce05be0875 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 3 Mar 2017 14:12:04 -0800 Subject: [PATCH 34/64] Changed default for preferFingerOverStylus to false. --- interface/src/Application.cpp | 2 +- scripts/system/controllers/handControllerGrab.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0335743360..56b93e57e4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -549,7 +549,7 @@ const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f; const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true; const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false; const bool DEFAULT_TABLET_VISIBLE_TO_OTHERS = false; -const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = true; +const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false; Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) : QApplication(argc, argv), diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index db678044b5..f53512b7a7 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -896,7 +896,7 @@ function MyController(hand) { this.updateSmoothedTrigger(); this.maybeScaleMyAvatar(); - var DEFAULT_USE_FINGER_AS_STYLUS = true; + var DEFAULT_USE_FINGER_AS_STYLUS = false; var USE_FINGER_AS_STYLUS = Settings.getValue("preferAvatarFingerOverStylus"); if (USE_FINGER_AS_STYLUS === "") { USE_FINGER_AS_STYLUS = DEFAULT_USE_FINGER_AS_STYLUS; From 15d680d4f9fd1ed08ccddd7396ad4a18051fe5b1 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 3 Mar 2017 16:56:12 -0800 Subject: [PATCH 35/64] preserve audio data during pal refresh --- scripts/system/pal.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 70b2739c96..4914cbe34c 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -248,12 +248,16 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See } break; case 'refresh': + data = {}; + ExtendedOverlay.some(function (overlay) { // capture the audio data + data[overlay.key] = overlay; + }); removeOverlays(); // If filter is specified from .qml instead of through settings, update the settings. if (message.params.filter !== undefined) { Settings.setValue('pal/filtered', !!message.params.filter); } - populateUserList(message.params.selected); + populateUserList(message.params.selected, data); UserActivityLogger.palAction("refresh", ""); break; case 'displayNameUpdate': @@ -285,7 +289,7 @@ function addAvatarNode(id) { } // Each open/refresh will capture a stable set of avatarsOfInterest, within the specified filter. var avatarsOfInterest = {}; -function populateUserList(selectData) { +function populateUserList(selectData, oldAudioData) { var filter = Settings.getValue('pal/filtered') && {distance: Settings.getValue('pal/nearDistance')}; var data = [], avatars = AvatarList.getAvatarIdentifiers(); avatarsOfInterest = {}; @@ -317,12 +321,13 @@ function populateUserList(selectData) { if (id && filter && ((Math.abs(horizontal) > horizontalHalfAngle) || (Math.abs(vertical) > verticalHalfAngle))) { return; } + var oldAudio = oldAudioData && oldAudioData[id]; var avatarPalDatum = { displayName: name, userName: '', sessionId: id || '', - audioLevel: 0.0, - avgAudioLevel: 0.0, + audioLevel: (oldAudio && oldAudio.audioLevel) || 0.0, + avgAudioLevel: (oldAudio && oldAudio.avgAudioLevel) || 0.0, admin: false, personalMute: !!id && Users.getPersonalMuteStatus(id), // expects proper boolean, not null ignore: !!id && Users.getIgnoreStatus(id) // ditto From 6d4abca0c122d855825fdb2cf3212ab89ba8220f Mon Sep 17 00:00:00 2001 From: Menithal Date: Sat, 4 Mar 2017 11:12:19 +0200 Subject: [PATCH 36/64] Base line progress --- .../tutorials/entity_scripts/magneticBlock.js | 68 +++++++++++++++++++ scripts/tutorials/makeBlocks.js | 0 2 files changed, 68 insertions(+) create mode 100644 scripts/tutorials/entity_scripts/magneticBlock.js create mode 100644 scripts/tutorials/makeBlocks.js diff --git a/scripts/tutorials/entity_scripts/magneticBlock.js b/scripts/tutorials/entity_scripts/magneticBlock.js new file mode 100644 index 0000000000..6eb0900db5 --- /dev/null +++ b/scripts/tutorials/entity_scripts/magneticBlock.js @@ -0,0 +1,68 @@ +(function(){ + + // Helper for detecting nearby objects + function findEntitiesInRange(releasedProperties) { + var dimensions = releasedProperties.dimensions; + return Entities.findEntities(releasedProperties.position, ((dimensions.x + dimensions.y + dimensions.z) / 3) *1.5); + } + function getNearestValidEntityProperties(id) { + var releasedProperties = Entities.getEntityProperties(id,["position", "rotation", "dimensions"]); + var entities = findEntitiesInRange(releasedProperties); + var nearestEntity = null; + var nearest = -1; + var releaseSize = Vec3.length(releasedProperties.dimensions); + entities.forEach(function(entityId) { + print('ftest ' + entityId); + var entity = Entities.getEntityProperties(entityId, ['position', 'rotation', 'dimensions']); + var distance = Vec3.distance(releasedProperties.position, entity.position); + var scale = releaseSize/Vec3.length(entity.dimensions); + if ((nearest === -1 || distance < nearest && scale >= 0.5 && scale <= 2 ) && entity.id !== entityId) { + nearestEntity = entity; + dnearest = distance; + } + }) + return nearestEntity; + + } + + // Create the 'class' + function MagneticBlock () { } + // Bind pre-emptive events + MagneticBlock.prototype = { + // When script is bound to an entity, preload is the first callback called with the entityID. It will behave as the constructor + preload: function (id) { + /* + We will now override any existing userdata with the grabbable property. + Only retrieving userData + */ + var val = Entities.getEntityProperties(id, ['userData']) + var userData = {}; + if (val.userData && val.userData.length > 0 ) { + try { + userData = JSON.parse(val.userData); + } catch (e) {} + } + // Object must be triggerable inorder to bind events. + userData.grabbableKey = {grabbable: true}; + // Apply the new properties to entity of id + Entities.editEntity(id, {userData: JSON.stringify(userData)}); + this.held = false; + + // We will now create a custom binding, to keep the 'current' context as these are callbacks called without context + var t = this; + this.callbacks = {}; + this.callbacks["releaseGrab"] = function () { + var nearest = getNearestValidEntityProperties(id); + + print(JSON.stringify(nearest)); + } + + this.releaseGrab = this.callbacks["releaseGrab"]; + + Script.scriptEnding.connect( function () { + Script.removeEventHandler(id, "releaseGrab", this.callbacks["releaseGrab"]); //continueNearGrab + }) + } + } + return new MagneticBlock(); +}) diff --git a/scripts/tutorials/makeBlocks.js b/scripts/tutorials/makeBlocks.js new file mode 100644 index 0000000000..e69de29bb2 From ea3f7f02749856c9ca7bde0fc7a77f2464b13ffe Mon Sep 17 00:00:00 2001 From: Menithal Date: Sat, 4 Mar 2017 18:50:30 +0200 Subject: [PATCH 37/64] Initial Magnetic block --- scripts/system/assets/sounds/entitySnap.wav | Bin 0 -> 30858 bytes .../tutorials/entity_scripts/magneticBlock.js | 79 ++++++++++++++---- scripts/tutorials/makeBlocks.js | 15 ++++ 3 files changed, 78 insertions(+), 16 deletions(-) create mode 100644 scripts/system/assets/sounds/entitySnap.wav diff --git a/scripts/system/assets/sounds/entitySnap.wav b/scripts/system/assets/sounds/entitySnap.wav new file mode 100644 index 0000000000000000000000000000000000000000..4584f3dcaa7469e2efd170c68a30ed306674ca91 GIT binary patch literal 30858 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 0.5 && scale <= 2 ) && entity.id !== entityId) { - nearestEntity = entity; - dnearest = distance; + if(entityId !== releasedProperties.id) { + var entity = Entities.getEntityProperties(entityId, ['position', 'rotation', 'dimensions']); + var distance = Vec3.distance(releasedProperties.position, entity.position); + var scale = releaseSize/Vec3.length(entity.dimensions); + + if (distance < nearest && (scale >= 0.5 && scale <= 2)) { + nearestEntity = entity; + nearest = distance; + } } }) return nearestEntity; - } - // Create the 'class' function MagneticBlock () { } // Bind pre-emptive events @@ -52,13 +56,56 @@ var t = this; this.callbacks = {}; this.callbacks["releaseGrab"] = function () { - var nearest = getNearestValidEntityProperties(id); + var released = Entities.getEntityProperties(id,["position", "rotation", "dimensions"]); + var target = getNearestValidEntityProperties(released); + if (target !== null) { + // We found nearest, now lets do the snap calculations + // Plays the snap sound between the two objects. + Audio.playSound(SNAPSOUND, { + volume: 1, + position: Vec3.mix(target.position, released.position, 0.5) + }); + // Check Nearest Axis + var difference = Vec3.subtract(released.position, target.position); + var relativeDifference = Vec3.multiplyQbyV(Quat.inverse(target.rotation), difference); - print(JSON.stringify(nearest)); + var abs = { + x: Math.abs(relativeDifference.x), + y: Math.abs(relativeDifference.y), + z: Math.abs(relativeDifference.z) + }; + + if (abs.x >= abs.y && abs.x >= abs.z) { + relativeDifference.y = 0; + relativeDifference.z = 0; + if (relativeDifference.x > 0) { + relativeDifference.x = target.dimensions.x / 2 + released.dimensions.x / 2; + } else { + relativeDifference.x = -target.dimensions.x / 2 - released.dimensions.x / 2; + } + } else if (abs.y >= abs.x && abs.y >= abs.z) { + relativeDifference.x = 0; + relativeDifference.z = 0; + if (relativeDifference.y > 0) { + relativeDifference.y = target.dimensions.y / 2 + released.dimensions.y / 2; + } else { + relativeDifference.y = -target.dimensions.y / 2 - released.dimensions.y / 2; + } + } else if (abs.z >= abs.x && abs.z >= abs.y ) { + relativeDifference.x = 0; + relativeDifference.y = 0; + if (relativeDifference.z > 0) { + relativeDifference.z = target.dimensions.z / 2 + released.dimensions.z / 2; + } else { + relativeDifference.z = -target.dimensions.z / 2 - released.dimensions.z / 2; + } + } + var newPosition = Vec3.multiplyQbyV(target.rotation, relativeDifference); + Entities.editEntity(id, {rotation: target.rotation, position: Vec3.sum(target.position, newPosition)}) + } } this.releaseGrab = this.callbacks["releaseGrab"]; - Script.scriptEnding.connect( function () { Script.removeEventHandler(id, "releaseGrab", this.callbacks["releaseGrab"]); //continueNearGrab }) diff --git a/scripts/tutorials/makeBlocks.js b/scripts/tutorials/makeBlocks.js index e69de29bb2..6a8b95bb3f 100644 --- a/scripts/tutorials/makeBlocks.js +++ b/scripts/tutorials/makeBlocks.js @@ -0,0 +1,15 @@ +// Toy +const MAX_RGB_COMPONENT_VALUE = 256 / 2; // Limit the values to half the maximum. +const MIN_COLOR_VALUE = 127; +function newColor() { + color = { + red: randomPastelRGBComponent(), + green: randomPastelRGBComponent(), + blue: randomPastelRGBComponent() + }; + return color; + } +// Helper functions. +function randomPastelRGBComponent() { + return Math.floor(Math.random() * MAX_RGB_COMPONENT_VALUE) + MIN_COLOR_VALUE; +} From fe19b5511ce5b1f04c42e6db7369c1c9f075c289 Mon Sep 17 00:00:00 2001 From: Menithal Date: Sat, 4 Mar 2017 21:55:21 +0200 Subject: [PATCH 38/64] Fixed up blocks scripts --- .../tutorials/entity_scripts/magneticBlock.js | 240 ++++++++++-------- scripts/tutorials/makeBlocks.js | 79 ++++-- 2 files changed, 193 insertions(+), 126 deletions(-) diff --git a/scripts/tutorials/entity_scripts/magneticBlock.js b/scripts/tutorials/entity_scripts/magneticBlock.js index 73f317e3b2..a375025671 100644 --- a/scripts/tutorials/entity_scripts/magneticBlock.js +++ b/scripts/tutorials/entity_scripts/magneticBlock.js @@ -1,115 +1,133 @@ -(function(){ +// +// magneticBlock.js +// +// Created by Matti Lahtinen 4/3/2017 +// Copyright 2017 High Fidelity, Inc. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// Makes the entity the script is bound to connect to nearby, similarly sized entities, like a magnet. +(function() { + const SNAPSOUND_SOURCE = SoundCache.getSound(Script.resolvePath("../../system/assets/sounds/entitySnap.wav?xrs")); + // Preload trick for faster playback + const RANGE_MULTIPLER = 1.5; - const SNAPSOUND = SoundCache.getSound(Script.resolvePath("../../system/assets/sounds/entitySnap.wav?xrs")); - const RANGE_MULTIPLER = 1.5; - - // Helper for detecting nearby objects - function findEntitiesInRange(releasedProperties) { - var dimensions = releasedProperties.dimensions; - return Entities.findEntities(releasedProperties.position, ((dimensions.x + dimensions.y + dimensions.z) / 3) * RANGE_MULTIPLER); - } - - function getNearestValidEntityProperties(releasedProperties) { - var entities = findEntitiesInRange(releasedProperties); - var nearestEntity = null; - var nearest = 9999999999999; - var releaseSize = Vec3.length(releasedProperties.dimensions); - entities.forEach(function(entityId) { - if(entityId !== releasedProperties.id) { - var entity = Entities.getEntityProperties(entityId, ['position', 'rotation', 'dimensions']); - var distance = Vec3.distance(releasedProperties.position, entity.position); - var scale = releaseSize/Vec3.length(entity.dimensions); - - if (distance < nearest && (scale >= 0.5 && scale <= 2)) { - nearestEntity = entity; - nearest = distance; - } - } - }) - return nearestEntity; - } - // Create the 'class' - function MagneticBlock () { } - // Bind pre-emptive events - MagneticBlock.prototype = { - // When script is bound to an entity, preload is the first callback called with the entityID. It will behave as the constructor - preload: function (id) { - /* - We will now override any existing userdata with the grabbable property. - Only retrieving userData - */ - var val = Entities.getEntityProperties(id, ['userData']) - var userData = {}; - if (val.userData && val.userData.length > 0 ) { - try { - userData = JSON.parse(val.userData); - } catch (e) {} - } - // Object must be triggerable inorder to bind events. - userData.grabbableKey = {grabbable: true}; - // Apply the new properties to entity of id - Entities.editEntity(id, {userData: JSON.stringify(userData)}); - this.held = false; - - // We will now create a custom binding, to keep the 'current' context as these are callbacks called without context - var t = this; - this.callbacks = {}; - this.callbacks["releaseGrab"] = function () { - var released = Entities.getEntityProperties(id,["position", "rotation", "dimensions"]); - var target = getNearestValidEntityProperties(released); - if (target !== null) { - // We found nearest, now lets do the snap calculations - // Plays the snap sound between the two objects. - Audio.playSound(SNAPSOUND, { - volume: 1, - position: Vec3.mix(target.position, released.position, 0.5) - }); - // Check Nearest Axis - var difference = Vec3.subtract(released.position, target.position); - var relativeDifference = Vec3.multiplyQbyV(Quat.inverse(target.rotation), difference); - - var abs = { - x: Math.abs(relativeDifference.x), - y: Math.abs(relativeDifference.y), - z: Math.abs(relativeDifference.z) - }; - - if (abs.x >= abs.y && abs.x >= abs.z) { - relativeDifference.y = 0; - relativeDifference.z = 0; - if (relativeDifference.x > 0) { - relativeDifference.x = target.dimensions.x / 2 + released.dimensions.x / 2; - } else { - relativeDifference.x = -target.dimensions.x / 2 - released.dimensions.x / 2; - } - } else if (abs.y >= abs.x && abs.y >= abs.z) { - relativeDifference.x = 0; - relativeDifference.z = 0; - if (relativeDifference.y > 0) { - relativeDifference.y = target.dimensions.y / 2 + released.dimensions.y / 2; - } else { - relativeDifference.y = -target.dimensions.y / 2 - released.dimensions.y / 2; - } - } else if (abs.z >= abs.x && abs.z >= abs.y ) { - relativeDifference.x = 0; - relativeDifference.y = 0; - if (relativeDifference.z > 0) { - relativeDifference.z = target.dimensions.z / 2 + released.dimensions.z / 2; - } else { - relativeDifference.z = -target.dimensions.z / 2 - released.dimensions.z / 2; - } - } - var newPosition = Vec3.multiplyQbyV(target.rotation, relativeDifference); - Entities.editEntity(id, {rotation: target.rotation, position: Vec3.sum(target.position, newPosition)}) - } - } - - this.releaseGrab = this.callbacks["releaseGrab"]; - Script.scriptEnding.connect( function () { - Script.removeEventHandler(id, "releaseGrab", this.callbacks["releaseGrab"]); //continueNearGrab - }) + // Helper for detecting nearby objects + function findEntitiesInRange(releasedProperties) { + var dimensions = releasedProperties.dimensions; + return Entities.findEntities(releasedProperties.position, ((dimensions.x + dimensions.y + dimensions.z) / 3) * RANGE_MULTIPLER); } - } - return new MagneticBlock(); + + function getNearestValidEntityProperties(releasedProperties) { + var entities = findEntitiesInRange(releasedProperties); + var nearestEntity = null; + var nearest = 9999999999999; + var releaseSize = Vec3.length(releasedProperties.dimensions); + entities.forEach(function(entityId) { + if (entityId !== releasedProperties.id) { + var entity = Entities.getEntityProperties(entityId, ['position', 'rotation', 'dimensions']); + var distance = Vec3.distance(releasedProperties.position, entity.position); + var scale = releaseSize / Vec3.length(entity.dimensions); + + if (distance < nearest && (scale >= 0.5 && scale <= 2)) { + nearestEntity = entity; + nearest = distance; + } + } + }) + return nearestEntity; + } + // Create the 'class' + function MagneticBlock() {} + // Bind pre-emptive events + MagneticBlock.prototype = { + // When script is bound to an entity, preload is the first callback called with the entityID. It will behave as the constructor + preload: function(id) { + /* + We will now override any existing userdata with the grabbable property. + Only retrieving userData + */ + var val = Entities.getEntityProperties(id, ['userData']) + var userData = {grabbableKey: {}}; + + if (val.userData && val.userData.length > 0) { + try { + userData = JSON.parse(val.userData); + } catch (e) { + } + } + // Object must be triggerable inorder to bind events. + userData.grabbableKey.grabbable = true; + + // Apply the new properties to entity of id + Entities.editEntity(id, { + userData: JSON.stringify(userData) + }); + this.held = false; + // We will now create a custom binding, to keep the 'current' context as these are callbacks called without context + var t = this; + this.callbacks = {}; + this.releaseGrab = function() { + var released = Entities.getEntityProperties(id, ["position", "rotation", "dimensions"]); + var target = getNearestValidEntityProperties(released); + if (target !== null) { + // We found nearest, now lets do the snap calculations + // Plays the snap sound between the two objects. + Audio.playSound(SNAPSOUND_SOURCE, { + volume: 1, + position: Vec3.mix(target.position, released.position, 0.5) + }); + // Check Nearest Axis + var difference = Vec3.subtract(released.position, target.position); + var relativeDifference = Vec3.multiplyQbyV(Quat.inverse(target.rotation), difference); + + var abs = { + x: Math.abs(relativeDifference.x), + y: Math.abs(relativeDifference.y), + z: Math.abs(relativeDifference.z) + }; + // Check what value is greater. Simplified. + if (abs.x >= abs.y && abs.x >= abs.z) { + relativeDifference.y = 0; + relativeDifference.z = 0; + if (relativeDifference.x > 0) { + relativeDifference.x = target.dimensions.x / 2 + released.dimensions.x / 2; + } else { + relativeDifference.x = -target.dimensions.x / 2 - released.dimensions.x / 2; + } + } else if (abs.y >= abs.x && abs.y >= abs.z) { + relativeDifference.x = 0; + relativeDifference.z = 0; + if (relativeDifference.y > 0) { + relativeDifference.y = target.dimensions.y / 2 + released.dimensions.y / 2; + } else { + relativeDifference.y = -target.dimensions.y / 2 - released.dimensions.y / 2; + } + } else if (abs.z >= abs.x && abs.z >= abs.y) { + relativeDifference.x = 0; + relativeDifference.y = 0; + if (relativeDifference.z > 0) { + relativeDifference.z = target.dimensions.z / 2 + released.dimensions.z / 2; + } else { + relativeDifference.z = -target.dimensions.z / 2 - released.dimensions.z / 2; + } + } + // Can be expanded upon to work in nearest rotation as well, but was not in spec. + var newPosition = Vec3.multiplyQbyV(target.rotation, relativeDifference); + Entities.editEntity(id, { + rotation: target.rotation, + position: Vec3.sum(target.position, newPosition) + }) + } + } + + Script.scriptEnding.connect(function() { + Script.removeEventHandler(id, "releaseGrab", this.releaseGrab); + }) + } + } + return new MagneticBlock(); }) diff --git a/scripts/tutorials/makeBlocks.js b/scripts/tutorials/makeBlocks.js index 6a8b95bb3f..bb4974498c 100644 --- a/scripts/tutorials/makeBlocks.js +++ b/scripts/tutorials/makeBlocks.js @@ -1,15 +1,64 @@ -// Toy -const MAX_RGB_COMPONENT_VALUE = 256 / 2; // Limit the values to half the maximum. -const MIN_COLOR_VALUE = 127; -function newColor() { - color = { - red: randomPastelRGBComponent(), - green: randomPastelRGBComponent(), - blue: randomPastelRGBComponent() - }; - return color; - } -// Helper functions. -function randomPastelRGBComponent() { - return Math.floor(Math.random() * MAX_RGB_COMPONENT_VALUE) + MIN_COLOR_VALUE; -} +// +// makeBlocks.js +// +// Created by Matti Lahtinen 4/3/2017 +// Copyright 2017 High Fidelity, Inc. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// Creates multiple "magnetic" blocks with random colors that users clones of and snap together. + + +(function() { + const MAX_RGB_COMPONENT_VALUE = 256 / 2; // Limit the values to half the maximum. + const MIN_COLOR_VALUE = 127; + const SIZE = 0.3; + const LIFETIME = 600; + + // Random Pastel Generator based on Piper's script + function newColor() { + color = { + red: randomPastelRGBComponent(), + green: randomPastelRGBComponent(), + blue: randomPastelRGBComponent() + }; + return color; + } + // Helper functions. + function randomPastelRGBComponent() { + return Math.floor(Math.random() * MAX_RGB_COMPONENT_VALUE) + MIN_COLOR_VALUE; + } + + var SCRIPT_URL = Script.resolvePath("./entity_scripts/magneticBlock.js"); + + var frontVector = Quat.getFront(MyAvatar.orientation); + frontVector.y -=.25; + for(var x =0; x < 3; x++) { + for (var y = 0; y < 3; y++) { + + var frontOffset = { + x: 0, + y: SIZE * y + SIZE, + z: SIZE * x + SIZE + }; + + Entities.addEntity({ + type: "Box", + name: "MagneticBlock-" + y +'-' + x, + dimensions: { + x: SIZE, + y: SIZE, + z: SIZE + }, + userData: JSON.stringify({grabbableKey: { cloneable: true, grabbable: true, cloneLifetime : LIFETIME, cloneLimit: 9999}}), + position: Vec3.sum(MyAvatar.position, Vec3.sum(frontOffset, frontVector)), + color: newColor(), + script: SCRIPT_URL + }); + } + } + + Script.stop(); +})(); From 0bababf1f5866dff5f73c4650a87648cb427b5a1 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 4 Mar 2017 14:53:07 -0800 Subject: [PATCH 39/64] Safe replacement of glm_mat4_mul() for unaligned arguments instead of __m128 --- libraries/shared/src/GLMHelpers.h | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 4aac913768..609c3ab08b 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -245,4 +245,53 @@ inline bool isNaN(const glm::quat& value) { return isNaN(value.w) || isNaN(value glm::mat4 orthoInverse(const glm::mat4& m); +// +// Safe replacement of glm_mat4_mul() for unaligned arguments instead of __m128 +// +inline void glm_mat4u_mul(const glm::mat4& m1, const glm::mat4& m2, glm::mat4& r) { + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + __m128 u0 = _mm_loadu_ps((float*)&m1[0][0]); + __m128 u1 = _mm_loadu_ps((float*)&m1[1][0]); + __m128 u2 = _mm_loadu_ps((float*)&m1[2][0]); + __m128 u3 = _mm_loadu_ps((float*)&m1[3][0]); + + __m128 v0 = _mm_loadu_ps((float*)&m2[0][0]); + __m128 v1 = _mm_loadu_ps((float*)&m2[1][0]); + __m128 v2 = _mm_loadu_ps((float*)&m2[2][0]); + __m128 v3 = _mm_loadu_ps((float*)&m2[3][0]); + + __m128 t0 = _mm_mul_ps(_mm_shuffle_ps(v0, v0, _MM_SHUFFLE(0,0,0,0)), u0); + __m128 t1 = _mm_mul_ps(_mm_shuffle_ps(v0, v0, _MM_SHUFFLE(1,1,1,1)), u1); + __m128 t2 = _mm_mul_ps(_mm_shuffle_ps(v0, v0, _MM_SHUFFLE(2,2,2,2)), u2); + __m128 t3 = _mm_mul_ps(_mm_shuffle_ps(v0, v0, _MM_SHUFFLE(3,3,3,3)), u3); + v0 = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); + + t0 = _mm_mul_ps(_mm_shuffle_ps(v1, v1, _MM_SHUFFLE(0,0,0,0)), u0); + t1 = _mm_mul_ps(_mm_shuffle_ps(v1, v1, _MM_SHUFFLE(1,1,1,1)), u1); + t2 = _mm_mul_ps(_mm_shuffle_ps(v1, v1, _MM_SHUFFLE(2,2,2,2)), u2); + t3 = _mm_mul_ps(_mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3,3,3,3)), u3); + v1 = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); + + t0 = _mm_mul_ps(_mm_shuffle_ps(v2, v2, _MM_SHUFFLE(0,0,0,0)), u0); + t1 = _mm_mul_ps(_mm_shuffle_ps(v2, v2, _MM_SHUFFLE(1,1,1,1)), u1); + t2 = _mm_mul_ps(_mm_shuffle_ps(v2, v2, _MM_SHUFFLE(2,2,2,2)), u2); + t3 = _mm_mul_ps(_mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3,3,3,3)), u3); + v2 = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); + + t0 = _mm_mul_ps(_mm_shuffle_ps(v3, v3, _MM_SHUFFLE(0,0,0,0)), u0); + t1 = _mm_mul_ps(_mm_shuffle_ps(v3, v3, _MM_SHUFFLE(1,1,1,1)), u1); + t2 = _mm_mul_ps(_mm_shuffle_ps(v3, v3, _MM_SHUFFLE(2,2,2,2)), u2); + t3 = _mm_mul_ps(_mm_shuffle_ps(v3, v3, _MM_SHUFFLE(3,3,3,3)), u3); + v3 = _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3)); + + _mm_storeu_ps((float*)&r[0][0], v0); + _mm_storeu_ps((float*)&r[1][0], v1); + _mm_storeu_ps((float*)&r[2][0], v2); + _mm_storeu_ps((float*)&r[3][0], v3); +#else + r = m1 * m2; +#endif +} + #endif // hifi_GLMHelpers_h From 117bba8b6a79473190220e15b77617f32eb7171b Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 4 Mar 2017 15:17:09 -0800 Subject: [PATCH 40/64] redo unsafe optimization --- interface/src/avatar/CauterizedModel.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/interface/src/avatar/CauterizedModel.cpp b/interface/src/avatar/CauterizedModel.cpp index 0c3d863649..7faf89dec5 100644 --- a/interface/src/avatar/CauterizedModel.cpp +++ b/interface/src/avatar/CauterizedModel.cpp @@ -110,13 +110,7 @@ void CauterizedModel::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig->getJointTransform(cluster.jointIndex); -#if (GLM_ARCH & GLM_ARCH_SSE2) && !(defined Q_OS_MAC) - glm::mat4 out, inverseBindMatrix = cluster.inverseBindMatrix; - glm_mat4_mul((glm_vec4*)&jointMatrix, (glm_vec4*)&inverseBindMatrix, (glm_vec4*)&out); - state.clusterMatrices[j] = out; -#else - state.clusterMatrices[j] = jointMatrix * cluster.inverseBindMatrix; -#endif + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); } // Once computed the cluster matrices, update the buffer(s) From 46c5f961130a42e0434927f33d75470ce7b8323e Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 4 Mar 2017 15:24:03 -0800 Subject: [PATCH 41/64] redo unsafe optimization --- interface/src/avatar/CauterizedModel.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/interface/src/avatar/CauterizedModel.cpp b/interface/src/avatar/CauterizedModel.cpp index 7faf89dec5..1ca87a498a 100644 --- a/interface/src/avatar/CauterizedModel.cpp +++ b/interface/src/avatar/CauterizedModel.cpp @@ -143,13 +143,7 @@ void CauterizedModel::updateClusterMatrices() { if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { jointMatrix = cauterizeMatrix; } -#if (GLM_ARCH & GLM_ARCH_SSE2) && !(defined Q_OS_MAC) - glm::mat4 out, inverseBindMatrix = cluster.inverseBindMatrix; - glm_mat4_mul((glm_vec4*)&jointMatrix, (glm_vec4*)&inverseBindMatrix, (glm_vec4*)&out); - state.clusterMatrices[j] = out; -#else - state.clusterMatrices[j] = jointMatrix * cluster.inverseBindMatrix; -#endif + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); } if (!_cauterizeBoneSet.empty() && (state.clusterMatrices.size() > 1)) { From 50f92cb934034767416cc5946e886b1cdb4048e8 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 4 Mar 2017 15:29:23 -0800 Subject: [PATCH 42/64] redo unsafe optimization --- interface/src/avatar/SoftAttachmentModel.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/interface/src/avatar/SoftAttachmentModel.cpp b/interface/src/avatar/SoftAttachmentModel.cpp index 6ed54afb27..0521f7a893 100644 --- a/interface/src/avatar/SoftAttachmentModel.cpp +++ b/interface/src/avatar/SoftAttachmentModel.cpp @@ -60,13 +60,7 @@ void SoftAttachmentModel::updateClusterMatrices() { } else { jointMatrix = _rig->getJointTransform(cluster.jointIndex); } -#if (GLM_ARCH & GLM_ARCH_SSE2) && !(defined Q_OS_MAC) - glm::mat4 out, inverseBindMatrix = cluster.inverseBindMatrix; - glm_mat4_mul((glm_vec4*)&jointMatrix, (glm_vec4*)&inverseBindMatrix, (glm_vec4*)&out); - state.clusterMatrices[j] = out; -#else - state.clusterMatrices[j] = jointMatrix * cluster.inverseBindMatrix; -#endif + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); } // Once computed the cluster matrices, update the buffer(s) From 44c1f8500dfafc8de6ee0338baaeee40790f1451 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 4 Mar 2017 15:55:53 -0800 Subject: [PATCH 43/64] redo unsafe optimization --- libraries/animation/src/AnimPose.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/libraries/animation/src/AnimPose.cpp b/libraries/animation/src/AnimPose.cpp index 5638cacabc..e1c8528e0b 100644 --- a/libraries/animation/src/AnimPose.cpp +++ b/libraries/animation/src/AnimPose.cpp @@ -50,15 +50,9 @@ glm::vec3 AnimPose::xformVector(const glm::vec3& rhs) const { } AnimPose AnimPose::operator*(const AnimPose& rhs) const { -#if (GLM_ARCH & GLM_ARCH_SSE2) && !(defined Q_OS_MAC) glm::mat4 result; - glm::mat4 lhsMat = *this; - glm::mat4 rhsMat = rhs; - glm_mat4_mul((glm_vec4*)&lhsMat, (glm_vec4*)&rhsMat, (glm_vec4*)&result); + glm_mat4u_mul(*this, rhs, result); return AnimPose(result); -#else - return AnimPose(static_cast(*this) * static_cast(rhs)); -#endif } AnimPose AnimPose::inverse() const { From a5571bd49dbd4e71f236e95d8bf637aa9574f67c Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 4 Mar 2017 16:02:39 -0800 Subject: [PATCH 44/64] redo unsafe optimization --- libraries/render-utils/src/Model.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index adfffe2614..d4de05c84d 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1178,13 +1178,7 @@ void Model::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig->getJointTransform(cluster.jointIndex); -#if (GLM_ARCH & GLM_ARCH_SSE2) && !(defined Q_OS_MAC) - glm::mat4 out, inverseBindMatrix = cluster.inverseBindMatrix; - glm_mat4_mul((glm_vec4*)&jointMatrix, (glm_vec4*)&inverseBindMatrix, (glm_vec4*)&out); - state.clusterMatrices[j] = out; -#else - state.clusterMatrices[j] = jointMatrix * cluster.inverseBindMatrix; -#endif + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]); } // Once computed the cluster matrices, update the buffer(s) From 818425707b182343ecbd0739fcc2d9df5b5cd689 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sat, 4 Mar 2017 16:14:31 -0800 Subject: [PATCH 45/64] update unit tests --- tests/shared/src/GLMHelpersTests.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/shared/src/GLMHelpersTests.cpp b/tests/shared/src/GLMHelpersTests.cpp index 8d26d35c69..b4af4729a3 100644 --- a/tests/shared/src/GLMHelpersTests.cpp +++ b/tests/shared/src/GLMHelpersTests.cpp @@ -115,8 +115,8 @@ void GLMHelpersTests::testSimd() { a1 = a * b; b1 = b * a; - glm_mat4_mul((glm_vec4*)&a, (glm_vec4*)&b, (glm_vec4*)&a2); - glm_mat4_mul((glm_vec4*)&b, (glm_vec4*)&a, (glm_vec4*)&b2); + glm_mat4u_mul(a, b, a2); + glm_mat4u_mul(b, a, b2); { @@ -133,8 +133,8 @@ void GLMHelpersTests::testSimd() { QElapsedTimer timer; timer.start(); for (size_t i = 0; i < LOOPS; ++i) { - glm_mat4_mul((glm_vec4*)&a, (glm_vec4*)&b, (glm_vec4*)&a2); - glm_mat4_mul((glm_vec4*)&b, (glm_vec4*)&a, (glm_vec4*)&b2); + glm_mat4u_mul(a, b, a2); + glm_mat4u_mul(b, a, b2); } qDebug() << "SIMD " << timer.elapsed(); } From 04d3bf0c3802e1a77dee971eca94a915ca6c1dc6 Mon Sep 17 00:00:00 2001 From: Menithal Date: Mon, 6 Mar 2017 10:55:47 +0200 Subject: [PATCH 46/64] Cleanup and safeguards - RegistrationPoint can no longer be set for magnetic blocks, will set it to 0.5 on snap. - Simplified axis lock logic --- .../tutorials/entity_scripts/magneticBlock.js | 147 ++++++++++-------- 1 file changed, 80 insertions(+), 67 deletions(-) diff --git a/scripts/tutorials/entity_scripts/magneticBlock.js b/scripts/tutorials/entity_scripts/magneticBlock.js index a375025671..911e9c0eb5 100644 --- a/scripts/tutorials/entity_scripts/magneticBlock.js +++ b/scripts/tutorials/entity_scripts/magneticBlock.js @@ -12,13 +12,14 @@ (function() { const SNAPSOUND_SOURCE = SoundCache.getSound(Script.resolvePath("../../system/assets/sounds/entitySnap.wav?xrs")); - // Preload trick for faster playback const RANGE_MULTIPLER = 1.5; + const MAX_SCALE = 2; + const MIN_SCALE = 0.5; - // Helper for detecting nearby objects - function findEntitiesInRange(releasedProperties) { - var dimensions = releasedProperties.dimensions; - return Entities.findEntities(releasedProperties.position, ((dimensions.x + dimensions.y + dimensions.z) / 3) * RANGE_MULTIPLER); + // Helper for detecting nearby objects near entityProperties, with the scale calculated by the dimensions of the object. + function findEntitiesInRange(entityProperties) { + var dimensions = entityProperties.dimensions; + return Entities.findEntities(entityProperties.position, ((dimensions.x + dimensions.y + dimensions.z) / 3) * RANGE_MULTIPLER); } function getNearestValidEntityProperties(releasedProperties) { @@ -32,7 +33,7 @@ var distance = Vec3.distance(releasedProperties.position, entity.position); var scale = releaseSize / Vec3.length(entity.dimensions); - if (distance < nearest && (scale >= 0.5 && scale <= 2)) { + if (distance < nearest && (scale >= MIN_SCALE && scale <= MAX_SCALE)) { nearestEntity = entity; nearest = distance; } @@ -51,82 +52,94 @@ Only retrieving userData */ var val = Entities.getEntityProperties(id, ['userData']) - var userData = {grabbableKey: {}}; - + var userData = { + grabbableKey: {} + }; + // Check if existing userData field exists. if (val.userData && val.userData.length > 0) { try { userData = JSON.parse(val.userData); + if (!userData.grabbableKey) { + userData.grabbableKey = {}; // If by random change there is no grabbableKey in the userData. + } } catch (e) { + // if user data is not valid json, we will simply overwrite it. } } - // Object must be triggerable inorder to bind events. + // Object must be triggerable inorder to bind releaseGrabEvent userData.grabbableKey.grabbable = true; // Apply the new properties to entity of id Entities.editEntity(id, { userData: JSON.stringify(userData) }); - this.held = false; - // We will now create a custom binding, to keep the 'current' context as these are callbacks called without context - var t = this; - this.callbacks = {}; - this.releaseGrab = function() { - var released = Entities.getEntityProperties(id, ["position", "rotation", "dimensions"]); - var target = getNearestValidEntityProperties(released); - if (target !== null) { - // We found nearest, now lets do the snap calculations - // Plays the snap sound between the two objects. - Audio.playSound(SNAPSOUND_SOURCE, { - volume: 1, - position: Vec3.mix(target.position, released.position, 0.5) - }); - // Check Nearest Axis - var difference = Vec3.subtract(released.position, target.position); - var relativeDifference = Vec3.multiplyQbyV(Quat.inverse(target.rotation), difference); - - var abs = { - x: Math.abs(relativeDifference.x), - y: Math.abs(relativeDifference.y), - z: Math.abs(relativeDifference.z) - }; - // Check what value is greater. Simplified. - if (abs.x >= abs.y && abs.x >= abs.z) { - relativeDifference.y = 0; - relativeDifference.z = 0; - if (relativeDifference.x > 0) { - relativeDifference.x = target.dimensions.x / 2 + released.dimensions.x / 2; - } else { - relativeDifference.x = -target.dimensions.x / 2 - released.dimensions.x / 2; - } - } else if (abs.y >= abs.x && abs.y >= abs.z) { - relativeDifference.x = 0; - relativeDifference.z = 0; - if (relativeDifference.y > 0) { - relativeDifference.y = target.dimensions.y / 2 + released.dimensions.y / 2; - } else { - relativeDifference.y = -target.dimensions.y / 2 - released.dimensions.y / 2; - } - } else if (abs.z >= abs.x && abs.z >= abs.y) { - relativeDifference.x = 0; - relativeDifference.y = 0; - if (relativeDifference.z > 0) { - relativeDifference.z = target.dimensions.z / 2 + released.dimensions.z / 2; - } else { - relativeDifference.z = -target.dimensions.z / 2 - released.dimensions.z / 2; - } - } - // Can be expanded upon to work in nearest rotation as well, but was not in spec. - var newPosition = Vec3.multiplyQbyV(target.rotation, relativeDifference); - Entities.editEntity(id, { - rotation: target.rotation, - position: Vec3.sum(target.position, newPosition) - }) - } - } - Script.scriptEnding.connect(function() { Script.removeEventHandler(id, "releaseGrab", this.releaseGrab); }) + }, + releaseGrab: function(entityId) { + // Release grab is called with entityId, + var released = Entities.getEntityProperties(entityId, ["position", "rotation", "dimensions"]); + var target = getNearestValidEntityProperties(released); + if (target !== null) { + // We found nearest, now lets do the snap calculations + // Plays the snap sound between the two objects. + Audio.playSound(SNAPSOUND_SOURCE, { + volume: 1, + position: Vec3.mix(target.position, released.position, 0.5) + }); + // Check Nearest Axis + var difference = Vec3.subtract(released.position, target.position); + var relativeDifference = Vec3.multiplyQbyV(Quat.inverse(target.rotation), difference); + + var abs = { + x: Math.abs(relativeDifference.x), + y: Math.abs(relativeDifference.y), + z: Math.abs(relativeDifference.z) + }; + // Check what value is greater. and lock down to that axis. + var newRelative = { + x: 0, + y: 0, + z: 0 + } + if (abs.x >= abs.y && abs.x >= abs.z) { + newRelative.x = target.dimensions.x / 2 + released.dimensions.x / 2; + if (relativeDifference.x < 0) { + newRelative.x = -newRelative.x; + } + } else if (abs.y >= abs.x && abs.y >= abs.z) { + newRelative.y = target.dimensions.y / 2 + released.dimensions.y / 2; + if (relativeDifference.y < 0) { + newRelative.y = -newRelative.y; + } + } else if (abs.z >= abs.x && abs.z >= abs.y) { + newRelative.z = target.dimensions.z / 2 + released.dimensions.z / 2; + if (relativeDifference.z < 0) { + newRelative.z = -newRelative.z; + } + } + // Can be expanded upon to work in nearest 90 degree rotation as well, but was not in spec. + var newPosition = Vec3.multiplyQbyV(target.rotation, newRelative); + Entities.editEntity(entityId, { + // Script relies on the registrationPoint being at the very center of the object. Thus override. + registrationPoint: { + x: 0.5, + y: 0.5, + z: 0.5 + }, + rotation: target.rotation, + position: Vec3.sum(target.position, newPosition) + }); + // Script relies on the registrationPoint being at the very center of the object. Thus override. + Entities.editEntity(target.id, { + registrationPoint: { + x: 0.5, + y: 0.5, + z: 0.5 + } + }) + } } } return new MagneticBlock(); From c9c07c4269bdd2a742b0ece1e1647bec1ce30d33 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 24 Feb 2017 09:38:23 -0800 Subject: [PATCH 47/64] Basically rebase and squash --- .../src/avatars/AvatarMixerSlave.cpp | 24 +++++---- interface/src/avatar/AvatarManager.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 48 ++++++++++++----- libraries/avatars/src/AvatarData.h | 3 +- scripts/system/pal.js | 52 +++++++------------ 5 files changed, 71 insertions(+), 58 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 49b4b1ced4..1c386caab7 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -137,14 +137,18 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { // keep track of the number of other avatar frames skipped int numAvatarsWithSkippedFrames = 0; - // When this is true, the AvatarMixer will send Avatar data to a client about avatars that are not in the view frustrum - bool getsOutOfView = nodeData->getRequestsDomainListData(); - - // When this is true, the AvatarMixer will send Avatar data to a client about avatars that they've ignored - bool getsIgnoredByMe = getsOutOfView; + // When this is true, the AvatarMixer will send Avatar data to a client + // about avatars they've ignored or that are out of view + bool PALIsOpen = nodeData->getRequestsDomainListData(); // When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them - bool getsAnyIgnored = getsIgnoredByMe && node->getCanKick(); + bool getsAnyIgnored = PALIsOpen && node->getCanKick(); + + // Increase minimumBytesPerAvatar if the PAL is open or we're gettingAnyIgnored + if (PALIsOpen || getsAnyIgnored) { + minimumBytesPerAvatar += sizeof(AvatarDataPacket::AvatarGlobalPosition) + + sizeof(AvatarDataPacket::AudioLoudness); + } // setup a PacketList for the avatarPackets auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData); @@ -222,7 +226,7 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { // or that has ignored the viewing node if (!avatarNode->getLinkedData() || avatarNode->getUUID() == node->getUUID() - || (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !getsIgnoredByMe) + || (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen) || (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) { shouldIgnore = true; } else { @@ -335,9 +339,9 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { if (overBudget) { overBudgetAvatars++; _stats.overBudgetAvatars++; - detail = AvatarData::NoData; - } else if (!isInView && !getsOutOfView) { - detail = AvatarData::NoData; + detail = (PALIsOpen || getsAnyIgnored) ? AvatarData::PALMinimum : AvatarData::NoData; + } else if (!isInView) { + detail = (PALIsOpen || getsAnyIgnored) ? AvatarData::PALMinimum : AvatarData::NoData; nodeData->incrementAvatarOutOfView(); } else { detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 7417f73102..94ce444416 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -329,7 +329,7 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID, KillAvatarReason remo } void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { - AvatarHashMap::handleRemovedAvatar(removedAvatar); + AvatarHashMap::handleRemovedAvatar(removedAvatar, removalReason); // removedAvatar is a shared pointer to an AvatarData but we need to get to the derived Avatar // class in this context so we can call methods that don't exist at the base class. diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 8025c680ca..7b33ada89c 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -186,6 +186,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent bool cullSmallChanges = (dataDetail == CullSmallData); bool sendAll = (dataDetail == SendAllData); bool sendMinimum = (dataDetail == MinimumData); + bool sendPALMinimum = (dataDetail == PALMinimum); lazyInitHeadData(); @@ -222,24 +223,45 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent auto parentID = getParentID(); bool hasAvatarGlobalPosition = true; // always include global position - bool hasAvatarOrientation = sendAll || rotationChangedSince(lastSentTime); - bool hasAvatarBoundingBox = sendAll || avatarBoundingBoxChangedSince(lastSentTime); - bool hasAvatarScale = sendAll || avatarScaleChangedSince(lastSentTime); - bool hasLookAtPosition = sendAll || lookAtPositionChangedSince(lastSentTime); - bool hasAudioLoudness = sendAll || audioLoudnessChangedSince(lastSentTime); - bool hasSensorToWorldMatrix = sendAll || sensorToWorldMatrixChangedSince(lastSentTime); - bool hasAdditionalFlags = sendAll || additionalFlagsChangedSince(lastSentTime); + bool hasAvatarOrientation = false; + bool hasAvatarBoundingBox = false; + bool hasAvatarScale = false; + bool hasLookAtPosition = false; + bool hasAudioLoudness = false; + bool hasSensorToWorldMatrix = false; + bool hasAdditionalFlags = false; // local position, and parent info only apply to avatars that are parented. The local position // and the parent info can change independently though, so we track their "changed since" // separately - bool hasParentInfo = sendAll || parentInfoChangedSince(lastSentTime); - bool hasAvatarLocalPosition = hasParent() && (sendAll || - tranlationChangedSince(lastSentTime) || - parentInfoChangedSince(lastSentTime)); + bool hasParentInfo = false; + bool hasAvatarLocalPosition = false; - bool hasFaceTrackerInfo = !dropFaceTracking && hasFaceTracker() && (sendAll || faceTrackerInfoChangedSince(lastSentTime)); - bool hasJointData = sendAll || !sendMinimum; + bool hasFaceTrackerInfo = false; + bool hasJointData = false; + + if (sendPALMinimum) { + hasAudioLoudness = true; + } else { + hasAvatarOrientation = sendAll || rotationChangedSince(lastSentTime); + hasAvatarBoundingBox = sendAll || avatarBoundingBoxChangedSince(lastSentTime); + hasAvatarScale = sendAll || avatarScaleChangedSince(lastSentTime); + hasLookAtPosition = sendAll || lookAtPositionChangedSince(lastSentTime); + hasAudioLoudness = sendAll || audioLoudnessChangedSince(lastSentTime); + hasSensorToWorldMatrix = sendAll || sensorToWorldMatrixChangedSince(lastSentTime); + hasAdditionalFlags = sendAll || additionalFlagsChangedSince(lastSentTime); + + // local position, and parent info only apply to avatars that are parented. The local position + // and the parent info can change independently though, so we track their "changed since" + // separately + hasParentInfo = sendAll || parentInfoChangedSince(lastSentTime); + hasAvatarLocalPosition = hasParent() && (sendAll || + tranlationChangedSince(lastSentTime) || + parentInfoChangedSince(lastSentTime)); + + hasFaceTrackerInfo = !dropFaceTracking && hasFaceTracker() && (sendAll || faceTrackerInfoChangedSince(lastSentTime)); + hasJointData = sendAll || !sendMinimum; + } // Leading flags, to indicate how much data is actually included in the packet... AvatarDataPacket::HasFlags packetStateFlags = diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index c2240f400f..ac6c2fcbe0 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -379,7 +379,8 @@ public: MinimumData, CullSmallData, IncludeSmallData, - SendAllData + SendAllData, + PALMinimum } AvatarDataDetail; virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 4914cbe34c..f9d0a60f5a 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -526,17 +526,23 @@ var button; var buttonName = "PEOPLE"; var tablet = null; +function onTabletScreenChanged(type, url) { + if (type !== "QML" || url !== "../Pal.qml") { + off(); + } +} + function startup() { tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ text: buttonName, icon: "icons/tablet-icons/people-i.svg", - activeIcon: "icons/tablet-icons/people-a.svg", sortOrder: 7 }); tablet.fromQml.connect(fromQml); button.clicked.connect(onTabletButtonClicked); tablet.screenChanged.connect(onTabletScreenChanged); + Users.usernameFromIDReply.connect(usernameFromIDReply); Window.domainChanged.connect(clearLocalQMLDataAndClosePAL); Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL); @@ -567,39 +573,17 @@ function off() { Users.requestsDomainListData = false; } -var onPalScreen = false; -var shouldActivateButton = false; - function onTabletButtonClicked() { - if (onPalScreen) { - // for toolbar-mode: go back to home screen, this will close the window. - tablet.gotoHomeScreen(); - } else { - shouldActivateButton = true; - tablet.loadQMLSource("../Pal.qml"); - onPalScreen = true; - Users.requestsDomainListData = true; - populateUserList(); - isWired = true; - Script.update.connect(updateOverlays); - Controller.mousePressEvent.connect(handleMouseEvent); - Controller.mouseMoveEvent.connect(handleMouseMoveEvent); - triggerMapping.enable(); - triggerPressMapping.enable(); - audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); - } -} - -function onTabletScreenChanged(type, url) { - // for toolbar mode: change button to active when window is first openend, false otherwise. - button.editProperties({isActive: shouldActivateButton}); - shouldActivateButton = false; - onPalScreen = false; - - // disable sphere overlays when not on pal screen. - if (type !== "QML" || url !== "../Pal.qml") { - off(); - } + tablet.loadQMLSource("../Pal.qml"); + Users.requestsDomainListData = true; + populateUserList(); + isWired = true; + Script.update.connect(updateOverlays); + Controller.mousePressEvent.connect(handleMouseEvent); + Controller.mouseMoveEvent.connect(handleMouseMoveEvent); + triggerMapping.enable(); + triggerPressMapping.enable(); + audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); } // @@ -699,12 +683,14 @@ function shutdown() { button.clicked.disconnect(onTabletButtonClicked); tablet.removeButton(button); tablet.screenChanged.disconnect(onTabletScreenChanged); + Users.usernameFromIDReply.disconnect(usernameFromIDReply); Window.domainChanged.disconnect(clearLocalQMLDataAndClosePAL); Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL); Messages.subscribe(CHANNEL); Messages.messageReceived.disconnect(receiveMessage); Users.avatarDisconnected.disconnect(avatarDisconnected); + off(); } From b927472e4e272846c59e8ab0cbc1904a48fa9540 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 24 Feb 2017 11:25:04 -0800 Subject: [PATCH 48/64] Fixup after rebase --- scripts/system/pal.js | 52 +++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index f9d0a60f5a..4914cbe34c 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -526,23 +526,17 @@ var button; var buttonName = "PEOPLE"; var tablet = null; -function onTabletScreenChanged(type, url) { - if (type !== "QML" || url !== "../Pal.qml") { - off(); - } -} - function startup() { tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ text: buttonName, icon: "icons/tablet-icons/people-i.svg", + activeIcon: "icons/tablet-icons/people-a.svg", sortOrder: 7 }); tablet.fromQml.connect(fromQml); button.clicked.connect(onTabletButtonClicked); tablet.screenChanged.connect(onTabletScreenChanged); - Users.usernameFromIDReply.connect(usernameFromIDReply); Window.domainChanged.connect(clearLocalQMLDataAndClosePAL); Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL); @@ -573,17 +567,39 @@ function off() { Users.requestsDomainListData = false; } +var onPalScreen = false; +var shouldActivateButton = false; + function onTabletButtonClicked() { - tablet.loadQMLSource("../Pal.qml"); - Users.requestsDomainListData = true; - populateUserList(); - isWired = true; - Script.update.connect(updateOverlays); - Controller.mousePressEvent.connect(handleMouseEvent); - Controller.mouseMoveEvent.connect(handleMouseMoveEvent); - triggerMapping.enable(); - triggerPressMapping.enable(); - audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); + if (onPalScreen) { + // for toolbar-mode: go back to home screen, this will close the window. + tablet.gotoHomeScreen(); + } else { + shouldActivateButton = true; + tablet.loadQMLSource("../Pal.qml"); + onPalScreen = true; + Users.requestsDomainListData = true; + populateUserList(); + isWired = true; + Script.update.connect(updateOverlays); + Controller.mousePressEvent.connect(handleMouseEvent); + Controller.mouseMoveEvent.connect(handleMouseMoveEvent); + triggerMapping.enable(); + triggerPressMapping.enable(); + audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); + } +} + +function onTabletScreenChanged(type, url) { + // for toolbar mode: change button to active when window is first openend, false otherwise. + button.editProperties({isActive: shouldActivateButton}); + shouldActivateButton = false; + onPalScreen = false; + + // disable sphere overlays when not on pal screen. + if (type !== "QML" || url !== "../Pal.qml") { + off(); + } } // @@ -683,14 +699,12 @@ function shutdown() { button.clicked.disconnect(onTabletButtonClicked); tablet.removeButton(button); tablet.screenChanged.disconnect(onTabletScreenChanged); - Users.usernameFromIDReply.disconnect(usernameFromIDReply); Window.domainChanged.disconnect(clearLocalQMLDataAndClosePAL); Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL); Messages.subscribe(CHANNEL); Messages.messageReceived.disconnect(receiveMessage); Users.avatarDisconnected.disconnect(avatarDisconnected); - off(); } From 81ce5cffcd6eb53dff514b8a41acca148acb62a0 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 24 Feb 2017 11:47:42 -0800 Subject: [PATCH 49/64] Force-send ID packets when PAL is open --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 1c386caab7..e6ca5e49df 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -311,7 +311,8 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); // make sure we send out identity packets to and from new arrivals. - bool forceSend = !nodeData->checkAndSetHasReceivedFirstPacketsFrom(otherNode->getUUID()); + // Also make sure we send identity packets if the PAL is open. + bool forceSend = !nodeData->checkAndSetHasReceivedFirstPacketsFrom(otherNode->getUUID()) || (PALIsOpen || getsAnyIgnored); // FIXME - this clause seems suspicious "... || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp ..." if (!overBudget From 4025601c2bfc8e9510585d7fcdb8ede57a80545e Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 24 Feb 2017 14:28:29 -0800 Subject: [PATCH 50/64] Force send ID even when 'overBudget' --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index e6ca5e49df..37406675b9 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -311,15 +311,16 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); // make sure we send out identity packets to and from new arrivals. - // Also make sure we send identity packets if the PAL is open. bool forceSend = !nodeData->checkAndSetHasReceivedFirstPacketsFrom(otherNode->getUUID()) || (PALIsOpen || getsAnyIgnored); // FIXME - this clause seems suspicious "... || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp ..." - if (!overBudget + if ((!overBudget && otherNodeData->getIdentityChangeTimestamp().time_since_epoch().count() > 0 && (forceSend || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp - || distribution(generator) < IDENTITY_SEND_PROBABILITY)) { + || distribution(generator) < IDENTITY_SEND_PROBABILITY)) || + // Also make sure we send identity packets if the PAL is open. + (PALIsOpen || getsAnyIgnored)) { identityBytesSent += sendIdentityPacket(otherNodeData, node); } From 9969d422d6d07eeeea29b2c3a925934edfa7dcf4 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 24 Feb 2017 15:38:30 -0800 Subject: [PATCH 51/64] Cleanup --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 37406675b9..88b363b73a 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -311,7 +311,7 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); // make sure we send out identity packets to and from new arrivals. - bool forceSend = !nodeData->checkAndSetHasReceivedFirstPacketsFrom(otherNode->getUUID()) || (PALIsOpen || getsAnyIgnored); + bool forceSend = !nodeData->checkAndSetHasReceivedFirstPacketsFrom(otherNode->getUUID()); // FIXME - this clause seems suspicious "... || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp ..." if ((!overBudget From cfb8534d71dd3b1da32a11e02a3ba1374d0add9c Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 24 Feb 2017 17:00:57 -0800 Subject: [PATCH 52/64] Comment --- libraries/avatars/src/AvatarData.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 7b33ada89c..06df75d451 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -250,10 +250,6 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent hasAudioLoudness = sendAll || audioLoudnessChangedSince(lastSentTime); hasSensorToWorldMatrix = sendAll || sensorToWorldMatrixChangedSince(lastSentTime); hasAdditionalFlags = sendAll || additionalFlagsChangedSince(lastSentTime); - - // local position, and parent info only apply to avatars that are parented. The local position - // and the parent info can change independently though, so we track their "changed since" - // separately hasParentInfo = sendAll || parentInfoChangedSince(lastSentTime); hasAvatarLocalPosition = hasParent() && (sendAll || tranlationChangedSince(lastSentTime) || From 718ecea404459d9eb779ada40c5b99e1103fc7b2 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 27 Feb 2017 16:10:53 -0800 Subject: [PATCH 53/64] Potential non-spammy solution using pseudo-state --- .../src/avatars/AvatarMixerSlave.cpp | 31 ++++++++++++------- .../src/avatars/AvatarMixerSlave.h | 12 +++++++ libraries/avatars/src/AvatarData.h | 4 +-- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 88b363b73a..15cf89754e 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -80,16 +80,6 @@ int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45; -// FIXME - There is some old logic (unchanged as of 2/17/17) that randomly decides to send an identity -// packet. That logic had the following comment about the constants it uses... -// -// An 80% chance of sending a identity packet within a 5 second interval. -// assuming 60 htz update rate. -// -// Assuming the calculation of the constant is in fact correct for 80% and 60hz and 5 seconds (an assumption -// that I have not verified) then the constant is definitely wrong now, since we send at 45hz. -const float IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f; - void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { quint64 start = usecTimestampNow(); @@ -150,6 +140,23 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { sizeof(AvatarDataPacket::AudioLoudness); } + if (PALIsOpen) { + if (_identitySendProbability == DEFAULT_IDENTITY_SEND_PROBABILITY) + { + // The client has just opened the PAL. Force all identity packets to be sent to + // this client. + _identitySendProbability = 1.0f; + } else { + // The user recently opened the PAL, but we've already gone through the above conditional. + // We want to receive identity updates more often than default when the PAL is open + // to be more confident that the user will see the most up-to-date information in the PAL. + _identitySendProbability = DEFAULT_IDENTITY_SEND_PROBABILITY * 2; + } + } else { + // If the PAL is closed, reset the identitySendProbability to the default. + _identitySendProbability = DEFAULT_IDENTITY_SEND_PROBABILITY; + } + // setup a PacketList for the avatarPackets auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData); @@ -318,9 +325,9 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { && otherNodeData->getIdentityChangeTimestamp().time_since_epoch().count() > 0 && (forceSend || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp - || distribution(generator) < IDENTITY_SEND_PROBABILITY)) || + || distribution(generator) < _identitySendProbability)) || // Also make sure we send identity packets if the PAL is open. - (PALIsOpen || getsAnyIgnored)) { + ((PALIsOpen || getsAnyIgnored) && distribution(generator) < _identitySendProbability)) { identityBytesSent += sendIdentityPacket(otherNodeData, node); } diff --git a/assignment-client/src/avatars/AvatarMixerSlave.h b/assignment-client/src/avatars/AvatarMixerSlave.h index 04141d9d72..2fa5fa4484 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.h +++ b/assignment-client/src/avatars/AvatarMixerSlave.h @@ -101,6 +101,18 @@ private: float _maxKbpsPerNode { 0.0f }; float _throttlingRatio { 0.0f }; + + // FIXME - There is some old logic (unchanged as of 2/17/17) that randomly decides to send an identity + // packet. That logic had the following comment about the constants it uses... + // + // An 80% chance of sending a identity packet within a 5 second interval. + // assuming 60 htz update rate. + // + // Assuming the calculation of the constant is in fact correct for 80% and 60hz and 5 seconds (an assumption + // that I have not verified) then the constant is definitely wrong now, since we send at 45hz. + const float DEFAULT_IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f; + float _identitySendProbability = DEFAULT_IDENTITY_SEND_PROBABILITY; + AvatarMixerSlaveStats _stats; }; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index ac6c2fcbe0..f0759aedbd 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -376,11 +376,11 @@ public: typedef enum { NoData, + PALMinimum, MinimumData, CullSmallData, IncludeSmallData, - SendAllData, - PALMinimum + SendAllData } AvatarDataDetail; virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail); From 8bdbbd4b25aa2cb8d943cacf3724a4bb13a95224 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 1 Mar 2017 09:07:27 -0800 Subject: [PATCH 54/64] CR feedback 1 --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 15cf89754e..49353fd88f 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -134,15 +134,14 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { // When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them bool getsAnyIgnored = PALIsOpen && node->getCanKick(); - // Increase minimumBytesPerAvatar if the PAL is open or we're gettingAnyIgnored - if (PALIsOpen || getsAnyIgnored) { + // Increase minimumBytesPerAvatar if the PAL is open + if (PALIsOpen) { minimumBytesPerAvatar += sizeof(AvatarDataPacket::AvatarGlobalPosition) + sizeof(AvatarDataPacket::AudioLoudness); } if (PALIsOpen) { - if (_identitySendProbability == DEFAULT_IDENTITY_SEND_PROBABILITY) - { + if (_identitySendProbability == DEFAULT_IDENTITY_SEND_PROBABILITY) { // The client has just opened the PAL. Force all identity packets to be sent to // this client. _identitySendProbability = 1.0f; @@ -327,7 +326,7 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp || distribution(generator) < _identitySendProbability)) || // Also make sure we send identity packets if the PAL is open. - ((PALIsOpen || getsAnyIgnored) && distribution(generator) < _identitySendProbability)) { + (PALIsOpen && distribution(generator) < _identitySendProbability)) { identityBytesSent += sendIdentityPacket(otherNodeData, node); } @@ -348,9 +347,9 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { if (overBudget) { overBudgetAvatars++; _stats.overBudgetAvatars++; - detail = (PALIsOpen || getsAnyIgnored) ? AvatarData::PALMinimum : AvatarData::NoData; + detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData; } else if (!isInView) { - detail = (PALIsOpen || getsAnyIgnored) ? AvatarData::PALMinimum : AvatarData::NoData; + detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData; nodeData->incrementAvatarOutOfView(); } else { detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO From fda87b3a531c95856a949d5df1d9e4032883f20a Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 1 Mar 2017 09:09:41 -0800 Subject: [PATCH 55/64] Quick cleanup --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 49353fd88f..47efb39c3c 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -134,13 +134,10 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { // When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them bool getsAnyIgnored = PALIsOpen && node->getCanKick(); - // Increase minimumBytesPerAvatar if the PAL is open if (PALIsOpen) { + // Increase minimumBytesPerAvatar if the PAL is open minimumBytesPerAvatar += sizeof(AvatarDataPacket::AvatarGlobalPosition) + sizeof(AvatarDataPacket::AudioLoudness); - } - - if (PALIsOpen) { if (_identitySendProbability == DEFAULT_IDENTITY_SEND_PROBABILITY) { // The client has just opened the PAL. Force all identity packets to be sent to // this client. From 5fa5e6e0a74eabcfe1ab99ecd216bde4734044fc Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 1 Mar 2017 14:27:50 -0800 Subject: [PATCH 56/64] First pass at implementing Brad's simplification ideas --- .../src/avatars/AvatarMixerClientData.cpp | 10 ------- .../src/avatars/AvatarMixerClientData.h | 9 ++---- .../src/avatars/AvatarMixerSlave.cpp | 28 ++----------------- .../src/avatars/AvatarMixerSlave.h | 12 -------- 4 files changed, 6 insertions(+), 53 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 717e14535f..43b8816111 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -65,15 +65,6 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message) { // compute the offset to the data payload return _avatar->parseDataFromBuffer(message.readWithoutCopy(message.getBytesLeftToRead())); } - -bool AvatarMixerClientData::checkAndSetHasReceivedFirstPacketsFrom(const QUuid& uuid) { - if (_hasReceivedFirstPacketsFrom.find(uuid) == _hasReceivedFirstPacketsFrom.end()) { - _hasReceivedFirstPacketsFrom.insert(uuid); - return false; - } - return true; -} - uint64_t AvatarMixerClientData::getLastBroadcastTime(const QUuid& nodeUUID) const { // return the matching PacketSequenceNumber, or the default if we don't have it auto nodeMatch = _lastBroadcastTimes.find(nodeUUID); @@ -103,7 +94,6 @@ void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointe killPacket->writePrimitive(KillAvatarReason::YourAvatarEnteredTheirBubble); } DependencyManager::get()->sendUnreliablePacket(*killPacket, *self); - _hasReceivedFirstPacketsFrom.erase(other->getUUID()); } } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 51b8d692e2..1449005246 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -45,8 +45,6 @@ public: const AvatarData* getConstAvatarData() const { return _avatar.get(); } AvatarSharedPointer getAvatarSharedPointer() const { return _avatar; } - bool checkAndSetHasReceivedFirstPacketsFrom(const QUuid& uuid); - uint16_t getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const; void setLastBroadcastSequenceNumber(const QUuid& nodeUUID, uint16_t sequenceNumber) { _lastBroadcastSequenceNumbers[nodeUUID] = sequenceNumber; } @@ -63,8 +61,8 @@ public: uint16_t getLastReceivedSequenceNumber() const { return _lastReceivedSequenceNumber; } - HRCTime getIdentityChangeTimestamp() const { return _identityChangeTimestamp; } - void flagIdentityChange() { _identityChangeTimestamp = p_high_resolution_clock::now(); } + uint64_t getIdentityChangeTimestamp() const { return _identityChangeTimestamp; } + void flagIdentityChange() { _identityChangeTimestamp = usecTimestampNow(); } bool getAvatarSessionDisplayNameMustChange() const { return _avatarSessionDisplayNameMustChange; } void setAvatarSessionDisplayNameMustChange(bool set = true) { _avatarSessionDisplayNameMustChange = set; } @@ -139,7 +137,6 @@ private: uint16_t _lastReceivedSequenceNumber { 0 }; std::unordered_map _lastBroadcastSequenceNumbers; - std::unordered_set _hasReceivedFirstPacketsFrom; std::unordered_map _lastBroadcastTimes; // this is a map of the last time we encoded an "other" avatar for @@ -147,7 +144,7 @@ private: std::unordered_map _lastOtherAvatarEncodeTime; std::unordered_map> _lastOtherAvatarSentJoints; - HRCTime _identityChangeTimestamp; + uint64_t _identityChangeTimestamp; bool _avatarSessionDisplayNameMustChange{ false }; int _numAvatarsSentLastFrame = 0; diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 47efb39c3c..60dfad7687 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -138,19 +138,6 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { // Increase minimumBytesPerAvatar if the PAL is open minimumBytesPerAvatar += sizeof(AvatarDataPacket::AvatarGlobalPosition) + sizeof(AvatarDataPacket::AudioLoudness); - if (_identitySendProbability == DEFAULT_IDENTITY_SEND_PROBABILITY) { - // The client has just opened the PAL. Force all identity packets to be sent to - // this client. - _identitySendProbability = 1.0f; - } else { - // The user recently opened the PAL, but we've already gone through the above conditional. - // We want to receive identity updates more often than default when the PAL is open - // to be more confident that the user will see the most up-to-date information in the PAL. - _identitySendProbability = DEFAULT_IDENTITY_SEND_PROBABILITY * 2; - } - } else { - // If the PAL is closed, reset the identitySendProbability to the default. - _identitySendProbability = DEFAULT_IDENTITY_SEND_PROBABILITY; } // setup a PacketList for the avatarPackets @@ -313,18 +300,9 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); - // make sure we send out identity packets to and from new arrivals. - bool forceSend = !nodeData->checkAndSetHasReceivedFirstPacketsFrom(otherNode->getUUID()); - - // FIXME - this clause seems suspicious "... || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp ..." - if ((!overBudget - && otherNodeData->getIdentityChangeTimestamp().time_since_epoch().count() > 0 - && (forceSend - || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp - || distribution(generator) < _identitySendProbability)) || - // Also make sure we send identity packets if the PAL is open. - (PALIsOpen && distribution(generator) < _identitySendProbability)) { - + // If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO + // the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A. + if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) { identityBytesSent += sendIdentityPacket(otherNodeData, node); } diff --git a/assignment-client/src/avatars/AvatarMixerSlave.h b/assignment-client/src/avatars/AvatarMixerSlave.h index 2fa5fa4484..04141d9d72 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.h +++ b/assignment-client/src/avatars/AvatarMixerSlave.h @@ -101,18 +101,6 @@ private: float _maxKbpsPerNode { 0.0f }; float _throttlingRatio { 0.0f }; - - // FIXME - There is some old logic (unchanged as of 2/17/17) that randomly decides to send an identity - // packet. That logic had the following comment about the constants it uses... - // - // An 80% chance of sending a identity packet within a 5 second interval. - // assuming 60 htz update rate. - // - // Assuming the calculation of the constant is in fact correct for 80% and 60hz and 5 seconds (an assumption - // that I have not verified) then the constant is definitely wrong now, since we send at 45hz. - const float DEFAULT_IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f; - float _identitySendProbability = DEFAULT_IDENTITY_SEND_PROBABILITY; - AvatarMixerSlaveStats _stats; }; From 5418a7c2304c2773fb09584070b28e8707db13f3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 1 Mar 2017 16:54:53 -0800 Subject: [PATCH 57/64] Important addition before rebase --- assignment-client/src/avatars/AvatarMixerClientData.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 43b8816111..0df3edbd11 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -94,6 +94,7 @@ void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointe killPacket->writePrimitive(KillAvatarReason::YourAvatarEnteredTheirBubble); } DependencyManager::get()->sendUnreliablePacket(*killPacket, *self); + setLastBroadcastTime(other->getUUID(), 0); } } From 685bd95105f96b828ce62292b8b83b3291c6e83a Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 3 Mar 2017 11:21:55 -0800 Subject: [PATCH 58/64] I think I'm done. Not straightforward! --- assignment-client/src/avatars/AvatarMixer.cpp | 26 ++++++++++++++++++- .../src/avatars/AvatarMixerClientData.cpp | 2 +- .../src/avatars/AvatarMixerSlave.cpp | 3 ++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 0f6863f9ae..1d1a1a57a8 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -409,7 +409,31 @@ void AvatarMixer::handleKillAvatarPacket(QSharedPointer message void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer message, SharedNodePointer senderNode) { auto start = usecTimestampNow(); - senderNode->parseIgnoreRequestMessage(message); + auto nodeList = DependencyManager::get(); + AvatarMixerClientData* nodeData = reinterpret_cast(senderNode->getLinkedData()); + bool addToIgnore; + message->readPrimitive(&addToIgnore); + while (message->getBytesLeftToRead()) { + // parse out the UUID being ignored from the packet + QUuid ignoredUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + // Reset the lastBroadcastTime for the ignored avatar to 0 + // so the AvatarMixer knows it'll have to send identity data about the ignored avatar + // to the ignorer if the ignorer unignores. + nodeData->setLastBroadcastTime(ignoredUUID, 0); + + // Reset the lastBroadcastTime for the ignorer (FROM THE PERSPECTIVE OF THE IGNORED) to 0 + // so the AvatarMixer knows it'll have to send identity data about the ignorer + // to the ignored if the ignorer unignores. + auto ignoredNode = nodeList->nodeWithUUID(ignoredUUID); + AvatarMixerClientData* ignoredNodeData = reinterpret_cast(ignoredNode->getLinkedData()); + ignoredNodeData->setLastBroadcastTime(senderNode->getUUID(), 0); + + if (addToIgnore) { + senderNode->addIgnoredNode(ignoredUUID); + } else { + senderNode->removeIgnoredNode(ignoredUUID); + } + } auto end = usecTimestampNow(); _handleNodeIgnoreRequestPacketElapsedTime += (end - start); } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 0df3edbd11..15a7f50fa3 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -93,8 +93,8 @@ void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointe } else { killPacket->writePrimitive(KillAvatarReason::YourAvatarEnteredTheirBubble); } - DependencyManager::get()->sendUnreliablePacket(*killPacket, *self); setLastBroadcastTime(other->getUUID(), 0); + DependencyManager::get()->sendUnreliablePacket(*killPacket, *self); } } diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 60dfad7687..05de209e81 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -222,7 +222,8 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { } else { // Check to see if the space bubble is enabled - if (node->isIgnoreRadiusEnabled() || avatarNode->isIgnoreRadiusEnabled()) { + // Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored + if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) { // Define the scale of the box for the current other node glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f; From 0000b8fb2159a9b489fa61cd56f6b21ed9fa021e Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 3 Mar 2017 17:01:57 -0800 Subject: [PATCH 59/64] OMG I think it's actually fully working --- assignment-client/src/avatars/AvatarMixer.cpp | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 1d1a1a57a8..c10a616818 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -365,6 +365,28 @@ void AvatarMixer::handleRequestsDomainListDataPacket(QSharedPointerreadPrimitive(&isRequesting); nodeData->setRequestsDomainListData(isRequesting); qCDebug(avatars) << "node" << nodeData->getNodeID() << "requestsDomainListData" << isRequesting; + + // If we just opened the PAL... + if (isRequesting) { + // For each node in the NodeList... + auto nodeList = DependencyManager::get(); + nodeList->eachMatchingNode( + // Discover the valid nodes we're ignoring... + [&](const SharedNodePointer& node)->bool { + if (node->getUUID() != senderNode->getUUID() && + (nodeData->isRadiusIgnoring(node->getUUID()) || + senderNode->isIgnoringNodeWithID(node->getUUID()))) { + return true; + } + return false; + }, + // ...For those nodes, reset the lastBroadcastTime to 0 + // so that the AvatarMixer will send Identity data to us + [&](const SharedNodePointer& node) { + nodeData->setLastBroadcastTime(node->getUUID(), 0); + } + ); + } } } auto end = usecTimestampNow(); From 19a31d76304393f5488196a3c70bf6475eaf410b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 6 Mar 2017 10:15:53 -0800 Subject: [PATCH 60/64] don't automatically unhook overlays from hands unless they were grabbable overlays --- scripts/system/controllers/handControllerGrab.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index aa0a3d9abd..febeea0c8e 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -3570,13 +3570,21 @@ function MyController(hand) { } _this.previouslyUnhooked[childID] = now; - // we don't know if it's an entity or an overlay + if (Overlays.getProperty(childID, "grabbable")) { + // only auto-unhook overlays that were flagged as grabbable. this avoids unhooking overlays + // used in tutorial. + Overlays.editOverlay(childID, { + parentID: previousParentID, + parentJointIndex: previousParentJointIndex + }); + } Entities.editEntity(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex }); - Overlays.editOverlay(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex }); } else { Entities.editEntity(childID, { parentID: NULL_UUID }); - Overlays.editOverlay(childID, { parentID: NULL_UUID }); + if (Overlays.getProperty(childID, "grabbable")) { + Overlays.editOverlay(childID, { parentID: NULL_UUID }); + } } } }); From d50a0e33a99b6cb0181186f8fae1dd496dd1f3f2 Mon Sep 17 00:00:00 2001 From: Menithal Date: Mon, 6 Mar 2017 21:07:16 +0200 Subject: [PATCH 61/64] CR. Run through Lint ECMAScript 5 standard Meaning all const are out, non-variable definitions are out, etc --- .../tutorials/entity_scripts/magneticBlock.js | 37 +++++++++++-------- scripts/tutorials/makeBlocks.js | 32 ++++++++++------ 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/scripts/tutorials/entity_scripts/magneticBlock.js b/scripts/tutorials/entity_scripts/magneticBlock.js index 911e9c0eb5..7771a3668d 100644 --- a/scripts/tutorials/entity_scripts/magneticBlock.js +++ b/scripts/tutorials/entity_scripts/magneticBlock.js @@ -11,21 +11,23 @@ // Makes the entity the script is bound to connect to nearby, similarly sized entities, like a magnet. (function() { - const SNAPSOUND_SOURCE = SoundCache.getSound(Script.resolvePath("../../system/assets/sounds/entitySnap.wav?xrs")); - const RANGE_MULTIPLER = 1.5; - const MAX_SCALE = 2; - const MIN_SCALE = 0.5; + var SNAPSOUND_SOURCE = SoundCache.getSound(Script.resolvePath("../../system/assets/sounds/entitySnap.wav?xrs")); + var RANGE_MULTIPLER = 1.5; + var MAX_SCALE = 2; + var MIN_SCALE = 0.5; // Helper for detecting nearby objects near entityProperties, with the scale calculated by the dimensions of the object. function findEntitiesInRange(entityProperties) { var dimensions = entityProperties.dimensions; - return Entities.findEntities(entityProperties.position, ((dimensions.x + dimensions.y + dimensions.z) / 3) * RANGE_MULTIPLER); + // Average of the dimensions instead of full value. + return Entities.findEntities(entityProperties.position, + ((dimensions.x + dimensions.y + dimensions.z) / 3) * RANGE_MULTIPLER); } function getNearestValidEntityProperties(releasedProperties) { var entities = findEntitiesInRange(releasedProperties); var nearestEntity = null; - var nearest = 9999999999999; + var nearest = Number.MAX_SAFE_INTEGER; var releaseSize = Vec3.length(releasedProperties.dimensions); entities.forEach(function(entityId) { if (entityId !== releasedProperties.id) { @@ -38,27 +40,30 @@ nearest = distance; } } - }) + }); return nearestEntity; } // Create the 'class' function MagneticBlock() {} // Bind pre-emptive events MagneticBlock.prototype = { - // When script is bound to an entity, preload is the first callback called with the entityID. It will behave as the constructor + /* + When script is bound to an entity, preload is the first callback called with the entityID. + It will behave as the constructor + */ preload: function(id) { /* We will now override any existing userdata with the grabbable property. Only retrieving userData */ - var val = Entities.getEntityProperties(id, ['userData']) + var entity = Entities.getEntityProperties(id, ['userData']); var userData = { grabbableKey: {} }; // Check if existing userData field exists. - if (val.userData && val.userData.length > 0) { + if (entity.userData && entity.userData.length > 0) { try { - userData = JSON.parse(val.userData); + userData = JSON.parse(entity.userData); if (!userData.grabbableKey) { userData.grabbableKey = {}; // If by random change there is no grabbableKey in the userData. } @@ -75,7 +80,7 @@ }); Script.scriptEnding.connect(function() { Script.removeEventHandler(id, "releaseGrab", this.releaseGrab); - }) + }); }, releaseGrab: function(entityId) { // Release grab is called with entityId, @@ -102,7 +107,7 @@ x: 0, y: 0, z: 0 - } + }; if (abs.x >= abs.y && abs.x >= abs.z) { newRelative.x = target.dimensions.x / 2 + released.dimensions.x / 2; if (relativeDifference.x < 0) { @@ -138,9 +143,9 @@ y: 0.5, z: 0.5 } - }) + }); } } - } + }; return new MagneticBlock(); -}) +}); diff --git a/scripts/tutorials/makeBlocks.js b/scripts/tutorials/makeBlocks.js index bb4974498c..54bdead792 100644 --- a/scripts/tutorials/makeBlocks.js +++ b/scripts/tutorials/makeBlocks.js @@ -12,19 +12,20 @@ (function() { - const MAX_RGB_COMPONENT_VALUE = 256 / 2; // Limit the values to half the maximum. - const MIN_COLOR_VALUE = 127; - const SIZE = 0.3; - const LIFETIME = 600; - + var MAX_RGB_COMPONENT_VALUE = 256 / 2; // Limit the values to half the maximum. + var MIN_COLOR_VALUE = 127; + var SIZE = 0.3; + var LIFETIME = 600; + var VERTICAL_OFFSET = -0.25; + var ROWS = 3; + var COLUMNS = 3; // Random Pastel Generator based on Piper's script function newColor() { - color = { + return { red: randomPastelRGBComponent(), green: randomPastelRGBComponent(), blue: randomPastelRGBComponent() }; - return color; } // Helper functions. function randomPastelRGBComponent() { @@ -34,9 +35,9 @@ var SCRIPT_URL = Script.resolvePath("./entity_scripts/magneticBlock.js"); var frontVector = Quat.getFront(MyAvatar.orientation); - frontVector.y -=.25; - for(var x =0; x < 3; x++) { - for (var y = 0; y < 3; y++) { + frontVector.y += VERTICAL_OFFSET; + for (var x = 0; x < COLUMNS; x++) { + for (var y = 0; y < ROWS; y++) { var frontOffset = { x: 0, @@ -46,13 +47,20 @@ Entities.addEntity({ type: "Box", - name: "MagneticBlock-" + y +'-' + x, + name: "MagneticBlock-" + y + '-' + x, dimensions: { x: SIZE, y: SIZE, z: SIZE }, - userData: JSON.stringify({grabbableKey: { cloneable: true, grabbable: true, cloneLifetime : LIFETIME, cloneLimit: 9999}}), + userData: JSON.stringify({ + grabbableKey: { + cloneable: true, + grabbable: true, + cloneLifetime: LIFETIME, + cloneLimit: 9999 + } + }), position: Vec3.sum(MyAvatar.position, Vec3.sum(frontOffset, frontVector)), color: newColor(), script: SCRIPT_URL From 01ba44c572d66be6c86d79390918bda798576ba6 Mon Sep 17 00:00:00 2001 From: Menithal Date: Mon, 6 Mar 2017 21:32:27 +0200 Subject: [PATCH 62/64] Fixed print --- scripts/tutorials/entity_scripts/magneticBlock.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/tutorials/entity_scripts/magneticBlock.js b/scripts/tutorials/entity_scripts/magneticBlock.js index 7771a3668d..1ec5f2a6c6 100644 --- a/scripts/tutorials/entity_scripts/magneticBlock.js +++ b/scripts/tutorials/entity_scripts/magneticBlock.js @@ -27,7 +27,7 @@ function getNearestValidEntityProperties(releasedProperties) { var entities = findEntitiesInRange(releasedProperties); var nearestEntity = null; - var nearest = Number.MAX_SAFE_INTEGER; + var nearest = Number.MAX_VALUE - 1; var releaseSize = Vec3.length(releasedProperties.dimensions); entities.forEach(function(entityId) { if (entityId !== releasedProperties.id) { @@ -56,14 +56,14 @@ We will now override any existing userdata with the grabbable property. Only retrieving userData */ - var entity = Entities.getEntityProperties(id, ['userData']); + var entityProperties = Entities.getEntityProperties(id, ['userData']); var userData = { grabbableKey: {} }; // Check if existing userData field exists. - if (entity.userData && entity.userData.length > 0) { + if (entityProperties.userData && entityProperties.userData.length > 0) { try { - userData = JSON.parse(entity.userData); + userData = JSON.parse(entityProperties.userData); if (!userData.grabbableKey) { userData.grabbableKey = {}; // If by random change there is no grabbableKey in the userData. } From a2d2c41f02876e90711e1c222044af048a5d4c84 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 6 Mar 2017 11:45:49 -0800 Subject: [PATCH 63/64] remove debug print --- scripts/system/controllers/handControllerGrab.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index febeea0c8e..7e9aae17af 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -3552,7 +3552,6 @@ function MyController(hand) { // we appear to be holding something and this script isn't in a state that would be holding something. // unhook it. if we previously took note of this entity's parent, put it back where it was. This // works around some problems that happen when more than one hand or avatar is passing something around. - print("disconnecting stray child of hand: (" + _this.hand + ") " + childID); if (_this.previousParentID[childID]) { var previousParentID = _this.previousParentID[childID]; var previousParentJointIndex = _this.previousParentJointIndex[childID]; From 21f36d72123a292f2045dd96504ea74f80581551 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 6 Mar 2017 12:41:00 -0800 Subject: [PATCH 64/64] removing comments and restoring the correct behavior for Pal.js --- libraries/render-utils/src/MeshPartPayload.h | 1 - scripts/system/pal.js | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 9d021f4f34..c585c95025 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -119,7 +119,6 @@ public: private: mutable quint64 _fadeStartTime { 0 }; mutable uint8_t _fadeState { FADE_WAITING_TO_START }; - // mutable uint8_t _fadeState { FADE_COMPLETE }; }; namespace render { diff --git a/scripts/system/pal.js b/scripts/system/pal.js index ae9c8265aa..70b2739c96 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -184,8 +184,7 @@ function HighlightedEntity(id, entityProperties) { }, lineWidth: 1.0, ignoreRayIntersection: true, - //drawInFront: false // Arguable. For now, let's not distract with mysterious wires around the scene. - drawInFront: true // Arguable. For now, let's not distract with mysterious wires around the scene. + drawInFront: false // Arguable. For now, let's not distract with mysterious wires around the scene. }); HighlightedEntity.overlays.push(this); }