From 37541e4ed2ce178508db014664139d650e78b324 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 10 Feb 2017 14:29:29 -0800 Subject: [PATCH 01/66] 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/66] 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/66] 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/66] 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/66] 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 a00216cb4f43d967ac49f6e05a528eab00a44b5b Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 21 Feb 2017 18:20:55 -0800 Subject: [PATCH 06/66] 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 c7b164d8f26d1bb45666f1c1ad96c354b648b4ae Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 22 Feb 2017 18:21:18 -0800 Subject: [PATCH 07/66] 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 08/66] 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 67031850aab6e723a230b8d06507c90b6a9790f1 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 24 Feb 2017 00:05:54 -0800 Subject: [PATCH 09/66] 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 10/66] 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 11/66] 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 1b501487fd9eb019cd2894aeb8caba9c49ab623e Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 24 Feb 2017 16:03:28 -0800 Subject: [PATCH 12/66] 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 13/66] 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 14/66] 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 15/66] 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 6ac85aee7e22f1fd29b0ae257f9b0a033d0213f4 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 28 Feb 2017 18:12:35 -0800 Subject: [PATCH 16/66] 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 17/66] 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 18/66] 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 19/66] 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 20/66] 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 4f03c06a948ce37283f07247e73ffc793fa24f2e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 1 Mar 2017 18:07:53 -0800 Subject: [PATCH 21/66] 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 644e29a43d63bf8029e4f71bf4d6d576d693eaab Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 2 Mar 2017 14:15:05 -0800 Subject: [PATCH 22/66] 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 23/66] 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 24/66] 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 25/66] 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 26/66] 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 27/66] 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 zcmeHv33yf2+4Va2W)6@r&kzEFC_@H@5J7|l6ct23#i7*z0TDtlL_i!{r&=vqajHYL z4p{3v)KA4apr9x!3M$AXgdvQ9%)`BB{mIA!PWePtGI!C_!%GNbKK2h{)JESAS3W0 zpXXLqQ}aHBzHpj&W_doJJQ z6kp${716(mDvl_OcroJbh~fTk-Lq;sRraemy?j$ydd0A+rPaM^y9TfFEr>g<#n@K! z6Sl*_xqZoBV_qQ{G#DZ4LvUBZ%tKP4XDDzfd%t(PRcA2S|r zmz{O!5ns2quO@s~dg``oik9rYbnmd5p3UBCwYKSPaThhYJ32SGq~>>Z4_9w2ZC~}N z@0G}IToTyqzRGxiyV&6|-{Q==vZ@;^V*<0IGMjuD_h|IG$SuBSg6nJA*NzQ*7I>+4 zPgPE3x5}1PGitYRn}4JK9^W|sb^hVb@0`z~>f(09T^@IL?6dxLb)VNB$BBHgu3z2C z+P{<^I9PLdTHUXFYn(-ay@9_(AK&8f#FJv4kK7Qom#xeDmUZI7n9m|l4nA7>L}{DS z$u$>5_iM4X`O=tVcX#Ep<&Rbuqjz+Z=$rk?&L8<&@XlZXg1$OuA+y=X>FkSg?&o=o z!Q)tokMS0UpeL6FzYLt`4)f27`6ym-`ulwio zkG0phC7{ozIgvPPA6Vmx1grBZZCf4f7+Mr^m5kXCU)h!DD(A**z1q+ zIcyV*bu(}`HoMmb4+O8^Ry^)(aF#o>ovnBh*E_NP$NYErw%|doavyLX<8bFbCjwi7 zcLm-EJmTK#{L(+w*B;IJ8v8p#{2xS=`cHKV*p5%QvF@F2H|_}D7g!uDabIwQ?%U1- z5hEh2BGyOD_P>b&Hb+0~cc%ss=v{Yw;A8h`tU-V0Io~w@^}cH7eP2iaA?JAv#S}gi zd_Axt*q$da=zdK&w>d@5rM`K-zd4!CU!5C#<9$!#cDFG2X0Vl87`!*|Y2X6)S{ zwXe>paK7_h?4RX}bk4wPw&yl?GN0rk&fvu?b{}?U@lNc;uA#2WTPG2X)%T#1Q@;wA1bE_43J*^Um* zL(YA;)IAg^4+MfYu?&B3Zg4Jg#yRV7koRx``a9LA<@r2=U3t)bj2)bH&Or>}@$Lie zNIdP_;9P*6yako`9onOmcd-k{GQd&T&FReGO*{vg&Q#}FY~m{Z9_KsVoWa<^OswUZ zZf}I%!f<4^`wnHg$oH5Sd&<#cG zgl90xS?1jBGJ6~{u`>8w4S??bkQRiEZHtwdn z)9cO&M7o1eIr+nMa#ft%Tu zvslN+@Rswr?@r$bc+Nd9=nJk6Ud2-Ma0&o)#ie)dmZn@ROd-2*#UOC@3?E&%IWE> zWOH|Xa7XY|F2E!Bj+6L4*JGV?wr_xMkyC(&naV_V;RufB#eA7*ScG}F1Sew~@8U}= zrytoUMpLH?#&b2Vz++5s*9LoV2DafuXS!2@1H6pucspv)&1vGCir3w|;4gyh-GgpF zR5(SxFP(Ro?LHAK4SvT5e82aXJD>0|cYpAgLAa~g$rB*7)w$1k z2yeKL2B)}vFwyDhWTGcKy32xJy4#WAi}3Yv=3@yjb3X{CyZL+*1D)~sqx(wma`$+A z>>T!G`zQMD!3@seW+tE+R`NZ!FnC^YwL1ojaVi#KIj+XZ*o=3arOqvw&1jBiB^O}~ zPGVW`qTq+Yo$h43;PmlLaJF#@&&K7>)z0JinuWZCw{tz$GLx6NHNgzG7w6+fXPHxr z&)JLlOv1hR22Guh@ipVwmFKd|{lI;K-{4dy&iNxY^9y%|o5Hj4H_SEl{UN@^QCNxJ z;9I`MHYni~{+{Pz6b5st+m5&Mc^-#SOmZCOWK3a&dkddKS7$1&Vh-2Q<*od}y}-?L zJMu*MoFwN%+=1IsfWFwq7r2(^;WoU+8{9eWz5ENd;3gdAAZ~JJ@iKgc>(LDR*$h*# z1!J8)PDkADt`A<}Ud5&C%=PX8cc27rIa!+@kc5h@1 zA}}18&PZRTuf0RAVrw|KoNahIm+~$Cm0Q>olQ0vv;3?dRK3KzIo{eeP%SBwwHT;Y( z^A+Ai*L~JKjxF#2uES7d;~Lz9oA3~J!*TwEM7+*>SjcJo4PWF#oXob2;RP(^IP?T? zEwY{SoL^%Jhj2Py<4$ho)4Yy1@kN$%8nz*b8?lvt;%-jBLs*H=a1Ea3LvBm=5AG&@ ziPy23Rc?`cB{Q)Bqny*6C-DM%b0Qb9BR_JJxr{qm#4P+3ccU``JP{Lc4OU@0Zp0qW zWPj#x3#&Mlhurho5(Dumuj0kLgzxYUoa|&dE0Bt{+`%b$6Js!jceq!(Z@P3ZWgM2^ zE~Fz3o3O|k=uE*h zHT)L65sxJ7=j9y7Kl5|u@UR=l+58{+aS5))85oRNSd8m&10KZTCr?QZfx!wKTy@eOzG2D-baRn;*6v?Y_0p8^KT*znn zGFS0LJcOkfh*d1+d~C)?n2+9A%?XTUU*5uZxq@$TCHJryI-@=MAs>(9dNjvM*6}Jl zj26h_G=9QQIE1_0b9jhNL5{(Ln1fgZnTCn@C8nVtKHyEfm3Q-XcEC)GMKxb!KF{LA zY>6a9<6?Y>>#&<^*$lgRHL3+ZcrcT#NH@ zD%#-%-obWQihO*+2N~pej7D>;#q&mkM-+{ktOh7QJK5wh?J zFJgE0>o0rbOdOkxL4;DapTSS-OJIQTQa&f zz{MzFje7xs2{;o?@hoTZW)^cKW+4~nVKP$i2G8OYKEnr?!@u$d#5xsNg7$cl3-}~= z(uY=v!)v^lzhyVvfd_FFMqwi-u_e#peojR$96Zl=*#&d32*1E^w8a|U#b=m+3ve3Z zu$3QjIZHSKb8t3V;B#KjGx=L)qZDuo@f8>HWF|3>J@6!chb#=nN$7wU=!vb&;qQ43 z_TvO}=3Bzy!y5dttV==D7cl;Au;aUvGqa4UVyn!V=2Tx)R zUcgCsi?{FzZelb#ppH*)9EWltH*gqk#@#5uEIfs`k&g4(nIH1^cpH=O8awe@cNj~V zjsD2OUAPGcn9F(G%}KZ)ui#<)5^b=PU+`P*<_Da^lX(@t;dXw>_P7~$;6fDQEj)zY zC}kbD^A*0x*LXco2VTcwq~LSj&#(AfL_4p*j}N(x@9-u*#qC_q zhq;q|QN}y?JATAcX5eKUz}=|ed=BFTK28T0;BovB-SHroa2o-aLvb@Mz&E^;f9A*B z$atKCYp@U(p$FFSDZa+{xsln2=ZS?Gzc`2b&{%ad>>2B4O&8f{)Ba5>iD3yj2kHsLSmauj+X$O=}oJFdg6 zIKbf?#77w5nRoy?P{I9-LLFD|MT3S8=z$Cjgb!cwATw|dx?>N&;R@cv z8@Y^S+|7@;i@k6vPRH5EMj{TdlI2{%r};4tu$U!mhvN~Az1+@C+`>qlg0pb~D)}up zQB3j%_b~&fp#vh(6}>=y%WaH64|GK-*RhoCLB7TZxr(t!#SrvH2Xsbj6!9(YV>Zq} z5wGVB{Dd_;%u^q#gDj*?{F*qh(}X&M;|l;&>drO26`g~ zmE6Tue1wbnS8nF}e1vP5iizlit=zx}48|E4jcjC~jCb)@{FHuFu!x7akDqZf+aVpz zv7dWb&3JT0R{-0&moeytY)r%;RPtTE!LLYmK?l@wC-?C%_n0y1>ZH*X?QkNx;wvuZ zL;Qw2xPmLVhX?opU*b1xiBoVP=HY5wjIKDq{RB$+Az$Ms{F1No0Y1+?OvZ4G#%ahx z3X;(qebF9~Xo47Q<@?;o8Xn|2e#%vRhwIn|<8co90ocZ`_%T;-KS$v<6e1DJ_$o_y z0)}A_QqU6bat43N7uXSbxCs}b8P;<(*YF#o30cXY(P%$o(F?uM9)7Ih65hu5c!=e! zWE7%N%P0)Q1-Jm2h=Tga_ql_0j6^Nh@~>RM5=I~bk!XsxI39zMhHgkiCD-zERxt^^ zOy7`z3U1;C?qmf?AEM9%ktpE~2AGTt3_wR5;`@AtPx2|gXV{?|TA(9(p*6@Tbir}x zfCTuki_7^cS8ywLaw9kKFyqh_X~;klYPgS)=z*Sy#SVT>b%KXk$toV?mwcTc5g3fq zFx14Z6(Ui^Lo8z*E4hs;`6^%Ja_(m*3`T#nLXd}fkkyPqSDb{?aRR>OJ$#5e*cX#9 z5xuaPkMa-vfHh3QK%}8Lw(}jn$9+5wXW<+SF-)m5Q?eb}A;{1881LoF+{QSlJGu~A z=#CbM15n30%7#rQ@7C~5{*8NiA|~QY^g<+Rs1v5+a0<>u8fy75-{qIw%#9`+i@1e5 z2y{Vrv_?}jLp<x~ydlfha_RtY(?9xtx2snMI7i2{;L9Xp0)|MhjH&Ykt60+)gqPiHHITL?Z$1 z&RGQQow?F_Ox+MqdN;If)P8=Qdt=!_u0<3{c$8Erhei=XgA?q(bG zMQ7A;2a9-s)r>?t9B1sTU=^u!Ru`~3_Sinx~RxQW}igWI`* zU+^0ivxZG@B2L3t3_>eZaToUzXp6Q0iugG{;phCC#f(ELhT}xUn{VljV#991TA5BqK5!6)DEN$jtj9?|A`yc)G(j^o zLoED=LTe-&UUhkZ+xZ>$vWhj_!wuZbN;WgPwLvSiKmy|6hvsdHc(^=dkP@JSSTr~F zSnR#c@NF`VLlcu{#Re(IqbHi9hQ-{?assv7$K9-C1Y#jHTdfk&!sK5y53_;+MxZ%5 zn@r!weJo=YgKUD%=zt5#^zGnQZsIQ1Fa|Br5$%zP1aw5QiHS0~nk6ja7yN*qatABvpcy)%6A}@L zNVLKU7=i)jY~ow4RsAB~Wa2JbNY49hutu?z; z@kkpqg-h*Q>nKD7Si)lNtFO92ma~*D6VVmj4Z0lE8Dy0hYyvT8V%{p}A%i+U+MolP zqLzD&b&*I$I?{0*Vo}VmxS17bdp8+3uXs5WSV8gAn^ z++uKkhzE@C0&IdVCfC~os9+8Kh%vle#Zs2=AP*S^5kt3zABTB>b!=+*x-H@n;C}8j zU5!?131A;Lay@r4zy!2M2edMI+62wf3e6FLa??3% z0$L)$bT{(%UX#~N%$;f;WQmDmS0tkiA`xIUt5{3F>5^*=JC?GHrKV@qePw%dGiPhW zntU!}fPTax20*3ZWbsXm$(JY`KwV42kRrIc~!w%84igz=!EHoOSq?=A^m7!SSrTEzS{V< zsj)&asH(@Nd>n63;j)wm%ykQNG5bMbShflmQ3$e>#oWfNEM^t`h(iKeqb*t?0nznm zAnJ>RICTo@AH^tQmY~@ssgrDqCWu7@f>bSY8G{5gHQp}fMs8sx+nWBaD77^a>Vp2lq3;Skqy+EN2Nz88oxBKr6IFyz#!+M_lGZgsJ-aCPYUg&M=Zo*TmKC zB-Ej($JLd3A7w$TvAyE^N)l(hTw`<=r;6#sZ9#(q14)CENE0#jb;aDpgRG-=lj^7R z7x0<-+Xb!Q;IQd!Dj1}+t2O;>iRt&nGl_<0B=WV*QSEUfP1m8yqO%_B4UKMs2snr^ zY^GckLnso;SM3PJda8!PiL93u%KK_o(&oMpt_rICr5IE@E=4QS_)fT02dume)^}*a zk@&Qk>3uX-RT9Qenp5l%U=3>x`gJ9L0jfT&(ZXOwU764z-gc?oiy|j2rKj##eWOjb zv_c}{5se5lm*OE#S9Mp0sUs7b+n^IV8NSp^vgwdvV&U6*M%A-5TBDU=O?CQJEHj*2 zYVui;i!pwUF-#a+kM?FJPY$!1j>!s_m1dV@br#MP1I15Sq1~yxDO@?Gf7NUO!@ueV zTbn*iHd~QDwQo@8E#9tWW&KW92#~(&U2V;kr(KG-inz<foidL4*sxaE& zx`rc_jq2W|p=QJG>#n1`pf?nv3mY}Jz`&emEAslHw;o9~Y!n@*I z!!lMEVPhov^6>i>Yc@YC1L{LU&XN^mer2aMfMqp5_!QS$?w?=t_2~ zk5KQZ(*bpg!i}w;wtfqTmJ`Ll>KipyADvMMM|v|nd&I)Zennkkd0Zzkc7Ds`$}#03 z4Nj$<_*I%{R(V*vNUg0As!f_JXjZkh$kVD6;u+o7K2e$mSiw?*N9`k<*4GU2x4IEU zU3jn@Mrto&^;b5l7q%b8RjfxUzsn8tS+3NZV*3_m*Q$Mpep^t5ki}wVag^<(Y%L9) zipe^4Bw|>rgP2c#&_@x`{zZrqVigTr11;Zro=~2u+DkwA*LE_>I@`-z6j)}Kt@4*5 zty$%zIK#iVsCH#-TPaH?0+ zIvU;7^h!G6t1+3UN*b!LFee$!P1m3kY0Dng?-o54yW%A6rNzd|cX>@-sWTn6dVHHB zino|T`yS<|xKo{`&RgwihGk#HRK8H}F8;NZRQ7l}=nO*DCuq){)Vrz=m2IAPR5hfX zc8Fs8sQS1`ggkjlIC7~fEj|>#k>b*5bKmBz&NM8#Yj?F`x zC)Sgyg6ikRr$UjK&pr_b;?UacMQ!h<{jYLOcu~Z3<(Md{JC88gqs~Vt5UPYhoo!gm zSk{s6l(p(6V(Ry5dhWoj&r)ldP$oXHvC-a7{|StM$|A@o^KtM?Etbs8$ZQ639_HlM^Jp{%wnXM0F-hsSZ^8jt5J^9p13 zBwqF^##&7*th%DAu9~P^Ro02oZT+;hN70TkmfKmy>6W9sObqQ;g-IJ#;aA_RsJEAX zioBvK-)moK_jKYGWv0hgUfs|P$^mJsx+t$y89vkLmA;da^}L{rk)4*u6b;)8S-jeu zmpwMm6nTkG0mSpFG!_@0ZkkCsER3m#uq)eLfVfR)myPxkb!<^QXPdo(Lx^Jto?P%n4RU9u?ULMKg^0`H+ zG_)M7h}czat+tiN_7*nFZNzL;z1Z8xi_7%3aAY&y=DbepET)w&p_nTs;&)}Va?P_w z{HwET?UAIJ&@6N+b8SUXE{enLsjqg4+HWXp)YaQl4X>lNJ&3H+xrFr4zSsKR_BEjz zEX~C=mc1+|2$vR_Hnz5gTV_y{)#Ir*Qf_%2mTHiynO({H+EzWGw#59pRc1PVWrAf+ z#X^-tano+_kQt@DyLuLN)8Z}p%F7~Q)7D7uzU?tQOxWH*R!B2(mKe##S~iLqJlqP~ z9y`cR{m+ZHBC2>QmxNIHUAs`*y;xopqSZGF?es4 z*m~h%TD1ZhixXQ@ZKl}zDUsF6P^+Cq zvWI@wvE7xonZFaf+CD$9hRfSClJpX{1%Hg|^SJ$gz=AA7I%-&-BFW=xoQRQxoqTP9hdm?NtY> z98jNUYp7R~6%os6ijJ~Jo>XP=w9vn@NqnkIusE0f7VWai+NEAWwg`jzSK6vyvr&@Q zypt|rN%hhGIu<%1@n*8Vv5YO;$O`Qs?0lXlJr8Prt*wl+HOBLwjf}Fv#!q6=EURo* zXsnmDvRY&GhCFKb@UmanROVY0*mt~Ht*30XY_(8VYDWq^(oS<&?pCLwo>V=EW>j6X zJ6$hBJnQ9Y<)meEyIYdaWtAeL`Mi%d2jJ$&j{^Vi>ismPUvm<*hbD) z0_kmI?0H#Ytx%;@XJXH_tVcb)EZf=)vu6*gy0T2zv0ST}Z4PN}iQRG9(|lQ`krp?$ z=kdHQt1K3^wxZzK8Omm1Q26t>#-caG;odv8AG7gRrdXT8-}5>)>j68D^wK-tEFm3q zH^ganl)NGySGH+yBve`7hY;jtv8|QjEk)Qexc#mxMOGs%YOR+wmuijjK{a2$Bw1W& zcAFLYD-2nbX$Gr#2s;|96)Y!tnP7QI{4I}%J|4?IJ90JhA=> z@w=kzVb$i3?ANRs8LA21ytWe+?`V|QV_F^Ts=8~L#`a=f7i_uP;}z9=uiLO07@Esw zqHMK#gtA{+*;Onugo}`0lmWW7j9_(Ad_6zfJMxnqr8n)zX0!b(tcOP0(cUs`%gKjHE7{9-N8T$T^j z0eP6QDAr6`T_3Fwn%@)M^BBzYp@$6nroC(R(Gx2+Zq~*7$Q#z5b`86l zm`+}><1I?%rEvSaXSSkyqpinfPs7NC#G54)Is2~FB9sdueXLHQ_iU!gE7k@{Xnu)z z$Ifg;-t?m7F@}B5&SNEfRo(aU(XMHAw5w`;uODpe7jG8L@1fg6uSB@>EDe{&c32zj zY!(gDLvi)6WBqK!d!`xf9sAA0sm9um{9utRuUdONw8%@g5`@k*Jn{Tlzu@;Xd+&Pw zw3RY6v!}7m7mEyeFT_5c$3hx=`i17Qh_mcty9}EJo>uaf?6HWntIKwqpPr@ik{1=P zkCBA0Z1t6Wy014wwrHFek&r!}SRFz-ds%E_<3%epDx|L@Jc6EB6pDw#5#))ddAR?= zr6HnhUV2eF+B-I;;oM=pE6;jXd)X~*8_sY2Z*2}eX*g#nTHzu)?0lj3JURLsRziN4 zPeU4p+h}LDx_Wczp2jrxfqm}9yRn44Z8O-j)UGB>3K5|iq1i)r$v$~jD>t;#)6n8W zBSK@WM&WvTHd~R7*6*P)_Bs@?&`3|bS@o|Kjqz6Y?u1`^BQ?&O#Ui0GS{jNsuYJqn z$XnBs(8^Z4`|_T*n#Nf6^0cyIudKi9JmL2x-fZ^1ccr;Q-+xR(?^@l%=e1gfMo6Sd z!!h=5!%^Nn^QFO+=k0J0*jY7iXnaHQ-U|7|dww)sLVmQXcs@K*$B@)N`~e-prSVMO z+u>vE+Tk{Nqr7`wRP~m9Ce0<@Ja&Yqzh}K?pB?3m@$TB|5F^{!y{Fzg-do;Uq3e*? zvEkBi7Kt4l8soj)@J`4oJr6yz;=R-OnV0>IvnpJ?G2!B&#cCJ+q_Mu<%Aqm3BP);8 z^2bE0+K(q8JtVra71!ghkX?=6v*SX~Jqh=aX0yF(Xq_YNIdavbi`5`BQ$q>&$3E8*{i+wjkbH)ptRe}8U0v2hK33t#=nH$!*KD-A}6BxJWn*pcC5y*r+GI)rBM z-U{9E#)j@3O*E?E{Uh%*mLn16t=@R99~SxE`&hA84Mq2ab-Sv)vK>gc9^v0@me{!( z-j`Uvgw_Zj=Y4PdR_MOBa_CO@Slw;7dc*Mz#g6vIhl}?lT!I$A$H6h^3D%!upYN^s$nL>o&ad#Lj20!oP=$z3(B^yYjBX*YWOYO!y3q#hat? z{eMo5wrY6nB}W_M$&ontdk71kHH4_}_Z!wlukwW6^WO3#^h6SV75=@kG+eRq$i~;< z5_%T;7A{A>d!&SG@c*kc#Cix}jqm?w`RAXHY{MBEUj1|;r2e>AJRd8ne>!Q1f&T`v z-2LBR$+61+9yP~?%wv;d!}-thv-~VSwOl-Y?Bq6GfuX|}&dr%RE4MIdO74uAbA~0C zEPE$8Y38(H$>$9mn=*E8R_>)UPg_)wJ8{vtNmCcinmS}!^6-=6hAzxpm^U{sw=gGZ zVczUH^D-9>OU{{=KP5MF&b&b#VH?K1pdQDH;7!2KP@(>zkU9nVOoJnwC^A$tTAp4K0{9J##|#==$Xf zrcED~d}(3f+|2&{7c5xNZ$Wy${DK+%Q-=&0(my3llN3yw-gn-Wa|&}7_MJ1YyQZ*n zWarMCS}=2N;mrIwNt!cfO8ymv!;+KZv{=0@d2_#?e9pXn#;$%-^Yi*I%$eIiwO>mA zMuW$W{o&zxc@5r}S2!Uzr2SDBm^bOlxw-u(_IBI_34=>qp zf>HBx=M*-WVnNRQzcWGJ-2Mx4<{x3^)Pmfc!u)~}h530$e=%&p5ic*yo16Xje3WNh zntkP*oV=M+$L3C(nPa`RFmG<=*!*cTr(c|-6DC7W^^jZUAGIz;drIIz*|W^{hRr2PEZ9;7GcUomIe zl>Gd{OOvuD4oo_J^4Rg&`BTrDJI_;T?AXk+3TDojIVWd!cK*~W@^a@Cj>#UDyfANW zziBh4We&<7FnUnNsDbGNQ&L6^PE8$>mXbYcV0uc{kks^yw2|py(;V&f)FFdYMyCuK zl{Lt|K4Ngzfb6uaj3EO@q>N5U85H*Vm^t$bbLLFV^;Vxbb6V!8tkjhB0ojAHGwkab zg9eQnIV5#JYWm>O*#icQHm@(pnV&f>r*P){-0Yb%a_1EeOU@oMaeSXKBPLAhGbU@S z{+u08h2`+F{h53&}YoJ5o7y|nK*jVNh7mTholY|Fl5A#wDhdh^wjLM zltCHkSt(iRgEIz>%ou3$GHK|-Jh>`6w_xV{+-ai=^7BkKnncN*c@))CGmgRX`uC?D z#qp!kM~zM&oj&phJy-vJ{y!7I{^A|azSCyTE6gvr(%iCSG%@#bdu1ekmFK(gyWzsQ%PTbLPy*oi;4F|4IE-EtIwOzWQlg zG3po+>wD||O2 z9`iKHhyjyQ(=yWsWu~S6-zA5CMMjKD``Hn;{2x;d{5M0yPni;_1COPN_z?%Br~T)r zMCzdbKu7!wibU$*f7%ZjnFBNa3jlFU?e!04#(#+;j%A1S@8*b~k|RfrJcd2u4>;h+ zjr#Y4|8;wce@WYLESu%;Z9B4m`hVhxMjSb`zYe^-J?GH=cGn%gD;*kkij%ou=A3Ey z3+Cy_$81Z(pXDwr%$+mO>`v{@F8txlIrH@Sbw%#@{F!qKlg8#0%*rjWr#a?yQ1hCBI-eVsJo?OYy|Lc@)=oCPASW+( zf;qODo;GkmO6s5#BaKtDUY{dQChLy@j#O=AZq5;Eg^#j&X_TkXk7@M13Rd$xYqEE@ z@iD~_+w{X_DzyZ#~h z*= 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 28/66] 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 29/66] 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 30/66] 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 31/66] 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 32/66] 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 33/66] 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 34/66] 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 35/66] 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 36/66] 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 37/66] 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 38/66] 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 39/66] 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 40/66] 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 41/66] 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 42/66] 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 43/66] 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 44/66] 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 45/66] 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 46/66] 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 47/66] 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 48/66] 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 49/66] 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 50/66] 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 b6671d92c8cf533526511999c2e7b58b160295bc Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 6 Mar 2017 18:46:57 +0000 Subject: [PATCH 51/66] removed duplicated audio devices --- scripts/system/selectAudioDevice.js | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/scripts/system/selectAudioDevice.js b/scripts/system/selectAudioDevice.js index 9b97b24455..d77bef2aec 100644 --- a/scripts/system/selectAudioDevice.js +++ b/scripts/system/selectAudioDevice.js @@ -103,6 +103,42 @@ function setupAudioMenus() { } } +function removeAudioDevices() { + Menu.removeSeparator("Audio", "Input Audio Device"); + + var inputDeviceSetting = Settings.getValue(INPUT_DEVICE_SETTING); + var inputDevices = AudioDevice.getInputDevices(); + var selectedInputDevice = AudioDevice.getInputDevice(); + if (inputDevices.indexOf(inputDeviceSetting) != -1 && selectedInputDevice != inputDeviceSetting) { + if (AudioDevice.setInputDevice(inputDeviceSetting)) { + selectedInputDevice = inputDeviceSetting; + } + } + print("audio input devices: " + inputDevices); + for(var i = 0; i < inputDevices.length; i++) { + var thisDeviceSelected = (inputDevices[i] == selectedInputDevice); + var menuItem = "Use " + inputDevices[i] + " for Input"; + Menu.removeMenuItem("Audio", menuItem); + } + + Menu.removeSeparator("Audio", "Output Audio Device"); + + var outputDeviceSetting = Settings.getValue(OUTPUT_DEVICE_SETTING); + var outputDevices = AudioDevice.getOutputDevices(); + var selectedOutputDevice = AudioDevice.getOutputDevice(); + if (outputDevices.indexOf(outputDeviceSetting) != -1 && selectedOutputDevice != outputDeviceSetting) { + if (AudioDevice.setOutputDevice(outputDeviceSetting)) { + selectedOutputDevice = outputDeviceSetting; + } + } + print("audio output devices: " + outputDevices); + for (var i = 0; i < outputDevices.length; i++) { + var thisDeviceSelected = (outputDevices[i] == selectedOutputDevice); + var menuItem = "Use " + outputDevices[i] + " for Output"; + Menu.removeMenuItem("Audio", menuItem); + } +} + function onDevicechanged() { print("audio devices changed, removing Audio > Devices menu..."); Menu.removeMenu("Audio > Devices"); @@ -218,6 +254,7 @@ Script.update.connect(checkHMDAudio); Script.scriptEnding.connect(function () { restoreAudio(); + removeAudioDevices(); Menu.menuItemEvent.disconnect(menuItemEvent); Script.update.disconnect(checkHMDAudio); }); From d50a0e33a99b6cb0181186f8fae1dd496dd1f3f2 Mon Sep 17 00:00:00 2001 From: Menithal Date: Mon, 6 Mar 2017 21:07:16 +0200 Subject: [PATCH 52/66] 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 53/66] 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 54/66] 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 55/66] 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); } From fc65723d685f6376b1f88d6e8eafcc47ff00e2a3 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 6 Mar 2017 22:14:20 +0000 Subject: [PATCH 56/66] corrected removing duplicate devices --- scripts/system/selectAudioDevice.js | 53 +++++++++-------------------- 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/scripts/system/selectAudioDevice.js b/scripts/system/selectAudioDevice.js index d77bef2aec..f5929ce151 100644 --- a/scripts/system/selectAudioDevice.js +++ b/scripts/system/selectAudioDevice.js @@ -51,7 +51,9 @@ const OUTPUT_DEVICE_SETTING = "audio_output_device"; var selectedInputMenu = ""; var selectedOutputMenu = ""; + var audioDevicesList = []; function setupAudioMenus() { + removeAudioMenus(); Menu.addSeparator("Audio", "Input Audio Device"); var inputDeviceSetting = Settings.getValue(INPUT_DEVICE_SETTING); @@ -67,11 +69,12 @@ function setupAudioMenus() { var thisDeviceSelected = (inputDevices[i] == selectedInputDevice); var menuItem = "Use " + inputDevices[i] + " for Input"; Menu.addMenuItem({ - menuName: "Audio", - menuItemName: menuItem, - isCheckable: true, - isChecked: thisDeviceSelected - }); + menuName: "Audio", + menuItemName: menuItem, + isCheckable: true, + isChecked: thisDeviceSelected + }); + audioDevicesList.push(menuItem); if (thisDeviceSelected) { selectedInputMenu = menuItem; } @@ -97,46 +100,22 @@ function setupAudioMenus() { isCheckable: true, isChecked: thisDeviceSelected }); + audioDevicesList.push(menuItem); if (thisDeviceSelected) { selectedOutputMenu = menuItem; } } } -function removeAudioDevices() { - Menu.removeSeparator("Audio", "Input Audio Device"); - - var inputDeviceSetting = Settings.getValue(INPUT_DEVICE_SETTING); - var inputDevices = AudioDevice.getInputDevices(); - var selectedInputDevice = AudioDevice.getInputDevice(); - if (inputDevices.indexOf(inputDeviceSetting) != -1 && selectedInputDevice != inputDeviceSetting) { - if (AudioDevice.setInputDevice(inputDeviceSetting)) { - selectedInputDevice = inputDeviceSetting; - } - } - print("audio input devices: " + inputDevices); - for(var i = 0; i < inputDevices.length; i++) { - var thisDeviceSelected = (inputDevices[i] == selectedInputDevice); - var menuItem = "Use " + inputDevices[i] + " for Input"; - Menu.removeMenuItem("Audio", menuItem); - } - +function removeAudioMenus() { + Menu.removeSeparator("Audio", "Input Audio Device"); Menu.removeSeparator("Audio", "Output Audio Device"); - var outputDeviceSetting = Settings.getValue(OUTPUT_DEVICE_SETTING); - var outputDevices = AudioDevice.getOutputDevices(); - var selectedOutputDevice = AudioDevice.getOutputDevice(); - if (outputDevices.indexOf(outputDeviceSetting) != -1 && selectedOutputDevice != outputDeviceSetting) { - if (AudioDevice.setOutputDevice(outputDeviceSetting)) { - selectedOutputDevice = outputDeviceSetting; - } - } - print("audio output devices: " + outputDevices); - for (var i = 0; i < outputDevices.length; i++) { - var thisDeviceSelected = (outputDevices[i] == selectedOutputDevice); - var menuItem = "Use " + outputDevices[i] + " for Output"; - Menu.removeMenuItem("Audio", menuItem); + for (var index = 0; index < audioDevicesList.length; index++) { + Menu.removeMenuItem("Audio", audioDevicesList[index]); } + + audioDevicesList = []; } function onDevicechanged() { @@ -254,7 +233,7 @@ Script.update.connect(checkHMDAudio); Script.scriptEnding.connect(function () { restoreAudio(); - removeAudioDevices(); + removeAudioMenus(); Menu.menuItemEvent.disconnect(menuItemEvent); Script.update.disconnect(checkHMDAudio); }); From db036d997c801e22fe3ca2e3a2b51146709e65fb Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 6 Mar 2017 15:18:35 -0700 Subject: [PATCH 57/66] first pass --- interface/resources/qml/hifi/Pal.qml | 30 ++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 28384f9c1c..670a29c82d 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -63,7 +63,16 @@ Rectangle { } function refreshWithFilter() { // We should just be able to set settings.filtered to filter.checked, but see #3249, so send to .js for saving. - pal.sendToScript({method: 'refresh', params: {filter: filter.checked && {distance: settings.nearDistance}}}); + var userIds = []; + table.selection.forEach(function (userIndex) { + userIds.push(userModelData[userIndex].sessionId); + }); + table.selection.clear(); + var params = {filter: filter.checked && {distance: settings.nearDistance}}; + if (userIds.length > 0) { + params.selected = [[userIds[0]], true, true]; + } + pal.sendToScript({method: 'refresh', params: params}); } // This is the container for the PAL @@ -286,7 +295,7 @@ Rectangle { HifiControls.GlyphButton { function getGlyph() { var fileName = "vol_"; - if (model["personalMute"]) { + if (model && model["personalMute"]) { fileName += "x_"; } fileName += (4.0*(model ? model.avgAudioLevel : 0.0)).toFixed(0); @@ -611,10 +620,20 @@ Rectangle { console.log('Unrecognized message:', JSON.stringify(message)); } } + function getSelectedSessionIDs() { + var sessionIDs = []; + table.selection.forEach(function (userIndex) { + sessionIDs.push(userModelData[userIndex].sessionId); + }); + return sessionIDs; + } function sortModel() { var sortProperty = table.getColumn(table.sortIndicatorColumn).role; var before = (table.sortIndicatorOrder === Qt.AscendingOrder) ? -1 : 1; var after = -1 * before; + + // get selection(s) before sorting + var selectedIDs = getSelectedSessionIDs(); userModelData.sort(function (a, b) { var aValue = a[sortProperty].toString().toLowerCase(), bValue = b[sortProperty].toString().toLowerCase(); switch (true) { @@ -627,6 +646,7 @@ Rectangle { userModel.clear(); var userIndex = 0; + var newSelectedIndexes=[]; userModelData.forEach(function (datum) { function init(property) { if (datum[property] === undefined) { @@ -636,7 +656,13 @@ Rectangle { ['personalMute', 'ignore', 'mute', 'kick'].forEach(init); datum.userIndex = userIndex++; userModel.append(datum); + if (selectedIDs.indexOf(datum.sessionId) != -1) { + newSelectedIndexes.push(datum.userIndex); + } }); + if (newSelectedIndexes.length > 0) { + table.selection.select(newSelectedIndexes); + } } signal sendToScript(var message); function noticeSelection() { From e14a1ad1af19cc4cbdd480f09ca24d5c22f44a68 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 6 Mar 2017 15:26:03 -0700 Subject: [PATCH 58/66] minor cleanup --- interface/resources/qml/hifi/Pal.qml | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 670a29c82d..9de7817d1b 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -61,13 +61,16 @@ Rectangle { property int sortIndicatorColumn: 1 property int sortIndicatorOrder: Qt.AscendingOrder } + function getSelectedSessionIDs() { + var sessionIDs = []; + table.selection.forEach(function (userIndex) { + sessionIDs.push(userModelData[userIndex].sessionId); + }); + return sessionIDs; + } function refreshWithFilter() { // We should just be able to set settings.filtered to filter.checked, but see #3249, so send to .js for saving. - var userIds = []; - table.selection.forEach(function (userIndex) { - userIds.push(userModelData[userIndex].sessionId); - }); - table.selection.clear(); + var userIds = getSelectedSessionIDs(); var params = {filter: filter.checked && {distance: settings.nearDistance}}; if (userIds.length > 0) { params.selected = [[userIds[0]], true, true]; @@ -620,13 +623,6 @@ Rectangle { console.log('Unrecognized message:', JSON.stringify(message)); } } - function getSelectedSessionIDs() { - var sessionIDs = []; - table.selection.forEach(function (userIndex) { - sessionIDs.push(userModelData[userIndex].sessionId); - }); - return sessionIDs; - } function sortModel() { var sortProperty = table.getColumn(table.sortIndicatorColumn).role; var before = (table.sortIndicatorOrder === Qt.AscendingOrder) ? -1 : 1; From 3d39aae35b0e91a594c9a3aedf8d6548938b8654 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 6 Mar 2017 15:52:33 -0700 Subject: [PATCH 59/66] minor tweak - just in case --- interface/resources/qml/hifi/Pal.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 9de7817d1b..db975f3d8a 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -658,6 +658,7 @@ Rectangle { }); if (newSelectedIndexes.length > 0) { table.selection.select(newSelectedIndexes); + table.positionViewAtRow(userIndex, ListView.Beginning); } } signal sendToScript(var message); From 10b3e7fc676736c46aafa354065bd6a879cfda8c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 6 Mar 2017 15:14:51 -0800 Subject: [PATCH 60/66] sphere shapeType for models means 'sphere' --- libraries/entities/src/ShapeEntityItem.cpp | 2 +- libraries/physics/src/ShapeFactory.cpp | 13 ++++++++++++- libraries/shared/src/ShapeInfo.h | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index eaef4c5c0e..345d9e54ab 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -163,7 +163,7 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit // This value specifes how the shape should be treated by physics calculations. // For now, all polys will act as spheres ShapeType ShapeEntityItem::getShapeType() const { - return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_SPHERE; + return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_ELLIPSOID; } void ShapeEntityItem::setColor(const rgbColor& value) { diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 100dab0fd1..560b0a6db2 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -256,9 +256,20 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) } break; case SHAPE_TYPE_SPHERE: { + glm::vec3 halfExtents = info.getHalfExtents(); + float radius = glm::max(halfExtents.x, glm::max(halfExtents.y, halfExtents.z)); + shape = new btSphereShape(radius); + } + break; + case SHAPE_TYPE_ELLIPSOID: { glm::vec3 halfExtents = info.getHalfExtents(); float radius = halfExtents.x; - if (radius == halfExtents.y && radius == halfExtents.z) { + const float MIN_RADIUS = 0.001f; + const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; + if (radius > MIN_RADIUS + && fabs(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR + && fabs(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { + // close enough to true sphere shape = new btSphereShape(radius); } else { ShapeInfo::PointList points; diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index a6ff8d6d4a..98b397ee16 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -45,7 +45,8 @@ enum ShapeType { SHAPE_TYPE_COMPOUND, SHAPE_TYPE_SIMPLE_HULL, SHAPE_TYPE_SIMPLE_COMPOUND, - SHAPE_TYPE_STATIC_MESH + SHAPE_TYPE_STATIC_MESH, + SHAPE_TYPE_ELLIPSOID }; class ShapeInfo { From d749c0c8beb9936bfec689309a1c5c77d0dce341 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 6 Mar 2017 15:50:32 -0800 Subject: [PATCH 61/66] use fabsf() rather than fabs() --- libraries/physics/src/ShapeFactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 560b0a6db2..35e050024a 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -267,8 +267,8 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) const float MIN_RADIUS = 0.001f; const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; if (radius > MIN_RADIUS - && fabs(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR - && fabs(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { + && fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR + && fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) { // close enough to true sphere shape = new btSphereShape(radius); } else { From 51739f2f99bbbe4a1f8a4f9ed6bb538a85fff19e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 7 Mar 2017 15:02:26 +1300 Subject: [PATCH 62/66] Remove Developer > Network > Bandwith Details dialog --- interface/src/Application.cpp | 6 -- interface/src/Application.h | 2 +- interface/src/Menu.cpp | 2 - interface/src/Menu.h | 1 - interface/src/ui/BandwidthDialog.cpp | 135 --------------------------- interface/src/ui/BandwidthDialog.h | 94 ------------------- interface/src/ui/DialogsManager.cpp | 15 --- interface/src/ui/DialogsManager.h | 4 - interface/src/ui/HMDToolsDialog.cpp | 3 - 9 files changed, 1 insertion(+), 261 deletions(-) delete mode 100644 interface/src/ui/BandwidthDialog.cpp delete mode 100644 interface/src/ui/BandwidthDialog.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ba63f4f064..f870bd9f83 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4236,12 +4236,6 @@ void Application::updateDialogs(float deltaTime) const { PerformanceWarning warn(showWarnings, "Application::updateDialogs()"); auto dialogsManager = DependencyManager::get(); - // Update bandwidth dialog, if any - BandwidthDialog* bandwidthDialog = dialogsManager->getBandwidthDialog(); - if (bandwidthDialog) { - bandwidthDialog->update(); - } - QPointer octreeStatsDialog = dialogsManager->getOctreeStatsDialog(); if (octreeStatsDialog) { octreeStatsDialog->update(); diff --git a/interface/src/Application.h b/interface/src/Application.h index ec6d9b19f7..c4ba760153 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -51,6 +51,7 @@ #include #include "avatar/MyAvatar.h" +#include "BandwidthRecorder.h" #include "Bookmarks.h" #include "Camera.h" #include "ConnectionMonitor.h" @@ -61,7 +62,6 @@ #include "scripting/ControllerScriptingInterface.h" #include "scripting/DialogsManagerScriptingInterface.h" #include "ui/ApplicationOverlay.h" -#include "ui/BandwidthDialog.h" #include "ui/EntityScriptServerLogDialog.h" #include "ui/LodToolsDialog.h" #include "ui/LogDialog.h" diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c131367aee..beacbaccab 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -566,8 +566,6 @@ Menu::Menu() { dialogsManager.data(), SLOT(toggleDiskCacheEditor())); addActionToQMenuAndActionHash(networkMenu, MenuOption::ShowDSConnectTable, 0, dialogsManager.data(), SLOT(showDomainConnectionDialog())); - addActionToQMenuAndActionHash(networkMenu, MenuOption::BandwidthDetails, 0, - dialogsManager.data(), SLOT(bandwidthDetails())); #if (PR_BUILD || DEV_BUILD) addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::SendWrongProtocolVersion, 0, false, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 1b2564735b..c806ffa9ee 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -49,7 +49,6 @@ namespace MenuOption { const QString AutoMuteAudio = "Auto Mute Microphone"; const QString AvatarReceiveStats = "Show Receive Stats"; const QString Back = "Back"; - const QString BandwidthDetails = "Bandwidth Details"; const QString BinaryEyelidControl = "Binary Eyelid Control"; const QString BookmarkLocation = "Bookmark Location"; const QString Bookmarks = "Bookmarks"; diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp deleted file mode 100644 index f07c844894..0000000000 --- a/interface/src/ui/BandwidthDialog.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// -// BandwidthDialog.cpp -// interface/src/ui -// -// Created by Tobias Schwinger on 6/21/13. -// Copyright 2013 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 - -#include "BandwidthRecorder.h" -#include "ui/BandwidthDialog.h" - -#include -#include - -#include -#include - - -BandwidthChannelDisplay::BandwidthChannelDisplay(QVector nodeTypesToFollow, - QFormLayout* form, - char const* const caption, char const* unitCaption, - const float unitScale, unsigned colorRGBA) : - _nodeTypesToFollow(nodeTypesToFollow), - _caption(caption), - _unitCaption(unitCaption), - _unitScale(unitScale), - _colorRGBA(colorRGBA) -{ - _label = new QLabel(); - _label->setAlignment(Qt::AlignRight); - - QPalette palette = _label->palette(); - unsigned rgb = colorRGBA >> 8; - rgb = ((rgb & 0xfefefeu) >> 1) + ((rgb & 0xf8f8f8) >> 3); - palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb)); - _label->setPalette(palette); - - form->addRow(QString(" ") + _caption + " Bandwidth In/Out:", _label); -} - - - -void BandwidthChannelDisplay::bandwidthAverageUpdated() { - float inTotal = 0.; - float outTotal = 0.; - - QSharedPointer bandwidthRecorder = DependencyManager::get(); - - for (int i = 0; i < _nodeTypesToFollow.size(); ++i) { - inTotal += bandwidthRecorder->getAverageInputKilobitsPerSecond(_nodeTypesToFollow.at(i)); - outTotal += bandwidthRecorder->getAverageOutputKilobitsPerSecond(_nodeTypesToFollow.at(i)); - } - - _strBuf = - QString("").setNum((int) (inTotal * _unitScale)) + "/" + - QString("").setNum((int) (outTotal * _unitScale)) + " " + _unitCaption; -} - - -void BandwidthChannelDisplay::paint() { - _label->setText(_strBuf); -} - - -BandwidthDialog::BandwidthDialog(QWidget* parent) : - QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) { - - this->setWindowTitle("Bandwidth Details"); - - // Create layout - QFormLayout* form = new QFormLayout(); - form->setSizeConstraint(QLayout::SetFixedSize); - this->QDialog::setLayout(form); - - QSharedPointer bandwidthRecorder = DependencyManager::get(); - - _allChannelDisplays[0] = _audioChannelDisplay = - new BandwidthChannelDisplay({NodeType::AudioMixer}, form, "Audio", "Kbps", 1.0, COLOR0); - _allChannelDisplays[1] = _avatarsChannelDisplay = - new BandwidthChannelDisplay({NodeType::Agent, NodeType::AvatarMixer}, form, "Avatars", "Kbps", 1.0, COLOR1); - _allChannelDisplays[2] = _octreeChannelDisplay = - new BandwidthChannelDisplay({NodeType::EntityServer}, form, "Octree", "Kbps", 1.0, COLOR2); - _allChannelDisplays[3] = _octreeChannelDisplay = - new BandwidthChannelDisplay({NodeType::DomainServer}, form, "Domain", "Kbps", 1.0, COLOR2); - _allChannelDisplays[4] = _otherChannelDisplay = - new BandwidthChannelDisplay({NodeType::Unassigned}, form, "Other", "Kbps", 1.0, COLOR2); - _allChannelDisplays[5] = _totalChannelDisplay = - new BandwidthChannelDisplay({ - NodeType::DomainServer, NodeType::EntityServer, - NodeType::AudioMixer, NodeType::Agent, - NodeType::AvatarMixer, NodeType::Unassigned - }, form, "Total", "Kbps", 1.0, COLOR2); - - connect(averageUpdateTimer, SIGNAL(timeout()), this, SLOT(updateTimerTimeout())); - averageUpdateTimer->start(1000); -} - - -BandwidthDialog::~BandwidthDialog() { - for (unsigned int i = 0; i < _CHANNELCOUNT; i++) { - delete _allChannelDisplays[i]; - } -} - - -void BandwidthDialog::updateTimerTimeout() { - for (unsigned int i = 0; i < _CHANNELCOUNT; i++) { - _allChannelDisplays[i]->bandwidthAverageUpdated(); - } -} - - -void BandwidthDialog::paintEvent(QPaintEvent* event) { - for (unsigned int i=0; i<_CHANNELCOUNT; i++) - _allChannelDisplays[i]->paint(); - this->QDialog::paintEvent(event); -} - -void BandwidthDialog::reject() { - - // Just regularly close upon ESC - this->QDialog::close(); -} - -void BandwidthDialog::closeEvent(QCloseEvent* event) { - - this->QDialog::closeEvent(event); - emit closed(); -} - diff --git a/interface/src/ui/BandwidthDialog.h b/interface/src/ui/BandwidthDialog.h deleted file mode 100644 index a53cc21030..0000000000 --- a/interface/src/ui/BandwidthDialog.h +++ /dev/null @@ -1,94 +0,0 @@ -// -// BandwidthDialog.h -// interface/src/ui -// -// Created by Tobias Schwinger on 6/21/13. -// Copyright 2013 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 -// - -#ifndef hifi_BandwidthDialog_h -#define hifi_BandwidthDialog_h - -#include -#include -#include -#include -#include - -#include "Node.h" -#include "BandwidthRecorder.h" - - -const unsigned int COLOR0 = 0x33cc99ff; -const unsigned int COLOR1 = 0xffef40c0; -const unsigned int COLOR2 = 0xd0d0d0a0; - - -class BandwidthChannelDisplay : public QObject { - Q_OBJECT - - public: - BandwidthChannelDisplay(QVector nodeTypesToFollow, - QFormLayout* form, - char const* const caption, char const* unitCaption, float unitScale, unsigned colorRGBA); - void paint(); - - private: - QVector _nodeTypesToFollow; - QLabel* _label; - QString _strBuf; - char const* const _caption; - char const* _unitCaption; - float const _unitScale; - unsigned _colorRGBA; - - - public slots: - void bandwidthAverageUpdated(); -}; - - -class BandwidthDialog : public QDialog { - Q_OBJECT -public: - BandwidthDialog(QWidget* parent); - ~BandwidthDialog(); - - void paintEvent(QPaintEvent*) override; - -private: - BandwidthChannelDisplay* _audioChannelDisplay; - BandwidthChannelDisplay* _avatarsChannelDisplay; - BandwidthChannelDisplay* _octreeChannelDisplay; - BandwidthChannelDisplay* _domainChannelDisplay; - BandwidthChannelDisplay* _otherChannelDisplay; - BandwidthChannelDisplay* _totalChannelDisplay; // sums of all the other channels - - static const unsigned int _CHANNELCOUNT = 6; - BandwidthChannelDisplay* _allChannelDisplays[_CHANNELCOUNT]; - - -signals: - - void closed(); - -public slots: - - void reject() override; - void updateTimerTimeout(); - - -protected: - - // Emits a 'closed' signal when this dialog is closed. - void closeEvent(QCloseEvent*) override; - -private: - QTimer* averageUpdateTimer = new QTimer(this); - -}; - -#endif // hifi_BandwidthDialog_h diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 03c71d8573..3252fef4f0 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -19,7 +19,6 @@ #include #include "AddressBarDialog.h" -#include "BandwidthDialog.h" #include "CachesSizeDialog.h" #include "ConnectionFailureDialog.h" #include "DiskCacheEditor.h" @@ -108,20 +107,6 @@ void DialogsManager::cachesSizeDialog() { _cachesSizeDialog->raise(); } -void DialogsManager::bandwidthDetails() { - if (! _bandwidthDialog) { - _bandwidthDialog = new BandwidthDialog(qApp->getWindow()); - connect(_bandwidthDialog, SIGNAL(closed()), _bandwidthDialog, SLOT(deleteLater())); - - if (_hmdToolsDialog) { - _hmdToolsDialog->watchWindow(_bandwidthDialog->windowHandle()); - } - - _bandwidthDialog->show(); - } - _bandwidthDialog->raise(); -} - void DialogsManager::lodTools() { if (!_lodToolsDialog) { maybeCreateDialog(_lodToolsDialog); diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index c02c1fc2c3..54aef38984 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -21,7 +21,6 @@ class AnimationsDialog; class AttachmentsDialog; -class BandwidthDialog; class CachesSizeDialog; class DiskCacheEditor; class LodToolsDialog; @@ -36,7 +35,6 @@ class DialogsManager : public QObject, public Dependency { SINGLETON_DEPENDENCY public: - QPointer getBandwidthDialog() const { return _bandwidthDialog; } QPointer getHMDToolsDialog() const { return _hmdToolsDialog; } QPointer getLodToolsDialog() const { return _lodToolsDialog; } QPointer getOctreeStatsDialog() const { return _octreeStatsDialog; } @@ -53,7 +51,6 @@ public slots: void showLoginDialog(); void octreeStatsDetails(); void cachesSizeDialog(); - void bandwidthDetails(); void lodTools(); void hmdTools(bool showTools); void showScriptEditor(); @@ -79,7 +76,6 @@ private: QPointer _animationsDialog; QPointer _attachmentsDialog; - QPointer _bandwidthDialog; QPointer _cachesSizeDialog; QPointer _diskCacheEditor; QPointer _ircInfoBox; diff --git a/interface/src/ui/HMDToolsDialog.cpp b/interface/src/ui/HMDToolsDialog.cpp index a596403948..55c321723e 100644 --- a/interface/src/ui/HMDToolsDialog.cpp +++ b/interface/src/ui/HMDToolsDialog.cpp @@ -79,9 +79,6 @@ HMDToolsDialog::HMDToolsDialog(QWidget* parent) : // what screens we're allowed on watchWindow(windowHandle()); auto dialogsManager = DependencyManager::get(); - if (dialogsManager->getBandwidthDialog()) { - watchWindow(dialogsManager->getBandwidthDialog()->windowHandle()); - } if (dialogsManager->getOctreeStatsDialog()) { watchWindow(dialogsManager->getOctreeStatsDialog()->windowHandle()); } From ff9d6d657cc64907c3695591a8bb5e97b9ee14b6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 6 Mar 2017 19:35:00 -0800 Subject: [PATCH 63/66] Remove weighted offset, special case downward pressure --- .../animation/src/AnimInverseKinematics.cpp | 48 +++++++------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 173af3fdf6..fa8e4654f6 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -488,13 +488,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars // measure new _hipsOffset for next frame // by looking for discrepancies between where a targeted endEffector is // and where it wants to be (after IK solutions are done) - - // use weighted average between HMD and other targets - float HMD_WEIGHT = 10.0f; - float OTHER_WEIGHT = 1.0f; - float totalWeight = 0.0f; - - glm::vec3 additionalHipsOffset = Vectors::ZERO; + glm::vec3 newHipsOffset = Vectors::ZERO; for (auto& target: targets) { int targetIndex = target.getIndex(); if (targetIndex == _headIndex && _headIndex != -1) { @@ -505,42 +499,34 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans(); glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans(); const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; - additionalHipsOffset += (OTHER_WEIGHT * HEAD_OFFSET_SLAVE_FACTOR) * (under- actual); - totalWeight += OTHER_WEIGHT; + newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under); } else if (target.getType() == IKTarget::Type::HmdHead) { + // we want to shift the hips to bring the head to its designated position glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans(); - glm::vec3 thisOffset = target.getTranslation() - actual; - glm::vec3 futureHipsOffset = _hipsOffset + thisOffset; - if (glm::length(glm::vec2(futureHipsOffset.x, futureHipsOffset.z)) < _maxHipsOffsetLength) { - // it is imperative to shift the hips and bring the head to its designated position - // so we slam newHipsOffset here and ignore all other targets - additionalHipsOffset = futureHipsOffset - _hipsOffset; - totalWeight = 0.0f; - break; - } else { - additionalHipsOffset += HMD_WEIGHT * (target.getTranslation() - actual); - totalWeight += HMD_WEIGHT; - } + _hipsOffset += target.getTranslation() - actual; + // and ignore all other targets + newHipsOffset = _hipsOffset; + break; + } else if (target.getType() == IKTarget::Type::RotationAndPosition) { + glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans(); + glm::vec3 targetPosition = target.getTranslation(); + newHipsOffset += targetPosition - actualPosition; + + // Add downward pressure on the hips + newHipsOffset *= 0.95f; + newHipsOffset -= 1.0f; } } else if (target.getType() == IKTarget::Type::RotationAndPosition) { glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans(); glm::vec3 targetPosition = target.getTranslation(); - additionalHipsOffset += OTHER_WEIGHT * (targetPosition - actualPosition); - totalWeight += OTHER_WEIGHT; + newHipsOffset += targetPosition - actualPosition; } } - if (totalWeight > 1.0f) { - additionalHipsOffset /= totalWeight; - } - - // Add downward pressure on the hips - additionalHipsOffset *= 0.95f; - additionalHipsOffset -= 1.0f; // smooth transitions by relaxing _hipsOffset toward the new value const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f; float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f; - _hipsOffset += additionalHipsOffset * tau; + _hipsOffset += (newHipsOffset - _hipsOffset) * tau; // clamp the hips offset float hipsOffsetLength = glm::length(_hipsOffset); From 2d2b2094fd7d79c9c636de3f9fcd765774f400a3 Mon Sep 17 00:00:00 2001 From: Vladyslav Stelmakhovskyi Date: Tue, 7 Mar 2017 10:11:09 +0100 Subject: [PATCH 64/66] Adding ability for QML/JS file to be visible in QtCreator. Also changed files will be installed to destination --- CMakeLists.txt | 11 +++++++++++ interface/CMakeLists.txt | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ab7e55343..0703866ac6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,6 +206,17 @@ foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS}) include(${CUSTOM_MACRO}) endforeach() +file(GLOB_RECURSE JS_SRC scripts/*.js) +add_custom_target(js SOURCES ${JS_SRC}) + +if (UNIX) + install( + DIRECTORY "${CMAKE_SOURCE_DIR}/scripts" + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/interface + COMPONENT ${CLIENT_COMPONENT} + ) +endif() + if (ANDROID) file(GLOB ANDROID_CUSTOM_MACROS "cmake/android/*.cmake") foreach(CUSTOM_MACRO ${ANDROID_CUSTOM_MACROS}) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 868a2cf933..dbc484d0b9 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -63,6 +63,17 @@ qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}") # add them to the interface source files set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}") +file(GLOB_RECURSE QML_SRC resources/qml/*.qml resources/qml/*.js) +add_custom_target(qml SOURCES ${QML_SRC}) + +if (UNIX) + install( + DIRECTORY "${CMAKE_SOURCE_DIR}/interface/resources/qml" + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/resources + COMPONENT ${CLIENT_COMPONENT} + ) +endif() + # translation disabled until we strip out the line numbers # set(QM ${TARGET_NAME}_en.qm) # set(TS ${TARGET_NAME}_en.ts) From c6dbfc85f055bc95646b04b36b38c7b3526a00ad Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 7 Mar 2017 09:54:00 -0700 Subject: [PATCH 65/66] cr feedback --- interface/resources/qml/hifi/Pal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index db975f3d8a..3608c03e79 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -658,7 +658,7 @@ Rectangle { }); if (newSelectedIndexes.length > 0) { table.selection.select(newSelectedIndexes); - table.positionViewAtRow(userIndex, ListView.Beginning); + table.positionViewAtRow(newSelectedIndexes[0], ListView.Beginning); } } signal sendToScript(var message); From b760e8622606c91be1eac4995c30426ff56fb30a Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 7 Mar 2017 10:17:32 -0700 Subject: [PATCH 66/66] rest of cr feedback --- interface/resources/qml/hifi/Pal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 3608c03e79..7f9de35c90 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -642,7 +642,7 @@ Rectangle { userModel.clear(); var userIndex = 0; - var newSelectedIndexes=[]; + var newSelectedIndexes = []; userModelData.forEach(function (datum) { function init(property) { if (datum[property] === undefined) {