From e406e3d47e129acf1c35c294b3ce4b20406a518b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 3 Jan 2017 14:46:51 -0500 Subject: [PATCH 01/38] Make Forward DrawBounds enableable --- .../render-utils/src/RenderForwardTask.h | 26 ++++++++++++------- libraries/render/src/render/Task.h | 3 ++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 000210c761..9d93c7d5c3 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -33,11 +33,25 @@ private: gpu::FramebufferPointer _framebuffer; }; -class DrawBounds { +class DrawBackground { public: using Inputs = render::ItemBounds; - using JobModel = render::Job::ModelI; + using JobModel = render::Job::ModelI; + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& background); +}; + +class DrawBounds { +public: + class Config : public render::JobConfig { + public: + Config() : JobConfig(false) {} + }; + + using Inputs = render::ItemBounds; + using JobModel = render::Job::ModelI; + + void configure(const Config& configuration) {} void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& items); private: @@ -47,12 +61,4 @@ private: int _scaleLocation { -1 }; }; -class DrawBackground { -public: - using Inputs = render::ItemBounds; - using JobModel = render::Job::ModelI; - - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& background); -}; - #endif // hifi_RenderForwardTask_h diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 49273d79a5..4e3aa79c8d 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -371,6 +371,7 @@ protected: class JobConfig : public QObject { Q_OBJECT Q_PROPERTY(double cpuRunTime READ getCPURunTime NOTIFY newStats()) //ms + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) double _msCPURunTime{ 0.0 }; public: @@ -380,7 +381,7 @@ public: JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {} bool isEnabled() { return alwaysEnabled || enabled; } - void setEnabled(bool enable) { enabled = enable; } + void setEnabled(bool enable) { enabled = alwaysEnabled || enable; } bool alwaysEnabled{ true }; bool enabled{ true }; From 01cf48807c7af9f37e834908ad0a2bc9392bb1f2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 3 Jan 2017 14:47:48 -0500 Subject: [PATCH 02/38] change Render.RenderForwardTask to Render.Forward --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b58bedb363..8372e7f609 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1824,7 +1824,7 @@ void Application::initializeGL() { assert(items.canCast()); static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD"; if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) { - _renderEngine->addJob("RenderForwardTask", items.get()); + _renderEngine->addJob("Forward", items.get()); } else { _renderEngine->addJob("RenderDeferredTask", items.get()); } From 2e274b026da979abcb5c6d64865b028260f5e4e2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 3 Jan 2017 14:54:44 -0500 Subject: [PATCH 03/38] fix line lengths --- libraries/render-utils/src/RenderForwardTask.cpp | 11 +++++++---- libraries/render-utils/src/RenderForwardTask.h | 12 ++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index e78d457666..be47abeeab 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -49,7 +49,8 @@ RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { addJob("Blit", framebuffer); } -void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer) { +void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + gpu::FramebufferPointer& framebuffer) { auto framebufferCache = DependencyManager::get(); auto framebufferSize = framebufferCache->getFrameBufferSize(); glm::uvec2 frameSize(framebufferSize.width(), framebufferSize.height()); @@ -112,7 +113,8 @@ const gpu::PipelinePointer DrawBounds::getPipeline() { return _boundsPipeline; } -void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Inputs& items) { +void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const Inputs& items) { RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { @@ -143,7 +145,8 @@ void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContex }); } -void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Inputs& items) { +void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const Inputs& background) { RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { @@ -161,7 +164,7 @@ void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderCo batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - renderItems(sceneContext, renderContext, items); + renderItems(sceneContext, renderContext, background); }); args->_batch = nullptr; } diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 9d93c7d5c3..21fe43af64 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -25,9 +25,11 @@ public: class PrepareFramebuffer { public: - using JobModel = render::Job::ModelO; + using Inputs = gpu::FramebufferPointer; + using JobModel = render::Job::ModelO; - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, gpu::FramebufferPointer& framebuffer); + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + gpu::FramebufferPointer& framebuffer); private: gpu::FramebufferPointer _framebuffer; @@ -38,7 +40,8 @@ public: using Inputs = render::ItemBounds; using JobModel = render::Job::ModelI; - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& background); + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + const Inputs& background); }; class DrawBounds { @@ -52,7 +55,8 @@ public: using JobModel = render::Job::ModelI; void configure(const Config& configuration) {} - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& items); + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + const Inputs& items); private: const gpu::PipelinePointer getPipeline(); From f8e8065e93a39170824eae2f30d85952f1e9a892 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 3 Jan 2017 14:56:47 -0500 Subject: [PATCH 04/38] mv DrawBounds to end of ForwardTask --- .../render-utils/src/RenderForwardTask.cpp | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index be47abeeab..51dc2dcd47 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -90,6 +90,30 @@ void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const Rend framebuffer = _framebuffer; } +void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const Inputs& background) { + RenderArgs* args = renderContext->args; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + batch.enableSkybox(true); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + // Setup projection + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + + renderItems(sceneContext, renderContext, background); + }); + args->_batch = nullptr; +} + const gpu::PipelinePointer DrawBounds::getPipeline() { if (!_boundsPipeline) { auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); @@ -144,27 +168,3 @@ void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContex } }); } - -void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, - const Inputs& background) { - RenderArgs* args = renderContext->args; - - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - args->_batch = &batch; - - batch.enableSkybox(true); - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - // Setup projection - glm::mat4 projMat; - Transform viewMat; - args->getViewFrustum().evalProjectionMatrix(projMat); - args->getViewFrustum().evalViewTransform(viewMat); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - renderItems(sceneContext, renderContext, background); - }); - args->_batch = nullptr; -} From 89917b41fd08d9936c133a8e71cdfd596249f0d0 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 3 Jan 2017 15:18:22 -0500 Subject: [PATCH 05/38] add Forward Draw for opaques (no pipelines) --- .../render-utils/src/RenderForwardTask.cpp | 26 +++++++++++++++++++ .../render-utils/src/RenderForwardTask.h | 13 ++++++++++ 2 files changed, 39 insertions(+) diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 51dc2dcd47..ebc9ac5b94 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -30,6 +30,9 @@ using namespace render; RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { + // Prepare the ShapePipelines + ShapePlumberPointer shapePlumber = std::make_shared(); + // Extract opaques / transparents / lights / overlays const auto opaques = items[0]; const auto transparents = items[1]; @@ -40,6 +43,7 @@ RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { const auto framebuffer = addJob("PrepareFramebuffer"); + addJob("DrawOpaques", opaques, shapePlumber); addJob("DrawBackground", background); // bounds do not draw on stencil buffer, so they must come last @@ -90,6 +94,28 @@ void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const Rend framebuffer = _framebuffer; } +void Draw::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const Inputs& items) { + RenderArgs* args = renderContext->args; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + // Setup projection + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + // Render items + renderStateSortShapes(sceneContext, renderContext, _shapePlumber, items, -1); + }); + args->_batch = nullptr; +} + void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Inputs& background) { RenderArgs* args = renderContext->args; diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 21fe43af64..5f9386ceba 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -35,6 +35,19 @@ private: gpu::FramebufferPointer _framebuffer; }; +class Draw { +public: + using Inputs = render::ItemBounds; + using JobModel = render::Job::ModelI; + + Draw(const render::ShapePlumberPointer& shapePlumber) : _shapePlumber(shapePlumber) {} + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + const Inputs& items); + +private: + render::ShapePlumberPointer _shapePlumber; +}; + class DrawBackground { public: using Inputs = render::ItemBounds; From 62eeb0c8072e1f64580a81523bca251f66c43a9b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 3 Jan 2017 18:33:14 -0500 Subject: [PATCH 06/38] clean RenderPipelines with forward decls --- .../render-utils/src/RenderPipelines.cpp | 76 +++++++++++-------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 1f4b7ca445..506a6b87f0 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -48,40 +48,11 @@ using namespace render; -gpu::BufferView getDefaultMaterialBuffer() { - model::Material::Schema schema; - schema._albedo = vec3(1.0f); - schema._opacity = 1.0f; - schema._metallic = 0.1f; - schema._roughness = 0.9f; - return gpu::BufferView(std::make_shared(sizeof(model::Material::Schema), (const gpu::Byte*) &schema)); -} +void initOverlay3DPipelines(ShapePlumber& plumber); +void initDeferredPipelines(render::ShapePlumber& plumber); -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) { - static const gpu::BufferView OPAQUE_SCHEMA_BUFFER = getDefaultMaterialBuffer(); - batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, OPAQUE_SCHEMA_BUFFER); - } -} - -void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { - batchSetter(pipeline, batch); - // Set the light - if (pipeline.locations->lightBufferUnit >= 0) { - DependencyManager::get()->setupKeyLightBatch(batch, - pipeline.locations->lightBufferUnit, - pipeline.locations->lightAmbientBufferUnit, - pipeline.locations->lightAmbientMapUnit); - } -} +void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch); +void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch); void initOverlay3DPipelines(ShapePlumber& plumber) { auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert)); @@ -283,3 +254,42 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { skinModelShadowVertex, modelShadowPixel); } + +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) { + // Create a default schema + static bool isMaterialSet = false; + static model::Material material; + if (!isMaterialSet) { + material.setAlbedo(vec3(1.0f)); + material.setOpacity(1.0f); + material.setMetallic(0.1f); + material.setRoughness(0.9f); + isMaterialSet = true; + } + + // Set a default schema + batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, material.getSchemaBuffer()); + } +} + +void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { + // Set the batch + batchSetter(pipeline, batch); + + // Set the light + if (pipeline.locations->lightBufferUnit >= 0) { + DependencyManager::get()->setupKeyLightBatch(batch, + pipeline.locations->lightBufferUnit, + pipeline.locations->lightAmbientBufferUnit, + pipeline.locations->lightAmbientMapUnit); + } +} From a414ba4cb50286261e0afb6c0b4d4e99985685e8 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 3 Jan 2017 18:54:34 -0500 Subject: [PATCH 07/38] take addPipeline lambda out of initDeferredPipelines --- .../render-utils/src/RenderPipelines.cpp | 95 ++++++++++--------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 506a6b87f0..d28e1aa0a2 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -10,6 +10,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include #include @@ -47,9 +49,13 @@ using namespace render; +using namespace std::placeholders; void initOverlay3DPipelines(ShapePlumber& plumber); -void initDeferredPipelines(render::ShapePlumber& plumber); +void initDeferredPipelines(ShapePlumber& plumber); + +void addPlumberPipeline(ShapePlumber& plumber, + const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel); void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch); void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch); @@ -101,50 +107,6 @@ void initOverlay3DPipelines(ShapePlumber& plumber) { } void initDeferredPipelines(render::ShapePlumber& plumber) { - using Key = render::ShapeKey; - using ShaderPointer = gpu::ShaderPointer; - - auto addPipeline = [&plumber](const Key& key, const ShaderPointer& vertexShader, const ShaderPointer& pixelShader) { - // These keyvalues' pipelines will be added by this lamdba in addition to the key passed - assert(!key.isWireFrame()); - assert(!key.isDepthBiased()); - assert(key.isCullFace()); - - ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); - - for (int i = 0; i < 8; i++) { - bool isCulled = (i & 1); - bool isBiased = (i & 2); - bool isWireframed = (i & 4); - - ShapeKey::Builder builder(key); - auto state = std::make_shared(); - - // Depth test depends on transparency - state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); - state->setBlendFunction(key.isTranslucent(), - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - if (!isCulled) { - builder.withoutCullFace(); - } - state->setCullMode(isCulled ? gpu::State::CULL_BACK : gpu::State::CULL_NONE); - if (isWireframed) { - builder.withWireframe(); - state->setFillMode(gpu::State::FILL_LINE); - } - if (isBiased) { - builder.withDepthBias(); - state->setDepthBias(1.0f); - state->setDepthBiasSlopeScale(1.0f); - } - - plumber.addPipeline(builder.build(), program, state, - key.isTranslucent() ? &lightBatchSetter : &batchSetter); - } - }; - // Vertex shaders auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); @@ -169,6 +131,8 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); + using Key = render::ShapeKey; + auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); // TODO: Refactor this to use a filter // Opaques addPipeline( @@ -252,7 +216,48 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withSkinned().withDepthOnly(), skinModelShadowVertex, modelShadowPixel); +} +void addPlumberPipeline(ShapePlumber& plumber, + const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel) { + // These key-values' pipelines are added by this functor in addition to the key passed + assert(!key.isWireFrame()); + assert(!key.isDepthBiased()); + assert(key.isCullFace()); + + gpu::ShaderPointer program = gpu::Shader::createProgram(vertex, pixel); + + for (int i = 0; i < 8; i++) { + bool isCulled = (i & 1); + bool isBiased = (i & 2); + bool isWireframed = (i & 4); + + auto state = std::make_shared(); + + // Depth test depends on transparency + state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); + state->setBlendFunction(key.isTranslucent(), + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + ShapeKey::Builder builder(key); + if (!isCulled) { + builder.withoutCullFace(); + } + state->setCullMode(isCulled ? gpu::State::CULL_BACK : gpu::State::CULL_NONE); + if (isWireframed) { + builder.withWireframe(); + state->setFillMode(gpu::State::FILL_LINE); + } + if (isBiased) { + builder.withDepthBias(); + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(1.0f); + } + + plumber.addPipeline(builder.build(), program, state, + key.isTranslucent() ? &lightBatchSetter : &batchSetter); + } } void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { From f7cb2ec85baaf41cffa3ff4e050680e5059d443c Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 3 Jan 2017 20:41:57 -0500 Subject: [PATCH 08/38] add plain forward model shaders --- .../render-utils/src/RenderForwardTask.cpp | 42 ++++++++++++++++++- .../render-utils/src/RenderForwardTask.h | 11 +++++ .../render-utils/src/RenderPipelines.cpp | 16 +++++++ libraries/render-utils/src/nop.slf | 16 +++++++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 libraries/render-utils/src/nop.slf diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index ebc9ac5b94..c7a3433c96 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -26,12 +26,15 @@ #include #include +#include "nop_frag.h" using namespace render; +extern void initForwardPipelines(ShapePlumber& plumber); RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared(); + initForwardPipelines(*shapePlumber); // Extract opaques / transparents / lights / overlays const auto opaques = items[0]; @@ -44,9 +47,10 @@ RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { const auto framebuffer = addJob("PrepareFramebuffer"); addJob("DrawOpaques", opaques, shapePlumber); + addJob("Stencil"); addJob("DrawBackground", background); - // bounds do not draw on stencil buffer, so they must come last + // Bounds do not draw on stencil buffer, so they must come last addJob("DrawBounds", opaques); // Blit! @@ -116,6 +120,42 @@ void Draw::run(const SceneContextPointer& sceneContext, const RenderContextPoint args->_batch = nullptr; } +const gpu::PipelinePointer Stencil::getPipeline() { + if (!_stencilPipeline) { + auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); + auto ps = gpu::Shader::createPixel(std::string(nop_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + gpu::Shader::makeProgram(*program); + + auto state = std::make_shared(); + state->setDepthTest(true, false, gpu::LESS_EQUAL); + const gpu::int8 STENCIL_OPAQUE = 1; + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_OPAQUE, 0xFF, gpu::ALWAYS, + gpu::State::STENCIL_OP_REPLACE, + gpu::State::STENCIL_OP_REPLACE, + gpu::State::STENCIL_OP_KEEP)); + + _stencilPipeline = gpu::Pipeline::create(program, state); + } + return _stencilPipeline; +} + +void Stencil::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + RenderArgs* args = renderContext->args; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + batch.enableStereo(false); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + batch.setPipeline(getPipeline()); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); + args->_batch = nullptr; +} + void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Inputs& background) { RenderArgs* args = renderContext->args; diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 5f9386ceba..a957f7493e 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -48,6 +48,17 @@ private: render::ShapePlumberPointer _shapePlumber; }; +class Stencil { +public: + using JobModel = render::Job::Model; + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + +private: + const gpu::PipelinePointer getPipeline(); + gpu::PipelinePointer _stencilPipeline; +}; + class DrawBackground { public: using Inputs = render::ItemBounds; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index d28e1aa0a2..2f04d778e2 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -53,6 +53,7 @@ using namespace std::placeholders; void initOverlay3DPipelines(ShapePlumber& plumber); void initDeferredPipelines(ShapePlumber& plumber); +void initForwardPipelines(ShapePlumber& plumber); void addPlumberPipeline(ShapePlumber& plumber, const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel); @@ -218,6 +219,21 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { skinModelShadowVertex, modelShadowPixel); } +void initForwardPipelines(render::ShapePlumber& plumber) { + // Vertex shaders + auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); + + // Pixel shaders + auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); + + using Key = render::ShapeKey; + auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); + // Opaques + addPipeline( + Key::Builder(), + modelVertex, modelPixel); + } + void addPlumberPipeline(ShapePlumber& plumber, const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel) { // These key-values' pipelines are added by this functor in addition to the key passed diff --git a/libraries/render-utils/src/nop.slf b/libraries/render-utils/src/nop.slf new file mode 100644 index 0000000000..f87db4e138 --- /dev/null +++ b/libraries/render-utils/src/nop.slf @@ -0,0 +1,16 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// nop.frag +// fragment shader +// +// Created by Zach Pomerantz on 1/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 +// + +void main(void) { +} From 6b984d38d3415a8f86dcd8261c72381fa0a1b701 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 4 Jan 2017 15:37:17 -0500 Subject: [PATCH 09/38] add opaque forward model shaders --- .../render-utils/src/RenderPipelines.cpp | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 2f04d778e2..d65db9b818 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -222,9 +222,14 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { void initForwardPipelines(render::ShapePlumber& plumber) { // Vertex shaders auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); + auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); // Pixel shaders auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); + auto modelUnlitPixel = gpu::Shader::createPixel(std::string(model_unlit_frag)); + auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); + auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); + auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); using Key = render::ShapeKey; auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); @@ -232,7 +237,20 @@ void initForwardPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder(), modelVertex, modelPixel); - } + addPipeline( + Key::Builder().withUnlit(), + modelVertex, modelUnlitPixel); + addPipeline( + Key::Builder().withTangents(), + modelNormalMapVertex, modelNormalMapPixel); + addPipeline( + Key::Builder().withSpecular(), + modelVertex, modelSpecularMapPixel); + addPipeline( + Key::Builder().withTangents().withSpecular(), + modelNormalMapVertex, modelNormalSpecularMapPixel); + +} void addPlumberPipeline(ShapePlumber& plumber, const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel) { From 1b948c7a05393016f19e58892b846a102e559182 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 4 Jan 2017 15:49:29 -0500 Subject: [PATCH 10/38] add skinned forward model shaders --- libraries/render-utils/src/RenderPipelines.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index d65db9b818..b0d676ef78 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -223,6 +223,8 @@ void initForwardPipelines(render::ShapePlumber& plumber) { // Vertex shaders auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); + auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); + auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); // Pixel shaders auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); @@ -249,7 +251,19 @@ void initForwardPipelines(render::ShapePlumber& plumber) { addPipeline( Key::Builder().withTangents().withSpecular(), modelNormalMapVertex, modelNormalSpecularMapPixel); - + // Skinned + addPipeline( + Key::Builder().withSkinned(), + skinModelVertex, modelPixel); + addPipeline( + Key::Builder().withSkinned().withTangents(), + skinModelNormalMapVertex, modelNormalMapPixel); + addPipeline( + Key::Builder().withSkinned().withSpecular(), + skinModelVertex, modelSpecularMapPixel); + addPipeline( + Key::Builder().withSkinned().withTangents().withSpecular(), + skinModelNormalMapVertex, modelNormalSpecularMapPixel); } void addPlumberPipeline(ShapePlumber& plumber, From 4278d7b20dd903422734b316049d1a0dee7c7b23 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 11:05:27 -0800 Subject: [PATCH 11/38] download and link oculus platform for oculus plugin --- cmake/externals/LibOVRPlatform/CMakeLists.txt | 32 +++++++++++++++ cmake/modules/FindLibOVRPlatform.cmake | 41 +++++++++++++++++++ plugins/oculus/CMakeLists.txt | 36 +++++++++------- 3 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 cmake/externals/LibOVRPlatform/CMakeLists.txt create mode 100644 cmake/modules/FindLibOVRPlatform.cmake diff --git a/cmake/externals/LibOVRPlatform/CMakeLists.txt b/cmake/externals/LibOVRPlatform/CMakeLists.txt new file mode 100644 index 0000000000..75338ce041 --- /dev/null +++ b/cmake/externals/LibOVRPlatform/CMakeLists.txt @@ -0,0 +1,32 @@ +include(ExternalProject) +include(SelectLibraryConfigurations) + +set(EXTERNAL_NAME LibOVRPlatform) + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +if (WIN32) + + ExternalProject_Add( + ${EXTERNAL_NAME} + URL http://hifi-public.s3.amazonaws.com/dependencies/OVRPlatformSDK_v1.10.0.zip + URL_MD5 e6c8264af16d904e6506acd5172fa0a9 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 + ) + + ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(${EXTERNAL_NAME_UPPER}_LIB ${SOURCE_DIR}/Windows/LibOVRPlatform64_1.lib CACHE TYPE INTERNAL) + else() + set(${EXTERNAL_NAME_UPPER}_LIB ${SOURCE_DIR}/Windows/LibOVRPlatform32_1.lib CACHE TYPE INTERNAL) + endif() + + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/Include CACHE TYPE INTERNAL) +endif () + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") diff --git a/cmake/modules/FindLibOVRPlatform.cmake b/cmake/modules/FindLibOVRPlatform.cmake new file mode 100644 index 0000000000..e09fa21895 --- /dev/null +++ b/cmake/modules/FindLibOVRPlatform.cmake @@ -0,0 +1,41 @@ +# +# FindLibOVRPlatform.cmake +# +# Try to find the LibOVRPlatform library to use the Oculus Platform SDK +# +# You must provide a LIBOVRPLATFORM_ROOT_DIR which contains Windows and Include directories +# +# Once done this will define +# +# LIBOVRPLATFORM_FOUND - system found Oculus Platform SDK +# LIBOVRPLATFORM_INCLUDE_DIRS - the Oculus Platform include directory +# LIBOVRPLATFORM_LIBRARIES - Link this to use Oculus Platform +# +# Created on December 16, 2016 by Stephen Birarda +# Copyright 2016 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 +# + + +if (WIN32) + # setup hints for LIBOVRPLATFORM search + include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") + hifi_library_search_hints("LibOVRPlatform") + + find_path(LIBOVRPLATFORM_INCLUDE_DIRS OVR_Platform.h PATH_SUFFIXES Include HINTS ${LIBOVRPLATFORM_SEARCH_DIRS}) + + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(_LIB_NAME LibOVRPlatform64_1.lib) + else() + set(_LIB_NAME LibOVRPlatform32_1.lib) + endif() + + find_library(LIBOVRPLATFORM_LIBRARY_RELEASE NAMES ${_LIB_NAME} PATH_SUFFIXES Windows HINTS ${LIBOVRPLATFORM_SEARCH_DIRS}) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(LIBOVRPLATFORM DEFAULT_MSG LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES) + + mark_as_advanced(LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES LIBOVRPLATFORM_SEARCH_DIRS) +endif () diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index a768af932e..7ee0228616 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -8,21 +8,27 @@ if (WIN32) - # we're using static GLEW, so define GLEW_STATIC - add_definitions(-DGLEW_STATIC) + # we're using static GLEW, so define GLEW_STATIC + add_definitions(-DGLEW_STATIC) - set(TARGET_NAME oculus) - setup_hifi_plugin(Multimedia) - link_hifi_libraries(shared gl gpu gpu-gl controllers ui - plugins ui-plugins display-plugins input-plugins - audio-client networking render-utils) - - include_hifi_library_headers(octree) - - add_dependency_external_projects(LibOVR) - find_package(LibOVR REQUIRED) - target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) - target_link_libraries(${TARGET_NAME} Winmm.lib) + set(TARGET_NAME oculus) + setup_hifi_plugin(Multimedia) + link_hifi_libraries( + shared gl gpu gpu-gl controllers ui + plugins ui-plugins display-plugins input-plugins + audio-client networking render-utils + ) + include_hifi_library_headers(octree) + + add_dependency_external_projects(LibOVR) + find_package(LibOVR REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) + target_link_libraries(${TARGET_NAME} Winmm.lib) + + add_dependency_external_projects(LibOVRPlatform) + find_package(LibOVRPlatform REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVRPLATFORM_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${LIBOVRPLATFORM_LIBRARIES}) endif() From ac7637f8ff897e9d9133a327b9a16e485b8dbd88 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 13:10:49 -0800 Subject: [PATCH 12/38] use _LIBRARY_RELEASE for LibOVRPlatform external --- cmake/externals/LibOVRPlatform/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/externals/LibOVRPlatform/CMakeLists.txt b/cmake/externals/LibOVRPlatform/CMakeLists.txt index 75338ce041..3622972a13 100644 --- a/cmake/externals/LibOVRPlatform/CMakeLists.txt +++ b/cmake/externals/LibOVRPlatform/CMakeLists.txt @@ -20,9 +20,9 @@ if (WIN32) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") - set(${EXTERNAL_NAME_UPPER}_LIB ${SOURCE_DIR}/Windows/LibOVRPlatform64_1.lib CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/Windows/LibOVRPlatform64_1.lib CACHE TYPE INTERNAL) else() - set(${EXTERNAL_NAME_UPPER}_LIB ${SOURCE_DIR}/Windows/LibOVRPlatform32_1.lib CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/Windows/LibOVRPlatform32_1.lib CACHE TYPE INTERNAL) endif() set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/Include CACHE TYPE INTERNAL) From 1a50a1174125b0ed2257d1c0563e510435e47a2c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 13:15:14 -0800 Subject: [PATCH 13/38] have FindLibOVRPlatform produce LIBOVRPLATFORM_LIBRARY --- cmake/modules/FindLibOVRPlatform.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/modules/FindLibOVRPlatform.cmake b/cmake/modules/FindLibOVRPlatform.cmake index e09fa21895..fd07ff6f06 100644 --- a/cmake/modules/FindLibOVRPlatform.cmake +++ b/cmake/modules/FindLibOVRPlatform.cmake @@ -9,7 +9,7 @@ # # LIBOVRPLATFORM_FOUND - system found Oculus Platform SDK # LIBOVRPLATFORM_INCLUDE_DIRS - the Oculus Platform include directory -# LIBOVRPLATFORM_LIBRARIES - Link this to use Oculus Platform +# LIBOVRPLATFORM_LIBRARY - Link this to use Oculus Platform # # Created on December 16, 2016 by Stephen Birarda # Copyright 2016 High Fidelity, Inc. @@ -35,7 +35,7 @@ if (WIN32) find_library(LIBOVRPLATFORM_LIBRARY_RELEASE NAMES ${_LIB_NAME} PATH_SUFFIXES Windows HINTS ${LIBOVRPLATFORM_SEARCH_DIRS}) include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(LIBOVRPLATFORM DEFAULT_MSG LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES) + find_package_handle_standard_args(LIBOVRPLATFORM DEFAULT_MSG LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARY) - mark_as_advanced(LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES LIBOVRPLATFORM_SEARCH_DIRS) + mark_as_advanced(LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARY LIBOVRPLATFORM_SEARCH_DIRS) endif () From d0236af33468d251317d54443ec0c4c76db3b380 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 13:25:35 -0800 Subject: [PATCH 14/38] use select_library_configurations for LibOVRPlatform --- cmake/modules/FindLibOVRPlatform.cmake | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cmake/modules/FindLibOVRPlatform.cmake b/cmake/modules/FindLibOVRPlatform.cmake index fd07ff6f06..e9caa2cb98 100644 --- a/cmake/modules/FindLibOVRPlatform.cmake +++ b/cmake/modules/FindLibOVRPlatform.cmake @@ -9,7 +9,7 @@ # # LIBOVRPLATFORM_FOUND - system found Oculus Platform SDK # LIBOVRPLATFORM_INCLUDE_DIRS - the Oculus Platform include directory -# LIBOVRPLATFORM_LIBRARY - Link this to use Oculus Platform +# LIBOVRPLATFORM_LIBRARIES - Link this to use Oculus Platform # # Created on December 16, 2016 by Stephen Birarda # Copyright 2016 High Fidelity, Inc. @@ -34,8 +34,11 @@ if (WIN32) find_library(LIBOVRPLATFORM_LIBRARY_RELEASE NAMES ${_LIB_NAME} PATH_SUFFIXES Windows HINTS ${LIBOVRPLATFORM_SEARCH_DIRS}) - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(LIBOVRPLATFORM DEFAULT_MSG LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARY) + include(SelectLibraryConfigurations) + select_library_configurations(LIBOVRPLATFORM) - mark_as_advanced(LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARY LIBOVRPLATFORM_SEARCH_DIRS) + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(LIBOVRPLATFORM DEFAULT_MSG LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES) + + mark_as_advanced(LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES LIBOVRPLATFORM_SEARCH_DIRS) endif () From ea3e5f702a26e80c3653d70a39a7c7853a8a3ef2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 13:44:06 -0800 Subject: [PATCH 15/38] add popping of messages for entitlement check --- plugins/oculus/src/OculusHelpers.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 8a160b67ff..7cdf5cfeef 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -15,6 +15,9 @@ #include #include +#define OVRPL_DISABLED +#include + #include #include #include @@ -27,6 +30,7 @@ static ovrSession session { nullptr }; static bool _quitRequested { false }; static bool _reorientRequested { false }; +static bool _entitlementCheckFailed { false }; inline ovrErrorInfo getError() { ovrErrorInfo error; @@ -125,6 +129,20 @@ void handleOVREvents() { return; } + // pop messages to see if we got a return for an entitlement check + while ((message = ovr_PopMessage()) != nullptr) { + switch (ovr_Message_GetType(message)) { + case ovrMessage_Entitlement_GetIsViewerEntitled: { + if (!ovr_Message_IsError(message)) { + // this viewer is entitled, no need to flag anything + } else { + // we failed the entitlement check, set our flag so the app can stop + _entitlementCheckFailed = true; + } + } + } + } + _quitRequested = status.ShouldQuit; _reorientRequested = status.ShouldRecenter; } @@ -217,4 +235,4 @@ controller::Pose ovrControllerPoseToHandPose( pose.velocity = toGlm(handPose.LinearVelocity); pose.valid = true; return pose; -} \ No newline at end of file +} From b87a1b2b2bb3afe0090e01adfc48849e8011a35f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 14:53:48 -0800 Subject: [PATCH 16/38] only fire the entitlement check if OCULUS_APP_ID is set --- plugins/oculus/CMakeLists.txt | 6 ++++- plugins/oculus/src/OculusHelpers.cpp | 35 +++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 7ee0228616..6b8d1a2ff9 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -11,6 +11,11 @@ if (WIN32) # we're using static GLEW, so define GLEW_STATIC add_definitions(-DGLEW_STATIC) + # if we were passed an Oculus App ID for entitlement checks, send that along + if (DEFINED ENV{OCULUS_APP_ID}) + add_definitions(-DOCULUS_APP_ID="\\"$ENV{OCULUS_APP_ID}\\"") + endif () + set(TARGET_NAME oculus) setup_hifi_plugin(Multimedia) link_hifi_libraries( @@ -18,7 +23,6 @@ if (WIN32) plugins ui-plugins display-plugins input-plugins audio-client networking render-utils ) - include_hifi_library_headers(octree) add_dependency_external_projects(LibOVR) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 7cdf5cfeef..ef9b667342 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -30,7 +30,6 @@ static ovrSession session { nullptr }; static bool _quitRequested { false }; static bool _reorientRequested { false }; -static bool _entitlementCheckFailed { false }; inline ovrErrorInfo getError() { ovrErrorInfo error; @@ -92,6 +91,18 @@ ovrSession acquireOculusSession() { logWarning("Failed to initialize Oculus SDK"); return session; } + +#ifdef OCULUS_APP_ID + if (true) { + if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { + // we were unable to initialize the platform for entitlement check - fail the check + _quitRequested = true; + } else { + qCDebug(oculus) << "Performing Oculus Platform entitlement check"; + ovr_Entitlement_GetIsViewerEntitled(); + } + } +#endif Q_ASSERT(0 == refCount); ovrGraphicsLuid luid; @@ -129,22 +140,34 @@ void handleOVREvents() { return; } + _quitRequested = status.ShouldQuit; + _reorientRequested = status.ShouldRecenter; + + #ifdef OCULUS_APP_ID // pop messages to see if we got a return for an entitlement check - while ((message = ovr_PopMessage()) != nullptr) { + ovrMessageHandle message = ovr_PopMessage(); + + while (message) { switch (ovr_Message_GetType(message)) { case ovrMessage_Entitlement_GetIsViewerEntitled: { if (!ovr_Message_IsError(message)) { // this viewer is entitled, no need to flag anything + qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally"; } else { // we failed the entitlement check, set our flag so the app can stop - _entitlementCheckFailed = true; + qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID; + _quitRequested = true; } } } - } - _quitRequested = status.ShouldQuit; - _reorientRequested = status.ShouldRecenter; + // free the message handle to cleanup and not leak + ovr_FreeMessage(message); + + // pop the next message to check, if there is one + message = ovr_PopMessage(); + } +#endif } bool quitRequested() { From f592d8d894fa7abe6c3072397061d857b7070481 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 15:19:26 -0800 Subject: [PATCH 17/38] force entitlement check for all builds with OCULUS_APP_ID --- plugins/oculus/src/OculusHelpers.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index ef9b667342..92cfbcc5bd 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -93,14 +93,13 @@ ovrSession acquireOculusSession() { } #ifdef OCULUS_APP_ID - if (true) { - if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { - // we were unable to initialize the platform for entitlement check - fail the check - _quitRequested = true; - } else { - qCDebug(oculus) << "Performing Oculus Platform entitlement check"; - ovr_Entitlement_GetIsViewerEntitled(); - } + if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { + // we were unable to initialize the platform for entitlement check - fail the check + _quitRequested = true; + } + else { + qCDebug(oculus) << "Performing Oculus Platform entitlement check"; + ovr_Entitlement_GetIsViewerEntitled(); } #endif From 2ec9b81aa6880a13d83269df2c8fa0b37960365e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 15:48:16 -0800 Subject: [PATCH 18/38] fix passing of OCULUS_APP_ID to platform SDK initialization --- plugins/oculus/CMakeLists.txt | 2 +- plugins/oculus/src/OculusHelpers.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 6b8d1a2ff9..55eb9c7b85 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -13,7 +13,7 @@ if (WIN32) # if we were passed an Oculus App ID for entitlement checks, send that along if (DEFINED ENV{OCULUS_APP_ID}) - add_definitions(-DOCULUS_APP_ID="\\"$ENV{OCULUS_APP_ID}\\"") + add_definitions(-DOCULUS_APP_ID="$ENV{OCULUS_APP_ID}") endif () set(TARGET_NAME oculus) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 92cfbcc5bd..7cafe9a1d4 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -96,8 +96,7 @@ ovrSession acquireOculusSession() { if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { // we were unable to initialize the platform for entitlement check - fail the check _quitRequested = true; - } - else { + } else { qCDebug(oculus) << "Performing Oculus Platform entitlement check"; ovr_Entitlement_GetIsViewerEntitled(); } From 46086cdcceb4b25a1e8cbf73e03a787f2a56fc39 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 5 Jan 2017 13:50:45 -0800 Subject: [PATCH 19/38] set the OCULUS_STORE property with oculus store arg --- interface/src/Application.cpp | 41 ++++++++++--------- .../shared/src/shared/GlobalAppProperties.cpp | 1 + .../shared/src/shared/GlobalAppProperties.h | 1 + plugins/oculus/src/OculusHelpers.cpp | 17 ++++---- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 832419a75c..75290f77d5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -250,7 +250,7 @@ public: static const unsigned long MAX_HEARTBEAT_AGE_USECS = 30 * USECS_PER_SECOND; static const int WARNING_ELAPSED_HEARTBEAT = 500 * USECS_PER_MSEC; // warn if elapsed heartbeat average is large static const int HEARTBEAT_SAMPLES = 100000; // ~5 seconds worth of samples - + // Set the heartbeat on launch DeadlockWatchdogThread() { setObjectName("Deadlock Watchdog"); @@ -613,7 +613,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _window->setWindowTitle("Interface"); Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us - + auto nodeList = DependencyManager::get(); // Set up a watchdog thread to intentionally crash the application on deadlocks @@ -634,6 +634,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qCDebug(interfaceapp) << "[VERSION] We will use DEVELOPMENT global services."; #endif + // set the OCULUS_STORE property so the oculus plugin can know if we ran from the Oculus Store + static const QString OCULUS_STORE_ARG = "--oculus-store"; + setProperty(hifi::properties::OCULUS_STORE, arguments().indexOf(OCULUS_STORE_ARG) != -1); static const QString NO_UPDATER_ARG = "--no-updater"; static const bool noUpdater = arguments().indexOf(NO_UPDATER_ARG) != -1; @@ -694,7 +697,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo audioIO->setPositionGetter([]{ auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; - + return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO; }); audioIO->setOrientationGetter([]{ @@ -877,7 +880,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo #ifdef Q_OS_MAC auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget #else - // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the + // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the // window menu, which is a pain, so only hide it for the GL surface auto cursorTarget = _glWidget; #endif @@ -1122,7 +1125,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo loadSettings(); // Now that we've loaded the menu and thus switched to the previous display plugin - // we can unlock the desktop repositioning code, since all the positions will be + // we can unlock the desktop repositioning code, since all the positions will be // relative to the desktop size for this plugin auto offscreenUi = DependencyManager::get(); offscreenUi->getDesktop()->setProperty("repositionLocked", false); @@ -1595,7 +1598,7 @@ void Application::checkChangeCursor() { #ifdef Q_OS_MAC auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget #else - // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the + // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the // window menu, which is a pain, so only hide it for the GL surface auto cursorTarget = _glWidget; #endif @@ -1782,7 +1785,7 @@ Application::~Application() { #endif // The window takes ownership of the menu, so this has the side effect of destroying it. _window->setMenuBar(nullptr); - + _window->deleteLater(); // Can't log to file passed this point, FileLogger about to be deleted @@ -1808,10 +1811,10 @@ void Application::initializeGL() { _glWidget->makeCurrent(); gpu::Context::init(); - qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK, + qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK, QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram))); _gpuContext = std::make_shared(); - // The gpu context can make child contexts for transfers, so + // The gpu context can make child contexts for transfers, so // we need to restore primary rendering context _glWidget->makeCurrent(); @@ -2027,7 +2030,7 @@ void Application::paintGL() { // FIXME not needed anymore? _offscreenContext->makeCurrent(); - // If a display plugin loses it's underlying support, it + // If a display plugin loses it's underlying support, it // needs to be able to signal us to not use it if (!displayPlugin->beginFrameRender(_frameCount)) { _inPaint = false; @@ -2839,7 +2842,7 @@ void Application::keyPressEvent(QKeyEvent* event) { if (isMirrorChecked) { // if we got here without coming in from a non-Full Screen mirror case, then our - // _returnFromFullScreenMirrorTo is unknown. In that case we'll go to the old + // _returnFromFullScreenMirrorTo is unknown. In that case we'll go to the old // behavior of returning to ThirdPerson if (_returnFromFullScreenMirrorTo.isEmpty()) { _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; @@ -3013,7 +3016,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { maybeToggleMenuVisible(event); auto& compositor = getApplicationCompositor(); - // if this is a real mouse event, and we're in HMD mode, then we should use it to move the + // if this is a real mouse event, and we're in HMD mode, then we should use it to move the // compositor reticle // handleRealMouseMoveEvent() will return true, if we shouldn't process the event further if (!compositor.fakeEventActive() && compositor.handleRealMouseMoveEvent()) { @@ -4027,7 +4030,7 @@ void Application::setKeyboardFocusEntity(EntityItemID entityItemID) { } _lastAcceptedKeyPress = usecTimestampNow(); - setKeyboardFocusHighlight(entity->getPosition(), entity->getRotation(), + setKeyboardFocusHighlight(entity->getPosition(), entity->getRotation(), entity->getDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR); } } @@ -4618,7 +4621,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node _octreeQuery.setMaxQueryPacketsPerSecond(0); } - // if asked to forceResend, then set the query's position/orientation to be degenerate in a manner + // if asked to forceResend, then set the query's position/orientation to be degenerate in a manner // that will cause our next query to be guarenteed to be different and the server will resend to us if (forceResend) { _octreeQuery.setCameraPosition(glm::vec3(-0.1, -0.1, -0.1)); @@ -5751,7 +5754,7 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin mapping = mapping.insert(mapping.lastIndexOf("."), "-" + QString::number(copy)); addAssetToWorldWithNewMapping(filePath, mapping, copy); } else { - QString errorInfo = "Too many copies of asset name: " + QString errorInfo = "Too many copies of asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); qWarning(interfaceapp) << "Error downloading asset: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); @@ -5818,7 +5821,7 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { // Note: Model dimensions are not available here; model is scaled per FBX mesh in RenderableModelEntityItem::update() later // on. But FBX dimensions may be in cm, so we monitor for the dimension change and rescale again if warranted. - + if (entityID == QUuid()) { QString errorInfo = "Could not add asset " + mapping + " to world."; qWarning(interfaceapp) << "Could not add asset to world: " + errorInfo; @@ -6283,7 +6286,7 @@ glm::uvec2 Application::getCanvasSize() const { } QRect Application::getRenderingGeometry() const { - auto geometry = _glWidget->geometry(); + auto geometry = _glWidget->geometry(); auto topLeft = geometry.topLeft(); auto topLeftScreen = _glWidget->mapToGlobal(topLeft); geometry.moveTopLeft(topLeftScreen); @@ -6646,8 +6649,8 @@ bool Application::makeRenderingContextCurrent() { return _offscreenContext->makeCurrent(); } -bool Application::isForeground() const { - return _isForeground && !_window->isMinimized(); +bool Application::isForeground() const { + return _isForeground && !_window->isMinimized(); } void Application::sendMousePressOnEntity(QUuid id, PointerEvent event) { diff --git a/libraries/shared/src/shared/GlobalAppProperties.cpp b/libraries/shared/src/shared/GlobalAppProperties.cpp index a8a38457f2..f2d8990708 100644 --- a/libraries/shared/src/shared/GlobalAppProperties.cpp +++ b/libraries/shared/src/shared/GlobalAppProperties.cpp @@ -13,6 +13,7 @@ namespace hifi { namespace properties { const char* CRASHED = "com.highfidelity.crashed"; const char* STEAM = "com.highfidelity.launchedFromSteam"; const char* LOGGER = "com.highfidelity.logger"; + const char* OCULUS_STORE = "com.highfidelity.oculusStore"; const char* TEST = "com.highfidelity.test"; const char* TRACING = "com.highfidelity.tracing"; diff --git a/libraries/shared/src/shared/GlobalAppProperties.h b/libraries/shared/src/shared/GlobalAppProperties.h index 92d8388f09..609f2afd94 100644 --- a/libraries/shared/src/shared/GlobalAppProperties.h +++ b/libraries/shared/src/shared/GlobalAppProperties.h @@ -15,6 +15,7 @@ namespace hifi { namespace properties { extern const char* CRASHED; extern const char* STEAM; extern const char* LOGGER; + extern const char* OCULUS_STORE; extern const char* TEST; extern const char* TRACING; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 7cafe9a1d4..be4866a71e 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -20,6 +20,7 @@ #include #include +#include #include Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display") @@ -91,14 +92,16 @@ ovrSession acquireOculusSession() { logWarning("Failed to initialize Oculus SDK"); return session; } - + #ifdef OCULUS_APP_ID - if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { - // we were unable to initialize the platform for entitlement check - fail the check - _quitRequested = true; - } else { - qCDebug(oculus) << "Performing Oculus Platform entitlement check"; - ovr_Entitlement_GetIsViewerEntitled(); + if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) { + if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { + // we were unable to initialize the platform for entitlement check - fail the check + _quitRequested = true; + } else { + qCDebug(oculus) << "Performing Oculus Platform entitlement check"; + ovr_Entitlement_GetIsViewerEntitled(); + } } #endif From 8f279ce1f7db4367bfce1d6362cad4768d8f0439 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 5 Jan 2017 14:21:35 -0800 Subject: [PATCH 20/38] only pop to check entitlements if oculus store build --- plugins/oculus/src/OculusHelpers.cpp | 39 +++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index be4866a71e..340b804404 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -145,28 +145,31 @@ void handleOVREvents() { _reorientRequested = status.ShouldRecenter; #ifdef OCULUS_APP_ID - // pop messages to see if we got a return for an entitlement check - ovrMessageHandle message = ovr_PopMessage(); - while (message) { - switch (ovr_Message_GetType(message)) { - case ovrMessage_Entitlement_GetIsViewerEntitled: { - if (!ovr_Message_IsError(message)) { - // this viewer is entitled, no need to flag anything - qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally"; - } else { - // we failed the entitlement check, set our flag so the app can stop - qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID; - _quitRequested = true; + if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) { + // pop messages to see if we got a return for an entitlement check + ovrMessageHandle message = ovr_PopMessage(); + + while (message) { + switch (ovr_Message_GetType(message)) { + case ovrMessage_Entitlement_GetIsViewerEntitled: { + if (!ovr_Message_IsError(message)) { + // this viewer is entitled, no need to flag anything + qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally"; + } else { + // we failed the entitlement check, set our flag so the app can stop + qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID; + _quitRequested = true; + } } } + + // free the message handle to cleanup and not leak + ovr_FreeMessage(message); + + // pop the next message to check, if there is one + message = ovr_PopMessage(); } - - // free the message handle to cleanup and not leak - ovr_FreeMessage(message); - - // pop the next message to check, if there is one - message = ovr_PopMessage(); } #endif } From 8bb200902f3b1c496afadfba0cc9ecb249f70857 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 10 Jan 2017 16:40:48 -0800 Subject: [PATCH 21/38] First pass --- assignment-client/src/audio/AudioMixer.cpp | 18 ++++++++-- assignment-client/src/audio/AudioMixer.h | 1 + .../src/audio/AudioMixerClientData.h | 6 ++++ .../src/audio/AudioMixerSlave.cpp | 7 ++-- assignment-client/src/audio/AudioMixerSlave.h | 2 +- interface/resources/qml/hifi/NameCard.qml | 33 ++++++++++++++++++- interface/resources/qml/hifi/Pal.qml | 2 ++ libraries/networking/src/NodeList.cpp | 23 +++++++++++++ libraries/networking/src/NodeList.h | 1 + libraries/networking/src/udt/PacketHeaders.h | 3 +- .../src/UsersScriptingInterface.cpp | 5 +++ .../src/UsersScriptingInterface.h | 8 +++++ scripts/system/pal.js | 4 +++ 13 files changed, 105 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 19ebd4ea87..fddd2d641e 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -68,7 +68,8 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListener(PacketType::NodeMuteRequest, this, "handleNodeMuteRequestPacket"); packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket"); - packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); + packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); + packetReceiver.registerListener(PacketType::PerAvatarGainSet, this, "handlePerAvatarGainSetDataPacket"); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); } @@ -186,7 +187,9 @@ void AudioMixer::handleNodeKilled(SharedNodePointer killedNode) { nodeList->eachNode([&killedNode](const SharedNodePointer& node) { auto clientData = dynamic_cast(node->getLinkedData()); if (clientData) { - clientData->removeHRTFsForNode(killedNode->getUUID()); + QUuid killedUUID = killedNode->getUUID(); + clientData->removePerAvatarGain(killedUUID); + clientData->removeHRTFsForNode(killedUUID); } }); } @@ -240,6 +243,17 @@ void AudioMixer::handleNodeIgnoreRequestPacket(QSharedPointer p sendingNode->parseIgnoreRequestMessage(packet); } +void AudioMixer::handlePerAvatarGainSetDataPacket(QSharedPointer packet, SharedNodePointer sendingNode) { + auto clientData = dynamic_cast(sendingNode->getLinkedData()); + if (clientData) { + // parse the UUID from the packet + QUuid ignoredUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + float gain; + packet->readPrimitive(&gain); + clientData->setPerAvatarGain(ignoredUUID, gain); + } +} + void AudioMixer::handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode) { sendingNode->parseIgnoreRadiusRequestMessage(packet); } diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index d9759653fb..d88bc3b917 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -66,6 +66,7 @@ private slots: void handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleKillAvatarPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleNodeMuteRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void handlePerAvatarGainSetDataPacket(QSharedPointer packet, SharedNodePointer sendingNode); void start(); void removeHRTFsForFinishedInjector(const QUuid& streamID); diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index e637fd0409..d7fbfe5112 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -95,6 +95,10 @@ public: bool getRequestsDomainListData() { return _requestsDomainListData; } void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; } + float getPerAvatarGain(const QUuid& avatarID) { return (_perAvatarGain.count(avatarID) ? _perAvatarGain.at(avatarID) : 1.0f); } + void setPerAvatarGain(const QUuid& avatarID, float gain) { _perAvatarGain[avatarID] = gain; } + void removePerAvatarGain(const QUuid& avatarID) { _perAvatarGain.erase(avatarID); } + signals: void injectorStreamFinished(const QUuid& streamIdentifier); @@ -125,6 +129,8 @@ private: bool _shouldMuteClient { false }; bool _requestsDomainListData { false }; + + std::unordered_map _perAvatarGain; }; #endif // hifi_AudioMixerClientData_h diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 28d3358eb5..90037b7187 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -252,12 +252,13 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& node) { // Enumerate the audio streams attached to the otherNode auto streamsCopy = otherData->getAudioStreams(); + float thisAvatarGain = nodeData->getPerAvatarGain(otherNode->getUUID()); for (auto& streamPair : streamsCopy) { auto otherNodeStream = streamPair.second; bool isSelfWithEcho = ((*otherNode == *node) && (otherNodeStream->shouldLoopbackForNode())); // Add all audio streams that should be added to the mix if (isSelfWithEcho || (!isSelfWithEcho && !insideIgnoreRadius)) { - addStreamToMix(*nodeData, otherNode->getUUID(), *nodeAudioStream, *otherNodeStream); + addStreamToMix(*nodeData, otherNode->getUUID(), *nodeAudioStream, *otherNodeStream, thisAvatarGain); } } } @@ -278,7 +279,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& node) { } void AudioMixerSlave::addStreamToMix(AudioMixerClientData& listenerNodeData, const QUuid& sourceNodeID, - const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd) { + const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, float perAvatarGain) { // to reduce artifacts we calculate the gain and azimuth for every source for this listener // even if we are not going to end up mixing in this source @@ -295,7 +296,7 @@ void AudioMixerSlave::addStreamToMix(AudioMixerClientData& listenerNodeData, con float distance = glm::max(glm::length(relativePosition), EPSILON); // figure out the gain for this source at the listener - float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho); + float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho) + (perAvatarGain - 1.0f); // figure out the azimuth to this source at the listener float azimuth = isEcho ? 0.0f : azimuthForSource(listeningNodeStream, listeningNodeStream, relativePosition); diff --git a/assignment-client/src/audio/AudioMixerSlave.h b/assignment-client/src/audio/AudioMixerSlave.h index c4aabfbb4a..89aa70f99a 100644 --- a/assignment-client/src/audio/AudioMixerSlave.h +++ b/assignment-client/src/audio/AudioMixerSlave.h @@ -43,7 +43,7 @@ private: bool prepareMix(const SharedNodePointer& node); // add a stream to the mix void addStreamToMix(AudioMixerClientData& listenerData, const QUuid& streamerID, - const AvatarAudioStream& listenerStream, const PositionalAudioStream& streamer); + const AvatarAudioStream& listenerStream, const PositionalAudioStream& streamer, float perAvatarGain); float gainForSource(const AvatarAudioStream& listener, const PositionalAudioStream& streamer, const glm::vec3& relativePosition, bool isEcho); diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index a0dde8bacc..0a0b662193 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -10,6 +10,7 @@ // import QtQuick 2.5 +import QtQuick.Controls 1.4 import QtGraphicalEffects 1.0 import "../styles-uit" @@ -27,12 +28,14 @@ Row { } // Properties - property int contentHeight: 50 + property int contentHeight: isMyCard ? 50 : 70 + property string uuid: "" property string displayName: "" property string userName: "" property int displayTextHeight: 18 property int usernameTextHeight: 12 property real audioLevel: 0.0 + property bool isMyCard: false /* User image commented out for now - will probably be re-introduced later. Column { @@ -138,5 +141,33 @@ Row { } } } + + // Per-Avatar Gain Slider Spacer + Item { + width: parent.width + height: 4 + visible: !isMyCard + } + // Per-Avatar Gain Slider + Slider { + id: gainSlider + visible: !isMyCard + width: parent.width + height: 16 + value: 1.0 + minimumValue: 0.0 + maximumValue: 1.5 + stepSize: 0.1 + updateValueWhileDragging: false + onValueChanged: updateGainFromQML(uuid, value) + } + } + + function updateGainFromQML(avatarUuid, gainValue) { + var data = { + sessionId: avatarUuid, + gain: (Math.exp(gainValue) - 1) / (Math.E - 1) + }; + pal.sendToScript({method: 'updateGain', params: data}); } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 66dce622ff..4f65497da5 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -65,6 +65,7 @@ Rectangle { displayName: myData.displayName userName: myData.userName audioLevel: myData.audioLevel + isMyCard: true // Size width: nameCardWidth height: parent.height @@ -206,6 +207,7 @@ Rectangle { userName: model && model.userName audioLevel: model && model.audioLevel visible: !isCheckBox && !isButton + uuid: model && model.sessionId // Size width: nameCardWidth height: parent.height diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index d890431a45..00f13dff3d 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -951,6 +951,29 @@ void NodeList::maybeSendIgnoreSetToNode(SharedNodePointer newNode) { } } +void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { + // cannot set gain of yourself or nobody + if (!nodeID.isNull() && _sessionUUID != nodeID) { + auto audioMixer = soloNodeOfType(NodeType::AudioMixer); + if (audioMixer) { + // setup the packet + auto setAvatarGainPacket = NLPacket::create(PacketType::PerAvatarGainSet, NUM_BYTES_RFC4122_UUID + sizeof(float), true); + + // write the node ID to the packet + setAvatarGainPacket->write(nodeID.toRfc4122()); + setAvatarGainPacket->writePrimitive((gain < 5.0f ? gain : 5.0f)); + + qCDebug(networking) << "Sending Set Avatar Gain packet UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; + + sendPacket(std::move(setAvatarGainPacket), *audioMixer); + } else { + qWarning() << "Couldn't find audio mixer to send set gain request"; + } + } else { + qWarning() << "NodeList::setAvatarGain called with an invalid ID or an ID which matches the current session ID:" << nodeID; + } +} + void NodeList::kickNodeBySessionID(const QUuid& nodeID) { // send a request to domain-server to kick the node with the given session ID // the domain-server will handle the persistence of the kick (via username or IP) diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 8e285629dc..5c477303e2 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -82,6 +82,7 @@ public: bool isIgnoringNode(const QUuid& nodeID) const; void personalMuteNodeBySessionID(const QUuid& nodeID, bool muteEnabled); bool isPersonalMutingNode(const QUuid& nodeID) const; + void setAvatarGain(const QUuid& nodeID, float gain); void kickNodeBySessionID(const QUuid& nodeID); void muteNodeBySessionID(const QUuid& nodeID); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index e4c4937622..0328037eb3 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -106,7 +106,8 @@ public: ViewFrustum, RequestsDomainListData, ExitingSpaceBubble, - LAST_PACKET_TYPE = ExitingSpaceBubble + PerAvatarGainSet, + LAST_PACKET_TYPE = ExitingSpaceBubble // FIXME!!! }; }; diff --git a/libraries/script-engine/src/UsersScriptingInterface.cpp b/libraries/script-engine/src/UsersScriptingInterface.cpp index d0ad699846..3a3225ec75 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.cpp +++ b/libraries/script-engine/src/UsersScriptingInterface.cpp @@ -42,6 +42,11 @@ bool UsersScriptingInterface::getPersonalMuteStatus(const QUuid& nodeID) { return DependencyManager::get()->isPersonalMutingNode(nodeID); } +void UsersScriptingInterface::setAvatarGain(const QUuid& nodeID, float gain) { + // ask the NodeList to set the gain of the specified avatar + DependencyManager::get()->setAvatarGain(nodeID, gain); +} + void UsersScriptingInterface::kick(const QUuid& nodeID) { // ask the NodeList to kick the user with the given session ID DependencyManager::get()->kickNodeBySessionID(nodeID); diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 341285a742..d2d77a6796 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -61,6 +61,14 @@ public slots: */ bool getPersonalMuteStatus(const QUuid& nodeID); + /**jsdoc + * Sets an avatar's gain for you and you only. + * @function Users.setAvatarGain + * @param {nodeID} nodeID The node or session ID of the user whose gain you want to modify. + * @param {float} gain The gain of the avatar you'd like to set. + */ + void setAvatarGain(const QUuid& nodeID, float gain); + /**jsdoc * Kick another user. * @function Users.kick diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 48f44570fd..12f0793b97 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -233,6 +233,10 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like removeOverlays(); populateUserList(); break; + case 'updateGain': + data = message.params; + Users.setAvatarGain(data['sessionId'], data['gain']); + break; default: print('Unrecognized message from Pal.qml:', JSON.stringify(message)); } From dcff873cd46d4747c53539a728c3717c774453fa Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 10 Jan 2017 16:50:38 -0800 Subject: [PATCH 22/38] Modify slider function --- assignment-client/src/audio/AudioMixerSlave.cpp | 2 +- interface/resources/qml/hifi/NameCard.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 90037b7187..d502239341 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -296,7 +296,7 @@ void AudioMixerSlave::addStreamToMix(AudioMixerClientData& listenerNodeData, con float distance = glm::max(glm::length(relativePosition), EPSILON); // figure out the gain for this source at the listener - float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho) + (perAvatarGain - 1.0f); + float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho) * perAvatarGain; // figure out the azimuth to this source at the listener float azimuth = isEcho ? 0.0f : azimuthForSource(listeningNodeStream, listeningNodeStream, relativePosition); diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 0a0b662193..18dbaf1fe1 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -166,7 +166,7 @@ Row { function updateGainFromQML(avatarUuid, gainValue) { var data = { sessionId: avatarUuid, - gain: (Math.exp(gainValue) - 1) / (Math.E - 1) + gain: (Math.pow(20, gainValue) - 1) / (20 - 1) }; pal.sendToScript({method: 'updateGain', params: data}); } From 503468e49b865f341ffdcfd7a965b12b1a959f39 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 10 Jan 2017 17:20:25 -0800 Subject: [PATCH 23/38] Style changes --- interface/resources/qml/hifi/NameCard.qml | 19 +++++++++++++++++-- interface/resources/qml/hifi/Pal.qml | 6 +++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 18dbaf1fe1..1f4ef07131 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -11,6 +11,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 import "../styles-uit" @@ -28,7 +29,7 @@ Row { } // Properties - property int contentHeight: isMyCard ? 50 : 70 + property int contentHeight: 70 property string uuid: "" property string displayName: "" property string userName: "" @@ -153,13 +154,27 @@ Row { id: gainSlider visible: !isMyCard width: parent.width - height: 16 + height: 18 value: 1.0 minimumValue: 0.0 maximumValue: 1.5 stepSize: 0.1 updateValueWhileDragging: false onValueChanged: updateGainFromQML(uuid, value) + style: SliderStyle { + groove: Rectangle { + color: "#dbdbdb" + implicitWidth: gainSlider.width + implicitHeight: 4 + radius: 2 + } + handle: Rectangle { + anchors.centerIn: parent + color: (control.pressed || control.hovered) ? "#00b4ef" : "#8F8F8F" + implicitWidth: 10 + implicitHeight: 18 + } + } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 4f65497da5..2cc07bf90d 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -24,8 +24,8 @@ Rectangle { // Style color: "#E3E3E3" // Properties - property int myCardHeight: 70 - property int rowHeight: 70 + property int myCardHeight: 90 + property int rowHeight: 90 property int actionButtonWidth: 75 property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4 : 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth property var myData: ({displayName: "", userName: "", audioLevel: 0.0}) // valid dummy until set @@ -51,7 +51,7 @@ Rectangle { id: myInfo // Size width: palContainer.width - height: myCardHeight + 20 + height: myCardHeight // Style color: pal.color // Anchors From 8c3766dfe81d26192b0f1447f55d511041e73f58 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 10 Jan 2017 17:21:51 -0800 Subject: [PATCH 24/38] Fixme --- libraries/networking/src/udt/PacketHeaders.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 0328037eb3..c012ed8f67 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -107,7 +107,7 @@ public: RequestsDomainListData, ExitingSpaceBubble, PerAvatarGainSet, - LAST_PACKET_TYPE = ExitingSpaceBubble // FIXME!!! + LAST_PACKET_TYPE = PerAvatarGainSet }; }; From b9cddc31a941f940067692537b2117449244ee52 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 11 Jan 2017 11:56:35 -0800 Subject: [PATCH 25/38] Checkpoint before implementing Ken's suggestions --- interface/resources/qml/hifi/NameCard.qml | 3 ++- interface/resources/qml/hifi/Pal.qml | 4 +++- scripts/system/pal.js | 12 ++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 1f4ef07131..4b8ee6cbc3 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -155,7 +155,7 @@ Row { visible: !isMyCard width: parent.width height: 18 - value: 1.0 + value: pal.gain[uuid] ? pal.gain[uuid] : 1.0 minimumValue: 0.0 maximumValue: 1.5 stepSize: 0.1 @@ -179,6 +179,7 @@ Row { } function updateGainFromQML(avatarUuid, gainValue) { + pal.gain[avatarUuid] = gainValue; var data = { sessionId: avatarUuid, gain: (Math.pow(20, gainValue) - 1) / (20 - 1) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 2cc07bf90d..039ab78baf 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -32,6 +32,7 @@ Rectangle { property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring. property var userModelData: [] // This simple list is essentially a mirror of the userModel listModel without all the extra complexities. property bool iAmAdmin: false + property var gain: ({}); // Keep a local list of per-avatar gain. Far faster than keeping this data on the server. // This is the container for the PAL Rectangle { @@ -494,8 +495,9 @@ Rectangle { } } break; - case 'clearIgnored': + case 'clearLocalQMLData': ignored = {}; + gain = {}; break; default: console.log('Unrecognized message:', JSON.stringify(message)); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 12f0793b97..6b3fd00c3b 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -586,14 +586,14 @@ button.clicked.connect(onClicked); pal.visibleChanged.connect(onVisibleChanged); pal.closed.connect(off); Users.usernameFromIDReply.connect(usernameFromIDReply); -function clearIgnoredInQMLAndClosePAL() { - pal.sendToQml({ method: 'clearIgnored' }); +function clearLocalQMLDataAndClosePAL() { + pal.sendToQml({ method: 'clearLocalQMLData' }); if (pal.visible) { onClicked(); // Close the PAL } } -Window.domainChanged.connect(clearIgnoredInQMLAndClosePAL); -Window.domainConnectionRefused.connect(clearIgnoredInQMLAndClosePAL); +Window.domainChanged.connect(clearLocalQMLDataAndClosePAL); +Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL); // // Cleanup. @@ -604,8 +604,8 @@ Script.scriptEnding.connect(function () { pal.visibleChanged.disconnect(onVisibleChanged); pal.closed.disconnect(off); Users.usernameFromIDReply.disconnect(usernameFromIDReply); - Window.domainChanged.disconnect(clearIgnoredInQMLAndClosePAL); - Window.domainConnectionRefused.disconnect(clearIgnoredInQMLAndClosePAL); + Window.domainChanged.disconnect(clearLocalQMLDataAndClosePAL); + Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL); Messages.unsubscribe(CHANNEL); Messages.messageReceived.disconnect(receiveMessage); off(); From b0b6aeac6c0eba9331eaa4f837803032acb93944 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 11 Jan 2017 16:16:35 -0800 Subject: [PATCH 26/38] Ken's feedback --- assignment-client/src/audio/AudioMixer.cpp | 13 ++++---- .../src/audio/AudioMixerClientData.h | 6 ---- .../src/audio/AudioMixerSlave.cpp | 7 ++--- assignment-client/src/audio/AudioMixerSlave.h | 2 +- interface/resources/qml/hifi/NameCard.qml | 30 ++++++++++++------- interface/resources/qml/hifi/Pal.qml | 6 ++-- libraries/audio/src/AudioHRTF.h | 2 +- libraries/networking/src/NodeList.cpp | 4 ++- .../src/UsersScriptingInterface.h | 3 +- 9 files changed, 41 insertions(+), 32 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index fddd2d641e..07639867eb 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -28,6 +28,7 @@ #include #include +#include "AudioHelpers.h" #include "AudioRingBuffer.h" #include "AudioMixerClientData.h" #include "AvatarAudioStream.h" @@ -188,7 +189,6 @@ void AudioMixer::handleNodeKilled(SharedNodePointer killedNode) { auto clientData = dynamic_cast(node->getLinkedData()); if (clientData) { QUuid killedUUID = killedNode->getUUID(); - clientData->removePerAvatarGain(killedUUID); clientData->removeHRTFsForNode(killedUUID); } }); @@ -246,11 +246,14 @@ void AudioMixer::handleNodeIgnoreRequestPacket(QSharedPointer p void AudioMixer::handlePerAvatarGainSetDataPacket(QSharedPointer packet, SharedNodePointer sendingNode) { auto clientData = dynamic_cast(sendingNode->getLinkedData()); if (clientData) { + QUuid listeningNodeUUID = sendingNode->getUUID(); // parse the UUID from the packet - QUuid ignoredUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - float gain; - packet->readPrimitive(&gain); - clientData->setPerAvatarGain(ignoredUUID, gain); + QUuid audioSourceUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + uint8_t packedGain; + packet->readPrimitive(&packedGain); + float gain = unpackFloatGainFromByte(packedGain); + clientData->hrtfForStream(audioSourceUUID, QUuid()).setGainAdjustment(gain); + qDebug() << "Setting gain adjustment for hrtf[" << listeningNodeUUID << "][" << audioSourceUUID << "] to " << gain; } } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index d7fbfe5112..e637fd0409 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -95,10 +95,6 @@ public: bool getRequestsDomainListData() { return _requestsDomainListData; } void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; } - float getPerAvatarGain(const QUuid& avatarID) { return (_perAvatarGain.count(avatarID) ? _perAvatarGain.at(avatarID) : 1.0f); } - void setPerAvatarGain(const QUuid& avatarID, float gain) { _perAvatarGain[avatarID] = gain; } - void removePerAvatarGain(const QUuid& avatarID) { _perAvatarGain.erase(avatarID); } - signals: void injectorStreamFinished(const QUuid& streamIdentifier); @@ -129,8 +125,6 @@ private: bool _shouldMuteClient { false }; bool _requestsDomainListData { false }; - - std::unordered_map _perAvatarGain; }; #endif // hifi_AudioMixerClientData_h diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index d502239341..28d3358eb5 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -252,13 +252,12 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& node) { // Enumerate the audio streams attached to the otherNode auto streamsCopy = otherData->getAudioStreams(); - float thisAvatarGain = nodeData->getPerAvatarGain(otherNode->getUUID()); for (auto& streamPair : streamsCopy) { auto otherNodeStream = streamPair.second; bool isSelfWithEcho = ((*otherNode == *node) && (otherNodeStream->shouldLoopbackForNode())); // Add all audio streams that should be added to the mix if (isSelfWithEcho || (!isSelfWithEcho && !insideIgnoreRadius)) { - addStreamToMix(*nodeData, otherNode->getUUID(), *nodeAudioStream, *otherNodeStream, thisAvatarGain); + addStreamToMix(*nodeData, otherNode->getUUID(), *nodeAudioStream, *otherNodeStream); } } } @@ -279,7 +278,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& node) { } void AudioMixerSlave::addStreamToMix(AudioMixerClientData& listenerNodeData, const QUuid& sourceNodeID, - const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, float perAvatarGain) { + const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd) { // to reduce artifacts we calculate the gain and azimuth for every source for this listener // even if we are not going to end up mixing in this source @@ -296,7 +295,7 @@ void AudioMixerSlave::addStreamToMix(AudioMixerClientData& listenerNodeData, con float distance = glm::max(glm::length(relativePosition), EPSILON); // figure out the gain for this source at the listener - float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho) * perAvatarGain; + float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho); // figure out the azimuth to this source at the listener float azimuth = isEcho ? 0.0f : azimuthForSource(listeningNodeStream, listeningNodeStream, relativePosition); diff --git a/assignment-client/src/audio/AudioMixerSlave.h b/assignment-client/src/audio/AudioMixerSlave.h index 89aa70f99a..c4aabfbb4a 100644 --- a/assignment-client/src/audio/AudioMixerSlave.h +++ b/assignment-client/src/audio/AudioMixerSlave.h @@ -43,7 +43,7 @@ private: bool prepareMix(const SharedNodePointer& node); // add a stream to the mix void addStreamToMix(AudioMixerClientData& listenerData, const QUuid& streamerID, - const AvatarAudioStream& listenerStream, const PositionalAudioStream& streamer, float perAvatarGain); + const AvatarAudioStream& listenerStream, const PositionalAudioStream& streamer); float gainForSource(const AvatarAudioStream& listener, const PositionalAudioStream& streamer, const glm::vec3& relativePosition, bool isEcho); diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 4b8ee6cbc3..3e8ee355c8 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -155,10 +155,10 @@ Row { visible: !isMyCard width: parent.width height: 18 - value: pal.gain[uuid] ? pal.gain[uuid] : 1.0 - minimumValue: 0.0 - maximumValue: 1.5 - stepSize: 0.1 + value: pal.gainSliderValueDB[uuid] ? pal.gainSliderValueDB[uuid] : 0.0 + minimumValue: -60.0 + maximumValue: 20.0 + stepSize: 2 updateValueWhileDragging: false onValueChanged: updateGainFromQML(uuid, value) style: SliderStyle { @@ -167,6 +167,12 @@ Row { implicitWidth: gainSlider.width implicitHeight: 4 radius: 2 + MouseArea { + anchors.fill: parent + onDoubleClicked: { + gainSlider.value = 0.0 + } + } } handle: Rectangle { anchors.centerIn: parent @@ -178,12 +184,14 @@ Row { } } - function updateGainFromQML(avatarUuid, gainValue) { - pal.gain[avatarUuid] = gainValue; - var data = { - sessionId: avatarUuid, - gain: (Math.pow(20, gainValue) - 1) / (20 - 1) - }; - pal.sendToScript({method: 'updateGain', params: data}); + function updateGainFromQML(avatarUuid, sliderValue) { + if (pal.gainSliderValueDB[avatarUuid] !== sliderValue) { + pal.gainSliderValueDB[avatarUuid] = sliderValue; + var data = { + sessionId: avatarUuid, + gain: sliderValue + }; + pal.sendToScript({method: 'updateGain', params: data}); + } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 039ab78baf..c74d8757f7 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -32,7 +32,9 @@ Rectangle { property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring. property var userModelData: [] // This simple list is essentially a mirror of the userModel listModel without all the extra complexities. property bool iAmAdmin: false - property var gain: ({}); // Keep a local list of per-avatar gain. Far faster than keeping this data on the server. + // Keep a local list of per-avatar gainSliderValueDBs. Far faster than fetching this data from the server. + // NOTE: if another script modifies the per-avatar gain, this value won't be accurate! + property var gainSliderValueDB: ({}); // This is the container for the PAL Rectangle { @@ -497,7 +499,7 @@ Rectangle { break; case 'clearLocalQMLData': ignored = {}; - gain = {}; + gainSliderValueDB = {}; break; default: console.log('Unrecognized message:', JSON.stringify(message)); diff --git a/libraries/audio/src/AudioHRTF.h b/libraries/audio/src/AudioHRTF.h index c9d053bec4..6a17a2d3cc 100644 --- a/libraries/audio/src/AudioHRTF.h +++ b/libraries/audio/src/AudioHRTF.h @@ -45,7 +45,7 @@ public: void renderSilent(int16_t* input, float* output, int index, float azimuth, float distance, float gain, int numFrames); // - // HRTF local gain adjustment + // HRTF local gain adjustment in amplitude (1.0 == unity) // void setGainAdjustment(float gain) { _gainAdjust = HRTF_GAIN * gain; }; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 00f13dff3d..98a563c4e5 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -26,6 +26,7 @@ #include "AccountManager.h" #include "AddressManager.h" #include "Assignment.h" +#include "AudioHelpers.h" #include "HifiSockAddr.h" #include "FingerprintUtils.h" @@ -961,7 +962,8 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { // write the node ID to the packet setAvatarGainPacket->write(nodeID.toRfc4122()); - setAvatarGainPacket->writePrimitive((gain < 5.0f ? gain : 5.0f)); + // We need to convert the gain in dB (from the script) to an amplitude before packing it. + setAvatarGainPacket->writePrimitive(packFloatGainToByte(fastExp2f(gain / 6.0206f))); qCDebug(networking) << "Sending Set Avatar Gain packet UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index d2d77a6796..0b6b7855b5 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -63,9 +63,10 @@ public slots: /**jsdoc * Sets an avatar's gain for you and you only. + * Units are Decibels (dB) * @function Users.setAvatarGain * @param {nodeID} nodeID The node or session ID of the user whose gain you want to modify. - * @param {float} gain The gain of the avatar you'd like to set. + * @param {float} gain The gain of the avatar you'd like to set. Units are dB. */ void setAvatarGain(const QUuid& nodeID, float gain); From a9226e303c666e72bdb3b1b67b7b601cbf4b4025 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 12 Jan 2017 11:18:43 -0800 Subject: [PATCH 27/38] Pull out visual changess & move them to other PR --- interface/resources/qml/controls-uit/CheckBox.qml | 1 + interface/resources/qml/hifi/LetterboxMessage.qml | 6 +++--- interface/resources/qml/hifi/NameCard.qml | 8 ++++---- interface/resources/qml/hifi/Pal.qml | 1 - 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index 09a0e04148..d3cbb87e5b 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -16,6 +16,7 @@ import "../styles-uit" Original.CheckBox { id: checkBox + HifiConstants { id: hifi } property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index c8adcdcb74..290cff6634 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -15,7 +15,7 @@ import "../styles-uit" Item { property alias text: popupText.text - property real popupRadius: hifi.dimensions.borderRadius + property real radius: hifi.dimensions.borderRadius visible: false id: letterbox anchors.fill: parent @@ -23,13 +23,13 @@ Item { anchors.fill: parent color: "black" opacity: 0.5 - radius: popupRadius + radius: radius } Rectangle { width: Math.max(parent.width * 0.75, 400) height: popupText.contentHeight*1.5 anchors.centerIn: parent - radius: popupRadius + radius: radius color: "white" FiraSansSemiBold { id: popupText diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 3e8ee355c8..7892e0755e 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 @@ -135,10 +136,9 @@ Row { start: Qt.point(0, 0) end: Qt.point(parent.width, 0) gradient: Gradient { - GradientStop { position: 0.0; color: "#2c8e72" } - GradientStop { position: 0.9; color: "#1fc6a6" } - GradientStop { position: 0.91; color: "#ea4c5f" } - GradientStop { position: 1.0; color: "#ea4c5f" } + GradientStop { position: 0.05; color: "#00CFEF" } + GradientStop { position: 0.5; color: "#9450A5" } + GradientStop { position: 0.95; color: "#EA4C5F" } } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index c74d8757f7..fe0c25d803 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -451,7 +451,6 @@ Rectangle { if (selected) { table.selection.clear(); // for now, no multi-select table.selection.select(userIndex); - table.positionViewAtRow(userIndex, ListView.Visible); } else { table.selection.deselect(userIndex); } From a69a10b8e4dd687c107d7732661ba3d0734b865b Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 13 Jan 2017 13:15:01 -0800 Subject: [PATCH 28/38] Cleanup after rebase --- interface/resources/qml/controls-uit/CheckBox.qml | 1 - interface/resources/qml/hifi/LetterboxMessage.qml | 6 +++--- interface/resources/qml/hifi/NameCard.qml | 8 ++++---- interface/resources/qml/hifi/Pal.qml | 1 + 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index d3cbb87e5b..09a0e04148 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -16,7 +16,6 @@ import "../styles-uit" Original.CheckBox { id: checkBox - HifiConstants { id: hifi } property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index 290cff6634..c8adcdcb74 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -15,7 +15,7 @@ import "../styles-uit" Item { property alias text: popupText.text - property real radius: hifi.dimensions.borderRadius + property real popupRadius: hifi.dimensions.borderRadius visible: false id: letterbox anchors.fill: parent @@ -23,13 +23,13 @@ Item { anchors.fill: parent color: "black" opacity: 0.5 - radius: radius + radius: popupRadius } Rectangle { width: Math.max(parent.width * 0.75, 400) height: popupText.contentHeight*1.5 anchors.centerIn: parent - radius: radius + radius: popupRadius color: "white" FiraSansSemiBold { id: popupText diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 7892e0755e..3e8ee355c8 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -9,7 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 @@ -136,9 +135,10 @@ Row { start: Qt.point(0, 0) end: Qt.point(parent.width, 0) gradient: Gradient { - GradientStop { position: 0.05; color: "#00CFEF" } - GradientStop { position: 0.5; color: "#9450A5" } - GradientStop { position: 0.95; color: "#EA4C5F" } + GradientStop { position: 0.0; color: "#2c8e72" } + GradientStop { position: 0.9; color: "#1fc6a6" } + GradientStop { position: 0.91; color: "#ea4c5f" } + GradientStop { position: 1.0; color: "#ea4c5f" } } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index fe0c25d803..c74d8757f7 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -451,6 +451,7 @@ Rectangle { if (selected) { table.selection.clear(); // for now, no multi-select table.selection.select(userIndex); + table.positionViewAtRow(userIndex, ListView.Visible); } else { table.selection.deselect(userIndex); } From 8343769352f8a94d941ce15535aab88caa914257 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 13 Jan 2017 15:25:07 -0800 Subject: [PATCH 29/38] NameCard improvements & user feedback --- interface/resources/qml/hifi/NameCard.qml | 41 +++++++++++++---------- interface/resources/qml/hifi/Pal.qml | 2 +- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 3e8ee355c8..b5bd0a88f8 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -20,16 +20,13 @@ Row { // Spacing spacing: 10 // Anchors - anchors.top: parent.top anchors { - topMargin: (parent.height - contentHeight)/2 - bottomMargin: (parent.height - contentHeight)/2 + verticalCenter: parent.verticalCenter leftMargin: 10 rightMargin: 10 } // Properties - property int contentHeight: 70 property string uuid: "" property string displayName: "" property string userName: "" @@ -42,7 +39,7 @@ Row { Column { id: avatarImage // Size - height: contentHeight + height: parent.height width: height Image { id: userImage @@ -56,9 +53,8 @@ Row { Column { id: textContainer // Size - width: parent.width - /*avatarImage.width - */parent.anchors.leftMargin - parent.anchors.rightMargin - parent.spacing - height: contentHeight - + width: parent.width - /*avatarImage.width - parent.spacing - */parent.anchors.leftMargin - parent.anchors.rightMargin + anchors.verticalCenter: parent.verticalCenter // DisplayName Text FiraSansSemiBold { id: displayNameText @@ -94,7 +90,7 @@ Row { // Spacer Item { - height: 4 + height: 3 width: parent.width } @@ -146,7 +142,7 @@ Row { // Per-Avatar Gain Slider Spacer Item { width: parent.width - height: 4 + height: 3 visible: !isMyCard } // Per-Avatar Gain Slider @@ -159,20 +155,31 @@ Row { minimumValue: -60.0 maximumValue: 20.0 stepSize: 2 - updateValueWhileDragging: false + updateValueWhileDragging: true onValueChanged: updateGainFromQML(uuid, value) + MouseArea { + anchors.fill: parent + onWheel: { + // Do nothing. + } + onDoubleClicked: { + gainSlider.value = 0.0 + } + onPressed: { + // Pass through to Slider + mouse.accepted = false + } + onReleased: { + // Pass through to Slider + mouse.accepted = false + } + } style: SliderStyle { groove: Rectangle { color: "#dbdbdb" implicitWidth: gainSlider.width implicitHeight: 4 radius: 2 - MouseArea { - anchors.fill: parent - onDoubleClicked: { - gainSlider.value = 0.0 - } - } } handle: Rectangle { anchors.centerIn: parent diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index c74d8757f7..0b093ed430 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -25,7 +25,7 @@ Rectangle { color: "#E3E3E3" // Properties property int myCardHeight: 90 - property int rowHeight: 90 + property int rowHeight: 80 property int actionButtonWidth: 75 property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4 : 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth property var myData: ({displayName: "", userName: "", audioLevel: 0.0}) // valid dummy until set From a89868dcad7cf23c27396d861e6bdcedf3d9678f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 13 Jan 2017 15:41:17 -0800 Subject: [PATCH 30/38] Make sliders appear only when row is selected --- interface/resources/qml/hifi/NameCard.qml | 5 +++-- interface/resources/qml/hifi/Pal.qml | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index b5bd0a88f8..10afee2e6a 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -34,6 +34,7 @@ Row { property int usernameTextHeight: 12 property real audioLevel: 0.0 property bool isMyCard: false + property bool selected: false /* User image commented out for now - will probably be re-introduced later. Column { @@ -143,12 +144,12 @@ Row { Item { width: parent.width height: 3 - visible: !isMyCard + visible: !isMyCard && selected } // Per-Avatar Gain Slider Slider { id: gainSlider - visible: !isMyCard + visible: !isMyCard && selected width: parent.width height: 18 value: pal.gainSliderValueDB[uuid] ? pal.gainSliderValueDB[uuid] : 0.0 diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 0b093ed430..052c953316 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -25,7 +25,7 @@ Rectangle { color: "#E3E3E3" // Properties property int myCardHeight: 90 - property int rowHeight: 80 + property int rowHeight: 70 property int actionButtonWidth: 75 property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4 : 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth property var myData: ({displayName: "", userName: "", audioLevel: 0.0}) // valid dummy until set @@ -190,7 +190,7 @@ Rectangle { // This Rectangle refers to each Row in the table. rowDelegate: Rectangle { // The only way I know to specify a row height. // Size - height: rowHeight + height: rowHeight + (styleData.selected ? 20 : 0) color: styleData.selected ? hifi.colors.orangeHighlight : styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd @@ -211,6 +211,7 @@ Rectangle { audioLevel: model && model.audioLevel visible: !isCheckBox && !isButton uuid: model && model.sessionId + selected: styleData.selected // Size width: nameCardWidth height: parent.height From a5343d9aa9104e1c9117ef26d1cc1e9224e24c4d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 13 Jan 2017 17:20:29 -0800 Subject: [PATCH 31/38] Final tweaks before PR! --- interface/resources/qml/hifi/NameCard.qml | 73 ++++++++++++++++------- interface/resources/qml/hifi/Pal.qml | 2 +- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 10afee2e6a..c6daf53b9a 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -15,10 +15,8 @@ import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 import "../styles-uit" -Row { +Item { id: thisNameCard - // Spacing - spacing: 10 // Anchors anchors { verticalCenter: parent.verticalCenter @@ -51,10 +49,11 @@ Row { } } */ - Column { + Item { id: textContainer // Size width: parent.width - /*avatarImage.width - parent.spacing - */parent.anchors.leftMargin - parent.anchors.rightMargin + height: childrenRect.height anchors.verticalCenter: parent.verticalCenter // DisplayName Text FiraSansSemiBold { @@ -64,6 +63,8 @@ Row { elide: Text.ElideRight // Size width: parent.width + // Anchors + anchors.top: parent.top // Text Size size: thisNameCard.displayTextHeight // Text Positioning @@ -81,6 +82,8 @@ Row { visible: thisNameCard.displayName // Size width: parent.width + // Anchors + anchors.top: displayNameText.bottom // Text Size size: thisNameCard.usernameTextHeight // Text Positioning @@ -91,25 +94,56 @@ Row { // Spacer Item { - height: 3 + id: spacer + height: 4 width: parent.width + // Anchors + anchors.top: userNameText.bottom } // VU Meter - Rectangle { // CHANGEME to the appropriate type! + Rectangle { id: nameCardVUMeter // Size - width: parent.width + width: ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width height: 8 + // Anchors + anchors.top: spacer.bottom // Style radius: 4 + color: "#c5c5c5" + // Rectangle for the zero-gain point on the VU meter + Rectangle { + id: vuMeterZeroGain + visible: gainSlider.visible + // Size + width: 4 + height: 18 + // Style + color: hifi.colors.darkGray + // Anchors + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: (-gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue) * gainSlider.width - 4 + } + // Rectangle for the VU meter line + Rectangle { + id: vuMeterLine + width: gainSlider.width + visible: gainSlider.visible + // Style + color: vuMeterBase.color + radius: nameCardVUMeter.radius + height: nameCardVUMeter.height / 2 + anchors.verticalCenter: nameCardVUMeter.verticalCenter + } // Rectangle for the VU meter base Rectangle { id: vuMeterBase // Anchors anchors.fill: parent // Style - color: "#c5c5c5" + color: parent.color radius: parent.radius } // Rectangle for the VU meter audio level @@ -118,7 +152,7 @@ Row { // Size width: (thisNameCard.audioLevel) * parent.width // Style - color: "#c5c5c5" + color: parent.color radius: parent.radius // Anchors anchors.bottom: parent.bottom @@ -140,22 +174,20 @@ Row { } } - // Per-Avatar Gain Slider Spacer - Item { - width: parent.width - height: 3 - visible: !isMyCard && selected - } // Per-Avatar Gain Slider Slider { id: gainSlider - visible: !isMyCard && selected + // Size width: parent.width - height: 18 + height: 14 + // Anchors + anchors.verticalCenter: nameCardVUMeter.verticalCenter + // Properties + visible: !isMyCard && selected value: pal.gainSliderValueDB[uuid] ? pal.gainSliderValueDB[uuid] : 0.0 minimumValue: -60.0 maximumValue: 20.0 - stepSize: 2 + stepSize: 5 updateValueWhileDragging: true onValueChanged: updateGainFromQML(uuid, value) MouseArea { @@ -177,16 +209,17 @@ Row { } style: SliderStyle { groove: Rectangle { - color: "#dbdbdb" + color: "#c5c5c5" implicitWidth: gainSlider.width implicitHeight: 4 radius: 2 + opacity: 0 } handle: Rectangle { anchors.centerIn: parent color: (control.pressed || control.hovered) ? "#00b4ef" : "#8F8F8F" implicitWidth: 10 - implicitHeight: 18 + implicitHeight: 16 } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 052c953316..3438baa217 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -190,7 +190,7 @@ Rectangle { // This Rectangle refers to each Row in the table. rowDelegate: Rectangle { // The only way I know to specify a row height. // Size - height: rowHeight + (styleData.selected ? 20 : 0) + height: rowHeight color: styleData.selected ? hifi.colors.orangeHighlight : styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd From baed3bc3b3493ad9c75a3b808378bd2437751ad2 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Sat, 14 Jan 2017 12:57:00 -0700 Subject: [PATCH 32/38] Manage audio interval timer in PAL Now, it is only running when PAL is up. Was running (but doing nothing before. Somewhat more efficient this way. --- scripts/system/pal.js | 121 ++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 57 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 48f44570fd..f65fa10d88 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -448,50 +448,6 @@ triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Cont triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand)); triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand)); triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand)); -// -// Manage the connection between the button and the window. -// -var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); -var buttonName = "pal"; -var button = toolBar.addButton({ - objectName: buttonName, - imageURL: Script.resolvePath("assets/images/tools/people.svg"), - visible: true, - hoverState: 2, - defaultState: 1, - buttonState: 1, - alpha: 0.9 -}); -var isWired = false; -function off() { - if (isWired) { // It is not ok to disconnect these twice, hence guard. - Script.update.disconnect(updateOverlays); - Controller.mousePressEvent.disconnect(handleMouseEvent); - Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); - isWired = false; - } - triggerMapping.disable(); // It's ok if we disable twice. - triggerPressMapping.disable(); // see above - removeOverlays(); - Users.requestsDomainListData = false; -} -function onClicked() { - if (!pal.visible) { - Users.requestsDomainListData = true; - populateUserList(); - pal.raise(); - isWired = true; - Script.update.connect(updateOverlays); - Controller.mousePressEvent.connect(handleMouseEvent); - Controller.mouseMoveEvent.connect(handleMouseMoveEvent); - triggerMapping.enable(); - triggerPressMapping.enable(); - } else { - off(); - } - pal.setVisible(!pal.visible); -} - // // Message from other scripts, such as edit.js // @@ -523,6 +479,7 @@ var LOUDNESS_SCALE = 2.8 / 5.0; var LOG2 = Math.log(2.0); var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too) var myData = {}; // we're not includied in ExtendedOverlay.get. +var audioInterval; function getAudioLevel(id) { // the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged @@ -555,21 +512,71 @@ function getAudioLevel(id) { return audioLevel; } +function createAudioInterval() { + // we will update the audioLevels periodically + // TODO: tune for efficiency - expecially with large numbers of avatars + return Script.setInterval(function () { + if (pal.visible) { + var param = {}; + AvatarList.getAvatarIdentifiers().forEach(function (id) { + var level = getAudioLevel(id); + // qml didn't like an object with null/empty string for a key, so... + var userId = id || 0; + param[userId] = level; + }); + pal.sendToQml({method: 'updateAudioLevel', params: param}); + } + }, AUDIO_LEVEL_UPDATE_INTERVAL_MS); +} -// we will update the audioLevels periodically -// TODO: tune for efficiency - expecially with large numbers of avatars -Script.setInterval(function () { - if (pal.visible) { - var param = {}; - AvatarList.getAvatarIdentifiers().forEach(function (id) { - var level = getAudioLevel(id); - // qml didn't like an object with null/empty string for a key, so... - var userId = id || 0; - param[userId] = level; - }); - pal.sendToQml({method: 'updateAudioLevel', params: param}); +// +// Manage the connection between the button and the window. +// +var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); +var buttonName = "pal"; +var button = toolBar.addButton({ + objectName: buttonName, + imageURL: Script.resolvePath("assets/images/tools/people.svg"), + visible: true, + hoverState: 2, + defaultState: 1, + buttonState: 1, + alpha: 0.9 +}); +var isWired = false; +function off() { + if (isWired) { // It is not ok to disconnect these twice, hence guard. + Script.update.disconnect(updateOverlays); + Controller.mousePressEvent.disconnect(handleMouseEvent); + Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); + isWired = false; } -}, AUDIO_LEVEL_UPDATE_INTERVAL_MS); + triggerMapping.disable(); // It's ok if we disable twice. + triggerPressMapping.disable(); // see above + removeOverlays(); + Users.requestsDomainListData = false; + if (audioInterval) { + Script.clearInterval(audioInterval); + } +} +function onClicked() { + if (!pal.visible) { + Users.requestsDomainListData = true; + populateUserList(); + pal.raise(); + isWired = true; + Script.update.connect(updateOverlays); + Controller.mousePressEvent.connect(handleMouseEvent); + Controller.mouseMoveEvent.connect(handleMouseMoveEvent); + triggerMapping.enable(); + triggerPressMapping.enable(); + createAudioInterval(); + } else { + off(); + } + pal.setVisible(!pal.visible); +} + // // Button state. // From bd67715cd2ff44c8f16c6d7966e37bb637559222 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 16 Jan 2017 08:54:56 -0800 Subject: [PATCH 33/38] don't early-exit from the loop that checks for loaded collision hulls because the check is what causes the hulls to be constructed --- interface/src/Application.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b056a8e378..28f4d54594 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5294,15 +5294,17 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { if (_nearbyEntitiesStabilityCount >= MINIMUM_NEARBY_ENTITIES_STABILITY_COUNT) { // We've seen the same number of nearby entities for several stats packets in a row. assume we've got all // the local entities. + bool result = true; foreach (EntityItemPointer entity, entities) { if (entity->shouldBePhysical() && !entity->isReadyToComputeShape()) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("Physics disabled until entity loads: .*"); qCDebug(interfaceapp) << "Physics disabled until entity loads: " << entity->getID() << entity->getName(); - return false; + // don't break here because we want all the relevant entities to start their downloads + result = false; } } - return true; + return result; } return false; } From 67ce5040ec66a03d3db0041bd9a811048f0582cb Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 16 Jan 2017 10:09:47 -0800 Subject: [PATCH 34/38] Fix bug in FBX parse changes --- libraries/fbx/src/FBXReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 5272969e6b..42922ce226 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -972,7 +972,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS static const QVariant EMISSIVE = QByteArray("Emissive"); static const QVariant AMBIENT_FACTOR = QByteArray("AmbientFactor"); static const QVariant SHININESS = QByteArray("Shininess"); - static const QVariant OPACITY = QByteArray("Shininess"); + static const QVariant OPACITY = QByteArray("Opacity"); static const QVariant MAYA_USE_NORMAL_MAP = QByteArray("Maya|use_normal_map"); static const QVariant MAYA_BASE_COLOR = QByteArray("Maya|base_color"); static const QVariant MAYA_USE_COLOR_MAP = QByteArray("Maya|use_color_map"); From e22c1ac30e35b376bfe28b0309536f9e1c5de911 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 11:48:51 -0800 Subject: [PATCH 35/38] Fix the bug --- .../src/DomainServerSettingsManager.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index c8895839ff..c6bcc5af34 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -780,12 +780,12 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer message, SharedNodePointer sendingNode) { - // Before we do any processing on this packet, make sure it comes from a node that is allowed to kick (is an admin) - if (sendingNode->getCanKick()) { - // From the packet, pull the UUID we're identifying - QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - - if (!nodeUUID.isNull()) { + // From the packet, pull the UUID we're identifying + QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + if (!nodeUUID.isNull()) { + // Before we do any processing on this packet, make sure it comes from a node that is allowed to kick (is an admin) + // OR from a node whose UUID matches the one in the packet + if (sendingNode->getCanKick() || nodeUUID == sendingNode->getUUID()) { // First, make sure we actually have a node with this UUID auto limitedNodeList = DependencyManager::get(); auto matchingNode = limitedNodeList->nodeWithUUID(nodeUUID); @@ -813,12 +813,12 @@ void DomainServerSettingsManager::processUsernameFromIDRequestPacket(QSharedPoin qWarning() << "Node username request received for unknown node. Refusing to process."; } } else { - qWarning() << "Node username request received for invalid node ID. Refusing to process."; + qWarning() << "Refusing to process a username request packet from node" << uuidStringWithoutCurlyBraces(sendingNode->getUUID()) + << ". Either node doesn't have kick permissions or is requesting a username not from their UUID."; } } else { - qWarning() << "Refusing to process a username request packet from node" << uuidStringWithoutCurlyBraces(sendingNode->getUUID()) - << "that does not have kick permissions."; + qWarning() << "Node username request received for invalid node ID. Refusing to process."; } } From 0a3236dcc91d7ec0c0a392ed10e788094ed93e27 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 16 Jan 2017 14:54:32 -0800 Subject: [PATCH 36/38] handControllerGrab update loop change --- scripts/system/controllers/handControllerGrab.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 2ed09232e6..57698bd0dc 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -3082,7 +3082,7 @@ var handleHandMessages = function(channel, message, sender) { Messages.messageReceived.connect(handleHandMessages); -var TARGET_UPDATE_HZ = 50; // 50hz good enough (no change in logic) +var TARGET_UPDATE_HZ = 60; // 50hz good enough, but we're using update var BASIC_TIMER_INTERVAL_MS = 1000 / TARGET_UPDATE_HZ; var lastInterval = Date.now(); @@ -3095,7 +3095,7 @@ var updateTotalWork = 0; var UPDATE_PERFORMANCE_DEBUGGING = false; -var updateIntervalTimer = Script.setInterval(function(){ +function updateWrapper(){ intervalCount++; var thisInterval = Date.now(); @@ -3141,11 +3141,12 @@ var updateIntervalTimer = Script.setInterval(function(){ updateTotalWork = 0; } -}, BASIC_TIMER_INTERVAL_MS); +} +Script.update.connect(updateWrapper); function cleanup() { Menu.removeMenuItem("Developer", "Show Grab Sphere"); - Script.clearInterval(updateIntervalTimer); + Script.update.disconnect(updateWrapper); rightController.cleanup(); leftController.cleanup(); Controller.disableMapping(MAPPING_NAME); From fd284578073e665df4d9f1b9fd5fd0da4b772c59 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 16 Jan 2017 15:13:28 -0800 Subject: [PATCH 37/38] fix cauterization hack --- .../render-utils/src/MeshPartPayload.cpp | 19 ++++++++++++++++--- libraries/render-utils/src/MeshPartPayload.h | 5 ++++- libraries/render-utils/src/Model.cpp | 2 +- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 5c4c0890a7..e3b2527e67 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -359,8 +359,11 @@ void ModelMeshPartPayload::notifyLocationChanged() { } -void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, const QVector& clusterMatrices) { +void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, + const QVector& clusterMatrices, + const QVector& cauterizedClusterMatrices) { _transform = transform; + _cauterizedTransform = transform; if (clusterMatrices.size() > 0) { _worldBound = AABox(); @@ -373,6 +376,11 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transf _worldBound.transform(transform); if (clusterMatrices.size() == 1) { _transform = _transform.worldTransform(Transform(clusterMatrices[0])); + if (cauterizedClusterMatrices.size() != 0) { + _cauterizedTransform = _cauterizedTransform.worldTransform(Transform(cauterizedClusterMatrices[0])); + } else { + _cauterizedTransform = _transform; + } } } } @@ -527,9 +535,14 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline: } else { batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.clusterBuffer); } + batch.setModelTransform(_transform); + } else { + if (canCauterize && _model->getCauterizeBones()) { + batch.setModelTransform(_cauterizedTransform); + } else { + batch.setModelTransform(_transform); + } } - - batch.setModelTransform(_transform); } void ModelMeshPartPayload::startFade() { diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index b048dc903f..b7a8cf63f0 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -85,7 +85,9 @@ public: typedef Payload::DataPointer Pointer; void notifyLocationChanged() override; - void updateTransformForSkinnedMesh(const Transform& transform, const QVector& clusterMatrices); + void updateTransformForSkinnedMesh(const Transform& transform, + const QVector& clusterMatrices, + const QVector& cauterizedClusterMatrices); // Entity fade in void startFade(); @@ -106,6 +108,7 @@ public: Model* _model; + Transform _cauterizedTransform; int _meshIndex; int _shapeID; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7c1a6e14d0..3a3095458c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -238,7 +238,7 @@ void Model::updateRenderItems() { // update the model transform and bounding box for this render item. const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); - data.updateTransformForSkinnedMesh(modelTransform, state.clusterMatrices); + data.updateTransformForSkinnedMesh(modelTransform, state.clusterMatrices, state.cauterizedClusterMatrices); } } }); From 5e49e8025ab84d11a8363e058ee5b837961e5b68 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 16 Jan 2017 21:06:38 -0600 Subject: [PATCH 38/38] improve comment in domain settings --- domain-server/resources/describe-settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index dd0e4ad4a1..c813ffc54c 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -40,7 +40,7 @@ { "name": "local_port", "label": "Local UDP Port", - "help": "This is the local port your domain-server binds to for UDP connections.
Depending on your router, this may need to be changed to run multiple full automatic networking domain-servers in the same network.", + "help": "This is the local port your domain-server binds to for UDP connections.
Depending on your router, this may need to be changed to unique values for each domain-server in order to run multiple full automatic networking domain-servers in the same network. You can use the value 0 to have the domain-server select a random port, which will help in preventing port collisions.", "default": "40102", "type": "int", "advanced": true