From e7a3d98ae5ede6b5643029b3abb5f97963283273 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Thu, 11 Jan 2018 19:34:54 -0800
Subject: [PATCH 01/57] don't draw head-descendent entities when in 1st-person
 camera mode

---
 interface/src/avatar/MyAvatar.cpp             | 19 +++++++++++++++++++
 interface/src/avatar/MyAvatar.h               |  2 ++
 .../src/RenderableModelEntityItem.cpp         |  5 +++--
 libraries/entities/src/EntityItem.h           |  4 ++++
 4 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index e863a58e14..b680925b3e 100755
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -46,6 +46,7 @@
 #include <recording/Frame.h>
 #include <RecordingScriptingInterface.h>
 #include <trackers/FaceTracker.h>
+#include <RenderableModelEntityItem.h>
 
 #include "MyHead.h"
 #include "MySkeletonModel.h"
@@ -501,11 +502,29 @@ void MyAvatar::updateEyeContactTarget(float deltaTime) {
 extern QByteArray avatarStateToFrame(const AvatarData* _avatar);
 extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
 
+void MyAvatar::updateChildCauterization(SpatiallyNestablePointer object) {
+    if (object->getNestableType() == NestableType::Entity) {
+        EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
+        entity->setCauterized(!_prevShouldDrawHead);
+    }
+}
+
 void MyAvatar::simulate(float deltaTime) {
     PerformanceTimer perfTimer("simulate");
 
     animateScaleChanges(deltaTime);
 
+    const std::unordered_set<int>& headBoneSet = _skeletonModel->getCauterizeBoneSet();
+    forEachChild([&](SpatiallyNestablePointer object) {
+        bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
+        if (isChildOfHead) {
+            updateChildCauterization(object);
+            object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
+                updateChildCauterization(descendant);
+            });
+        }
+    });
+
     {
         PerformanceTimer perfTimer("transform");
         bool stepAction = false;
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index ab74460d4e..7b82a64e23 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -841,6 +841,8 @@ private:
 
     // height of user in sensor space, when standing erect.
     ThreadSafeValueCache<float> _userHeight { DEFAULT_AVATAR_HEIGHT };
+
+    void updateChildCauterization(SpatiallyNestablePointer object);
 };
 
 QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 86237e75a4..a08cf23d7b 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1281,11 +1281,12 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
 
     entity->updateModelBounds();
 
-    if (model->isVisible() != _visible) {
+    bool shouldBeVisible = _visible && !entity->getCauterized();
+    if (model->isVisible() != shouldBeVisible) {
         // FIXME: this seems like it could be optimized if we tracked our last known visible state in
         //        the renderable item. As it stands now the model checks it's visible/invisible state
         //        so most of the time we don't do anything in this function.
-        model->setVisibleInScene(_visible, scene);
+        model->setVisibleInScene(shouldBeVisible, scene);
     }
     // TODO? early exit here when not visible?
 
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index ecfb7b5dcd..68639e0d3a 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -469,6 +469,9 @@ public:
     static QString _marketplacePublicKey;
     static void retrieveMarketplacePublicKey();
 
+    void setCauterized(bool value) { _cauterized = value; }
+    bool getCauterized() const { return _cauterized; }
+
 signals:
     void requestRenderUpdate();
 
@@ -622,6 +625,7 @@ protected:
     quint64 _lastUpdatedAccelerationTimestamp { 0 };
     quint64 _lastUpdatedQueryAACubeTimestamp { 0 };
 
+    bool _cauterized { false }; // it true, don't draw because it would obscure 1st-person camera
 };
 
 #endif // hifi_EntityItem_h

From 9d4ab13a10df7ffc139df39c5fc24b33f473b302 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Thu, 11 Jan 2018 19:45:15 -0800
Subject: [PATCH 02/57] cauterize all head-based entities rather than just
 models

---
 libraries/entities-renderer/src/RenderableEntityItem.cpp     | 2 +-
 .../entities-renderer/src/RenderableModelEntityItem.cpp      | 5 ++---
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index fb9aba636b..49bc4deac5 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -365,7 +365,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
         }
 
         _moving = entity->isMovingRelativeToParent();
-        _visible = entity->getVisible();
+        _visible = entity->getVisible() && !entity->getCauterized();
         _needsRenderUpdate = false;
     });
 }
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index a08cf23d7b..86237e75a4 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1281,12 +1281,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
 
     entity->updateModelBounds();
 
-    bool shouldBeVisible = _visible && !entity->getCauterized();
-    if (model->isVisible() != shouldBeVisible) {
+    if (model->isVisible() != _visible) {
         // FIXME: this seems like it could be optimized if we tracked our last known visible state in
         //        the renderable item. As it stands now the model checks it's visible/invisible state
         //        so most of the time we don't do anything in this function.
-        model->setVisibleInScene(shouldBeVisible, scene);
+        model->setVisibleInScene(_visible, scene);
     }
     // TODO? early exit here when not visible?
 

From 9bdb89df2ea40108f440df59f89feb2a8d92c144 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Fri, 12 Jan 2018 07:26:09 -0800
Subject: [PATCH 03/57] trying to get mirror to work

---
 libraries/entities-renderer/src/RenderableEntityItem.cpp | 6 ++++--
 libraries/entities-renderer/src/RenderableEntityItem.h   | 1 +
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index 49bc4deac5..8d9cc326f3 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -185,7 +185,8 @@ void EntityRenderer::render(RenderArgs* args) {
         emit requestRenderUpdate();
     }
 
-    if (_visible) {
+    bool defaultMode = args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE;
+    if (_visible && (defaultMode || !_cauterized)) {
         doRender(args);
     }
 }
@@ -365,7 +366,8 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
         }
 
         _moving = entity->isMovingRelativeToParent();
-        _visible = entity->getVisible() && !entity->getCauterized();
+        _visible = entity->getVisible();
+        _cauterized = entity->getCauterized();
         _needsRenderUpdate = false;
     });
 }
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h
index 8eb82e2c6e..f8685df5da 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableEntityItem.h
@@ -124,6 +124,7 @@ protected:
     bool _isFading{ _entitiesShouldFadeFunction() };
     bool _prevIsTransparent { false };
     bool _visible { false };
+    bool _cauterized { false };
     bool _moving { false };
     bool _needsRenderUpdate { false };
     // Only touched on the rendering thread

From 227dbd6f684b96755429f18b356a41cc607a0733 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Fri, 12 Jan 2018 08:52:07 -0800
Subject: [PATCH 04/57] put this back to a working state

---
 libraries/entities-renderer/src/RenderableEntityItem.cpp     | 3 +--
 .../entities-renderer/src/RenderableModelEntityItem.cpp      | 5 +++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index 8d9cc326f3..f2876da40a 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -185,8 +185,7 @@ void EntityRenderer::render(RenderArgs* args) {
         emit requestRenderUpdate();
     }
 
-    bool defaultMode = args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE;
-    if (_visible && (defaultMode || !_cauterized)) {
+    if (_visible) {
         doRender(args);
     }
 }
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 86237e75a4..a6d34f5826 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1281,11 +1281,12 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
 
     entity->updateModelBounds();
 
-    if (model->isVisible() != _visible) {
+    bool visible = _visible && !_cauterized;
+    if (model->isVisible() != visible) {
         // FIXME: this seems like it could be optimized if we tracked our last known visible state in
         //        the renderable item. As it stands now the model checks it's visible/invisible state
         //        so most of the time we don't do anything in this function.
-        model->setVisibleInScene(_visible, scene);
+        model->setVisibleInScene(visible, scene);
     }
     // TODO? early exit here when not visible?
 

From dbdc50ed244b7cc9a18c766d7afa2d5c439eee96 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Fri, 12 Jan 2018 08:56:06 -0800
Subject: [PATCH 05/57] also cauterize non-models that are children of head

---
 libraries/entities-renderer/src/RenderableEntityItem.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index f2876da40a..c51e1bccd7 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -185,7 +185,7 @@ void EntityRenderer::render(RenderArgs* args) {
         emit requestRenderUpdate();
     }
 
-    if (_visible) {
+    if (_visible && !_cauterized) {
         doRender(args);
     }
 }

From f81f50a6d282061fe2e5a271b4d852513f0513b4 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Fri, 12 Jan 2018 09:08:52 -0800
Subject: [PATCH 06/57] non-models act correctly in mirror now'

---
 libraries/entities-renderer/src/RenderableEntityItem.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index c51e1bccd7..f3ef956146 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -185,7 +185,12 @@ void EntityRenderer::render(RenderArgs* args) {
         emit requestRenderUpdate();
     }
 
-    if (_visible && !_cauterized) {
+    auto& renderMode = args->_renderMode;
+    bool cauterized = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE &&
+                       renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) &&
+        _cauterized;
+
+    if (_visible && !cauterized) {
         doRender(args);
     }
 }

From 836b69ab1b65a4d1618ffe052a60871d5d669e74 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 12 Jan 2018 17:42:18 -0800
Subject: [PATCH 07/57] exposing several visibility flags

---
 .../render-utils/src/RenderShadowTask.cpp     |  2 +-
 libraries/render-utils/src/RenderViewTask.cpp |  4 +--
 libraries/render-utils/src/RenderViewTask.h   |  2 +-
 libraries/render/src/render/Item.h            | 35 +++++++++++++++----
 .../src/render/RenderFetchCullSortTask.cpp    |  4 +--
 .../src/render/RenderFetchCullSortTask.h      |  2 +-
 6 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp
index 2e5b7132e4..02f6d70e43 100644
--- a/libraries/render-utils/src/RenderShadowTask.cpp
+++ b/libraries/render-utils/src/RenderShadowTask.cpp
@@ -264,7 +264,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
 
     const auto globalShadow = lightStage->getCurrentKeyShadow();
     if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
-        output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
+        output.edit1() = ItemFilter::Builder::visibleWorldItems(0x08).withTypeShape().withOpaque().withoutLayered();
 
         globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
 
diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp
index dc6c66e058..434e069d28 100644
--- a/libraries/render-utils/src/RenderViewTask.cpp
+++ b/libraries/render-utils/src/RenderViewTask.cpp
@@ -14,7 +14,7 @@
 #include "RenderDeferredTask.h"
 #include "RenderForwardTask.h"
 
-void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) {
+void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred, uint8_t visibilityMask) {
    // auto items = input.get<Input>();
 
     // Shadows use an orthographic projection because they are linked to sunlights
@@ -30,7 +30,7 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render:
         return true;
     });
 
-    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
+    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, visibilityMask);
     assert(items.canCast<RenderFetchCullSortTask::Output>());
 
     if (isDeferred) {
diff --git a/libraries/render-utils/src/RenderViewTask.h b/libraries/render-utils/src/RenderViewTask.h
index eb61f56eab..9c2bbe0281 100644
--- a/libraries/render-utils/src/RenderViewTask.h
+++ b/libraries/render-utils/src/RenderViewTask.h
@@ -23,7 +23,7 @@ public:
 
     RenderViewTask() {}
 
-    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred);
+    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred, uint8_t visibilityMask = 0xFF);
 
 };
 
diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h
index 77f5910b9e..c2f1312ec2 100644
--- a/libraries/render/src/render/Item.h
+++ b/libraries/render/src/render/Item.h
@@ -46,7 +46,10 @@ public:
         VIEW_SPACE,       // Transformed in view space, and not in world space
         DYNAMIC,          // Dynamic and bound will change unlike static item
         DEFORMED,         // Deformed within bound, not solid
-        INVISIBLE,        // Visible or not? could be just here to cast shadow
+        INVISIBLE0,       // Visible or not in this mask index?
+        INVISIBLE1,       // Visible or not in this mask index?
+        INVISIBLE2,       // Visible or not in this mask index?
+        INVISIBLE3,       // Visible or not in this mask index?
         SHADOW_CASTER,    // Item cast shadows
         PICKABLE,         // Item can be picked/selected
         LAYERED,          // Item belongs to one of the layers different from the default layer
@@ -57,6 +60,12 @@ public:
     };
     typedef std::bitset<NUM_FLAGS> Flags;
 
+    // VISIBLE MASK is defined from several bits in the Key.
+    // An Item can be visible in some mask bits and not other allowing for per view rendering
+    // Beware that the visibility mask is the oposite of what stored in the key vals.
+    const static uint8_t NUM_VISIBLE_MASK_INDICES{ 4 };
+    const static uint8_t VISIBLE_MASK_ALL{ 0x0F };
+
     // The key is the Flags
     Flags _flags;
 
@@ -82,7 +91,7 @@ public:
         Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); }
         Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); }
         Builder& withDeformed() { _flags.set(DEFORMED); return (*this); }
-        Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); }
+        Builder& withInvisible(uint8_t maskIndex = 0) { _flags.set(INVISIBLE0 + maskIndex); return (*this); }
         Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); }
         Builder& withPickable() { _flags.set(PICKABLE); return (*this); }
         Builder& withLayered() { _flags.set(LAYERED); return (*this); }
@@ -111,8 +120,10 @@ public:
     bool isRigid() const { return !_flags[DEFORMED]; }
     bool isDeformed() const { return _flags[DEFORMED]; }
 
-    bool isVisible() const { return !_flags[INVISIBLE]; }
-    bool isInvisible() const { return _flags[INVISIBLE]; }
+    bool isVisible(uint8_t maskIndex) const { return !_flags[INVISIBLE0 + maskIndex]; }
+    bool isInvisible(uint8_t maskIndex) const { return _flags[INVISIBLE0 + maskIndex]; }
+    uint8_t getVisibleMask() const { return (~(_flags.to_ulong() >> INVISIBLE0) & VISIBLE_MASK_ALL);}
+    bool isVisibleMask(uint8_t mask) const { return getVisibleMask() & mask; }
 
     bool isShadowCaster() const { return _flags[SHADOW_CASTER]; }
 
@@ -171,8 +182,18 @@ public:
         Builder& withRigid()            { _value.reset(ItemKey::DEFORMED); _mask.set(ItemKey::DEFORMED); return (*this); }
         Builder& withDeformed()         { _value.set(ItemKey::DEFORMED);  _mask.set(ItemKey::DEFORMED); return (*this); }
 
-        Builder& withVisible()          { _value.reset(ItemKey::INVISIBLE); _mask.set(ItemKey::INVISIBLE); return (*this); }
-        Builder& withInvisible()        { _value.set(ItemKey::INVISIBLE);  _mask.set(ItemKey::INVISIBLE); return (*this); }
+        Builder& withVisible(uint8_t maskIndex)          { _value.reset(ItemKey::INVISIBLE0 + maskIndex); _mask.set(ItemKey::INVISIBLE0 + maskIndex); return (*this); }
+        Builder& withInvisible(uint8_t maskIndex)        { _value.set(ItemKey::INVISIBLE0 + maskIndex);  _mask.set(ItemKey::INVISIBLE0 + maskIndex); return (*this); }
+        Builder& withVisibilityMask(uint8_t mask) {
+            for (int i = 0; i < ItemKey::NUM_VISIBLE_MASK_INDICES; i++) {
+                if ((1 << i) && mask) {
+                    withVisible(i);
+                } else {
+                    withInvisible(i);
+                }
+            }
+            return (*this);
+        }
 
         Builder& withNoShadowCaster()   { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
         Builder& withShadowCaster()     { _value.set(ItemKey::SHADOW_CASTER);  _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
@@ -185,7 +206,7 @@ public:
         Builder& withNothing()          { _value.reset(); _mask.reset(); return (*this); }
 
         // Convenient standard keys that we will keep on using all over the place
-        static Builder visibleWorldItems() { return Builder().withVisible().withWorldSpace(); }
+        static Builder visibleWorldItems(uint8_t visibilityMask) { return Builder().withVisibilityMask(visibilityMask).withWorldSpace(); }
         static Builder opaqueShape() { return Builder().withTypeShape().withOpaque().withWorldSpace(); }
         static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); }
         static Builder light() { return Builder().withTypeLight(); }
diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp
index d7294fa2bd..25c40ea7f7 100644
--- a/libraries/render/src/render/RenderFetchCullSortTask.cpp
+++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp
@@ -17,12 +17,12 @@
 
 using namespace render;
 
-void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor) {
+void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor, uint8_t visibilityMask) {
     cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
 
     // CPU jobs:
     // Fetch and cull the items from the scene
-    const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
+    const ItemFilter filter = ItemFilter::Builder::visibleWorldItems(visibilityMask).withoutLayered();
     const auto spatialFilter = render::Varying(filter);
     const auto spatialSelection = task.addJob<FetchSpatialTree>("FetchSceneSelection", spatialFilter);
     const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, spatialFilter).asVarying();
diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h
index b25480ae3a..3e5ad2bad8 100644
--- a/libraries/render/src/render/RenderFetchCullSortTask.h
+++ b/libraries/render/src/render/RenderFetchCullSortTask.h
@@ -36,7 +36,7 @@ public:
 
     RenderFetchCullSortTask() {}
 
-    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor);
+    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t visibilityMask = 0xFF);
 };
 
 #endif // hifi_RenderFetchCullSortTask_h

From 7a9740d25878a8f516329eeefbca7f68f0c30b31 Mon Sep 17 00:00:00 2001
From: Sam Gateau <samuel.gateau@gmail.com>
Date: Thu, 18 Jan 2018 02:18:46 -0800
Subject: [PATCH 08/57] visible-perview

---
 interface/src/Application.cpp                 |  2 +-
 interface/src/SecondaryCamera.cpp             |  2 +-
 .../render-utils/src/CauterizedModel.cpp      |  2 +-
 .../render-utils/src/MeshPartPayload.cpp      |  5 ++++-
 libraries/render-utils/src/MeshPartPayload.h  |  2 +-
 .../render-utils/src/RenderShadowTask.cpp     |  2 +-
 libraries/render-utils/src/RenderViewTask.cpp |  4 ++--
 libraries/render-utils/src/RenderViewTask.h   |  2 +-
 libraries/render/src/render/Item.h            | 19 +++++++++++++------
 .../src/render/RenderFetchCullSortTask.cpp    | 18 +++++++++---------
 .../src/render/RenderFetchCullSortTask.h      |  2 +-
 11 files changed, 35 insertions(+), 25 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 6849bd07b5..e9ea9a0295 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2200,7 +2200,7 @@ void Application::initializeGL() {
     bool isDeferred = !QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
     _renderEngine->addJob<UpdateSceneTask>("UpdateScene");
     _renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor);
-    _renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, isDeferred);
+    _renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, isDeferred, render::ItemKey::VISIBLE_MASK_0, render::ItemKey::VISIBLE_MASK_0);
     _renderEngine->load();
     _renderEngine->registerScene(_main3DScene);
 
diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp
index 4cfa4d6156..35eff68ab3 100644
--- a/interface/src/SecondaryCamera.cpp
+++ b/interface/src/SecondaryCamera.cpp
@@ -20,7 +20,7 @@ using RenderArgsPointer = std::shared_ptr<RenderArgs>;
 
 void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
     task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
-    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
+    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::VISIBLE_MASK_1, render::ItemKey::VISIBLE_MASK_1);
     assert(items.canCast<RenderFetchCullSortTask::Output>());
     if (!isDeferred) {
         task.addJob<RenderForwardTask>("Forward", items);
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index e3f26a43d8..09b6ada8e4 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -247,7 +247,7 @@ void CauterizedModel::updateRenderItems() {
                     data.updateTransformForCauterizedMesh(renderTransform);
 
                     data.setEnableCauterization(enableCauterization);
-                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
+                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, enableCauterization);
                     data.setLayer(isLayeredInFront, isLayeredInHUD);
                     data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
                 });
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index c506887fc4..ead2a767db 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -389,13 +389,16 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render
     _worldBound.transform(boundTransform);
 }
 
-void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) {
+void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, bool isCauterized) {
     ItemKey::Builder builder;
     builder.withTypeShape();
 
     if (!isVisible) {
         builder.withInvisible();
     }
+    else if (isCauterized) {
+        builder.withInvisible(0); // hide these items in the vibility mask #0
+    }
 
     if (isLayered) {
         builder.withLayered();
diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h
index 8160b9f009..ee515c7b3d 100644
--- a/libraries/render-utils/src/MeshPartPayload.h
+++ b/libraries/render-utils/src/MeshPartPayload.h
@@ -103,7 +103,7 @@ public:
     render::ShapeKey getShapeKey() const override; // shape interface
     void render(RenderArgs* args) override;
 
-    void setKey(bool isVisible, bool isLayered);
+    void setKey(bool isVisible, bool isLayered, bool isCauterized = false);
     void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
     void setShapeKey(bool invalidateShapeKey, bool isWireframe);
 
diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp
index 378b164e67..7a7714e1e0 100644
--- a/libraries/render-utils/src/RenderShadowTask.cpp
+++ b/libraries/render-utils/src/RenderShadowTask.cpp
@@ -264,7 +264,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
 
     const auto globalShadow = lightStage->getCurrentKeyShadow();
     if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
-        output.edit1() = ItemFilter::Builder::visibleWorldItems(0x08).withTypeShape().withOpaque().withoutLayered();
+        output.edit1() = ItemFilter::Builder::visibleWorldItems(0x00, 0x00).withTypeShape().withOpaque().withoutLayered();
 
         globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
 
diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp
index 434e069d28..83868e1443 100644
--- a/libraries/render-utils/src/RenderViewTask.cpp
+++ b/libraries/render-utils/src/RenderViewTask.cpp
@@ -14,7 +14,7 @@
 #include "RenderDeferredTask.h"
 #include "RenderForwardTask.h"
 
-void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred, uint8_t visibilityMask) {
+void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred, uint8_t visibilityMask, uint8_t visibilityMaskTouched) {
    // auto items = input.get<Input>();
 
     // Shadows use an orthographic projection because they are linked to sunlights
@@ -30,7 +30,7 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render:
         return true;
     });
 
-    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, visibilityMask);
+    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, visibilityMask, visibilityMaskTouched);
     assert(items.canCast<RenderFetchCullSortTask::Output>());
 
     if (isDeferred) {
diff --git a/libraries/render-utils/src/RenderViewTask.h b/libraries/render-utils/src/RenderViewTask.h
index 9c2bbe0281..faace7349e 100644
--- a/libraries/render-utils/src/RenderViewTask.h
+++ b/libraries/render-utils/src/RenderViewTask.h
@@ -23,7 +23,7 @@ public:
 
     RenderViewTask() {}
 
-    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred, uint8_t visibilityMask = 0xFF);
+    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred, uint8_t visibilityMask = 0xFF, uint8_t visibilityMaskTouched = 0x00);
 
 };
 
diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h
index 8594bc2954..3da7b07d7d 100644
--- a/libraries/render/src/render/Item.h
+++ b/libraries/render/src/render/Item.h
@@ -65,6 +65,10 @@ public:
     // Beware that the visibility mask is the oposite of what stored in the key vals.
     const static uint8_t NUM_VISIBLE_MASK_INDICES{ 4 };
     const static uint8_t VISIBLE_MASK_ALL{ 0x0F };
+    const static uint8_t VISIBLE_MASK_0{ 0x01 };
+    const static uint8_t VISIBLE_MASK_1{ 0x02 };
+    const static uint8_t VISIBLE_MASK_2{ 0x04 };
+    const static uint8_t VISIBLE_MASK_3{ 0x08 };
 
     // The key is the Flags
     Flags _flags;
@@ -184,12 +188,15 @@ public:
 
         Builder& withVisible(uint8_t maskIndex)          { _value.reset(ItemKey::INVISIBLE0 + maskIndex); _mask.set(ItemKey::INVISIBLE0 + maskIndex); return (*this); }
         Builder& withInvisible(uint8_t maskIndex)        { _value.set(ItemKey::INVISIBLE0 + maskIndex);  _mask.set(ItemKey::INVISIBLE0 + maskIndex); return (*this); }
-        Builder& withVisibilityMask(uint8_t mask) {
+        Builder& withVisibilityMask(uint8_t mask, uint8_t touchBits) {
             for (int i = 0; i < ItemKey::NUM_VISIBLE_MASK_INDICES; i++) {
-                if ((1 << i) && mask) {
-                    withVisible(i);
-                } else {
-                    withInvisible(i);
+                if ((1 << i) & touchBits) {
+                    if ((1 << i) & mask) {
+                        withVisible(i);
+                    }
+                    else {
+                        withInvisible(i);
+                    }
                 }
             }
             return (*this);
@@ -206,7 +213,7 @@ public:
         Builder& withNothing()          { _value.reset(); _mask.reset(); return (*this); }
 
         // Convenient standard keys that we will keep on using all over the place
-        static Builder visibleWorldItems(uint8_t visibilityMask) { return Builder().withVisibilityMask(visibilityMask).withWorldSpace(); }
+        static Builder visibleWorldItems(uint8_t visibilityMask, uint8_t visibilityMaskTouched) { return Builder().withVisibilityMask(visibilityMask, visibilityMaskTouched).withWorldSpace(); }
         static Builder opaqueShape() { return Builder().withTypeShape().withOpaque().withWorldSpace(); }
         static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); }
         static Builder light() { return Builder().withTypeLight(); }
diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp
index 25c40ea7f7..b4e1a618dc 100644
--- a/libraries/render/src/render/RenderFetchCullSortTask.cpp
+++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp
@@ -17,12 +17,12 @@
 
 using namespace render;
 
-void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor, uint8_t visibilityMask) {
+void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor, uint8_t visibilityMask, uint8_t visibilityMaskTouched) {
     cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
 
     // CPU jobs:
     // Fetch and cull the items from the scene
-    const ItemFilter filter = ItemFilter::Builder::visibleWorldItems(visibilityMask).withoutLayered();
+    const ItemFilter filter = ItemFilter::Builder::visibleWorldItems(visibilityMask, visibilityMaskTouched).withoutLayered();
     const auto spatialFilter = render::Varying(filter);
     const auto spatialSelection = task.addJob<FetchSpatialTree>("FetchSceneSelection", spatialFilter);
     const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, spatialFilter).asVarying();
@@ -40,15 +40,15 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
     const int META_BUCKET = 3;
     const int BACKGROUND_BUCKET = 2;
     MultiFilterItems<NUM_SPATIAL_FILTERS>::ItemFilterArray spatialFilters = { {
-            ItemFilter::Builder::opaqueShape(),
-            ItemFilter::Builder::transparentShape(),
-            ItemFilter::Builder::light(),
-            ItemFilter::Builder::meta()
+            ItemFilter::Builder::opaqueShape().withVisibilityMask(visibilityMask, visibilityMaskTouched),
+            ItemFilter::Builder::transparentShape().withVisibilityMask(visibilityMask, visibilityMaskTouched),
+            ItemFilter::Builder::light().withVisibilityMask(visibilityMask, visibilityMaskTouched),
+            ItemFilter::Builder::meta().withVisibilityMask(visibilityMask, visibilityMaskTouched)
         } };
     MultiFilterItems<NUM_NON_SPATIAL_FILTERS>::ItemFilterArray nonspatialFilters = { {
-            ItemFilter::Builder::opaqueShape(),
-            ItemFilter::Builder::transparentShape(),
-            ItemFilter::Builder::background()
+            ItemFilter::Builder::opaqueShape().withVisibilityMask(visibilityMask, visibilityMaskTouched),
+            ItemFilter::Builder::transparentShape().withVisibilityMask(visibilityMask, visibilityMaskTouched),
+            ItemFilter::Builder::background().withVisibilityMask(visibilityMask, visibilityMaskTouched)
         } };
     const auto filteredSpatialBuckets = 
         task.addJob<MultiFilterItems<NUM_SPATIAL_FILTERS>>("FilterSceneSelection", culledSpatialSelection, spatialFilters)
diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h
index 3e5ad2bad8..9aa235b3fb 100644
--- a/libraries/render/src/render/RenderFetchCullSortTask.h
+++ b/libraries/render/src/render/RenderFetchCullSortTask.h
@@ -36,7 +36,7 @@ public:
 
     RenderFetchCullSortTask() {}
 
-    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t visibilityMask = 0xFF);
+    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t visibilityMask = 0xFF, uint8_t visibilityMaskTouched = 0x00);
 };
 
 #endif // hifi_RenderFetchCullSortTask_h

From 97a4f141eb6048c3d245a02716f58c0bb4f67cdc Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Thu, 18 Jan 2018 08:12:14 -0800
Subject: [PATCH 09/57] fix link trouble

---
 libraries/render/src/render/Item.cpp |  8 ++++++++
 libraries/render/src/render/Item.h   | 12 ++++++------
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp
index 036c7d3a99..75c38ec615 100644
--- a/libraries/render/src/render/Item.cpp
+++ b/libraries/render/src/render/Item.cpp
@@ -34,6 +34,14 @@ const int Item::LAYER_3D = 1;
 const int Item::LAYER_3D_FRONT = 2;
 const int Item::LAYER_3D_HUD = 3;
 
+const uint8_t ItemKey::NUM_VISIBLE_MASK_INDICES { 4 };
+const uint8_t ItemKey::VISIBLE_MASK_ALL { 0x0F };
+const uint8_t ItemKey::VISIBLE_MASK_0 { 0x01 };
+const uint8_t ItemKey::VISIBLE_MASK_1 { 0x02 };
+const uint8_t ItemKey::VISIBLE_MASK_2 { 0x04 };
+const uint8_t ItemKey::VISIBLE_MASK_3 { 0x08 };
+
+
 void Item::Status::Value::setScale(float scale) {
     _scale = (std::numeric_limits<unsigned short>::max() -1) * 0.5f * (1.0f + std::max(std::min(scale, 1.0f), 0.0f));
  }
diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h
index 3da7b07d7d..ebf3980489 100644
--- a/libraries/render/src/render/Item.h
+++ b/libraries/render/src/render/Item.h
@@ -63,12 +63,12 @@ public:
     // VISIBLE MASK is defined from several bits in the Key.
     // An Item can be visible in some mask bits and not other allowing for per view rendering
     // Beware that the visibility mask is the oposite of what stored in the key vals.
-    const static uint8_t NUM_VISIBLE_MASK_INDICES{ 4 };
-    const static uint8_t VISIBLE_MASK_ALL{ 0x0F };
-    const static uint8_t VISIBLE_MASK_0{ 0x01 };
-    const static uint8_t VISIBLE_MASK_1{ 0x02 };
-    const static uint8_t VISIBLE_MASK_2{ 0x04 };
-    const static uint8_t VISIBLE_MASK_3{ 0x08 };
+    const static uint8_t NUM_VISIBLE_MASK_INDICES;
+    const static uint8_t VISIBLE_MASK_ALL;
+    const static uint8_t VISIBLE_MASK_0;
+    const static uint8_t VISIBLE_MASK_1;
+    const static uint8_t VISIBLE_MASK_2;
+    const static uint8_t VISIBLE_MASK_3;
 
     // The key is the Flags
     Flags _flags;

From 1c819c84224b077fa1e203429478a0916d9b4805 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Thu, 18 Jan 2018 09:12:37 -0800
Subject: [PATCH 10/57] formatting

---
 libraries/entities-renderer/src/RenderableEntityItem.cpp | 4 ++--
 libraries/render-utils/src/MeshPartPayload.cpp           | 3 +--
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index f3ef956146..0988c696dd 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -187,8 +187,8 @@ void EntityRenderer::render(RenderArgs* args) {
 
     auto& renderMode = args->_renderMode;
     bool cauterized = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE &&
-                       renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) &&
-        _cauterized;
+                       renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE &&
+                       _cauterized);
 
     if (_visible && !cauterized) {
         doRender(args);
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index ead2a767db..de03f2e03d 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -395,8 +395,7 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, bool isCauteri
 
     if (!isVisible) {
         builder.withInvisible();
-    }
-    else if (isCauterized) {
+    } else if (isCauterized) {
         builder.withInvisible(0); // hide these items in the vibility mask #0
     }
 

From fb974b0b9c93f77d75fe460ae7fcfa03c83e43ad Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Thu, 18 Jan 2018 10:09:23 -0800
Subject: [PATCH 11/57] attempt to straighten out use of view-visibility masks

---
 interface/src/avatar/MyAvatar.cpp                |  9 +++++----
 interface/src/ui/overlays/ModelOverlay.cpp       |  3 ++-
 .../src/RenderableModelEntityItem.cpp            | 10 +++++++---
 libraries/render-utils/src/CauterizedModel.cpp   |  2 +-
 libraries/render-utils/src/MeshPartPayload.cpp   |  6 +++---
 libraries/render-utils/src/MeshPartPayload.h     |  2 +-
 libraries/render-utils/src/Model.cpp             | 16 ++++++++--------
 libraries/render-utils/src/Model.h               |  2 +-
 8 files changed, 28 insertions(+), 22 deletions(-)

diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 0b5bdad6ae..e9205157b4 100755
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -1078,7 +1078,7 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
 }
 
 void MyAvatar::setEnableMeshVisible(bool isEnabled) {
-    _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene());
+    _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::VISIBLE_MASK_ALL);
 }
 
 void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
@@ -1428,7 +1428,7 @@ void MyAvatar::clearJointsData() {
 
 void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
     Avatar::setSkeletonModelURL(skeletonModelURL);
-    _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
+    _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::VISIBLE_MASK_ALL);
     _headBoneSet.clear();
     emit skeletonChanged();
 
@@ -1742,7 +1742,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
 
 void MyAvatar::setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visible) {
     if (model->isActive() && model->isRenderable()) {
-        model->setVisibleInScene(visible, scene);
+        model->setVisibleInScene(visible, scene, render::ItemKey::VISIBLE_MASK_ALL);
     }
 }
 
@@ -1937,7 +1937,8 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
                 _attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
                 _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
                 _attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
-                _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene());
+                _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(),
+                                                        render::ItemKey::VISIBLE_MASK_ALL);
             }
         }
     }
diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index ec586771af..f556bc9e24 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -86,7 +86,8 @@ void ModelOverlay::update(float deltatime) {
     }
     if (_visibleDirty) {
         _visibleDirty = false;
-        _model->setVisibleInScene(getVisible(), scene);
+        // don't show overlays in mirrors
+        _model->setVisibleInScene(getVisible(), scene, render::ItemKey::VISIBLE_MASK_ALL & ~render::ItemKey::VISIBLE_MASK_1);
     }
     if (_drawInFrontDirty) {
         _drawInFrontDirty = false;
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index f7d7eb2a06..421f8769b5 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1333,12 +1333,16 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
     entity->updateModelBounds();
     entity->stopModelOverrideIfNoParent();
 
-    bool visible = _visible && !_cauterized;
-    if (model->isVisible() != visible) {
+    if (model->isVisible() != _visible) {
         // FIXME: this seems like it could be optimized if we tracked our last known visible state in
         //        the renderable item. As it stands now the model checks it's visible/invisible state
         //        so most of the time we don't do anything in this function.
-        model->setVisibleInScene(visible, scene);
+        if (_cauterized) {
+            // draw this in every view except the main one
+            model->setVisibleInScene(_visible, scene, render::ItemKey::VISIBLE_MASK_ALL & ~render::ItemKey::VISIBLE_MASK_0);
+        } else {
+            model->setVisibleInScene(_visible, scene, render::ItemKey::VISIBLE_MASK_ALL);
+        }
     }
     // TODO? early exit here when not visible?
 
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index 09b6ada8e4..809be09436 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -247,7 +247,7 @@ void CauterizedModel::updateRenderItems() {
                     data.updateTransformForCauterizedMesh(renderTransform);
 
                     data.setEnableCauterization(enableCauterization);
-                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, enableCauterization);
+                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
                     data.setLayer(isLayeredInFront, isLayeredInHUD);
                     data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
                 });
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index de03f2e03d..797f385695 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -389,14 +389,14 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render
     _worldBound.transform(boundTransform);
 }
 
-void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, bool isCauterized) {
+void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, uint8_t viewVisiblityMask) {
     ItemKey::Builder builder;
     builder.withTypeShape();
 
     if (!isVisible) {
         builder.withInvisible();
-    } else if (isCauterized) {
-        builder.withInvisible(0); // hide these items in the vibility mask #0
+    } else {
+        builder.withInvisible(viewVisiblityMask);
     }
 
     if (isLayered) {
diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h
index ee515c7b3d..cf64879b3c 100644
--- a/libraries/render-utils/src/MeshPartPayload.h
+++ b/libraries/render-utils/src/MeshPartPayload.h
@@ -103,7 +103,7 @@ public:
     render::ShapeKey getShapeKey() const override; // shape interface
     void render(RenderArgs* args) override;
 
-    void setKey(bool isVisible, bool isLayered, bool isCauterized = false);
+    void setKey(bool isVisible, bool isLayered, uint8_t viewVisiblityMask);
     void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
     void setShapeKey(bool invalidateShapeKey, bool isWireframe);
 
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 6922e95d39..b04ff00f98 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -297,7 +297,7 @@ void Model::updateRenderItems() {
                 }
                 data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
 
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
                 data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
             });
@@ -659,7 +659,7 @@ void Model::calculateTriangleSets() {
     }
 }
 
-void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene) {
+void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t visibleMask) {
     if (_isVisible != isVisible) {
         _isVisible = isVisible;
 
@@ -669,12 +669,12 @@ void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene)
         render::Transaction transaction;
         foreach (auto item, _modelMeshRenderItemsMap.keys()) {
             transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
             });
         }
         foreach(auto item, _collisionRenderItemsMap.keys()) {
             transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
             });
         }
         scene->enqueueTransaction(transaction);
@@ -692,13 +692,13 @@ void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer&
         render::Transaction transaction;
         foreach(auto item, _modelMeshRenderItemsMap.keys()) {
             transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
         foreach(auto item, _collisionRenderItemsMap.keys()) {
             transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
@@ -716,13 +716,13 @@ void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& sce
         render::Transaction transaction;
         foreach(auto item, _modelMeshRenderItemsMap.keys()) {
             transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
         foreach(auto item, _collisionRenderItemsMap.keys()) {
             transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index 560aa82f0c..8d2619bf13 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -86,7 +86,7 @@ public:
     const QUrl& getURL() const { return _url; }
 
     // new Scene/Engine rendering support
-    void setVisibleInScene(bool isVisible, const render::ScenePointer& scene);
+    void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t visibleMask);
     void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene);
     void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene);
     bool needsFixupInScene() const;

From 0ad4cdc41b47618bdb712fad907b54e980281c12 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Thu, 18 Jan 2018 13:15:47 -0800
Subject: [PATCH 12/57] works now

---
 .../src/RenderableModelEntityItem.cpp         | 13 +++---
 .../render-utils/src/MeshPartPayload.cpp      | 13 +++++-
 libraries/render-utils/src/Model.cpp          | 46 ++++++++++++-------
 libraries/render-utils/src/Model.h            |  4 +-
 4 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 421f8769b5..80c5c97799 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1333,16 +1333,15 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
     entity->updateModelBounds();
     entity->stopModelOverrideIfNoParent();
 
-    if (model->isVisible() != _visible) {
+    uint32_t viewVisiblityMask = _cauterized ?
+        (render::ItemKey::VISIBLE_MASK_ALL & ~render::ItemKey::VISIBLE_MASK_0) : // draw in every view except the main one
+        render::ItemKey::VISIBLE_MASK_ALL;
+
+    if (model->isVisible() != _visible || model->getViewVisibilityMask() != viewVisiblityMask) {
         // FIXME: this seems like it could be optimized if we tracked our last known visible state in
         //        the renderable item. As it stands now the model checks it's visible/invisible state
         //        so most of the time we don't do anything in this function.
-        if (_cauterized) {
-            // draw this in every view except the main one
-            model->setVisibleInScene(_visible, scene, render::ItemKey::VISIBLE_MASK_ALL & ~render::ItemKey::VISIBLE_MASK_0);
-        } else {
-            model->setVisibleInScene(_visible, scene, render::ItemKey::VISIBLE_MASK_ALL);
-        }
+        model->setVisibleInScene(_visible, scene, viewVisiblityMask);
     }
     // TODO? early exit here when not visible?
 
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index 797f385695..b917f3df03 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -396,7 +396,18 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, uint8_t viewVi
     if (!isVisible) {
         builder.withInvisible();
     } else {
-        builder.withInvisible(viewVisiblityMask);
+        if (!(viewVisiblityMask & render::ItemKey::VISIBLE_MASK_0)) {
+            builder.withInvisible(render::ItemKey::INVISIBLE0 - render::ItemKey::INVISIBLE0);
+        }
+        if (!(viewVisiblityMask & render::ItemKey::VISIBLE_MASK_1)) {
+            builder.withInvisible(render::ItemKey::INVISIBLE1 - render::ItemKey::INVISIBLE0);
+        }
+        if (!(viewVisiblityMask & render::ItemKey::VISIBLE_MASK_2)) {
+            builder.withInvisible(render::ItemKey::INVISIBLE2 - render::ItemKey::INVISIBLE0);
+        }
+        if (!(viewVisiblityMask & render::ItemKey::VISIBLE_MASK_3)) {
+            builder.withInvisible(render::ItemKey::INVISIBLE3 - render::ItemKey::INVISIBLE0);
+        }
     }
 
     if (isLayered) {
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index b04ff00f98..9e6ec064b4 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -268,6 +268,7 @@ void Model::updateRenderItems() {
 
         bool isWireframe = self->isWireframe();
         bool isVisible = self->isVisible();
+        uint8_t viewVisibilityMask = self->getViewVisibilityMask();
         bool isLayeredInFront = self->isLayeredInFront();
         bool isLayeredInHUD = self->isLayeredInHUD();
 
@@ -280,8 +281,10 @@ void Model::updateRenderItems() {
 
             bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
 
-            transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms, invalidatePayloadShapeKey,
-                    isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
+            transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms,
+                                                                  invalidatePayloadShapeKey, isWireframe, isVisible,
+                                                                  viewVisibilityMask, isLayeredInFront,
+                                                                  isLayeredInHUD](ModelMeshPartPayload& data) {
                 data.updateClusterBuffer(clusterTransforms);
 
                 Transform renderTransform = modelTransform;
@@ -297,7 +300,7 @@ void Model::updateRenderItems() {
                 }
                 data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
 
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
                 data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
             });
@@ -659,22 +662,25 @@ void Model::calculateTriangleSets() {
     }
 }
 
-void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t visibleMask) {
-    if (_isVisible != isVisible) {
+void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewVisibilityMask) {
+    if (_isVisible != isVisible || _viewVisibilityMask != viewVisibilityMask) {
         _isVisible = isVisible;
+        _viewVisibilityMask = viewVisibilityMask;
 
         bool isLayeredInFront = _isLayeredInFront;
         bool isLayeredInHUD = _isLayeredInHUD;
 
         render::Transaction transaction;
         foreach (auto item, _modelMeshRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+                                                                isLayeredInHUD](ModelMeshPartPayload& data) {
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, 14);
             });
         }
         foreach(auto item, _collisionRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+                                                                isLayeredInHUD](ModelMeshPartPayload& data) {
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, 14);
             });
         }
         scene->enqueueTransaction(transaction);
@@ -687,18 +693,21 @@ void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer&
         _isLayeredInFront = isLayeredInFront;
 
         bool isVisible = _isVisible;
+        uint8_t viewVisibilityMask = _viewVisibilityMask;
         bool isLayeredInHUD = _isLayeredInHUD;
 
         render::Transaction transaction;
         foreach(auto item, _modelMeshRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+                                                                isLayeredInHUD](ModelMeshPartPayload& data) {
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
         foreach(auto item, _collisionRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+                                                                isLayeredInHUD](ModelMeshPartPayload& data) {
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
@@ -711,18 +720,21 @@ void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& sce
         _isLayeredInHUD = isLayeredInHUD;
 
         bool isVisible = _isVisible;
+        uint8_t viewVisibilityMask = _viewVisibilityMask;
         bool isLayeredInFront = _isLayeredInFront;
 
         render::Transaction transaction;
         foreach(auto item, _modelMeshRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+                                                                isLayeredInHUD](ModelMeshPartPayload& data) {
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
         foreach(auto item, _collisionRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+                                                                isLayeredInHUD](ModelMeshPartPayload& data) {
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index 8d2619bf13..c2f8a3d972 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -86,7 +86,7 @@ public:
     const QUrl& getURL() const { return _url; }
 
     // new Scene/Engine rendering support
-    void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t visibleMask);
+    void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewVisiblityMask);
     void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene);
     void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene);
     bool needsFixupInScene() const;
@@ -104,6 +104,7 @@ public:
     bool isRenderable() const;
 
     bool isVisible() const { return _isVisible; }
+    uint8_t getViewVisibilityMask() const { return _viewVisibilityMask; }
 
     bool isLayeredInFront() const { return _isLayeredInFront; }
     bool isLayeredInHUD() const { return _isLayeredInHUD; }
@@ -388,6 +389,7 @@ protected:
 
     QUrl _url;
     bool _isVisible;
+    uint32_t _viewVisibilityMask { 0 };
 
     gpu::Buffers _blendedVertexBuffers;
 

From 7c32d3c5360497bb8e531ad1fc1e49edc2879136 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Thu, 18 Jan 2018 13:49:17 -0800
Subject: [PATCH 13/57] flip logic back around

---
 interface/src/ui/overlays/ModelOverlay.cpp                | 2 +-
 .../entities-renderer/src/RenderableModelEntityItem.cpp   | 4 ++--
 libraries/render-utils/src/MeshPartPayload.cpp            | 8 ++++----
 libraries/render-utils/src/Model.cpp                      | 4 ++--
 libraries/render-utils/src/Model.h                        | 2 +-
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index f556bc9e24..7ba8694683 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -87,7 +87,7 @@ void ModelOverlay::update(float deltatime) {
     if (_visibleDirty) {
         _visibleDirty = false;
         // don't show overlays in mirrors
-        _model->setVisibleInScene(getVisible(), scene, render::ItemKey::VISIBLE_MASK_ALL & ~render::ItemKey::VISIBLE_MASK_1);
+        _model->setVisibleInScene(getVisible(), scene, render::ItemKey::VISIBLE_MASK_1);
     }
     if (_drawInFrontDirty) {
         _drawInFrontDirty = false;
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 80c5c97799..8257e53eea 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1334,8 +1334,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
     entity->stopModelOverrideIfNoParent();
 
     uint32_t viewVisiblityMask = _cauterized ?
-        (render::ItemKey::VISIBLE_MASK_ALL & ~render::ItemKey::VISIBLE_MASK_0) : // draw in every view except the main one
-        render::ItemKey::VISIBLE_MASK_ALL;
+        render::ItemKey::VISIBLE_MASK_0 : // draw in every view except the main one
+        render::ItemKey::VISIBLE_MASK_ALL; // draw in all views
 
     if (model->isVisible() != _visible || model->getViewVisibilityMask() != viewVisiblityMask) {
         // FIXME: this seems like it could be optimized if we tracked our last known visible state in
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index b917f3df03..f0412d8332 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -396,16 +396,16 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, uint8_t viewVi
     if (!isVisible) {
         builder.withInvisible();
     } else {
-        if (!(viewVisiblityMask & render::ItemKey::VISIBLE_MASK_0)) {
+        if (viewVisiblityMask & render::ItemKey::VISIBLE_MASK_0) {
             builder.withInvisible(render::ItemKey::INVISIBLE0 - render::ItemKey::INVISIBLE0);
         }
-        if (!(viewVisiblityMask & render::ItemKey::VISIBLE_MASK_1)) {
+        if (viewVisiblityMask & render::ItemKey::VISIBLE_MASK_1) {
             builder.withInvisible(render::ItemKey::INVISIBLE1 - render::ItemKey::INVISIBLE0);
         }
-        if (!(viewVisiblityMask & render::ItemKey::VISIBLE_MASK_2)) {
+        if (viewVisiblityMask & render::ItemKey::VISIBLE_MASK_2) {
             builder.withInvisible(render::ItemKey::INVISIBLE2 - render::ItemKey::INVISIBLE0);
         }
-        if (!(viewVisiblityMask & render::ItemKey::VISIBLE_MASK_3)) {
+        if (viewVisiblityMask & render::ItemKey::VISIBLE_MASK_3) {
             builder.withInvisible(render::ItemKey::INVISIBLE3 - render::ItemKey::INVISIBLE0);
         }
     }
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 9e6ec064b4..60eb0c4280 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -674,13 +674,13 @@ void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene,
         foreach (auto item, _modelMeshRenderItemsMap.keys()) {
             transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
                                                                 isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, 14);
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
             });
         }
         foreach(auto item, _collisionRenderItemsMap.keys()) {
             transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
                                                                 isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, 14);
+                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
             });
         }
         scene->enqueueTransaction(transaction);
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index c2f8a3d972..5f58906e9f 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -389,7 +389,7 @@ protected:
 
     QUrl _url;
     bool _isVisible;
-    uint32_t _viewVisibilityMask { 0 };
+    uint8_t _viewVisibilityMask { 0 };
 
     gpu::Buffers _blendedVertexBuffers;
 

From 31c007d1672a970dc5a1bfbe11b88801fb36f55b Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Thu, 18 Jan 2018 14:15:30 -0800
Subject: [PATCH 14/57] more backwards logic, added withViewVisibilityMask call
 in ItemKey

---
 interface/src/avatar/MyAvatar.cpp                |  8 ++++----
 .../src/RenderableModelEntityItem.cpp            |  4 ++--
 libraries/entities/src/EntityItem.h              |  2 +-
 libraries/render-utils/src/CauterizedModel.cpp   |  2 +-
 libraries/render-utils/src/MeshPartPayload.cpp   | 13 +------------
 libraries/render/src/render/Item.cpp             |  1 +
 libraries/render/src/render/Item.h               | 16 ++++++++++++++++
 7 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index e9205157b4..317eede6e9 100755
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -1078,7 +1078,7 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
 }
 
 void MyAvatar::setEnableMeshVisible(bool isEnabled) {
-    _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::VISIBLE_MASK_ALL);
+    _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::VISIBLE_MASK_NONE);
 }
 
 void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
@@ -1428,7 +1428,7 @@ void MyAvatar::clearJointsData() {
 
 void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
     Avatar::setSkeletonModelURL(skeletonModelURL);
-    _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::VISIBLE_MASK_ALL);
+    _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::VISIBLE_MASK_NONE);
     _headBoneSet.clear();
     emit skeletonChanged();
 
@@ -1742,7 +1742,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
 
 void MyAvatar::setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visible) {
     if (model->isActive() && model->isRenderable()) {
-        model->setVisibleInScene(visible, scene, render::ItemKey::VISIBLE_MASK_ALL);
+        model->setVisibleInScene(visible, scene, render::ItemKey::VISIBLE_MASK_NONE);
     }
 }
 
@@ -1938,7 +1938,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
                 _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
                 _attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
                 _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(),
-                                                        render::ItemKey::VISIBLE_MASK_ALL);
+                                                        render::ItemKey::VISIBLE_MASK_NONE);
             }
         }
     }
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 8257e53eea..a6991f101c 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1334,8 +1334,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
     entity->stopModelOverrideIfNoParent();
 
     uint32_t viewVisiblityMask = _cauterized ?
-        render::ItemKey::VISIBLE_MASK_0 : // draw in every view except the main one
-        render::ItemKey::VISIBLE_MASK_ALL; // draw in all views
+        render::ItemKey::VISIBLE_MASK_0 : // draw in every view except the main one (view zero)
+        render::ItemKey::VISIBLE_MASK_NONE; // draw in all views
 
     if (model->isVisible() != _visible || model->getViewVisibilityMask() != viewVisiblityMask) {
         // FIXME: this seems like it could be optimized if we tracked our last known visible state in
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 68639e0d3a..3024d646ff 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -625,7 +625,7 @@ protected:
     quint64 _lastUpdatedAccelerationTimestamp { 0 };
     quint64 _lastUpdatedQueryAACubeTimestamp { 0 };
 
-    bool _cauterized { false }; // it true, don't draw because it would obscure 1st-person camera
+    bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera
 };
 
 #endif // hifi_EntityItem_h
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index 809be09436..f67f5ef358 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -247,7 +247,7 @@ void CauterizedModel::updateRenderItems() {
                     data.updateTransformForCauterizedMesh(renderTransform);
 
                     data.setEnableCauterization(enableCauterization);
-                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
+                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_NONE);
                     data.setLayer(isLayeredInFront, isLayeredInHUD);
                     data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
                 });
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index f0412d8332..da636eed06 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -396,18 +396,7 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, uint8_t viewVi
     if (!isVisible) {
         builder.withInvisible();
     } else {
-        if (viewVisiblityMask & render::ItemKey::VISIBLE_MASK_0) {
-            builder.withInvisible(render::ItemKey::INVISIBLE0 - render::ItemKey::INVISIBLE0);
-        }
-        if (viewVisiblityMask & render::ItemKey::VISIBLE_MASK_1) {
-            builder.withInvisible(render::ItemKey::INVISIBLE1 - render::ItemKey::INVISIBLE0);
-        }
-        if (viewVisiblityMask & render::ItemKey::VISIBLE_MASK_2) {
-            builder.withInvisible(render::ItemKey::INVISIBLE2 - render::ItemKey::INVISIBLE0);
-        }
-        if (viewVisiblityMask & render::ItemKey::VISIBLE_MASK_3) {
-            builder.withInvisible(render::ItemKey::INVISIBLE3 - render::ItemKey::INVISIBLE0);
-        }
+        builder.withViewVisibilityMask(viewVisiblityMask);
     }
 
     if (isLayered) {
diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp
index 75c38ec615..0e4502a47c 100644
--- a/libraries/render/src/render/Item.cpp
+++ b/libraries/render/src/render/Item.cpp
@@ -36,6 +36,7 @@ const int Item::LAYER_3D_HUD = 3;
 
 const uint8_t ItemKey::NUM_VISIBLE_MASK_INDICES { 4 };
 const uint8_t ItemKey::VISIBLE_MASK_ALL { 0x0F };
+const uint8_t ItemKey::VISIBLE_MASK_NONE { 0x00 };
 const uint8_t ItemKey::VISIBLE_MASK_0 { 0x01 };
 const uint8_t ItemKey::VISIBLE_MASK_1 { 0x02 };
 const uint8_t ItemKey::VISIBLE_MASK_2 { 0x04 };
diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h
index ebf3980489..552e721073 100644
--- a/libraries/render/src/render/Item.h
+++ b/libraries/render/src/render/Item.h
@@ -65,6 +65,7 @@ public:
     // Beware that the visibility mask is the oposite of what stored in the key vals.
     const static uint8_t NUM_VISIBLE_MASK_INDICES;
     const static uint8_t VISIBLE_MASK_ALL;
+    const static uint8_t VISIBLE_MASK_NONE;
     const static uint8_t VISIBLE_MASK_0;
     const static uint8_t VISIBLE_MASK_1;
     const static uint8_t VISIBLE_MASK_2;
@@ -96,6 +97,21 @@ public:
         Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); }
         Builder& withDeformed() { _flags.set(DEFORMED); return (*this); }
         Builder& withInvisible(uint8_t maskIndex = 0) { _flags.set(INVISIBLE0 + maskIndex); return (*this); }
+        Builder& withViewVisibilityMask(uint8_t mask) {
+            if (mask & render::ItemKey::VISIBLE_MASK_0) {
+                _flags.set(INVISIBLE0);
+            }
+            if (mask & render::ItemKey::VISIBLE_MASK_1) {
+                _flags.set(INVISIBLE1);
+            }
+            if (mask & render::ItemKey::VISIBLE_MASK_2) {
+                _flags.set(INVISIBLE2);
+            }
+            if (mask & render::ItemKey::VISIBLE_MASK_3) {
+                _flags.set(INVISIBLE3);
+            }
+            return (*this);
+        }
         Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); }
         Builder& withPickable() { _flags.set(PICKABLE); return (*this); }
         Builder& withLayered() { _flags.set(LAYERED); return (*this); }

From 6aa389cad08f42b0e434dd20bbe17338adce9e78 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Fri, 19 Jan 2018 09:53:41 -0800
Subject: [PATCH 15/57] trying to now show overlays in mirrors

---
 interface/src/ui/overlays/OverlaysPayload.cpp |  7 +++++++
 libraries/render/src/render/Item.h            | 12 +++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp
index fceb261503..4bbe21f9a6 100644
--- a/interface/src/ui/overlays/OverlaysPayload.cpp
+++ b/interface/src/ui/overlays/OverlaysPayload.cpp
@@ -44,6 +44,13 @@ namespace render {
         } else {
             builder.withViewSpace();
         }
+
+        if (overlay->getVisible()) {
+            builder.withViewVisibilityMask(render::ItemKey::VISIBLE_MASK_1); // don't draw overlays in mirror
+        } else {
+            builder.withViewVisibilityMask(render::ItemKey::VISIBLE_MASK_ALL);
+        }
+
         return builder.build();
     }
     template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h
index 552e721073..9ea8421f1a 100644
--- a/libraries/render/src/render/Item.h
+++ b/libraries/render/src/render/Item.h
@@ -96,7 +96,17 @@ public:
         Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); }
         Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); }
         Builder& withDeformed() { _flags.set(DEFORMED); return (*this); }
-        Builder& withInvisible(uint8_t maskIndex = 0) { _flags.set(INVISIBLE0 + maskIndex); return (*this); }
+        Builder& withInvisible(uint8_t maskIndex = NUM_VISIBLE_MASK_INDICES) {
+            if (maskIndex == NUM_VISIBLE_MASK_INDICES) {
+                _flags.set(INVISIBLE0);
+                _flags.set(INVISIBLE1);
+                _flags.set(INVISIBLE2);
+                _flags.set(INVISIBLE3);
+            } else {
+                _flags.set(INVISIBLE0 + maskIndex);
+            }
+            return (*this);
+        }
         Builder& withViewVisibilityMask(uint8_t mask) {
             if (mask & render::ItemKey::VISIBLE_MASK_0) {
                 _flags.set(INVISIBLE0);

From d38d13cbb94d067f12d8fda6d4ff5f7ede15c95c Mon Sep 17 00:00:00 2001
From: Sam Gateau <samuel.gateau@gmail.com>
Date: Sun, 21 Jan 2018 23:47:45 -0800
Subject: [PATCH 16/57] Trying to address the overlays to not be visisble in
 2nd camera

---
 interface/src/ui/overlays/ModelOverlay.cpp    | 8 +++++---
 interface/src/ui/overlays/OverlaysPayload.cpp | 4 ++--
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index 79a7df338b..34644735ed 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -87,7 +87,7 @@ void ModelOverlay::update(float deltatime) {
     if (_visibleDirty) {
         _visibleDirty = false;
         // don't show overlays in mirrors
-        _model->setVisibleInScene(getVisible(), scene, render::ItemKey::VISIBLE_MASK_1);
+        _model->setVisibleInScene(getVisible(), scene, render::ItemKey::VISIBLE_MASK_0 * getVisible());
     }
     if (_drawInFrontDirty) {
         _drawInFrontDirty = false;
@@ -121,8 +121,10 @@ void ModelOverlay::removeFromScene(Overlay::Pointer overlay, const render::Scene
 }
 
 void ModelOverlay::setVisible(bool visible) {
-    Overlay::setVisible(visible);
-    _visibleDirty = true;
+    if (visible != getVisible()) {
+        Overlay::setVisible(visible);
+        _visibleDirty = true;
+    }
 }
 
 void ModelOverlay::setDrawInFront(bool drawInFront) {
diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp
index 30743964a4..c071c44d42 100644
--- a/interface/src/ui/overlays/OverlaysPayload.cpp
+++ b/interface/src/ui/overlays/OverlaysPayload.cpp
@@ -46,9 +46,9 @@ namespace render {
         }
 
         if (overlay->getVisible()) {
-            builder.withViewVisibilityMask(render::ItemKey::VISIBLE_MASK_1); // don't draw overlays in mirror
+            builder.withViewVisibilityMask(render::ItemKey::VISIBLE_MASK_0); // don't draw overlays in mirror
         } else {
-            builder.withViewVisibilityMask(render::ItemKey::VISIBLE_MASK_ALL);
+            builder.withViewVisibilityMask(render::ItemKey::VISIBLE_MASK_NONE);
         }
 
         return builder.build();

From 24692f13fdda4e3f6e0b36a6a871a7059592a196 Mon Sep 17 00:00:00 2001
From: Olivier Prat <olivier@zvork.fr>
Date: Tue, 23 Jan 2018 14:19:39 +0100
Subject: [PATCH 17/57] Added separate scribe function to
 evalGlobalLightingAlphaBlendedWithHaze to shorten shader C string

---
 libraries/render-utils/src/DeferredGlobalLight.slh         | 6 ++++++
 libraries/render-utils/src/model_normal_map.slf            | 2 +-
 libraries/render-utils/src/model_translucent.slf           | 2 +-
 libraries/render-utils/src/model_translucent_fade.slf      | 2 +-
 libraries/render-utils/src/overlay3D_model_translucent.slf | 2 +-
 libraries/render-utils/src/simple_transparent_textured.slf | 2 +-
 6 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh
index fae645fdbc..51884ccbee 100644
--- a/libraries/render-utils/src/DeferredGlobalLight.slh
+++ b/libraries/render-utils/src/DeferredGlobalLight.slh
@@ -203,6 +203,12 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl
 
     return color;
 }
+<@endfunc@>
+
+<@func declareEvalGlobalLightingAlphaBlendedWithHaze()@>
+
+<$declareLightingAmbient(1, 1, 1)$>
+<$declareLightingDirectional()$>
 
 vec3 evalGlobalLightingAlphaBlendedWithHaze(
     mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, 
diff --git a/libraries/render-utils/src/model_normal_map.slf b/libraries/render-utils/src/model_normal_map.slf
index bed85b4b15..b41e226e23 100644
--- a/libraries/render-utils/src/model_normal_map.slf
+++ b/libraries/render-utils/src/model_normal_map.slf
@@ -47,7 +47,7 @@ void main(void) {
     <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
 
     vec3 viewNormal;
-   <$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
+    <$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
 
     float scattering = getMaterialScattering(mat);
     <$evalMaterialScattering(scatteringTex, scattering, matKey, scattering)$>;
diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf
index 761e702595..67a5651ab8 100644
--- a/libraries/render-utils/src/model_translucent.slf
+++ b/libraries/render-utils/src/model_translucent.slf
@@ -16,7 +16,7 @@
 
 <@include DeferredGlobalLight.slh@>
 
-<$declareEvalGlobalLightingAlphaBlended()$>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
 
 <@include LightLocal.slh@>
 
diff --git a/libraries/render-utils/src/model_translucent_fade.slf b/libraries/render-utils/src/model_translucent_fade.slf
index a2d271653c..316dae7aad 100644
--- a/libraries/render-utils/src/model_translucent_fade.slf
+++ b/libraries/render-utils/src/model_translucent_fade.slf
@@ -16,7 +16,7 @@
 
 <@include DeferredGlobalLight.slh@>
 
-<$declareEvalGlobalLightingAlphaBlended()$>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
 
 <@include LightLocal.slh@>
 
diff --git a/libraries/render-utils/src/overlay3D_model_translucent.slf b/libraries/render-utils/src/overlay3D_model_translucent.slf
index 8dd3a81443..b66c114f4a 100644
--- a/libraries/render-utils/src/overlay3D_model_translucent.slf
+++ b/libraries/render-utils/src/overlay3D_model_translucent.slf
@@ -11,7 +11,7 @@
 //
 
 <@include DeferredGlobalLight.slh@>
-<$declareEvalGlobalLightingAlphaBlended()$>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
 
 <@include graphics/Material.slh@>
 
diff --git a/libraries/render-utils/src/simple_transparent_textured.slf b/libraries/render-utils/src/simple_transparent_textured.slf
index b16b19c8b4..30c420233f 100644
--- a/libraries/render-utils/src/simple_transparent_textured.slf
+++ b/libraries/render-utils/src/simple_transparent_textured.slf
@@ -16,7 +16,7 @@
 
 <@include DeferredBufferWrite.slh@>
 <@include DeferredGlobalLight.slh@>
-<$declareEvalGlobalLightingAlphaBlended()$>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
 
 <@include gpu/Transform.slh@>
 <$declareStandardCameraTransform()$>

From 55abaf33fb95a5e5bafa7e8db3be3ad7c8d65e3a Mon Sep 17 00:00:00 2001
From: Olivier Prat <olivier@zvork.fr>
Date: Tue, 23 Jan 2018 17:35:01 +0100
Subject: [PATCH 18/57] Added shaders to support normal maps on translucent
 objects

---
 .../render-utils/src/RenderPipelines.cpp      |  26 +++--
 .../src/model_translucent_normal_map.slf      |  91 ++++++++++++++++
 ...e.slv => model_translucent_normal_map.slv} |   6 +-
 .../src/model_translucent_normal_map_fade.slf | 101 ++++++++++++++++++
 .../src/simple_transparent_textured_fade.slf  |   2 +-
 5 files changed, 212 insertions(+), 14 deletions(-)
 create mode 100644 libraries/render-utils/src/model_translucent_normal_map.slf
 rename libraries/render-utils/src/{model_translucent_fade.slv => model_translucent_normal_map.slv} (88%)
 create mode 100644 libraries/render-utils/src/model_translucent_normal_map_fade.slf

diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp
index 29efaf914a..1718a9b041 100644
--- a/libraries/render-utils/src/RenderPipelines.cpp
+++ b/libraries/render-utils/src/RenderPipelines.cpp
@@ -30,7 +30,7 @@
 #include "model_lightmap_fade_vert.h"
 #include "model_lightmap_normal_map_fade_vert.h"
 #include "model_translucent_vert.h"
-#include "model_translucent_fade_vert.h"
+#include "model_translucent_normal_map_vert.h"
 #include "skin_model_fade_vert.h"
 #include "skin_model_normal_map_fade_vert.h"
 
@@ -72,6 +72,7 @@
 #include "model_lightmap_normal_specular_map_frag.h"
 #include "model_lightmap_specular_map_frag.h"
 #include "model_translucent_frag.h"
+#include "model_translucent_normal_map_frag.h"
 #include "model_translucent_unlit_frag.h"
 
 #include "model_lightmap_fade_frag.h"
@@ -79,6 +80,7 @@
 #include "model_lightmap_normal_specular_map_fade_frag.h"
 #include "model_lightmap_specular_map_fade_frag.h"
 #include "model_translucent_fade_frag.h"
+#include "model_translucent_normal_map_fade_frag.h"
 #include "model_translucent_unlit_fade_frag.h"
 
 #include "overlay3D_vert.h"
@@ -191,7 +193,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
     auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert));
     auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert));
     auto modelTranslucentVertex = gpu::Shader::createVertex(std::string(model_translucent_vert));
-    auto modelTranslucentFadeVertex = gpu::Shader::createVertex(std::string(model_translucent_fade_vert));
+    auto modelTranslucentNormalMapVertex = gpu::Shader::createVertex(std::string(model_translucent_normal_map_vert));
     auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
     auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert));
     auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert));
@@ -220,6 +222,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
     auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag));
     auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag));
     auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag));
+    auto modelTranslucentNormalMapPixel = gpu::Shader::createPixel(std::string(model_translucent_normal_map_frag));
     auto modelTranslucentUnlitPixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_frag));
     auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));
     auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag));
@@ -238,6 +241,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
     auto modelNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_fade_frag));
     auto modelShadowFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag));
     auto modelTranslucentFadePixel = gpu::Shader::createPixel(std::string(model_translucent_fade_frag));
+    auto modelTranslucentNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_translucent_normal_map_fade_frag));
     auto modelTranslucentUnlitFadePixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_fade_frag));
     auto simpleFadePixel = gpu::Shader::createPixel(std::string(simple_textured_fade_frag));
     auto simpleUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag));
@@ -307,13 +311,13 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
         simpleVertex, simpleTranslucentUnlitPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withTangents(),
-        modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
+        modelTranslucentNormalMapVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withSpecular(),
         modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular(),
-        modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
+        modelTranslucentNormalMapVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
     addPipeline(
         // FIXME: Ignore lightmap for translucents meshpart
         Key::Builder().withMaterial().withTranslucent().withLightmap(),
@@ -321,7 +325,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
     // Same thing but with Fade on
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withFade(),
-        modelTranslucentFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
+        modelTranslucentVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withTranslucent().withFade(),
         simpleFadeVertex, simpleTranslucentFadePixel, batchSetter, itemSetter);
@@ -333,13 +337,13 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
         simpleFadeVertex, simpleTranslucentUnlitFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withTangents().withFade(),
-        modelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
+        modelTranslucentNormalMapVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withSpecular().withFade(),
         modelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular().withFade(),
-        modelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
+        modelTranslucentNormalMapVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
     addPipeline(
         // FIXME: Ignore lightmap for translucents meshpart
         Key::Builder().withMaterial().withTranslucent().withLightmap().withFade(),
@@ -405,26 +409,26 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
         skinModelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents(),
-        skinModelNormalMapTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
+        skinModelNormalMapTranslucentVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular(),
         skinModelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(),
-        skinModelNormalMapTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
+        skinModelNormalMapTranslucentVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
     // Same thing but with Fade on
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withFade(),
         skinModelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withFade(),
-        skinModelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
+        skinModelNormalMapFadeVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular().withFade(),
         skinModelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular().withFade(),
-        skinModelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
+        skinModelNormalMapFadeVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
 
     // Depth-only
     addPipeline(
diff --git a/libraries/render-utils/src/model_translucent_normal_map.slf b/libraries/render-utils/src/model_translucent_normal_map.slf
new file mode 100644
index 0000000000..759007d93e
--- /dev/null
+++ b/libraries/render-utils/src/model_translucent_normal_map.slf
@@ -0,0 +1,91 @@
+<@include gpu/Config.slh@>
+<$VERSION_HEADER$>
+//  Generated on <$_SCRIBE_DATE$>
+//
+//  model_translucent_normal_map.frag
+//  fragment shader
+//
+//  Created by Olivier Prat on 23/01/2018.
+//  Copyright 2018 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+<@include graphics/Material.slh@>
+
+<@include DeferredGlobalLight.slh@>
+
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
+
+<@include LightLocal.slh@>
+
+<@include gpu/Transform.slh@>
+<$declareStandardCameraTransform()$>
+
+<@include MaterialTextures.slh@>
+<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
+
+in vec2 _texCoord0;
+in vec2 _texCoord1;
+in vec4 _position;
+in vec4 _worldPosition;
+in vec3 _normal;
+in vec3 _tangent;
+in vec3 _color;
+in float _alpha;
+
+out vec4 _fragColor;
+
+void main(void) {
+    Material mat = getMaterial();
+    int matKey = getMaterialKey(mat);
+    <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex)$>
+    <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
+
+    float opacity = getMaterialOpacity(mat) * _alpha;
+    <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
+
+    vec3 albedo = getMaterialAlbedo(mat);
+    <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
+    albedo *= _color;
+
+    float roughness = getMaterialRoughness(mat);
+    <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
+
+    float metallic = getMaterialMetallic(mat);
+    vec3 fresnel = getFresnelF0(metallic, albedo);
+
+    vec3 emissive = getMaterialEmissive(mat);
+    <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
+
+    vec3 fragPosition = _position.xyz;
+    vec3 fragNormal;
+    <$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
+
+    TransformCamera cam = getTransformCamera();
+    vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));
+    vec3 fragEyeDir = normalize(fragEyeVector);
+    SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
+
+    vec4 localLighting = vec4(0.0);
+
+    <$fetchClusterInfo(_worldPosition)$>;
+    if (hasLocalLights(numLights, clusterPos, dims)) {
+        localLighting = evalLocalLighting(cluster, numLights, _worldPosition.xyz, surface,
+                                          metallic, fresnel, albedo, 0.0,
+                                          vec4(0), vec4(0), opacity);
+    }
+
+    _fragColor =  vec4(evalGlobalLightingAlphaBlendedWithHaze(
+        cam._viewInverse,
+        1.0,
+        occlusionTex,
+        fragPosition,
+        albedo,
+        fresnel,
+        metallic,
+        emissive,
+        surface, opacity, localLighting.rgb),
+        opacity);
+}
diff --git a/libraries/render-utils/src/model_translucent_fade.slv b/libraries/render-utils/src/model_translucent_normal_map.slv
similarity index 88%
rename from libraries/render-utils/src/model_translucent_fade.slv
rename to libraries/render-utils/src/model_translucent_normal_map.slv
index 3fb9ad2cb4..db824a3709 100644
--- a/libraries/render-utils/src/model_translucent_fade.slv
+++ b/libraries/render-utils/src/model_translucent_normal_map.slv
@@ -1,10 +1,10 @@
 <@include gpu/Config.slh@>
 <$VERSION_HEADER$>
 //  Generated on <$_SCRIBE_DATE$>
-//  model_translucent_fade.slv
+//  model_translucent_normal_map.slv
 //  vertex shader
 //
-//  Created by Olivier Prat on 15/01/18.
+//  Created by Olivier Prat on 23/01/18.
 //  Copyright 2018 High Fidelity, Inc.
 //
 //  Distributed under the Apache License, Version 2.0.
@@ -25,6 +25,7 @@ out vec2 _texCoord1;
 out vec4 _position;
 out vec4 _worldPosition;
 out vec3 _normal;
+out vec3 _tangent;
 out vec3 _color;
 
 void main(void) {
@@ -41,4 +42,5 @@ void main(void) {
     <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
     <$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
     <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
+    <$transformModelToWorldDir(cam, obj, inTangent.xyz, _tangent)$>
 }
diff --git a/libraries/render-utils/src/model_translucent_normal_map_fade.slf b/libraries/render-utils/src/model_translucent_normal_map_fade.slf
new file mode 100644
index 0000000000..204b5ac56b
--- /dev/null
+++ b/libraries/render-utils/src/model_translucent_normal_map_fade.slf
@@ -0,0 +1,101 @@
+<@include gpu/Config.slh@>
+<$VERSION_HEADER$>
+//  Generated on <$_SCRIBE_DATE$>
+//
+//  model_translucent_normal_map_fade.frag
+//  fragment shader
+//
+//  Created by Olivier Prat on 23/01/18.
+//  Copyright 2018 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+<@include graphics/Material.slh@>
+
+<@include DeferredGlobalLight.slh@>
+
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
+
+<@include LightLocal.slh@>
+
+<@include gpu/Transform.slh@>
+<$declareStandardCameraTransform()$>
+
+<@include MaterialTextures.slh@>
+<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
+
+<@include Fade.slh@>
+<$declareFadeFragment()$>
+
+in vec2 _texCoord0;
+in vec2 _texCoord1;
+in vec4 _position;
+in vec3 _normal;
+in vec3 _tangent;
+in vec3 _color;
+in float _alpha;
+in vec4 _worldPosition;
+
+out vec4 _fragColor;
+
+void main(void) {
+    vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
+
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
+
+    Material mat = getMaterial();
+    int matKey = getMaterialKey(mat);
+    <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex)$>
+    <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
+
+    float opacity = getMaterialOpacity(mat) * _alpha;
+    <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
+
+    vec3 albedo = getMaterialAlbedo(mat);
+    <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
+    albedo *= _color;
+
+    float roughness = getMaterialRoughness(mat);
+    <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
+
+    float metallic = getMaterialMetallic(mat);
+    vec3 fresnel = getFresnelF0(metallic, albedo);
+
+    vec3 emissive = getMaterialEmissive(mat);
+    <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
+
+    vec3 fragPosition = _position.xyz;
+    // Lighting is done in world space
+    vec3 fragNormal;
+    <$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
+
+    TransformCamera cam = getTransformCamera();
+    vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));
+    vec3 fragEyeDir = normalize(fragEyeVector);
+    SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
+
+    vec4 localLighting = vec4(0.0);
+
+    <$fetchClusterInfo(_worldPosition)$>;
+    if (hasLocalLights(numLights, clusterPos, dims)) {
+        localLighting = evalLocalLighting(cluster, numLights, _worldPosition.xyz, surface,
+                                          metallic, fresnel, albedo, 0.0,
+                                          vec4(0), vec4(0), opacity);
+    }
+
+    _fragColor =  vec4(evalGlobalLightingAlphaBlendedWithHaze(
+        cam._viewInverse,
+        1.0,
+        occlusionTex,
+        fragPosition,
+        albedo,
+        fresnel,
+        metallic,
+        emissive+fadeEmissive,
+        surface, opacity, localLighting.rgb),
+        opacity);
+}
diff --git a/libraries/render-utils/src/simple_transparent_textured_fade.slf b/libraries/render-utils/src/simple_transparent_textured_fade.slf
index ad260210a7..a8a5875a4b 100644
--- a/libraries/render-utils/src/simple_transparent_textured_fade.slf
+++ b/libraries/render-utils/src/simple_transparent_textured_fade.slf
@@ -16,7 +16,7 @@
 
 <@include DeferredBufferWrite.slh@>
 <@include DeferredGlobalLight.slh@>
-<$declareEvalGlobalLightingAlphaBlended()$>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
 
 <@include gpu/Transform.slh@>
 <$declareStandardCameraTransform()$>

From ae6a95ec0d4f9f3aea4c3c54236e1220b14740b4 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 24 Jan 2018 18:07:35 -0800
Subject: [PATCH 19/57] fixing my bugs on vissibility

---
 interface/src/SecondaryCamera.cpp          |  2 +-
 interface/src/ui/overlays/ModelOverlay.cpp |  2 +-
 libraries/render-utils/src/Model.h         |  2 +-
 libraries/render/src/render/Item.h         | 20 ++++++++++++++++----
 4 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp
index cad4f7f1b5..9d5b6a44a5 100644
--- a/interface/src/SecondaryCamera.cpp
+++ b/interface/src/SecondaryCamera.cpp
@@ -205,7 +205,7 @@ public:
 
 void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
     const auto cachedArg = task.addJob<SecondaryCameraJob>("SecondaryCamera");
-    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
+    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::VISIBLE_MASK_1, render::ItemKey::VISIBLE_MASK_1);
     assert(items.canCast<RenderFetchCullSortTask::Output>());
     if (!isDeferred) {
         task.addJob<RenderForwardTask>("Forward", items);
diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index 367cb397d1..59d4521307 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -87,7 +87,7 @@ void ModelOverlay::update(float deltatime) {
     if (_visibleDirty) {
         _visibleDirty = false;
         // don't show overlays in mirrors
-        _model->setVisibleInScene(getVisible(), scene, render::ItemKey::VISIBLE_MASK_0 * getVisible());
+        _model->setVisibleInScene(getVisible(), scene, render::ItemKey::VISIBLE_MASK_0);
     }
     if (_drawInFrontDirty) {
         _drawInFrontDirty = false;
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index 5f58906e9f..d9845de9ed 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -389,7 +389,7 @@ protected:
 
     QUrl _url;
     bool _isVisible;
-    uint8_t _viewVisibilityMask { 0 };
+    uint8_t _viewVisibilityMask { render::ItemKey::VISIBLE_MASK_ALL };
 
     gpu::Buffers _blendedVertexBuffers;
 
diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h
index 9ea8421f1a..18e626d005 100644
--- a/libraries/render/src/render/Item.h
+++ b/libraries/render/src/render/Item.h
@@ -96,6 +96,18 @@ public:
         Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); }
         Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); }
         Builder& withDeformed() { _flags.set(DEFORMED); return (*this); }
+        Builder& withVisible(uint8_t maskIndex = NUM_VISIBLE_MASK_INDICES) {
+            if (maskIndex == NUM_VISIBLE_MASK_INDICES) {
+                _flags.reset(INVISIBLE0);
+                _flags.reset(INVISIBLE1);
+                _flags.reset(INVISIBLE2);
+                _flags.reset(INVISIBLE3);
+            }
+            else {
+                _flags.reset(INVISIBLE0 + maskIndex);
+            }
+            return (*this);
+        }
         Builder& withInvisible(uint8_t maskIndex = NUM_VISIBLE_MASK_INDICES) {
             if (maskIndex == NUM_VISIBLE_MASK_INDICES) {
                 _flags.set(INVISIBLE0);
@@ -109,16 +121,16 @@ public:
         }
         Builder& withViewVisibilityMask(uint8_t mask) {
             if (mask & render::ItemKey::VISIBLE_MASK_0) {
-                _flags.set(INVISIBLE0);
+                _flags.reset(INVISIBLE0);
             }
             if (mask & render::ItemKey::VISIBLE_MASK_1) {
-                _flags.set(INVISIBLE1);
+                _flags.reset(INVISIBLE1);
             }
             if (mask & render::ItemKey::VISIBLE_MASK_2) {
-                _flags.set(INVISIBLE2);
+                _flags.reset(INVISIBLE2);
             }
             if (mask & render::ItemKey::VISIBLE_MASK_3) {
-                _flags.set(INVISIBLE3);
+                _flags.reset(INVISIBLE3);
             }
             return (*this);
         }

From 2f4e61888fb4636d140b0ece98f46c1e016b581c Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 25 Jan 2018 16:57:35 -0800
Subject: [PATCH 20/57] Making it work maybe

---
 interface/src/ui/overlays/ModelOverlay.h      |  2 +-
 interface/src/ui/overlays/OverlaysPayload.cpp |  4 ++--
 .../src/RenderableModelEntityItem.cpp         |  4 ++--
 .../render-utils/src/CauterizedModel.cpp      |  2 +-
 .../render-utils/src/MeshPartPayload.cpp      |  2 +-
 libraries/render/src/render/Item.h            | 20 ++++++++-----------
 6 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h
index a39f762210..a012969621 100644
--- a/interface/src/ui/overlays/ModelOverlay.h
+++ b/interface/src/ui/overlays/ModelOverlay.h
@@ -106,7 +106,7 @@ private:
     bool _jointMappingCompleted { false };
     QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
 
-    bool _visibleDirty { false };
+    bool _visibleDirty { true };
     bool _drawInFrontDirty { false };
     bool _drawInHUDDirty { false };
 
diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp
index c071c44d42..937de1a236 100644
--- a/interface/src/ui/overlays/OverlaysPayload.cpp
+++ b/interface/src/ui/overlays/OverlaysPayload.cpp
@@ -46,9 +46,9 @@ namespace render {
         }
 
         if (overlay->getVisible()) {
-            builder.withViewVisibilityMask(render::ItemKey::VISIBLE_MASK_0); // don't draw overlays in mirror
+            builder.withVisibilityMask(render::ItemKey::VISIBLE_MASK_0); // don't draw overlays in mirror
         } else {
-            builder.withViewVisibilityMask(render::ItemKey::VISIBLE_MASK_NONE);
+            builder.withVisibilityMask(render::ItemKey::VISIBLE_MASK_NONE);
         }
 
         return builder.build();
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 0ae7efb652..ee3557346d 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1334,8 +1334,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
     entity->stopModelOverrideIfNoParent();
 
     uint32_t viewVisiblityMask = _cauterized ?
-        render::ItemKey::VISIBLE_MASK_0 : // draw in every view except the main one (view zero)
-        render::ItemKey::VISIBLE_MASK_NONE; // draw in all views
+        render::ItemKey::VISIBLE_MASK_1 : // draw in every view except the main one (view zero)
+        render::ItemKey::VISIBLE_MASK_ALL; // draw in all views
 
     if (model->isVisible() != _visible || model->getViewVisibilityMask() != viewVisiblityMask) {
         // FIXME: this seems like it could be optimized if we tracked our last known visible state in
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index f67f5ef358..809be09436 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -247,7 +247,7 @@ void CauterizedModel::updateRenderItems() {
                     data.updateTransformForCauterizedMesh(renderTransform);
 
                     data.setEnableCauterization(enableCauterization);
-                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_NONE);
+                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
                     data.setLayer(isLayeredInFront, isLayeredInHUD);
                     data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
                 });
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index da636eed06..451b168465 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -396,7 +396,7 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, uint8_t viewVi
     if (!isVisible) {
         builder.withInvisible();
     } else {
-        builder.withViewVisibilityMask(viewVisiblityMask);
+        builder.withVisibilityMask(viewVisiblityMask);
     }
 
     if (isLayered) {
diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h
index 18e626d005..97eaefcb53 100644
--- a/libraries/render/src/render/Item.h
+++ b/libraries/render/src/render/Item.h
@@ -119,18 +119,14 @@ public:
             }
             return (*this);
         }
-        Builder& withViewVisibilityMask(uint8_t mask) {
-            if (mask & render::ItemKey::VISIBLE_MASK_0) {
-                _flags.reset(INVISIBLE0);
-            }
-            if (mask & render::ItemKey::VISIBLE_MASK_1) {
-                _flags.reset(INVISIBLE1);
-            }
-            if (mask & render::ItemKey::VISIBLE_MASK_2) {
-                _flags.reset(INVISIBLE2);
-            }
-            if (mask & render::ItemKey::VISIBLE_MASK_3) {
-                _flags.reset(INVISIBLE3);
+        Builder& withVisibilityMask(uint8_t mask) {
+            for (int i = 0; i < ItemKey::NUM_VISIBLE_MASK_INDICES; i++) {
+                if ((1 << i) & mask) {
+                    withVisible(i);
+                }
+                else {
+                    withInvisible(i);
+                }
             }
             return (*this);
         }

From 51dac0437422f119d4457ca24c93b9db9e07fb55 Mon Sep 17 00:00:00 2001
From: Sam Gateau <samuel.gateau@gmail.com>
Date: Fri, 26 Jan 2018 02:59:43 -0800
Subject: [PATCH 21/57] Introducing the tag in lieu of the vsisiblity mask

---
 interface/src/Application.cpp                 |   2 +-
 interface/src/SecondaryCamera.cpp             |   4 +-
 interface/src/avatar/MyAvatar.cpp             |   8 +-
 interface/src/ui/overlays/ModelOverlay.cpp    |   2 +-
 interface/src/ui/overlays/OverlaysPayload.cpp |   8 +-
 .../src/RenderableModelEntityItem.cpp         |   4 +-
 .../render-utils/src/CauterizedModel.cpp      |   2 +-
 .../render-utils/src/MeshPartPayload.cpp      |   4 +-
 libraries/render-utils/src/Model.h            |   2 +-
 .../render-utils/src/RenderShadowTask.cpp     |   2 +-
 libraries/render/src/render/Item.cpp          |  20 ++-
 libraries/render/src/render/Item.h            | 138 ++++++++----------
 .../src/render/RenderFetchCullSortTask.cpp    |  18 +--
 .../src/render/RenderFetchCullSortTask.h      |   2 +-
 14 files changed, 102 insertions(+), 114 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 3284ed902e..bdb97bcdd8 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2274,7 +2274,7 @@ void Application::initializeGL() {
 #ifndef Q_OS_ANDROID
     _renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
 #endif
-    _renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::VISIBLE_MASK_0, render::ItemKey::VISIBLE_MASK_0);
+    _renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
     _renderEngine->load();
     _renderEngine->registerScene(_main3DScene);
 
diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp
index 9d5b6a44a5..1ae1cc3559 100644
--- a/interface/src/SecondaryCamera.cpp
+++ b/interface/src/SecondaryCamera.cpp
@@ -20,7 +20,7 @@ using RenderArgsPointer = std::shared_ptr<RenderArgs>;
 
 void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
     task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
-    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::VISIBLE_MASK_1, render::ItemKey::VISIBLE_MASK_1);
+    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
     assert(items.canCast<RenderFetchCullSortTask::Output>());
     if (!isDeferred) {
         task.addJob<RenderForwardTask>("Forward", items);
@@ -205,7 +205,7 @@ public:
 
 void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
     const auto cachedArg = task.addJob<SecondaryCameraJob>("SecondaryCamera");
-    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::VISIBLE_MASK_1, render::ItemKey::VISIBLE_MASK_1);
+    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
     assert(items.canCast<RenderFetchCullSortTask::Output>());
     if (!isDeferred) {
         task.addJob<RenderForwardTask>("Forward", items);
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index dd51de2079..a63af4435b 100755
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -1078,7 +1078,7 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
 }
 
 void MyAvatar::setEnableMeshVisible(bool isEnabled) {
-    _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::VISIBLE_MASK_NONE);
+    _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE);
 }
 
 void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
@@ -1428,7 +1428,7 @@ void MyAvatar::clearJointsData() {
 
 void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
     Avatar::setSkeletonModelURL(skeletonModelURL);
-    _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::VISIBLE_MASK_NONE);
+    _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE);
     _headBoneSet.clear();
     emit skeletonChanged();
 
@@ -1742,7 +1742,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
 
 void MyAvatar::setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visible) {
     if (model->isActive() && model->isRenderable()) {
-        model->setVisibleInScene(visible, scene, render::ItemKey::VISIBLE_MASK_NONE);
+        model->setVisibleInScene(visible, scene, render::ItemKey::TAG_BITS_NONE);
     }
 }
 
@@ -1938,7 +1938,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
                 _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
                 _attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
                 _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(),
-                                                        render::ItemKey::VISIBLE_MASK_NONE);
+                                                        render::ItemKey::TAG_BITS_NONE);
             }
         }
     }
diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index 59d4521307..015a1a4a3b 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -87,7 +87,7 @@ void ModelOverlay::update(float deltatime) {
     if (_visibleDirty) {
         _visibleDirty = false;
         // don't show overlays in mirrors
-        _model->setVisibleInScene(getVisible(), scene, render::ItemKey::VISIBLE_MASK_0);
+        _model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0);
     }
     if (_drawInFrontDirty) {
         _drawInFrontDirty = false;
diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp
index 937de1a236..f99ced0021 100644
--- a/interface/src/ui/overlays/OverlaysPayload.cpp
+++ b/interface/src/ui/overlays/OverlaysPayload.cpp
@@ -45,12 +45,12 @@ namespace render {
             builder.withViewSpace();
         }
 
-        if (overlay->getVisible()) {
-            builder.withVisibilityMask(render::ItemKey::VISIBLE_MASK_0); // don't draw overlays in mirror
-        } else {
-            builder.withVisibilityMask(render::ItemKey::VISIBLE_MASK_NONE);
+        if (!overlay->getVisible()) {
+            builder.withInvisible();
         }
 
+        builder.withTagBits(render::ItemKey::TAG_BITS_0); // Only draw overlays in main view
+
         return builder.build();
     }
     template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index ee3557346d..190864cecf 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1334,8 +1334,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
     entity->stopModelOverrideIfNoParent();
 
     uint32_t viewVisiblityMask = _cauterized ?
-        render::ItemKey::VISIBLE_MASK_1 : // draw in every view except the main one (view zero)
-        render::ItemKey::VISIBLE_MASK_ALL; // draw in all views
+        render::ItemKey::TAG_BITS_1 : // draw in every view except the main one (view zero)
+        render::ItemKey::TAG_BITS_ALL; // draw in all views
 
     if (model->isVisible() != _visible || model->getViewVisibilityMask() != viewVisiblityMask) {
         // FIXME: this seems like it could be optimized if we tracked our last known visible state in
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index 809be09436..574d3d741c 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -247,7 +247,7 @@ void CauterizedModel::updateRenderItems() {
                     data.updateTransformForCauterizedMesh(renderTransform);
 
                     data.setEnableCauterization(enableCauterization);
-                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::VISIBLE_MASK_ALL);
+                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::TAG_BITS_ALL);
                     data.setLayer(isLayeredInFront, isLayeredInHUD);
                     data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
                 });
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index 451b168465..aaec28e210 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -395,10 +395,10 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, uint8_t viewVi
 
     if (!isVisible) {
         builder.withInvisible();
-    } else {
-        builder.withVisibilityMask(viewVisiblityMask);
     }
 
+    builder.withTagBits(render::ItemKey::TAG_BITS_ALL); // Draw models in all tags
+
     if (isLayered) {
         builder.withLayered();
     }
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index d9845de9ed..1fa14f92d6 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -389,7 +389,7 @@ protected:
 
     QUrl _url;
     bool _isVisible;
-    uint8_t _viewVisibilityMask { render::ItemKey::VISIBLE_MASK_ALL };
+    uint8_t _viewVisibilityMask { render::ItemKey::TAG_BITS_ALL };
 
     gpu::Buffers _blendedVertexBuffers;
 
diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp
index 7a7714e1e0..d83dfd73a5 100644
--- a/libraries/render-utils/src/RenderShadowTask.cpp
+++ b/libraries/render-utils/src/RenderShadowTask.cpp
@@ -264,7 +264,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
 
     const auto globalShadow = lightStage->getCurrentKeyShadow();
     if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
-        output.edit1() = ItemFilter::Builder::visibleWorldItems(0x00, 0x00).withTypeShape().withOpaque().withoutLayered();
+        output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
 
         globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
 
diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp
index 0e4502a47c..1bf20ab510 100644
--- a/libraries/render/src/render/Item.cpp
+++ b/libraries/render/src/render/Item.cpp
@@ -34,13 +34,19 @@ const int Item::LAYER_3D = 1;
 const int Item::LAYER_3D_FRONT = 2;
 const int Item::LAYER_3D_HUD = 3;
 
-const uint8_t ItemKey::NUM_VISIBLE_MASK_INDICES { 4 };
-const uint8_t ItemKey::VISIBLE_MASK_ALL { 0x0F };
-const uint8_t ItemKey::VISIBLE_MASK_NONE { 0x00 };
-const uint8_t ItemKey::VISIBLE_MASK_0 { 0x01 };
-const uint8_t ItemKey::VISIBLE_MASK_1 { 0x02 };
-const uint8_t ItemKey::VISIBLE_MASK_2 { 0x04 };
-const uint8_t ItemKey::VISIBLE_MASK_3 { 0x08 };
+const uint8_t ItemKey::TAG_BITS_ALL{ 0xFF };
+const uint8_t ItemKey::TAG_BITS_NONE{ 0x00 };
+const uint8_t ItemKey::TAG_BITS_0{ 0x01 };
+const uint8_t ItemKey::TAG_BITS_1{ 0x02 };
+const uint8_t ItemKey::TAG_BITS_2{ 0x04 };
+const uint8_t ItemKey::TAG_BITS_3{ 0x08 };
+const uint8_t ItemKey::TAG_BITS_4 { 0x10 };
+const uint8_t ItemKey::TAG_BITS_5{ 0x20 };
+const uint8_t ItemKey::TAG_BITS_6{ 0x40 };
+const uint8_t ItemKey::TAG_BITS_7 { 0x80 };
+
+const uint32_t ItemKey::KEY_TAG_BITS_MASK = ((uint32_t) ItemKey::TAG_BITS_ALL) << FIRST_TAG_BIT;
+
 
 
 void Item::Status::Value::setScale(float scale) {
diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h
index 97eaefcb53..4833bd2f42 100644
--- a/libraries/render/src/render/Item.h
+++ b/libraries/render/src/render/Item.h
@@ -38,38 +38,61 @@ class Context;
 // Key is the KEY to filter Items and create specialized lists
 class ItemKey {
 public:
-    enum FlagBit {
+    // 8 tags are available to organize the items and filter them against as fields of the ItemKey.
+    // TAG & TAG_BITS are defined from several bits in the Key.
+    // An Item can be tagged and filtering can rely on the tags to keep or exclude items
+    // ItemKey are not taged by default
+    enum Tag : uint8_t {
+        TAG_0 = 0, // 8 Tags 
+        TAG_1,
+        TAG_2,
+        TAG_3,
+        TAG_4,
+        TAG_5,
+        TAG_6,
+        TAG_7,
+
+        NUM_TAGS,
+    };
+    // Tag bits are derived from the Tag enum
+    const static uint8_t TAG_BITS_ALL;
+    const static uint8_t TAG_BITS_NONE;
+    const static uint8_t TAG_BITS_0;
+    const static uint8_t TAG_BITS_1;
+    const static uint8_t TAG_BITS_2;
+    const static uint8_t TAG_BITS_3;
+    const static uint8_t TAG_BITS_4;
+    const static uint8_t TAG_BITS_5;
+    const static uint8_t TAG_BITS_6;
+    const static uint8_t TAG_BITS_7;
+
+    enum FlagBit : uint32_t {
         TYPE_SHAPE = 0,   // Item is a Shape
         TYPE_LIGHT,       // Item is a Light
         TYPE_META,        // Item is a Meta: meanning it s used to represent a higher level object, potentially represented by other render items
+
         TRANSLUCENT,      // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work...
         VIEW_SPACE,       // Transformed in view space, and not in world space
         DYNAMIC,          // Dynamic and bound will change unlike static item
         DEFORMED,         // Deformed within bound, not solid
-        INVISIBLE0,       // Visible or not in this mask index?
-        INVISIBLE1,       // Visible or not in this mask index?
-        INVISIBLE2,       // Visible or not in this mask index?
-        INVISIBLE3,       // Visible or not in this mask index?
+        INVISIBLE,        // Visible or not in the scene?
         SHADOW_CASTER,    // Item cast shadows
-        PICKABLE,         // Item can be picked/selected
         LAYERED,          // Item belongs to one of the layers different from the default layer
 
-        SMALLER,
+        FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against
+        LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS,
+
+        __SMALLER,        // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells)
 
         NUM_FLAGS,      // Not a valid flag
     };
     typedef std::bitset<NUM_FLAGS> Flags;
 
-    // VISIBLE MASK is defined from several bits in the Key.
-    // An Item can be visible in some mask bits and not other allowing for per view rendering
-    // Beware that the visibility mask is the oposite of what stored in the key vals.
-    const static uint8_t NUM_VISIBLE_MASK_INDICES;
-    const static uint8_t VISIBLE_MASK_ALL;
-    const static uint8_t VISIBLE_MASK_NONE;
-    const static uint8_t VISIBLE_MASK_0;
-    const static uint8_t VISIBLE_MASK_1;
-    const static uint8_t VISIBLE_MASK_2;
-    const static uint8_t VISIBLE_MASK_3;
+    // All the bits touching tag bits sets to true
+    const static uint32_t KEY_TAG_BITS_MASK;
+    static uint32_t evalTagBitsWithKeyBits(uint8_t tagBits, const uint32_t keyBits) {
+        return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT);
+    }
 
     // The key is the Flags
     Flags _flags;
@@ -96,44 +119,14 @@ public:
         Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); }
         Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); }
         Builder& withDeformed() { _flags.set(DEFORMED); return (*this); }
-        Builder& withVisible(uint8_t maskIndex = NUM_VISIBLE_MASK_INDICES) {
-            if (maskIndex == NUM_VISIBLE_MASK_INDICES) {
-                _flags.reset(INVISIBLE0);
-                _flags.reset(INVISIBLE1);
-                _flags.reset(INVISIBLE2);
-                _flags.reset(INVISIBLE3);
-            }
-            else {
-                _flags.reset(INVISIBLE0 + maskIndex);
-            }
-            return (*this);
-        }
-        Builder& withInvisible(uint8_t maskIndex = NUM_VISIBLE_MASK_INDICES) {
-            if (maskIndex == NUM_VISIBLE_MASK_INDICES) {
-                _flags.set(INVISIBLE0);
-                _flags.set(INVISIBLE1);
-                _flags.set(INVISIBLE2);
-                _flags.set(INVISIBLE3);
-            } else {
-                _flags.set(INVISIBLE0 + maskIndex);
-            }
-            return (*this);
-        }
-        Builder& withVisibilityMask(uint8_t mask) {
-            for (int i = 0; i < ItemKey::NUM_VISIBLE_MASK_INDICES; i++) {
-                if ((1 << i) & mask) {
-                    withVisible(i);
-                }
-                else {
-                    withInvisible(i);
-                }
-            }
-            return (*this);
-        }
+        Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); }
         Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); }
-        Builder& withPickable() { _flags.set(PICKABLE); return (*this); }
         Builder& withLayered() { _flags.set(LAYERED); return (*this); }
 
+        Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); }
+        // Set ALL the tags in one call using the Tag bits
+        Builder& withTagBits(uint8_t tagBits) { _flags = evalTagBitsWithKeyBits(tagBits, _flags.to_ulong()); return (*this); }
+
         // Convenient standard keys that we will keep on using all over the place
         static Builder opaqueShape() { return Builder().withTypeShape(); }
         static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); }
@@ -158,21 +151,20 @@ public:
     bool isRigid() const { return !_flags[DEFORMED]; }
     bool isDeformed() const { return _flags[DEFORMED]; }
 
-    bool isVisible(uint8_t maskIndex) const { return !_flags[INVISIBLE0 + maskIndex]; }
-    bool isInvisible(uint8_t maskIndex) const { return _flags[INVISIBLE0 + maskIndex]; }
-    uint8_t getVisibleMask() const { return (~(_flags.to_ulong() >> INVISIBLE0) & VISIBLE_MASK_ALL);}
-    bool isVisibleMask(uint8_t mask) const { return getVisibleMask() & mask; }
+    bool isVisible() const { return !_flags[INVISIBLE]; }
+    bool isInvisible() const { return _flags[INVISIBLE]; }
 
     bool isShadowCaster() const { return _flags[SHADOW_CASTER]; }
 
-    bool isPickable() const { return _flags[PICKABLE]; }
-
     bool isLayered() const { return _flags[LAYERED]; }
     bool isSpatial() const { return !isLayered(); }
 
+    bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; }
+    uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); }
+
     // Probably not public, flags used by the scene
-    bool isSmall() const { return _flags[SMALLER]; }
-    void setSmaller(bool smaller) { (smaller ? _flags.set(SMALLER) : _flags.reset(SMALLER)); }
+    bool isSmall() const { return _flags[__SMALLER]; }
+    void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); }
 
     bool operator==(const ItemKey& key) { return (_flags == key._flags); }
     bool operator!=(const ItemKey& key) { return (_flags != key._flags); }
@@ -220,34 +212,24 @@ public:
         Builder& withRigid()            { _value.reset(ItemKey::DEFORMED); _mask.set(ItemKey::DEFORMED); return (*this); }
         Builder& withDeformed()         { _value.set(ItemKey::DEFORMED);  _mask.set(ItemKey::DEFORMED); return (*this); }
 
-        Builder& withVisible(uint8_t maskIndex)          { _value.reset(ItemKey::INVISIBLE0 + maskIndex); _mask.set(ItemKey::INVISIBLE0 + maskIndex); return (*this); }
-        Builder& withInvisible(uint8_t maskIndex)        { _value.set(ItemKey::INVISIBLE0 + maskIndex);  _mask.set(ItemKey::INVISIBLE0 + maskIndex); return (*this); }
-        Builder& withVisibilityMask(uint8_t mask, uint8_t touchBits) {
-            for (int i = 0; i < ItemKey::NUM_VISIBLE_MASK_INDICES; i++) {
-                if ((1 << i) & touchBits) {
-                    if ((1 << i) & mask) {
-                        withVisible(i);
-                    }
-                    else {
-                        withInvisible(i);
-                    }
-                }
-            }
-            return (*this);
-        }
+        Builder& withVisible()          { _value.reset(ItemKey::INVISIBLE); _mask.set(ItemKey::INVISIBLE); return (*this); }
+        Builder& withInvisible()        { _value.set(ItemKey::INVISIBLE);  _mask.set(ItemKey::INVISIBLE); return (*this); }
 
         Builder& withNoShadowCaster()   { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
         Builder& withShadowCaster()     { _value.set(ItemKey::SHADOW_CASTER);  _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
 
-        Builder& withPickable()         { _value.set(ItemKey::PICKABLE);  _mask.set(ItemKey::PICKABLE); return (*this); }
-
         Builder& withoutLayered()       { _value.reset(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); }
         Builder& withLayered()          { _value.set(ItemKey::LAYERED);  _mask.set(ItemKey::LAYERED); return (*this); }
 
+        Builder& withoutTag(ItemKey::Tag tagIndex)    { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex);  _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); }
+        Builder& withTag(ItemKey::Tag tagIndex)       { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex);  _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); }
+        // Set ALL the tags in one call using the Tag bits and the Tag bits touched
+        Builder& withTagBits(uint8_t tagBits, uint8_t tagMask) { _value = ItemKey::evalTagBitsWithKeyBits(tagBits, _value.to_ulong()); _mask = ItemKey::evalTagBitsWithKeyBits(tagMask, _mask.to_ulong()); return (*this); }
+
         Builder& withNothing()          { _value.reset(); _mask.reset(); return (*this); }
 
         // Convenient standard keys that we will keep on using all over the place
-        static Builder visibleWorldItems(uint8_t visibilityMask, uint8_t visibilityMaskTouched) { return Builder().withVisibilityMask(visibilityMask, visibilityMaskTouched).withWorldSpace(); }
+        static Builder visibleWorldItems() { return Builder().withVisible().withWorldSpace(); }
         static Builder opaqueShape() { return Builder().withTypeShape().withOpaque().withWorldSpace(); }
         static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); }
         static Builder light() { return Builder().withTypeLight(); }
diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp
index b4e1a618dc..a402c3bc9d 100644
--- a/libraries/render/src/render/RenderFetchCullSortTask.cpp
+++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp
@@ -17,12 +17,12 @@
 
 using namespace render;
 
-void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor, uint8_t visibilityMask, uint8_t visibilityMaskTouched) {
+void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) {
     cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
 
     // CPU jobs:
     // Fetch and cull the items from the scene
-    const ItemFilter filter = ItemFilter::Builder::visibleWorldItems(visibilityMask, visibilityMaskTouched).withoutLayered();
+    const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered().withTagBits(tagBits, tagMask);
     const auto spatialFilter = render::Varying(filter);
     const auto spatialSelection = task.addJob<FetchSpatialTree>("FetchSceneSelection", spatialFilter);
     const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, spatialFilter).asVarying();
@@ -40,15 +40,15 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
     const int META_BUCKET = 3;
     const int BACKGROUND_BUCKET = 2;
     MultiFilterItems<NUM_SPATIAL_FILTERS>::ItemFilterArray spatialFilters = { {
-            ItemFilter::Builder::opaqueShape().withVisibilityMask(visibilityMask, visibilityMaskTouched),
-            ItemFilter::Builder::transparentShape().withVisibilityMask(visibilityMask, visibilityMaskTouched),
-            ItemFilter::Builder::light().withVisibilityMask(visibilityMask, visibilityMaskTouched),
-            ItemFilter::Builder::meta().withVisibilityMask(visibilityMask, visibilityMaskTouched)
+            ItemFilter::Builder::opaqueShape().withVisible().withTagBits(tagBits, tagMask),
+            ItemFilter::Builder::transparentShape().withVisible().withTagBits(tagBits, tagMask),
+            ItemFilter::Builder::light().withVisible().withTagBits(tagBits, tagMask),
+            ItemFilter::Builder::meta().withVisible().withTagBits(tagBits, tagMask)
         } };
     MultiFilterItems<NUM_NON_SPATIAL_FILTERS>::ItemFilterArray nonspatialFilters = { {
-            ItemFilter::Builder::opaqueShape().withVisibilityMask(visibilityMask, visibilityMaskTouched),
-            ItemFilter::Builder::transparentShape().withVisibilityMask(visibilityMask, visibilityMaskTouched),
-            ItemFilter::Builder::background().withVisibilityMask(visibilityMask, visibilityMaskTouched)
+            ItemFilter::Builder::opaqueShape().withVisible().withTagBits(tagBits, tagMask),
+            ItemFilter::Builder::transparentShape().withVisible().withTagBits(tagBits, tagMask),
+            ItemFilter::Builder::background().withVisible().withTagBits(tagBits, tagMask)
         } };
     const auto filteredSpatialBuckets = 
         task.addJob<MultiFilterItems<NUM_SPATIAL_FILTERS>>("FilterSceneSelection", culledSpatialSelection, spatialFilters)
diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h
index 9aa235b3fb..8c9f2e7304 100644
--- a/libraries/render/src/render/RenderFetchCullSortTask.h
+++ b/libraries/render/src/render/RenderFetchCullSortTask.h
@@ -36,7 +36,7 @@ public:
 
     RenderFetchCullSortTask() {}
 
-    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t visibilityMask = 0xFF, uint8_t visibilityMaskTouched = 0x00);
+    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
 };
 
 #endif // hifi_RenderFetchCullSortTask_h

From 8dfa3aace3c25fe0d966c9931a856309281518e8 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Fri, 26 Jan 2018 17:34:37 -0800
Subject: [PATCH 22/57] cleaning en route

---
 interface/src/Application_render.cpp          |  2 +-
 interface/src/SecondaryCamera.cpp             |  1 +
 .../src/avatars-renderer/Avatar.cpp           |  2 +-
 .../src/RenderableEntityItem.cpp              |  4 +-
 .../src/RenderableModelEntityItem.cpp         | 11 ++---
 .../RenderableParticleEffectEntityItem.cpp    |  4 +-
 .../src/RenderablePolyLineEntityItem.cpp      |  2 +-
 .../src/RenderableZoneEntityItem.cpp          |  2 +-
 libraries/render-utils/src/AnimDebugDraw.cpp  |  2 +-
 .../render-utils/src/CauterizedModel.cpp      |  2 +-
 libraries/render-utils/src/LightPayload.cpp   |  9 ++++-
 .../render-utils/src/MeshPartPayload.cpp      | 26 ++++++++----
 libraries/render-utils/src/MeshPartPayload.h  |  9 +++--
 libraries/render-utils/src/Model.cpp          | 40 +++++++++----------
 libraries/render-utils/src/Model.h            |  6 +--
 .../render-utils/src/RenderShadowTask.cpp     |  4 +-
 libraries/render-utils/src/RenderShadowTask.h |  2 +-
 libraries/render-utils/src/RenderViewTask.cpp |  4 +-
 libraries/render-utils/src/RenderViewTask.h   |  2 +-
 .../src/render/RenderFetchCullSortTask.cpp    | 14 +++----
 20 files changed, 85 insertions(+), 63 deletions(-)

diff --git a/interface/src/Application_render.cpp b/interface/src/Application_render.cpp
index 1231e5834b..e1f198eed2 100644
--- a/interface/src/Application_render.cpp
+++ b/interface/src/Application_render.cpp
@@ -178,7 +178,7 @@ public:
 render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
 
 namespace render {
-    template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
+    template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
     template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
     template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
         if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp
index 1ae1cc3559..748f1595db 100644
--- a/interface/src/SecondaryCamera.cpp
+++ b/interface/src/SecondaryCamera.cpp
@@ -19,6 +19,7 @@
 using RenderArgsPointer = std::shared_ptr<RenderArgs>;
 
 void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
+    
     task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
     const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
     assert(items.canCast<RenderFetchCullSortTask::Output>());
diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
index 500a24763d..86635cd3bf 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
@@ -50,7 +50,7 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
 
 namespace render {
     template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
-        return ItemKey::Builder::opaqueShape().withTypeMeta();
+        return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1);
     }
     template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
         return static_pointer_cast<Avatar>(avatar)->getBounds();
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index 0988c696dd..aca2f4d35b 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -159,10 +159,10 @@ Item::Bound EntityRenderer::getBound() {
 
 ItemKey EntityRenderer::getKey() {
     if (isTransparent()) {
-        return ItemKey::Builder::transparentShape().withTypeMeta();
+        return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
     }
 
-    return ItemKey::Builder::opaqueShape().withTypeMeta();
+    return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
 }
 
 uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 190864cecf..87767db4f4 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1014,9 +1014,9 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
 
 void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
     if (didVisualGeometryRequestSucceed) {
-        _itemKey = ItemKey::Builder().withTypeMeta();
+        _itemKey = ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
     } else {
-        _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape();
+        _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
     }
 }
 
@@ -1333,15 +1333,16 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
     entity->updateModelBounds();
     entity->stopModelOverrideIfNoParent();
 
-    uint32_t viewVisiblityMask = _cauterized ?
+    // Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
+    uint32_t viewTaskBits = _cauterized ?
         render::ItemKey::TAG_BITS_1 : // draw in every view except the main one (view zero)
         render::ItemKey::TAG_BITS_ALL; // draw in all views
 
-    if (model->isVisible() != _visible || model->getViewVisibilityMask() != viewVisiblityMask) {
+    if (model->isVisible() != _visible || model->getViewTagBits() != viewTaskBits) {
         // FIXME: this seems like it could be optimized if we tracked our last known visible state in
         //        the renderable item. As it stands now the model checks it's visible/invisible state
         //        so most of the time we don't do anything in this function.
-        model->setVisibleInScene(_visible, scene, viewVisiblityMask);
+        model->setVisibleInScene(_visible, scene, viewTaskBits);
     }
     // TODO? early exit here when not visible?
 
diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
index 2059487426..af95878213 100644
--- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
@@ -147,9 +147,9 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn
 
 ItemKey ParticleEffectEntityRenderer::getKey() {
     if (_visible) {
-        return ItemKey::Builder::transparentShape();
+        return ItemKey::Builder::transparentShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
     } else {
-        return ItemKey::Builder().withInvisible().build();
+        return ItemKey::Builder().withInvisible().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
     }
 }
 
diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
index 4d223669b4..42110170a0 100644
--- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
@@ -112,7 +112,7 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
 }
 
 ItemKey PolyLineEntityRenderer::getKey() {
-    return ItemKey::Builder::transparentShape().withTypeMeta();
+    return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
 }
 
 ShapeKey PolyLineEntityRenderer::getShapeKey() {
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
index b43944f26a..04f07c5bd3 100644
--- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
@@ -269,7 +269,7 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
 
 
 ItemKey ZoneEntityRenderer::getKey() {
-    return ItemKey::Builder().withTypeMeta().build();
+    return ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
 }
 
 bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp
index c22e99cbbc..4b5b06ab0b 100644
--- a/libraries/render-utils/src/AnimDebugDraw.cpp
+++ b/libraries/render-utils/src/AnimDebugDraw.cpp
@@ -67,7 +67,7 @@ public:
 typedef render::Payload<AnimDebugDrawData> AnimDebugDrawPayload;
 
 namespace render {
-    template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::opaqueShape() : ItemKey::Builder::opaqueShape().withInvisible()); }
+    template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::opaqueShape() : ItemKey::Builder::opaqueShape().withInvisible()).withTagBits(ItemKey::TAG_BITS_ALL); }
     template <> const Item::Bound payloadGetBound(const AnimDebugDrawData::Pointer& data) { return data->_bound; }
     template <> void payloadRender(const AnimDebugDrawData::Pointer& data, RenderArgs* args) {
         data->render(args);
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index 574d3d741c..e30c72e9d4 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -247,7 +247,7 @@ void CauterizedModel::updateRenderItems() {
                     data.updateTransformForCauterizedMesh(renderTransform);
 
                     data.setEnableCauterization(enableCauterization);
-                    data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::TAG_BITS_ALL);
+                    data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::TAG_BITS_ALL);
                     data.setLayer(isLayeredInFront, isLayeredInHUD);
                     data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
                 });
diff --git a/libraries/render-utils/src/LightPayload.cpp b/libraries/render-utils/src/LightPayload.cpp
index 09334faa13..f1eef19498 100644
--- a/libraries/render-utils/src/LightPayload.cpp
+++ b/libraries/render-utils/src/LightPayload.cpp
@@ -18,9 +18,13 @@ namespace render {
     template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload) {
         ItemKey::Builder builder;
         builder.withTypeLight();
-        if (!payload || !payload->isVisible()) {
-            builder.withInvisible();
+        builder.withTagBits(ItemKey::TAG_BITS_ALL);
+        if (!payload) {
+            if (!payload->isVisible()) {
+                builder.withInvisible();
+            }
         }
+
         return builder.build();
     }
 
@@ -87,6 +91,7 @@ namespace render {
     template <> const ItemKey payloadGetKey(const KeyLightPayload::Pointer& payload) {
         ItemKey::Builder builder;
         builder.withTypeLight();
+        builder.withTagBits(ItemKey::TAG_BITS_ALL);
         if (!payload || !payload->isVisible()) {
             builder.withInvisible();
         }
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index aaec28e210..9655b60a78 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -71,10 +71,20 @@ void MeshPartPayload::updateMaterial(graphics::MaterialPointer drawMaterial) {
     _drawMaterial = drawMaterial;
 }
 
-ItemKey MeshPartPayload::getKey() const {
+void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) {
     ItemKey::Builder builder;
     builder.withTypeShape();
 
+    if (!isVisible) {
+        builder.withInvisible();
+    }
+
+    builder.withTagBits(tagBits);
+
+    if (isLayered) {
+        builder.withLayered();
+    }
+
     if (_drawMaterial) {
         auto matKey = _drawMaterial->getKey();
         if (matKey.isTranslucent()) {
@@ -82,7 +92,11 @@ ItemKey MeshPartPayload::getKey() const {
         }
     }
 
-    return builder.build();
+    _itemKey = builder.build();
+}
+
+ItemKey MeshPartPayload::getKey() const {
+    return _itemKey;
 }
 
 Item::Bound MeshPartPayload::getBound() const {
@@ -389,7 +403,7 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render
     _worldBound.transform(boundTransform);
 }
 
-void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, uint8_t viewVisiblityMask) {
+void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) {
     ItemKey::Builder builder;
     builder.withTypeShape();
 
@@ -397,7 +411,7 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, uint8_t viewVi
         builder.withInvisible();
     }
 
-    builder.withTagBits(render::ItemKey::TAG_BITS_ALL); // Draw models in all tags
+    builder.withTagBits(tagBits);
 
     if (isLayered) {
         builder.withLayered();
@@ -417,10 +431,6 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered, uint8_t viewVi
     _itemKey = builder.build();
 }
 
-ItemKey ModelMeshPartPayload::getKey() const {
-    return _itemKey;
-}
-
 void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) {
     if (isLayeredInFront) {
         _layer = Item::LAYER_3D_FRONT;
diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h
index cf64879b3c..21f9dc2e68 100644
--- a/libraries/render-utils/src/MeshPartPayload.h
+++ b/libraries/render-utils/src/MeshPartPayload.h
@@ -33,6 +33,8 @@ public:
     typedef render::Payload<MeshPartPayload> Payload;
     typedef Payload::DataPointer Pointer;
 
+    virtual void updateKey(bool isVisible, bool isLayered, uint8_t tagBits);
+
     virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex);
 
     virtual void notifyLocationChanged() {}
@@ -70,6 +72,9 @@ public:
     size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; }
     int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; }
     bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; }
+
+protected:
+    render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
 };
 
 namespace render {
@@ -94,16 +99,15 @@ public:
     using TransformType = glm::mat4;
 #endif
 
+    void updateKey(bool isVisible, bool isLayered, uint8_t tagBits) override;
     void updateClusterBuffer(const std::vector<TransformType>& clusterTransforms);
     void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
 
     // Render Item interface
-    render::ItemKey getKey() const override;
     int getLayer() const;
     render::ShapeKey getShapeKey() const override; // shape interface
     void render(RenderArgs* args) override;
 
-    void setKey(bool isVisible, bool isLayered, uint8_t viewVisiblityMask);
     void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
     void setShapeKey(bool invalidateShapeKey, bool isWireframe);
 
@@ -126,7 +130,6 @@ private:
     void initCache(const ModelPointer& model);
 
     gpu::BufferPointer _blendedVertexBuffer;
-    render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() };
     render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
     int _layer { render::Item::LAYER_3D };
 };
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 4103dffefc..56bed15376 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -268,7 +268,7 @@ void Model::updateRenderItems() {
 
         bool isWireframe = self->isWireframe();
         bool isVisible = self->isVisible();
-        uint8_t viewVisibilityMask = self->getViewVisibilityMask();
+        uint8_t viewTagBits = self->getViewTagBits();
         bool isLayeredInFront = self->isLayeredInFront();
         bool isLayeredInHUD = self->isLayeredInHUD();
 
@@ -283,7 +283,7 @@ void Model::updateRenderItems() {
 
             transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms,
                                                                   invalidatePayloadShapeKey, isWireframe, isVisible,
-                                                                  viewVisibilityMask, isLayeredInFront,
+                                                                  viewTagBits, isLayeredInFront,
                                                                   isLayeredInHUD](ModelMeshPartPayload& data) {
                 data.updateClusterBuffer(clusterTransforms);
 
@@ -300,7 +300,7 @@ void Model::updateRenderItems() {
                 }
                 data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
 
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
+                data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
                 data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
             });
@@ -662,25 +662,25 @@ void Model::calculateTriangleSets() {
     }
 }
 
-void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewVisibilityMask) {
-    if (_isVisible != isVisible || _viewVisibilityMask != viewVisibilityMask) {
+void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits) {
+    if (_isVisible != isVisible || _viewTagBits != viewTagBits) {
         _isVisible = isVisible;
-        _viewVisibilityMask = viewVisibilityMask;
+        _viewTagBits = viewTagBits;
 
         bool isLayeredInFront = _isLayeredInFront;
         bool isLayeredInHUD = _isLayeredInHUD;
 
         render::Transaction transaction;
         foreach (auto item, _modelMeshRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
                                                                 isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
+                data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
             });
         }
         foreach(auto item, _collisionRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
                                                                 isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
+                data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
             });
         }
         scene->enqueueTransaction(transaction);
@@ -693,21 +693,21 @@ void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer&
         _isLayeredInFront = isLayeredInFront;
 
         bool isVisible = _isVisible;
-        uint8_t viewVisibilityMask = _viewVisibilityMask;
+        uint8_t viewTagBits = _viewTagBits;
         bool isLayeredInHUD = _isLayeredInHUD;
 
         render::Transaction transaction;
         foreach(auto item, _modelMeshRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
                                                                 isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
+                data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
         foreach(auto item, _collisionRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
                                                                 isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
+                data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
@@ -720,21 +720,21 @@ void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& sce
         _isLayeredInHUD = isLayeredInHUD;
 
         bool isVisible = _isVisible;
-        uint8_t viewVisibilityMask = _viewVisibilityMask;
+        uint8_t viewTagBits = _viewTagBits;
         bool isLayeredInFront = _isLayeredInFront;
 
         render::Transaction transaction;
         foreach(auto item, _modelMeshRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
                                                                 isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
+                data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
         foreach(auto item, _collisionRenderItemsMap.keys()) {
-            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewVisibilityMask, isLayeredInFront,
+            transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
                                                                 isLayeredInHUD](ModelMeshPartPayload& data) {
-                data.setKey(isVisible, isLayeredInFront || isLayeredInHUD, viewVisibilityMask);
+                data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
                 data.setLayer(isLayeredInFront, isLayeredInHUD);
             });
         }
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index 1fa14f92d6..72527e1fde 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -86,7 +86,7 @@ public:
     const QUrl& getURL() const { return _url; }
 
     // new Scene/Engine rendering support
-    void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewVisiblityMask);
+    void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits);
     void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene);
     void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene);
     bool needsFixupInScene() const;
@@ -104,7 +104,7 @@ public:
     bool isRenderable() const;
 
     bool isVisible() const { return _isVisible; }
-    uint8_t getViewVisibilityMask() const { return _viewVisibilityMask; }
+    uint8_t getViewTagBits() const { return _viewTagBits; }
 
     bool isLayeredInFront() const { return _isLayeredInFront; }
     bool isLayeredInHUD() const { return _isLayeredInHUD; }
@@ -389,7 +389,7 @@ protected:
 
     QUrl _url;
     bool _isVisible;
-    uint8_t _viewVisibilityMask { render::ItemKey::TAG_BITS_ALL };
+    uint8_t _viewTagBits{ render::ItemKey::TAG_BITS_ALL };
 
     gpu::Buffers _blendedVertexBuffers;
 
diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp
index d83dfd73a5..20af1278ac 100644
--- a/libraries/render-utils/src/RenderShadowTask.cpp
+++ b/libraries/render-utils/src/RenderShadowTask.cpp
@@ -200,7 +200,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
     });
 }
 
-void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) {
+void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) {
     cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&) { return true; };
 
     // Prepare the ShapePipeline
@@ -259,6 +259,8 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
     // Cache old render args
     RenderArgs* args = renderContext->args;
 
+ //   const auto& filterMask = inputs;
+
     output.edit0() = args->_renderMode;
     output.edit2() = args->_sizeScale;
 
diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h
index d8d4c624e7..2bc325cc81 100644
--- a/libraries/render-utils/src/RenderShadowTask.h
+++ b/libraries/render-utils/src/RenderShadowTask.h
@@ -48,7 +48,7 @@ public:
     using JobModel = render::Task::Model<RenderShadowTask, Config>;
 
     RenderShadowTask() {}
-    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender);
+    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
 
     void configure(const Config& configuration);
 };
diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp
index 83868e1443..42d3044b1b 100644
--- a/libraries/render-utils/src/RenderViewTask.cpp
+++ b/libraries/render-utils/src/RenderViewTask.cpp
@@ -14,7 +14,7 @@
 #include "RenderDeferredTask.h"
 #include "RenderForwardTask.h"
 
-void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred, uint8_t visibilityMask, uint8_t visibilityMaskTouched) {
+void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits, uint8_t tagMask) {
    // auto items = input.get<Input>();
 
     // Shadows use an orthographic projection because they are linked to sunlights
@@ -30,7 +30,7 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render:
         return true;
     });
 
-    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, visibilityMask, visibilityMaskTouched);
+    const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, tagBits, tagMask);
     assert(items.canCast<RenderFetchCullSortTask::Output>());
 
     if (isDeferred) {
diff --git a/libraries/render-utils/src/RenderViewTask.h b/libraries/render-utils/src/RenderViewTask.h
index faace7349e..5da3d18474 100644
--- a/libraries/render-utils/src/RenderViewTask.h
+++ b/libraries/render-utils/src/RenderViewTask.h
@@ -23,7 +23,7 @@ public:
 
     RenderViewTask() {}
 
-    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred, uint8_t visibilityMask = 0xFF, uint8_t visibilityMaskTouched = 0x00);
+    void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
 
 };
 
diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp
index a402c3bc9d..bb6bd462f6 100644
--- a/libraries/render/src/render/RenderFetchCullSortTask.cpp
+++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp
@@ -40,15 +40,15 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
     const int META_BUCKET = 3;
     const int BACKGROUND_BUCKET = 2;
     MultiFilterItems<NUM_SPATIAL_FILTERS>::ItemFilterArray spatialFilters = { {
-            ItemFilter::Builder::opaqueShape().withVisible().withTagBits(tagBits, tagMask),
-            ItemFilter::Builder::transparentShape().withVisible().withTagBits(tagBits, tagMask),
-            ItemFilter::Builder::light().withVisible().withTagBits(tagBits, tagMask),
-            ItemFilter::Builder::meta().withVisible().withTagBits(tagBits, tagMask)
+            ItemFilter::Builder::opaqueShape(),
+            ItemFilter::Builder::transparentShape(),
+            ItemFilter::Builder::light(),
+            ItemFilter::Builder::meta()
         } };
     MultiFilterItems<NUM_NON_SPATIAL_FILTERS>::ItemFilterArray nonspatialFilters = { {
-            ItemFilter::Builder::opaqueShape().withVisible().withTagBits(tagBits, tagMask),
-            ItemFilter::Builder::transparentShape().withVisible().withTagBits(tagBits, tagMask),
-            ItemFilter::Builder::background().withVisible().withTagBits(tagBits, tagMask)
+            ItemFilter::Builder::opaqueShape(),
+            ItemFilter::Builder::transparentShape(),
+            ItemFilter::Builder::background()
         } };
     const auto filteredSpatialBuckets = 
         task.addJob<MultiFilterItems<NUM_SPATIAL_FILTERS>>("FilterSceneSelection", culledSpatialSelection, spatialFilters)

From 4cbfef55efc3c0861612eebbc70e444069b659a7 Mon Sep 17 00:00:00 2001
From: Olivier Prat <olivier@zvork.fr>
Date: Mon, 29 Jan 2018 10:33:16 +0100
Subject: [PATCH 23/57] Merged with master. Had to add back shaders and code

---
 .../render-utils/src/DeferredGlobalLight.slh  |   7 ++
 .../render-utils/src/RenderPipelines.cpp      |  22 ++--
 .../render-utils/src/model_translucent.slf    |   2 +-
 .../src/model_translucent_fade.slf            |   2 +-
 .../src/model_translucent_normal_map.slf      |  91 ++++++++++++++++
 .../src/model_translucent_normal_map.slv      |  46 ++++++++
 .../src/model_translucent_normal_map_fade.slf | 101 ++++++++++++++++++
 .../src/overlay3D_model_translucent.slf       |   2 +-
 .../src/simple_transparent_textured.slf       |   2 +-
 .../src/simple_transparent_textured_fade.slf  |   2 +-
 10 files changed, 264 insertions(+), 13 deletions(-)
 create mode 100644 libraries/render-utils/src/model_translucent_normal_map.slf
 create mode 100644 libraries/render-utils/src/model_translucent_normal_map.slv
 create mode 100644 libraries/render-utils/src/model_translucent_normal_map_fade.slf

diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh
index fae645fdbc..faf8641926 100644
--- a/libraries/render-utils/src/DeferredGlobalLight.slh
+++ b/libraries/render-utils/src/DeferredGlobalLight.slh
@@ -204,6 +204,13 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl
     return color;
 }
 
+<@endfunc@>
+
+<@func declareEvalGlobalLightingAlphaBlendedWithHaze()@>
+
+<$declareLightingAmbient(1, 1, 1)$>
+<$declareLightingDirectional()$>
+
 vec3 evalGlobalLightingAlphaBlendedWithHaze(
     mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, 
     vec3 albedo, vec3 fresnel, float metallic, vec3 emissive, float roughness, float opacity) 
diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp
index 1c828c3d06..900eacec12 100644
--- a/libraries/render-utils/src/RenderPipelines.cpp
+++ b/libraries/render-utils/src/RenderPipelines.cpp
@@ -31,6 +31,7 @@
 #include "model_lightmap_normal_map_fade_vert.h"
 #include "model_translucent_vert.h"
 #include "model_translucent_fade_vert.h"
+#include "model_translucent_normal_map_vert.h"
 #include "skin_model_fade_vert.h"
 #include "skin_model_normal_map_fade_vert.h"
 
@@ -73,12 +74,14 @@
 #include "model_lightmap_specular_map_frag.h"
 #include "model_translucent_frag.h"
 #include "model_translucent_unlit_frag.h"
+#include "model_translucent_normal_map_frag.h"
 
 #include "model_lightmap_fade_frag.h"
 #include "model_lightmap_normal_map_fade_frag.h"
 #include "model_lightmap_normal_specular_map_fade_frag.h"
 #include "model_lightmap_specular_map_fade_frag.h"
 #include "model_translucent_fade_frag.h"
+#include "model_translucent_normal_map_fade_frag.h"
 #include "model_translucent_unlit_fade_frag.h"
 
 #include "overlay3D_vert.h"
@@ -191,6 +194,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
     auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert));
     auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert));
     auto modelTranslucentVertex = gpu::Shader::createVertex(std::string(model_translucent_vert));
+    auto modelTranslucentNormalMapVertex = gpu::Shader::createVertex(std::string(model_translucent_normal_map_vert));
     auto modelTranslucentFadeVertex = gpu::Shader::createVertex(std::string(model_translucent_fade_vert));
     auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
     auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert));
@@ -220,6 +224,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
     auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag));
     auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag));
     auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag));
+    auto modelTranslucentNormalMapPixel = gpu::Shader::createPixel(std::string(model_translucent_normal_map_frag));
     auto modelTranslucentUnlitPixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_frag));
     auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));
     auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag));
@@ -238,6 +243,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
     auto modelNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_fade_frag));
     auto modelShadowFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag));
     auto modelTranslucentFadePixel = gpu::Shader::createPixel(std::string(model_translucent_fade_frag));
+    auto modelTranslucentNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_translucent_normal_map_fade_frag));
     auto modelTranslucentUnlitFadePixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_fade_frag));
     auto simpleFadePixel = gpu::Shader::createPixel(std::string(simple_textured_fade_frag));
     auto simpleUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag));
@@ -307,13 +313,13 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
         simpleVertex, simpleTranslucentUnlitPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withTangents(),
-        modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
+        modelTranslucentNormalMapVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withSpecular(),
         modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular(),
-        modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
+        modelTranslucentNormalMapVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
     addPipeline(
         // FIXME: Ignore lightmap for translucents meshpart
         Key::Builder().withMaterial().withTranslucent().withLightmap(),
@@ -333,13 +339,13 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
         simpleFadeVertex, simpleTranslucentUnlitFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withTangents().withFade(),
-        modelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
+        modelTranslucentNormalMapVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withSpecular().withFade(),
         modelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular().withFade(),
-        modelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
+        modelTranslucentNormalMapVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
     addPipeline(
         // FIXME: Ignore lightmap for translucents meshpart
         Key::Builder().withMaterial().withTranslucent().withLightmap().withFade(),
@@ -405,26 +411,26 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
         skinModelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents(),
-        skinModelNormalMapTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
+        skinModelNormalMapTranslucentVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular(),
         skinModelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(),
-        skinModelNormalMapTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
+        skinModelNormalMapTranslucentVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
     // Same thing but with Fade on
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withFade(),
         skinModelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withFade(),
-        skinModelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
+        skinModelNormalMapFadeVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular().withFade(),
         skinModelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
     addPipeline(
         Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular().withFade(),
-        skinModelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
+        skinModelNormalMapFadeVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
 
     // Depth-only
     addPipeline(
diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf
index 761e702595..67a5651ab8 100644
--- a/libraries/render-utils/src/model_translucent.slf
+++ b/libraries/render-utils/src/model_translucent.slf
@@ -16,7 +16,7 @@
 
 <@include DeferredGlobalLight.slh@>
 
-<$declareEvalGlobalLightingAlphaBlended()$>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
 
 <@include LightLocal.slh@>
 
diff --git a/libraries/render-utils/src/model_translucent_fade.slf b/libraries/render-utils/src/model_translucent_fade.slf
index a2d271653c..316dae7aad 100644
--- a/libraries/render-utils/src/model_translucent_fade.slf
+++ b/libraries/render-utils/src/model_translucent_fade.slf
@@ -16,7 +16,7 @@
 
 <@include DeferredGlobalLight.slh@>
 
-<$declareEvalGlobalLightingAlphaBlended()$>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
 
 <@include LightLocal.slh@>
 
diff --git a/libraries/render-utils/src/model_translucent_normal_map.slf b/libraries/render-utils/src/model_translucent_normal_map.slf
new file mode 100644
index 0000000000..759007d93e
--- /dev/null
+++ b/libraries/render-utils/src/model_translucent_normal_map.slf
@@ -0,0 +1,91 @@
+<@include gpu/Config.slh@>
+<$VERSION_HEADER$>
+//  Generated on <$_SCRIBE_DATE$>
+//
+//  model_translucent_normal_map.frag
+//  fragment shader
+//
+//  Created by Olivier Prat on 23/01/2018.
+//  Copyright 2018 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+<@include graphics/Material.slh@>
+
+<@include DeferredGlobalLight.slh@>
+
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
+
+<@include LightLocal.slh@>
+
+<@include gpu/Transform.slh@>
+<$declareStandardCameraTransform()$>
+
+<@include MaterialTextures.slh@>
+<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
+
+in vec2 _texCoord0;
+in vec2 _texCoord1;
+in vec4 _position;
+in vec4 _worldPosition;
+in vec3 _normal;
+in vec3 _tangent;
+in vec3 _color;
+in float _alpha;
+
+out vec4 _fragColor;
+
+void main(void) {
+    Material mat = getMaterial();
+    int matKey = getMaterialKey(mat);
+    <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex)$>
+    <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
+
+    float opacity = getMaterialOpacity(mat) * _alpha;
+    <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
+
+    vec3 albedo = getMaterialAlbedo(mat);
+    <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
+    albedo *= _color;
+
+    float roughness = getMaterialRoughness(mat);
+    <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
+
+    float metallic = getMaterialMetallic(mat);
+    vec3 fresnel = getFresnelF0(metallic, albedo);
+
+    vec3 emissive = getMaterialEmissive(mat);
+    <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
+
+    vec3 fragPosition = _position.xyz;
+    vec3 fragNormal;
+    <$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
+
+    TransformCamera cam = getTransformCamera();
+    vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));
+    vec3 fragEyeDir = normalize(fragEyeVector);
+    SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
+
+    vec4 localLighting = vec4(0.0);
+
+    <$fetchClusterInfo(_worldPosition)$>;
+    if (hasLocalLights(numLights, clusterPos, dims)) {
+        localLighting = evalLocalLighting(cluster, numLights, _worldPosition.xyz, surface,
+                                          metallic, fresnel, albedo, 0.0,
+                                          vec4(0), vec4(0), opacity);
+    }
+
+    _fragColor =  vec4(evalGlobalLightingAlphaBlendedWithHaze(
+        cam._viewInverse,
+        1.0,
+        occlusionTex,
+        fragPosition,
+        albedo,
+        fresnel,
+        metallic,
+        emissive,
+        surface, opacity, localLighting.rgb),
+        opacity);
+}
diff --git a/libraries/render-utils/src/model_translucent_normal_map.slv b/libraries/render-utils/src/model_translucent_normal_map.slv
new file mode 100644
index 0000000000..db824a3709
--- /dev/null
+++ b/libraries/render-utils/src/model_translucent_normal_map.slv
@@ -0,0 +1,46 @@
+<@include gpu/Config.slh@>
+<$VERSION_HEADER$>
+//  Generated on <$_SCRIBE_DATE$>
+//  model_translucent_normal_map.slv
+//  vertex shader
+//
+//  Created by Olivier Prat on 23/01/18.
+//  Copyright 2018 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+<@include gpu/Inputs.slh@>
+<@include gpu/Color.slh@>
+<@include gpu/Transform.slh@>
+<$declareStandardTransform()$>
+
+<@include MaterialTextures.slh@>
+<$declareMaterialTexMapArrayBuffer()$>
+
+out float _alpha;
+out vec2 _texCoord0;
+out vec2 _texCoord1;
+out vec4 _position;
+out vec4 _worldPosition;
+out vec3 _normal;
+out vec3 _tangent;
+out vec3 _color;
+
+void main(void) {
+    _color = colorToLinearRGB(inColor.xyz);
+    _alpha = inColor.w;
+
+    TexMapArray texMapArray = getTexMapArray();
+    <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
+    <$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
+
+    // standard transform
+    TransformCamera cam = getTransformCamera();
+    TransformObject obj = getTransformObject();
+    <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
+    <$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
+    <$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
+    <$transformModelToWorldDir(cam, obj, inTangent.xyz, _tangent)$>
+}
diff --git a/libraries/render-utils/src/model_translucent_normal_map_fade.slf b/libraries/render-utils/src/model_translucent_normal_map_fade.slf
new file mode 100644
index 0000000000..204b5ac56b
--- /dev/null
+++ b/libraries/render-utils/src/model_translucent_normal_map_fade.slf
@@ -0,0 +1,101 @@
+<@include gpu/Config.slh@>
+<$VERSION_HEADER$>
+//  Generated on <$_SCRIBE_DATE$>
+//
+//  model_translucent_normal_map_fade.frag
+//  fragment shader
+//
+//  Created by Olivier Prat on 23/01/18.
+//  Copyright 2018 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+<@include graphics/Material.slh@>
+
+<@include DeferredGlobalLight.slh@>
+
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
+
+<@include LightLocal.slh@>
+
+<@include gpu/Transform.slh@>
+<$declareStandardCameraTransform()$>
+
+<@include MaterialTextures.slh@>
+<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
+
+<@include Fade.slh@>
+<$declareFadeFragment()$>
+
+in vec2 _texCoord0;
+in vec2 _texCoord1;
+in vec4 _position;
+in vec3 _normal;
+in vec3 _tangent;
+in vec3 _color;
+in float _alpha;
+in vec4 _worldPosition;
+
+out vec4 _fragColor;
+
+void main(void) {
+    vec3 fadeEmissive;
+    FadeObjectParams fadeParams;
+
+    <$fetchFadeObjectParams(fadeParams)$>
+    applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
+
+    Material mat = getMaterial();
+    int matKey = getMaterialKey(mat);
+    <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex)$>
+    <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
+
+    float opacity = getMaterialOpacity(mat) * _alpha;
+    <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
+
+    vec3 albedo = getMaterialAlbedo(mat);
+    <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
+    albedo *= _color;
+
+    float roughness = getMaterialRoughness(mat);
+    <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
+
+    float metallic = getMaterialMetallic(mat);
+    vec3 fresnel = getFresnelF0(metallic, albedo);
+
+    vec3 emissive = getMaterialEmissive(mat);
+    <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
+
+    vec3 fragPosition = _position.xyz;
+    // Lighting is done in world space
+    vec3 fragNormal;
+    <$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
+
+    TransformCamera cam = getTransformCamera();
+    vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));
+    vec3 fragEyeDir = normalize(fragEyeVector);
+    SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
+
+    vec4 localLighting = vec4(0.0);
+
+    <$fetchClusterInfo(_worldPosition)$>;
+    if (hasLocalLights(numLights, clusterPos, dims)) {
+        localLighting = evalLocalLighting(cluster, numLights, _worldPosition.xyz, surface,
+                                          metallic, fresnel, albedo, 0.0,
+                                          vec4(0), vec4(0), opacity);
+    }
+
+    _fragColor =  vec4(evalGlobalLightingAlphaBlendedWithHaze(
+        cam._viewInverse,
+        1.0,
+        occlusionTex,
+        fragPosition,
+        albedo,
+        fresnel,
+        metallic,
+        emissive+fadeEmissive,
+        surface, opacity, localLighting.rgb),
+        opacity);
+}
diff --git a/libraries/render-utils/src/overlay3D_model_translucent.slf b/libraries/render-utils/src/overlay3D_model_translucent.slf
index 8dd3a81443..b66c114f4a 100644
--- a/libraries/render-utils/src/overlay3D_model_translucent.slf
+++ b/libraries/render-utils/src/overlay3D_model_translucent.slf
@@ -11,7 +11,7 @@
 //
 
 <@include DeferredGlobalLight.slh@>
-<$declareEvalGlobalLightingAlphaBlended()$>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
 
 <@include graphics/Material.slh@>
 
diff --git a/libraries/render-utils/src/simple_transparent_textured.slf b/libraries/render-utils/src/simple_transparent_textured.slf
index b16b19c8b4..30c420233f 100644
--- a/libraries/render-utils/src/simple_transparent_textured.slf
+++ b/libraries/render-utils/src/simple_transparent_textured.slf
@@ -16,7 +16,7 @@
 
 <@include DeferredBufferWrite.slh@>
 <@include DeferredGlobalLight.slh@>
-<$declareEvalGlobalLightingAlphaBlended()$>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
 
 <@include gpu/Transform.slh@>
 <$declareStandardCameraTransform()$>
diff --git a/libraries/render-utils/src/simple_transparent_textured_fade.slf b/libraries/render-utils/src/simple_transparent_textured_fade.slf
index ad260210a7..a8a5875a4b 100644
--- a/libraries/render-utils/src/simple_transparent_textured_fade.slf
+++ b/libraries/render-utils/src/simple_transparent_textured_fade.slf
@@ -16,7 +16,7 @@
 
 <@include DeferredBufferWrite.slh@>
 <@include DeferredGlobalLight.slh@>
-<$declareEvalGlobalLightingAlphaBlended()$>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
 
 <@include gpu/Transform.slh@>
 <$declareStandardCameraTransform()$>

From 1fd4c5c1a45199581e89e63a1b1ffb89cdbdfd65 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Mon, 29 Jan 2018 12:20:51 -0800
Subject: [PATCH 24/57] Integrating the tag flags to the render item key and
 adding configration of the render pipelien with the Tag information

---
 interface/src/SecondaryCamera.cpp                       | 2 +-
 libraries/render-utils/src/RenderShadowTask.cpp         | 6 ++----
 libraries/render-utils/src/RenderShadowTask.h           | 4 +++-
 libraries/render-utils/src/RenderViewTask.cpp           | 2 +-
 libraries/render/src/render/CullTask.cpp                | 6 ++++--
 libraries/render/src/render/CullTask.h                  | 4 ++--
 libraries/render/src/render/RenderFetchCullSortTask.cpp | 4 +++-
 7 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp
index 748f1595db..6b8e370689 100644
--- a/interface/src/SecondaryCamera.cpp
+++ b/interface/src/SecondaryCamera.cpp
@@ -20,7 +20,7 @@ using RenderArgsPointer = std::shared_ptr<RenderArgs>;
 
 void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
     
-    task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
+    task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
     const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
     assert(items.canCast<RenderFetchCullSortTask::Output>());
     if (!isDeferred) {
diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp
index 20af1278ac..19a3f4ed73 100644
--- a/libraries/render-utils/src/RenderShadowTask.cpp
+++ b/libraries/render-utils/src/RenderShadowTask.cpp
@@ -216,7 +216,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
     task.addJob<RenderShadowSetup>("ShadowSetup");
 
     for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) {
-        const auto setupOutput = task.addJob<RenderShadowCascadeSetup>("ShadowCascadeSetup", i);
+        const auto setupOutput = task.addJob<RenderShadowCascadeSetup>("ShadowCascadeSetup", i, tagBits, tagMask);
         const auto shadowFilter = setupOutput.getN<RenderShadowCascadeSetup::Outputs>(1);
 
         // CPU jobs:
@@ -259,14 +259,12 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
     // Cache old render args
     RenderArgs* args = renderContext->args;
 
- //   const auto& filterMask = inputs;
-
     output.edit0() = args->_renderMode;
     output.edit2() = args->_sizeScale;
 
     const auto globalShadow = lightStage->getCurrentKeyShadow();
     if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
-        output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
+        output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask);
 
         globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
 
diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h
index 2bc325cc81..33e0ad4daa 100644
--- a/libraries/render-utils/src/RenderShadowTask.h
+++ b/libraries/render-utils/src/RenderShadowTask.h
@@ -67,12 +67,14 @@ public:
     using Outputs = render::VaryingSet3<RenderArgs::RenderMode, render::ItemFilter, float>;
     using JobModel = render::Job::ModelO<RenderShadowCascadeSetup, Outputs>;
 
-    RenderShadowCascadeSetup(unsigned int cascadeIndex) : _cascadeIndex{ cascadeIndex } {}
+    RenderShadowCascadeSetup(unsigned int cascadeIndex, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00) : _cascadeIndex{ cascadeIndex }, _tagBits(tagBits), _tagMask(tagMask) {}
     void run(const render::RenderContextPointer& renderContext, Outputs& output);
 
 private:
 
     unsigned int _cascadeIndex;
+    uint8_t _tagBits{ 0x00 };
+    uint8_t _tagMask{ 0x00 };
 };
 
 class RenderShadowCascadeTeardown {
diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp
index 42d3044b1b..19924b4ddc 100644
--- a/libraries/render-utils/src/RenderViewTask.cpp
+++ b/libraries/render-utils/src/RenderViewTask.cpp
@@ -28,7 +28,7 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render:
         const auto threshold = 1e-3f;
         return relativeBoundRadius > threshold;
         return true;
-    });
+    }, tagBits, tagMask);
 
     const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, tagBits, tagMask);
     assert(items.canCast<RenderFetchCullSortTask::Output>());
diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp
index 70331cdb47..8d99c3e8f2 100644
--- a/libraries/render/src/render/CullTask.cpp
+++ b/libraries/render/src/render/CullTask.cpp
@@ -61,7 +61,7 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc
     details._rendered += (int)outItems.size();
 }
 
-void FetchNonspatialItems::run(const RenderContextPointer& renderContext, ItemBounds& outItems) {
+void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemBounds& outItems) {
     assert(renderContext->args);
     assert(renderContext->args->hasViewFrustum());
     auto& scene = renderContext->_scene;
@@ -72,7 +72,9 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, ItemBo
     outItems.reserve(items.size());
     for (auto& id : items) {
         auto& item = scene->getItem(id);
-        outItems.emplace_back(ItemBound(id, item.getBound()));
+        if (filter.test(item.getKey())) {
+            outItems.emplace_back(ItemBound(id, item.getBound()));
+        }
     }
 }
 
diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h
index 486c4f4cdf..4461537109 100644
--- a/libraries/render/src/render/CullTask.h
+++ b/libraries/render/src/render/CullTask.h
@@ -24,8 +24,8 @@ namespace render {
 
     class FetchNonspatialItems {
     public:
-        using JobModel = Job::ModelO<FetchNonspatialItems, ItemBounds>;
-        void run(const RenderContextPointer& renderContext, ItemBounds& outItems);
+        using JobModel = Job::ModelIO<FetchNonspatialItems, ItemFilter, ItemBounds>;
+        void run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemBounds& outItems);
     };
 
     class FetchSpatialTreeConfig : public Job::Config {
diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp
index bb6bd462f6..7f60d5bb52 100644
--- a/libraries/render/src/render/RenderFetchCullSortTask.cpp
+++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp
@@ -29,7 +29,9 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
     const auto culledSpatialSelection = task.addJob<CullSpatialSelection>("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM);
 
     // Overlays are not culled
-    const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchOverlaySelection");
+    const ItemFilter overlayfilter = ItemFilter::Builder().withVisible().withTagBits(tagBits, tagMask);
+    const auto nonspatialFilter = render::Varying(overlayfilter);
+    const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchOverlaySelection", nonspatialFilter);
 
     // Multi filter visible items into different buckets
     const int NUM_SPATIAL_FILTERS = 4; 

From 2dcedf9f3901dac39067d6bf6aedad9b4ead28df Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Tue, 30 Jan 2018 12:52:05 -0800
Subject: [PATCH 25/57] cherry picking Tony's fix for shader compilation time
 not taking soo long and adding better feedback from shader compilation

---
 interface/src/Application.cpp                 |  23 ++-
 libraries/gl/src/gl/GLShaders.cpp             | 161 +++++++++++-------
 libraries/gl/src/gl/GLShaders.h               |   6 +-
 libraries/gpu-gl/src/gpu/gl/GLBackend.h       |   4 +-
 .../gpu-gl/src/gpu/gl/GLBackendShader.cpp     |  44 +++--
 libraries/gpu-gl/src/gpu/gl/GLShader.cpp      |   8 +-
 libraries/gpu-gl/src/gpu/gl/GLShader.h        |   4 +-
 libraries/gpu-gles/src/gpu/gl/GLBackend.h     |   4 +-
 .../gpu-gles/src/gpu/gl/GLBackendShader.cpp   |  65 ++++++-
 libraries/gpu-gles/src/gpu/gl/GLShader.cpp    |   8 +-
 libraries/gpu-gles/src/gpu/gl/GLShader.h      |   4 +-
 libraries/gpu/src/gpu/Context.cpp             |   4 +-
 libraries/gpu/src/gpu/Context.h               |   4 +-
 libraries/gpu/src/gpu/Shader.cpp              |  11 +-
 libraries/gpu/src/gpu/Shader.h                |  29 +++-
 libraries/render/src/render/ShapePipeline.cpp |  52 +++---
 16 files changed, 297 insertions(+), 134 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 64e9feea02..f1d0378792 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -396,6 +396,7 @@ public:
         setObjectName("Deadlock Watchdog");
         // Give the heartbeat an initial value
         _heartbeat = usecTimestampNow();
+        _paused = false;
         connect(qApp, &QCoreApplication::aboutToQuit, [this] {
             _quit = true;
         });
@@ -413,11 +414,20 @@ public:
         *crashTrigger = 0xDEAD10CC;
     }
 
+    static void pause() {
+        _paused = true;
+    }
+
+    static void resume() {
+        _paused = false;
+        updateHeartbeat();
+    }
+
     void run() override {
         while (!_quit) {
             QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
             // Don't do heartbeat detection under nsight
-            if (nsightActive()) {
+            if (nsightActive() || _paused) {
                 continue;
             }
             uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us
@@ -473,6 +483,7 @@ public:
         }
     }
 
+    static std::atomic<bool> _paused;
     static std::atomic<uint64_t> _heartbeat;
     static std::atomic<uint64_t> _maxElapsed;
     static std::atomic<int> _maxElapsedAverage;
@@ -481,6 +492,7 @@ public:
     bool _quit { false };
 };
 
+std::atomic<bool> DeadlockWatchdogThread::_paused;
 std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;
 std::atomic<uint64_t> DeadlockWatchdogThread::_maxElapsed;
 std::atomic<int> DeadlockWatchdogThread::_maxElapsedAverage;
@@ -2269,6 +2281,11 @@ void Application::initializeGL() {
     initDisplay();
     qCDebug(interfaceapp, "Initialized Display.");
 
+#ifdef Q_OS_OSX
+    // FIXME: on mac os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread.
+    +DeadlockWatchdogThread::pause();
+#endif
+
     // Set up the render engine
     render::CullFunctor cullFunctor = LODManager::shouldRender;
     static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
@@ -2283,6 +2300,10 @@ void Application::initializeGL() {
     // Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
     DependencyManager::get<GeometryCache>()->initializeShapePipelines();
 
+#ifdef Q_OS_OSX
+    DeadlockWatchdogThread::resume();
+#endif
+
     _offscreenContext = new OffscreenGLCanvas();
     _offscreenContext->setObjectName("MainThreadContext");
     _offscreenContext->create(_glWidget->qglContext());
diff --git a/libraries/gl/src/gl/GLShaders.cpp b/libraries/gl/src/gl/GLShaders.cpp
index 017c92b71c..ecd6fe3323 100644
--- a/libraries/gl/src/gl/GLShaders.cpp
+++ b/libraries/gl/src/gl/GLShaders.cpp
@@ -6,9 +6,9 @@ namespace gl {
 
 
 #ifdef SEPARATE_PROGRAM
-    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& error) {
+    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& message) {
 #else
-    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& error) {
+    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& message) {
 #endif
     if (shaderSource.empty()) {
         qCDebug(glLogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
@@ -34,52 +34,57 @@ namespace gl {
     GLint compiled = 0;
     glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled);
 
-    // if compilation fails
-    if (!compiled) {
-
-        // save the source code to a temp file so we can debug easily
-        /*
-        std::ofstream filestream;
-        filestream.open("debugshader.glsl");
-        if (filestream.is_open()) {
-        filestream << srcstr[0];
-        filestream << srcstr[1];
-        filestream.close();
-        }
-        */
-
-        GLint infoLength = 0;
-        glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
+    GLint infoLength = 0;
+    glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
 
+    if ((infoLength > 0) || !compiled) {
         char* temp = new char[infoLength];
         glGetShaderInfoLog(glshader, infoLength, NULL, temp);
 
+        message = std::string(temp);
 
-        /*
-        filestream.open("debugshader.glsl.info.txt");
-        if (filestream.is_open()) {
-        filestream << std::string(temp);
-        filestream.close();
-        }
-        */
-
-        qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
-        int lineNumber = 0;
-        for (auto s : srcstr) {
-            QString str(s);
-            QStringList lines = str.split("\n");
-            for (auto& line : lines) {
-                qCCritical(glLogging).noquote() << QString("%1: %2").arg(lineNumber++, 5, 10, QChar('0')).arg(line);
+        // if compilation fails
+        if (!compiled) {
+            // save the source code to a temp file so we can debug easily
+            /*
+            std::ofstream filestream;
+            filestream.open("debugshader.glsl");
+            if (filestream.is_open()) {
+            filestream << srcstr[0];
+            filestream << srcstr[1];
+            filestream.close();
             }
+            */
+
+            /*
+            filestream.open("debugshader.glsl.info.txt");
+            if (filestream.is_open()) {
+            filestream << std::string(temp);
+            filestream.close();
+            }
+            */
+
+            qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
+            int lineNumber = 0;
+            for (auto s : srcstr) {
+                QString str(s);
+                QStringList lines = str.split("\n");
+                for (auto& line : lines) {
+                    qCCritical(glLogging).noquote() << QString("%1: %2").arg(lineNumber++, 5, 10, QChar('0')).arg(line);
+                }
+            }
+            qCCritical(glLogging) << "GLShader::compileShader - errors:";
+            qCCritical(glLogging) << temp;
+
+            delete[] temp;
+            glDeleteShader(glshader);
+            return false;
         }
-        qCCritical(glLogging) << "GLShader::compileShader - errors:";
-        qCCritical(glLogging) << temp;
 
-        error = std::string(temp);
+        // Compilation success
+        qCWarning(glLogging) << "GLShader::compileShader - Success:";
+        qCWarning(glLogging) << temp;
         delete[] temp;
-
-        glDeleteShader(glshader);
-        return false;
     }
 
 #ifdef SEPARATE_PROGRAM
@@ -137,7 +142,7 @@ namespace gl {
     return true;
 }
 
-GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error) {
+GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message, std::vector<GLchar>& binary) {
     // A brand new program:
     GLuint glprogram = glCreateProgram();
     if (!glprogram) {
@@ -157,39 +162,65 @@ GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error)
     GLint linked = 0;
     glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
 
-    if (!linked) {
-        /*
-        // save the source code to a temp file so we can debug easily
-        std::ofstream filestream;
-        filestream.open("debugshader.glsl");
-        if (filestream.is_open()) {
-        filestream << shaderSource->source;
-        filestream.close();
-        }
-        */
-
-        GLint infoLength = 0;
-        glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
+    GLint infoLength = 0;
+    glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
 
+    if ((infoLength > 0) || !linked) {
         char* temp = new char[infoLength];
         glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
 
-        qCDebug(glLogging) << "GLShader::compileProgram -  failed to LINK the gl program object :";
-        qCDebug(glLogging) << temp;
+        message = std::string(temp);
 
-        error = std::string(temp);
-        delete[] temp;
+        if (!linked) {
+            /*
+            // save the source code to a temp file so we can debug easily
+            std::ofstream filestream;
+            filestream.open("debugshader.glsl");
+            if (filestream.is_open()) {
+            filestream << shaderSource->source;
+            filestream.close();
+            }
+            */
 
-        /*
-        filestream.open("debugshader.glsl.info.txt");
-        if (filestream.is_open()) {
-        filestream << std::string(temp);
-        filestream.close();
+            qCDebug(glLogging) << "GLShader::compileProgram -  failed to LINK the gl program object :";
+            qCDebug(glLogging) << temp;
+
+            delete[] temp;
+
+            /*
+            filestream.open("debugshader.glsl.info.txt");
+            if (filestream.is_open()) {
+            filestream << std::string(temp);
+            filestream.close();
+            }
+            */
+
+            glDeleteProgram(glprogram);
+            return 0;
+        } else {
+            qCDebug(glLogging) << "GLShader::compileProgram -  success:";
+            qCDebug(glLogging) << temp;
+            delete[] temp;
         }
-        */
+    }
 
-        glDeleteProgram(glprogram);
-        return 0;
+    // If linked get the binaries
+    if (linked) {
+        GLint binaryLength = 0;
+        glGetProgramiv(glprogram, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
+
+        if (binaryLength > 0) {
+            GLint numBinFormats = 0;
+            glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinFormats);
+            if (numBinFormats > 0) {
+                binary.resize(binaryLength);
+                std::vector<GLint> binFormats(numBinFormats);
+                glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, binFormats.data());
+
+                GLenum programBinFormat;
+                glGetProgramBinary(glprogram, binaryLength, NULL, &programBinFormat, binary.data());
+            }
+        }
     }
 
     return glprogram;
diff --git a/libraries/gl/src/gl/GLShaders.h b/libraries/gl/src/gl/GLShaders.h
index a6213fd280..c5262b6b61 100644
--- a/libraries/gl/src/gl/GLShaders.h
+++ b/libraries/gl/src/gl/GLShaders.h
@@ -17,12 +17,12 @@
 
 namespace gl {
 #ifdef SEPARATE_PROGRAM
-    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& error);
+    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& message);
 #else
-    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& error);
+    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& message);
 #endif
 
-    GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error);
+    GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message, , std::vector<GLchar>& binary);
 
 }
 
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h
index 5558d3ada1..004bfe1c85 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h
@@ -64,7 +64,7 @@ protected:
     explicit GLBackend(bool syncCache);
     GLBackend();
 public:
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet());
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet(), Shader::CompilationHandler handler = nullptr);
 
     virtual ~GLBackend();
 
@@ -424,7 +424,7 @@ protected:
 
     // Backend dependant compilation of the shader
     virtual GLShader* compileBackendProgram(const Shader& program);
-    virtual GLShader* compileBackendShader(const Shader& shader);
+    virtual GLShader* compileBackendShader(const Shader& shader, Shader::CompilationHandler handler);
     virtual std::string getBackendShaderHeader() const;
     virtual void makeProgramBindings(ShaderObject& shaderObject);
     class ElementResource {
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
index 9adfd550ef..84170dbffd 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
@@ -56,28 +56,43 @@ static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
     stereoVersion
 } };
 
-GLShader* GLBackend::compileBackendShader(const Shader& shader) {
+GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::CompilationHandler handler) {
     // Any GLSLprogram ? normally yes...
     const std::string& shaderSource = shader.getSource().getCode();
     GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
     GLShader::ShaderObjects shaderObjects;
+    Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
 
     for (int version = 0; version < GLShader::NumVersions; version++) {
         auto& shaderObject = shaderObjects[version];
 
         std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version];
-        std::string error;
+        if (handler) {
+            bool retest = true;
+            std::string currentSrc = shaderSource;
+            while (retest) {
+                bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
+                compilationLogs[version].compiled = result;
+                if (!result) {
+                    std::string newSrc;
+                    retest = handler(shader, currentSrc, compilationLogs[version], newSrc);
+                    currentSrc = newSrc;
+                } else {
+                    retest = false;
+                }
+            }
+        } else {
+            compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
+        }
 
-#ifdef SEPARATE_PROGRAM
-        bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram, error);
-#else
-        bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, error);
-#endif
-        if (!result) {
-            qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << error.c_str();
+         if (!compilationLogs[version].compiled) {
+            qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str();
+            shader.setCompilationLogs(compilationLogs);
             return nullptr;
         }
     }
+    // Compilation feedback
+    shader.setCompilationLogs(compilationLogs);
 
     // So far so good, the shader is created successfully
     GLShader* object = new GLShader(this->shared_from_this());
@@ -93,6 +108,8 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program) {
 
     GLShader::ShaderObjects programObjects;
 
+    Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
+
     for (int version = 0; version < GLShader::NumVersions; version++) {
         auto& programObject = programObjects[version];
 
@@ -104,14 +121,15 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program) {
                 shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
             } else {
                 qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?";
+                program.setCompilationLogs(compilationLogs);
                 return nullptr;
             }
         }
 
-        std::string error;
-        GLuint glprogram = ::gl::compileProgram(shaderGLObjects, error);
+        GLuint glprogram = ::gl::compileProgram(shaderGLObjects, compilationLogs[version].message, compilationLogs[version].binary);
         if (glprogram == 0) {
-            qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << error.c_str();
+            qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str(); 
+            program.setCompilationLogs(compilationLogs);
             return nullptr;
         }
 
@@ -119,6 +137,8 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program) {
 
         makeProgramBindings(programObject);
     }
+    // Compilation feedback
+    program.setCompilationLogs(compilationLogs);
 
     // So far so good, the program versions have all been created successfully
     GLShader* object = new GLShader(this->shared_from_this());
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
index 7ed9121978..a626376e27 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
@@ -30,7 +30,7 @@ GLShader::~GLShader() {
     }
 }
 
-GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
+GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, Shader::CompilationHandler handler) {
     GLShader* object = Backend::getGPUObject<GLShader>(shader);
 
     // If GPU object already created then good
@@ -45,7 +45,7 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
             Backend::setGPUObject(shader, object);
         }
     } else if (shader.isDomain()) {
-        GLShader* tempObject = backend.compileBackendShader(shader);
+        GLShader* tempObject = backend.compileBackendShader(shader, handler);
         if (tempObject) {
             object = tempObject;
             Backend::setGPUObject(shader, object);
@@ -56,10 +56,10 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
     return object;
 }
 
-bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings) {
+bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler) {
 
     // First make sure the Shader has been compiled
-    GLShader* object = sync(backend, shader);
+    GLShader* object = sync(backend, shader, handler);
     if (!object) {
         return false;
     }
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h
index dcf2dc330d..42d63f8dfb 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShader.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h
@@ -21,8 +21,8 @@ struct ShaderObject {
 
 class GLShader : public GPUObject {
 public:
-    static GLShader* sync(GLBackend& backend, const Shader& shader);
-    static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings);
+    static GLShader* sync(GLBackend& backend, const Shader& shader, Shader::CompilationHandler handler = nullptr);
+    static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler = nullptr);
 
     enum Version {
         Mono = 0,
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackend.h b/libraries/gpu-gles/src/gpu/gl/GLBackend.h
index ea06b6b672..bb8e15bad3 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackend.h
@@ -61,7 +61,7 @@ protected:
     explicit GLBackend(bool syncCache);
     GLBackend();
 public:
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet());
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet(), Shader::CompilationHandler handler = nullptr);
 
     virtual ~GLBackend();
 
@@ -421,7 +421,7 @@ protected:
 
     // Backend dependant compilation of the shader
     virtual GLShader* compileBackendProgram(const Shader& program);
-    virtual GLShader* compileBackendShader(const Shader& shader);
+    virtual GLShader* compileBackendShader(const Shader& shader, Shader::CompilationHandler handler);
     virtual std::string getBackendShaderHeader() const;
     virtual void makeProgramBindings(ShaderObject& shaderObject);
     class ElementResource {
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
index fd44ad462f..26dbb12cf7 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
@@ -56,11 +56,12 @@ static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
     stereoVersion
 } };
 
-GLShader* GLBackend::compileBackendShader(const Shader& shader) {
+GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::CompilationHandler handler) {
     // Any GLSLprogram ? normally yes...
     const std::string& shaderSource = shader.getSource().getCode();
     GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
     GLShader::ShaderObjects shaderObjects;
+    Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
 
     for (int version = 0; version < GLShader::NumVersions; version++) {
         auto& shaderObject = shaderObjects[version];
@@ -90,6 +91,55 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader) {
     return object;
 }
 
+GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::CompilationHandler handler) {
+    // Any GLSLprogram ? normally yes...
+    const std::string& shaderSource = shader.getSource().getCode();
+    GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
+    GLShader::ShaderObjects shaderObjects;
+    Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
+
+    for (int version = 0; version < GLShader::NumVersions; version++) {
+        auto& shaderObject = shaderObjects[version];
+
+        std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version]
+            + "\n#extension GL_EXT_texture_buffer : enable"
+            + "\nprecision lowp float; // check precision 2"
+            + "\nprecision lowp samplerBuffer;"
+            + "\nprecision lowp sampler2DShadow;";
+        if (handler) {
+            bool retest = true;
+            std::string currentSrc = shaderSource;
+            while (retest) {
+                bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
+                compilationLogs[version].compiled = result;
+                if (!result) {
+                    std::string newSrc;
+                    retest = handler(shader, currentSrc, compilationLogs[version], newSrc);
+                    currentSrc = newSrc;
+                } else {
+                    retest = false;
+                }
+            }
+        } else {
+            compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
+        }
+
+         if (!compilationLogs[version].compiled) {
+            qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str();
+            shader.setCompilationLogs(compilationLogs);
+            return nullptr;
+        }
+    }
+    // Compilation feedback
+    shader.setCompilationLogs(compilationLogs);
+
+    // So far so good, the shader is created successfully
+    GLShader* object = new GLShader(this->shared_from_this());
+    object->_shaderObjects = shaderObjects;
+
+    return object;
+}
+
 GLShader* GLBackend::compileBackendProgram(const Shader& program) {
     if (!program.isProgram()) {
         return nullptr;
@@ -97,25 +147,28 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program) {
 
     GLShader::ShaderObjects programObjects;
 
+    Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
+
     for (int version = 0; version < GLShader::NumVersions; version++) {
         auto& programObject = programObjects[version];
 
         // Let's go through every shaders and make sure they are ready to go
-        std::vector<GLuint> shaderGLObjects;
+        std::vector< GLuint > shaderGLObjects;
         for (auto subShader : program.getShaders()) {
             auto object = GLShader::sync((*this), *subShader);
             if (object) {
                 shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
             } else {
                 qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?";
+                program.setCompilationLogs(compilationLogs);
                 return nullptr;
             }
         }
 
-        std::string error;
-        GLuint glprogram = ::gl::compileProgram(shaderGLObjects, error);
+        GLuint glprogram = ::gl::compileProgram(shaderGLObjects, compilationLogs[version].message, compilationLogs[version].binary);
         if (glprogram == 0) {
-            qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << error.c_str();
+            qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str(); 
+            program.setCompilationLogs(compilationLogs);
             return nullptr;
         }
 
@@ -123,6 +176,8 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program) {
 
         makeProgramBindings(programObject);
     }
+    // Compilation feedback
+    program.setCompilationLogs(compilationLogs);
 
     // So far so good, the program versions have all been created successfully
     GLShader* object = new GLShader(this->shared_from_this());
diff --git a/libraries/gpu-gles/src/gpu/gl/GLShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
index 7ed9121978..a626376e27 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
@@ -30,7 +30,7 @@ GLShader::~GLShader() {
     }
 }
 
-GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
+GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, Shader::CompilationHandler handler) {
     GLShader* object = Backend::getGPUObject<GLShader>(shader);
 
     // If GPU object already created then good
@@ -45,7 +45,7 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
             Backend::setGPUObject(shader, object);
         }
     } else if (shader.isDomain()) {
-        GLShader* tempObject = backend.compileBackendShader(shader);
+        GLShader* tempObject = backend.compileBackendShader(shader, handler);
         if (tempObject) {
             object = tempObject;
             Backend::setGPUObject(shader, object);
@@ -56,10 +56,10 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
     return object;
 }
 
-bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings) {
+bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler) {
 
     // First make sure the Shader has been compiled
-    GLShader* object = sync(backend, shader);
+    GLShader* object = sync(backend, shader, handler);
     if (!object) {
         return false;
     }
diff --git a/libraries/gpu-gles/src/gpu/gl/GLShader.h b/libraries/gpu-gles/src/gpu/gl/GLShader.h
index dcf2dc330d..42d63f8dfb 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLShader.h
+++ b/libraries/gpu-gles/src/gpu/gl/GLShader.h
@@ -21,8 +21,8 @@ struct ShaderObject {
 
 class GLShader : public GPUObject {
 public:
-    static GLShader* sync(GLBackend& backend, const Shader& shader);
-    static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings);
+    static GLShader* sync(GLBackend& backend, const Shader& shader, Shader::CompilationHandler handler = nullptr);
+    static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler = nullptr);
 
     enum Version {
         Mono = 0,
diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp
index 24128524da..2399d3ddc3 100644
--- a/libraries/gpu/src/gpu/Context.cpp
+++ b/libraries/gpu/src/gpu/Context.cpp
@@ -127,7 +127,7 @@ void Context::executeFrame(const FramePointer& frame) const {
     _frameStats.evalDelta(beginStats, endStats);
 }
 
-bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
+bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings, Shader::CompilationHandler handler) {
     // If we're running in another DLL context, we need to fetch the program callback out of the application
     // FIXME find a way to do this without reliance on Qt app properties
     if (!_makeProgramCallback) {
@@ -135,7 +135,7 @@ bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
         _makeProgramCallback = reinterpret_cast<Context::MakeProgram>(rawCallback);
     }
     if (shader.isProgram() && _makeProgramCallback) {
-        return _makeProgramCallback(shader, bindings);
+        return _makeProgramCallback(shader, bindings, handler);
     }
     return false;
 }
diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h
index 7b7575e9ed..7d04463609 100644
--- a/libraries/gpu/src/gpu/Context.h
+++ b/libraries/gpu/src/gpu/Context.h
@@ -143,7 +143,7 @@ class Context {
 public:
     using Size = Resource::Size;
     typedef BackendPointer (*CreateBackend)();
-    typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings);
+    typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings, Shader::CompilationHandler handler);
 
 
     // This one call must happen before any context is created or used (Shader::MakeProgram) in order to setup the Backend and any singleton data needed
@@ -262,7 +262,7 @@ protected:
     // makeProgramShader(...) make a program shader ready to be used in a Batch.
     // It compiles the sub shaders, link them and defines the Slots and their bindings.
     // If the shader passed is not a program, nothing happens. 
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings);
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings, Shader::CompilationHandler handler = nullptr);
 
     static CreateBackend _createBackendCallback;
     static MakeProgram _makeProgramCallback;
diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp
index 398a269f3f..35c9ad8ae2 100755
--- a/libraries/gpu/src/gpu/Shader.cpp
+++ b/libraries/gpu/src/gpu/Shader.cpp
@@ -82,9 +82,16 @@ void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers,
     _outputs = outputs;
 }
 
-bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
+bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings, CompilationHandler handler) {
     if (shader.isProgram()) {
-        return Context::makeProgram(shader, bindings);
+        return Context::makeProgram(shader, bindings, handler);
     }
     return false;
 }
+
+void Shader::setCompilationLogs(const CompilationLogs& logs) const {
+    _compilationLogs.clear();
+    for (const auto& log : logs) {
+        _compilationLogs.emplace_back(CompilationLog(log));
+    }
+}
diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h
index 181c9b5e78..33449fe656 100755
--- a/libraries/gpu/src/gpu/Shader.h
+++ b/libraries/gpu/src/gpu/Shader.h
@@ -44,6 +44,19 @@ public:
         Language _lang = GLSL;
     };
 
+    struct CompilationLog {
+        std::string message;
+        std::vector<char> binary;
+        bool compiled{ false };
+
+        CompilationLog() {}
+        CompilationLog(const CompilationLog& src) :
+            message(src.message),
+            binary(src.binary),
+            compiled(src.compiled) {}
+    };
+    using CompilationLogs = std::vector<CompilationLog>;
+
     static const int32 INVALID_LOCATION = -1;
 
     class Slot {
@@ -155,6 +168,8 @@ public:
                      const SlotSet& inputs,
                      const SlotSet& outputs);
 
+    typedef bool(*CompilationHandler)(const Shader& shader, const std::string& src, CompilationLog& log, std::string& newSrc);
+
     // makeProgram(...) make a program shader ready to be used in a Batch.
     // It compiles the sub shaders, link them and defines the Slots and their bindings.
     // If the shader passed is not a program, nothing happens. 
@@ -168,7 +183,16 @@ public:
     // on a gl Context and the driver to compile the glsl shader. 
     // Hoppefully in a few years the shader compilation will be completely abstracted in a separate shader compiler library
     // independant of the graphics api in use underneath (looking at you opengl & vulkan).
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet(), CompilationHandler handler = nullptr);
+
+    // Check the compilation state
+    bool compilationHasFailed() const { return _compilationHasFailed; }
+    const CompilationLogs& getCompilationLogs() const { return _compilationLogs; }
+
+    // Set COmpilation logs can only be called by the Backend layers
+    void setCompilationHasFailed(bool compilationHasFailed) { _compilationHasFailed = compilationHasFailed; }
+    void setCompilationLogs(const CompilationLogs& logs) const;
+
 
     const GPUObjectPointer gpuObject {};
     
@@ -198,6 +222,9 @@ protected:
     // The type of the shader, the master key
     Type _type;
 
+    // Compilation logs (one for each versions generated)
+    mutable CompilationLogs _compilationLogs;
+
     // Whether or not the shader compilation failed
     bool _compilationHasFailed { false };
 };
diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp
index fb58c21dde..597a6a0fab 100644
--- a/libraries/render/src/render/ShapePipeline.cpp
+++ b/libraries/render/src/render/ShapePipeline.cpp
@@ -72,34 +72,36 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
         BatchSetter batchSetter, ItemSetter itemSetter) {
     ShapeKey key{ filter._flags };
 
-    gpu::Shader::BindingSet slotBindings;
-    slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
-    slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::BUFFER::SKINNING));
-    slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::BUFFER::MATERIAL));
-    slotBindings.insert(gpu::Shader::Binding(std::string("texMapArrayBuffer"), Slot::BUFFER::TEXMAPARRAY));
-    slotBindings.insert(gpu::Shader::Binding(std::string("albedoMap"), Slot::MAP::ALBEDO));
-    slotBindings.insert(gpu::Shader::Binding(std::string("roughnessMap"), Slot::MAP::ROUGHNESS));
-    slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::MAP::NORMAL));
-    slotBindings.insert(gpu::Shader::Binding(std::string("metallicMap"), Slot::MAP::METALLIC));
-    slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::MAP::EMISSIVE_LIGHTMAP));
-    slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), Slot::MAP::OCCLUSION));
-    slotBindings.insert(gpu::Shader::Binding(std::string("scatteringMap"), Slot::MAP::SCATTERING));
-    slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), Slot::BUFFER::KEY_LIGHT));
-    slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::BUFFER::LIGHT));
-    slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER));
-    slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
-    slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK));
-    slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
-    slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), Slot::BUFFER::HAZE_MODEL));
+    if (program->getInputs().empty()) {
+        gpu::Shader::BindingSet slotBindings;
+        slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
+        slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::BUFFER::SKINNING));
+        slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::BUFFER::MATERIAL));
+        slotBindings.insert(gpu::Shader::Binding(std::string("texMapArrayBuffer"), Slot::BUFFER::TEXMAPARRAY));
+        slotBindings.insert(gpu::Shader::Binding(std::string("albedoMap"), Slot::MAP::ALBEDO));
+        slotBindings.insert(gpu::Shader::Binding(std::string("roughnessMap"), Slot::MAP::ROUGHNESS));
+        slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::MAP::NORMAL));
+        slotBindings.insert(gpu::Shader::Binding(std::string("metallicMap"), Slot::MAP::METALLIC));
+        slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::MAP::EMISSIVE_LIGHTMAP));
+        slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), Slot::MAP::OCCLUSION));
+        slotBindings.insert(gpu::Shader::Binding(std::string("scatteringMap"), Slot::MAP::SCATTERING));
+        slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), Slot::BUFFER::KEY_LIGHT));
+        slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::BUFFER::LIGHT));
+        slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER));
+        slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
+        slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK));
+        slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
+        slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), Slot::BUFFER::HAZE_MODEL));
 
-    if (key.isTranslucent()) {
-        slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT));
-        slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT));
-        slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT));
+        if (key.isTranslucent()) {
+            slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT));
+            slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT));
+            slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT));
+        }
+
+        gpu::Shader::makeProgram(*program, slotBindings);
     }
 
-    gpu::Shader::makeProgram(*program, slotBindings);
-
     auto locations = std::make_shared<Locations>();
 
     locations->albedoTextureUnit = program->getTextures().findLocation("albedoMap");

From d5e52834ef7873270e28d0b86785d34a0679a642 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Tue, 30 Jan 2018 13:07:20 -0800
Subject: [PATCH 26/57] cherry picking Tony's fix for shader compilation time
 not taking soo long and adding better feedback from shader compilation

---
 libraries/gl/src/gl/GLShaders.h             | 2 +-
 libraries/gpu-gl/src/gpu/gl/GLBackend.cpp   | 4 ++--
 libraries/gpu-gles/src/gpu/gl/GLBackend.cpp | 4 ++--
 libraries/gpu/src/gpu/Shader.h              | 3 ---
 4 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/libraries/gl/src/gl/GLShaders.h b/libraries/gl/src/gl/GLShaders.h
index c5262b6b61..fc070d7659 100644
--- a/libraries/gl/src/gl/GLShaders.h
+++ b/libraries/gl/src/gl/GLShaders.h
@@ -22,7 +22,7 @@ namespace gl {
     bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& message);
 #endif
 
-    GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message, , std::vector<GLchar>& binary);
+    GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message, std::vector<GLchar>& binary);
 
 }
 
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
index eb6de5df13..2a052c5210 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
@@ -68,8 +68,8 @@ GLBackend& getBackend() {
     return *INSTANCE;
 }
 
-bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
-    return GLShader::makeProgram(getBackend(), shader, slotBindings);
+bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler) {
+    return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
 }
 
 GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = 
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp
index 6fd5df6f81..8a118b7b71 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp
@@ -61,8 +61,8 @@ GLBackend& getBackend() {
     return *INSTANCE;
 }
 
-bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
-    return GLShader::makeProgram(getBackend(), shader, slotBindings);
+bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler) {
+    return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
 }
 
 
diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h
index 33449fe656..d78077a396 100755
--- a/libraries/gpu/src/gpu/Shader.h
+++ b/libraries/gpu/src/gpu/Shader.h
@@ -138,9 +138,6 @@ public:
     bool isProgram() const { return getType() > NUM_DOMAINS; }
     bool isDomain() const { return getType() < NUM_DOMAINS; }
 
-    void setCompilationHasFailed(bool compilationHasFailed) { _compilationHasFailed = compilationHasFailed; }
-    bool compilationHasFailed() const { return _compilationHasFailed; }
-
     const Source& getSource() const { return _source; }
 
     const Shaders& getShaders() const { return _shaders; }

From f078ff611a4b19ac779d6e3926b09db4ec3ad4fc Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Tue, 30 Jan 2018 15:10:52 -0800
Subject: [PATCH 27/57] Refining the declaraion signatures and adding the
 binary capture

---
 .../src/display-plugins/hmd/HmdDisplayPlugin.cpp          | 3 ++-
 libraries/gpu-gl/src/gpu/gl/GLBackend.h                   | 4 ++--
 libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp           | 8 +++++---
 libraries/gpu-gl/src/gpu/gl/GLShader.cpp                  | 2 +-
 libraries/gpu-gl/src/gpu/gl/GLShader.h                    | 2 +-
 libraries/gpu-gles/src/gpu/gl/GLBackend.h                 | 2 +-
 libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp         | 4 ++--
 libraries/gpu/src/gpu/Context.h                           | 2 +-
 libraries/gpu/src/gpu/null/NullBackend.h                  | 2 +-
 plugins/openvr/src/OpenVrDisplayPlugin.cpp                | 3 ++-
 tests/shaders/src/main.cpp                                | 3 ++-
 11 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
index 90bb83a663..b64836627c 100644
--- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
@@ -398,7 +398,8 @@ void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
         auto vs = gpu::Shader::createVertex(std::string(hmd_ui_vert));
         auto ps = gpu::Shader::createPixel(std::string(hmd_ui_frag));
         auto program = gpu::Shader::createProgram(vs, ps);
-        gpu::gl::GLBackend::makeProgram(*program, gpu::Shader::BindingSet());
+    //    gpu::gl::GLBackend::makeProgram(*program, gpu::Shader::BindingSet());
+        gpu::Shader::makeProgram(*program, gpu::Shader::BindingSet());
         uniformsLocation = program->getUniformBuffers().findLocation("hudBuffer");
 
         gpu::StatePointer state = gpu::StatePointer(new gpu::State());
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h
index 004bfe1c85..f0b74803e4 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h
@@ -64,7 +64,7 @@ protected:
     explicit GLBackend(bool syncCache);
     GLBackend();
 public:
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet(), Shader::CompilationHandler handler = nullptr);
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler);
 
     virtual ~GLBackend();
 
@@ -423,7 +423,7 @@ protected:
     } _pipeline;
 
     // Backend dependant compilation of the shader
-    virtual GLShader* compileBackendProgram(const Shader& program);
+    virtual GLShader* compileBackendProgram(const Shader& program, Shader::CompilationHandler handler);
     virtual GLShader* compileBackendShader(const Shader& shader, Shader::CompilationHandler handler);
     virtual std::string getBackendShaderHeader() const;
     virtual void makeProgramBindings(ShaderObject& shaderObject);
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
index 84170dbffd..40b9c94610 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
@@ -101,7 +101,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::Compilat
     return object;
 }
 
-GLShader* GLBackend::compileBackendProgram(const Shader& program) {
+GLShader* GLBackend::compileBackendProgram(const Shader& program, Shader::CompilationHandler handler) {
     if (!program.isProgram()) {
         return nullptr;
     }
@@ -116,11 +116,13 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program) {
         // Let's go through every shaders and make sure they are ready to go
         std::vector< GLuint > shaderGLObjects;
         for (auto subShader : program.getShaders()) {
-            auto object = GLShader::sync((*this), *subShader);
+            auto object = GLShader::sync((*this), *subShader, handler);
             if (object) {
                 shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
             } else {
                 qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?";
+                compilationLogs[version].compiled = false;
+                compilationLogs[version].message = std::string("Failed to compile, one of the shaders of the program is not compiled ?");
                 program.setCompilationLogs(compilationLogs);
                 return nullptr;
             }
@@ -132,7 +134,7 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program) {
             program.setCompilationLogs(compilationLogs);
             return nullptr;
         }
-
+        compilationLogs[version].compiled = true;
         programObject.glprogram = glprogram;
 
         makeProgramBindings(programObject);
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
index a626376e27..42d4fe3845 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
@@ -39,7 +39,7 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, Shader::Compi
     }
     // need to have a gpu object?
     if (shader.isProgram()) {
-        GLShader* tempObject = backend.compileBackendProgram(shader);
+        GLShader* tempObject = backend.compileBackendProgram(shader, handler);
         if (tempObject) {
             object = tempObject;
             Backend::setGPUObject(shader, object);
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h
index 42d63f8dfb..8625b3e64a 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShader.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h
@@ -22,7 +22,7 @@ struct ShaderObject {
 class GLShader : public GPUObject {
 public:
     static GLShader* sync(GLBackend& backend, const Shader& shader, Shader::CompilationHandler handler = nullptr);
-    static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler = nullptr);
+    static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler);
 
     enum Version {
         Mono = 0,
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackend.h b/libraries/gpu-gles/src/gpu/gl/GLBackend.h
index bb8e15bad3..0db46985f7 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackend.h
@@ -420,7 +420,7 @@ protected:
     } _pipeline;
 
     // Backend dependant compilation of the shader
-    virtual GLShader* compileBackendProgram(const Shader& program);
+    virtual GLShader* compileBackendProgram(const Shader& program, Shader::CompilationHandler handler);
     virtual GLShader* compileBackendShader(const Shader& shader, Shader::CompilationHandler handler);
     virtual std::string getBackendShaderHeader() const;
     virtual void makeProgramBindings(ShaderObject& shaderObject);
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
index 26dbb12cf7..1d7636c159 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
@@ -140,7 +140,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::Compilat
     return object;
 }
 
-GLShader* GLBackend::compileBackendProgram(const Shader& program) {
+GLShader* GLBackend::compileBackendProgram(const Shader& program, Shader::CompilationHandler handler) {
     if (!program.isProgram()) {
         return nullptr;
     }
@@ -155,7 +155,7 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program) {
         // Let's go through every shaders and make sure they are ready to go
         std::vector< GLuint > shaderGLObjects;
         for (auto subShader : program.getShaders()) {
-            auto object = GLShader::sync((*this), *subShader);
+            auto object = GLShader::sync((*this), *subShader, handler);
             if (object) {
                 shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
             } else {
diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h
index 7d04463609..e22cc57570 100644
--- a/libraries/gpu/src/gpu/Context.h
+++ b/libraries/gpu/src/gpu/Context.h
@@ -262,7 +262,7 @@ protected:
     // makeProgramShader(...) make a program shader ready to be used in a Batch.
     // It compiles the sub shaders, link them and defines the Slots and their bindings.
     // If the shader passed is not a program, nothing happens. 
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings, Shader::CompilationHandler handler = nullptr);
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings, Shader::CompilationHandler handler);
 
     static CreateBackend _createBackendCallback;
     static MakeProgram _makeProgramCallback;
diff --git a/libraries/gpu/src/gpu/null/NullBackend.h b/libraries/gpu/src/gpu/null/NullBackend.h
index c9d249aec7..abaa24812f 100644
--- a/libraries/gpu/src/gpu/null/NullBackend.h
+++ b/libraries/gpu/src/gpu/null/NullBackend.h
@@ -28,7 +28,7 @@ class Backend : public gpu::Backend {
     friend class gpu::Context;
     static void init() {}
     static gpu::Backend* createBackend() { return new Backend(); }
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) { return true; }
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler) { return true; }
 
 protected:
     explicit Backend(bool syncCache) : Parent() { }
diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
index 4403eaeff7..4b5f0e6517 100644
--- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp
+++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
@@ -200,9 +200,10 @@ public:
             std::string fsSource = HMD_REPROJECTION_FRAG;
             GLuint vertexShader { 0 }, fragmentShader { 0 };
             std::string error;
+            std::vector<char> binary;
             ::gl::compileShader(GL_VERTEX_SHADER, vsSource, "", vertexShader, error);
             ::gl::compileShader(GL_FRAGMENT_SHADER, fsSource, "", fragmentShader, error);
-            _program = ::gl::compileProgram({ { vertexShader, fragmentShader } }, error);
+            _program = ::gl::compileProgram({ { vertexShader, fragmentShader } }, error, binary);
             glDeleteShader(vertexShader);
             glDeleteShader(fragmentShader);
             qDebug() << "Rebuild proigram";
diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp
index cd307ba362..3f48e37a76 100644
--- a/tests/shaders/src/main.cpp
+++ b/tests/shaders/src/main.cpp
@@ -137,12 +137,13 @@ const std::string PIXEL_SHADER_DEFINES{ R"GLSL(
 
 void testShaderBuild(const char* vs_src, const char * fs_src) {
     std::string error;
+    std::vector<char> binary;
     GLuint vs, fs;
     if (!gl::compileShader(GL_VERTEX_SHADER, vs_src, VERTEX_SHADER_DEFINES, vs, error) || 
         !gl::compileShader(GL_FRAGMENT_SHADER, fs_src, PIXEL_SHADER_DEFINES, fs, error)) {
         throw std::runtime_error("Failed to compile shader");
     }
-    auto pr = gl::compileProgram({ vs, fs }, error);
+    auto pr = gl::compileProgram({ vs, fs }, error, binary);
     if (!pr) {
         throw std::runtime_error("Failed to link shader");
     }

From 9ea6c78ac2526faea3035cb52b18a6e9c1993b86 Mon Sep 17 00:00:00 2001
From: Sam Gateau <sam@highfidelity.io>
Date: Tue, 30 Jan 2018 15:31:34 -0800
Subject: [PATCH 28/57] fix stupid copy paste

---
 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 f1d0378792..3390e71b07 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2283,7 +2283,7 @@ void Application::initializeGL() {
 
 #ifdef Q_OS_OSX
     // FIXME: on mac os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread.
-    +DeadlockWatchdogThread::pause();
+    DeadlockWatchdogThread::pause();
 #endif
 
     // Set up the render engine

From 9c81909be55ef6f60da6b5ab6c53c829322c38a7 Mon Sep 17 00:00:00 2001
From: Dante Ruiz <danteruiz102@gmail.com>
Date: Tue, 30 Jan 2018 16:42:08 -0800
Subject: [PATCH 29/57] restructures _dirtyFlags name and bits

---
 .../src/RenderableModelEntityItem.cpp         |   2 +-
 .../src/RenderablePolyVoxEntityItem.cpp       |   4 +-
 libraries/entities/src/EntityItem.cpp         | 123 +++++++++++-------
 libraries/entities/src/EntityItem.h           |  10 +-
 libraries/entities/src/ModelEntityItem.cpp    |  20 +--
 .../entities/src/ParticleEffectEntityItem.cpp |   2 +-
 libraries/entities/src/SimulationFlags.h      |   4 +-
 7 files changed, 97 insertions(+), 68 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 9fcb7640ef..1134c385f2 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1,4 +1,4 @@
-//
+ //
 //  RenderableModelEntityItem.cpp
 //  interface/src
 //
diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
index ade3790df6..abd14d017e 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
@@ -99,7 +99,7 @@ const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
 
   In RenderablePolyVoxEntityItem::render, these flags are checked and changes are propagated along the chain.
   decompressVolumeData() is called to decompress _voxelData into _volData.  recomputeMesh() is called to invoke the
-  polyVox surface extractor to create _mesh (as well as set Simulation _dirtyFlags).  Because Simulation::DIRTY_SHAPE
+  polyVox surface extractor to create _mesh (as well as set Simulation _flags).  Because Simulation::DIRTY_SHAPE
   is set, isReadyToComputeShape() gets called and _shape is created either from _volData or _shape, depending on
   the surface style.
 
@@ -1138,7 +1138,7 @@ void RenderablePolyVoxEntityItem::setMesh(graphics::MeshPointer mesh) {
     bool neighborsNeedUpdate;
     withWriteLock([&] {
         if (!_collisionless) {
-            _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+            _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
         }
         _mesh = mesh;
         _meshDirty = true;
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index fe5213baa8..7e227c90d6 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -933,7 +933,7 @@ void EntityItem::setDensity(float density) {
     withWriteLock([&] {
         if (_density != clampedDensity) {
             _density = clampedDensity;
-            _dirtyFlags |= Simulation::DIRTY_MASS;
+            _flags |= Simulation::DIRTY_MASS;
         }
     });
 }
@@ -958,7 +958,7 @@ void EntityItem::setMass(float mass) {
     withWriteLock([&] {
         if (_density != newDensity) {
             _density = newDensity;
-            _dirtyFlags |= Simulation::DIRTY_MASS;
+            _flags |= Simulation::DIRTY_MASS;
         }
     });
 }
@@ -1623,41 +1623,43 @@ void EntityItem::setParentID(const QUuid& value) {
         if (!value.isNull() && tree) {
             EntityItemPointer entity = tree->findEntityByEntityItemID(value);
             if (entity) {
-                newParentNoBootstrapping = entity->getDirtyFlags() & Simulation::NO_BOOTSTRAPPING;
+                newParentNoBootstrapping = entity->getSpecialFlags() & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
             }
         }
 
         if (!oldParentID.isNull() && tree) {
             EntityItemPointer entity = tree->findEntityByEntityItemID(oldParentID);
             if (entity) {
-                oldParentNoBootstrapping = entity->getDirtyFlags() & Simulation::NO_BOOTSTRAPPING;
+                oldParentNoBootstrapping = entity->getDirtyFlags() & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
             }
         }
 
         if (!value.isNull() && (value == Physics::getSessionUUID() || value == AVATAR_SELF_ID)) {
-            newParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING;
+            newParentNoBootstrapping |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
         }
 
         if (!oldParentID.isNull() && (oldParentID == Physics::getSessionUUID() || oldParentID == AVATAR_SELF_ID)) {
-            oldParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING;
+            oldParentNoBootstrapping |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
         }
 
         if ((bool)(oldParentNoBootstrapping ^ newParentNoBootstrapping)) {
-            if ((bool)(newParentNoBootstrapping & Simulation::NO_BOOTSTRAPPING)) {
-                markDirtyFlags(Simulation::NO_BOOTSTRAPPING);
-                forEachDescendant([&](SpatiallyNestablePointer object) {
-                        if (object->getNestableType() == NestableType::Entity) {
-                            EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
-                            entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP | Simulation::NO_BOOTSTRAPPING);
-                        }
-                });
-            } else {
-                clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
+            if ((bool)(newParentNoBootstrapping & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
+                markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
+                qDebug() << "setParentID" << QString::fromStdString(std::bitset<32>(_flags).to_string()) << " <--------";
                 forEachDescendant([&](SpatiallyNestablePointer object) {
                         if (object->getNestableType() == NestableType::Entity) {
                             EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
                             entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
-                            entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
+                            entity->markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
+                        }
+                });
+            } else {
+                clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
+                forEachDescendant([&](SpatiallyNestablePointer object) {
+                        if (object->getNestableType() == NestableType::Entity) {
+                            EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
+                            entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
+                            entity->clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
                         }
                 });
             }
@@ -1694,7 +1696,7 @@ void EntityItem::setUnscaledDimensions(const glm::vec3& value) {
         locationChanged();
         dimensionsChanged();
         withWriteLock([&] {
-            _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+            _flags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
             _queryAACubeSet = false;
         });
     }
@@ -1703,7 +1705,7 @@ void EntityItem::setUnscaledDimensions(const glm::vec3& value) {
 void EntityItem::setRotation(glm::quat rotation) {
     if (getLocalOrientation() != rotation) {
         setLocalOrientation(rotation);
-        _dirtyFlags |= Simulation::DIRTY_ROTATION;
+        _flags |= Simulation::DIRTY_ROTATION;
         forEachDescendant([&](SpatiallyNestablePointer object) {
             if (object->getNestableType() == NestableType::Entity) {
                 EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
@@ -1733,7 +1735,7 @@ void EntityItem::setVelocity(const glm::vec3& value) {
                     velocity = value;
                 }
                 setLocalVelocity(velocity);
-                _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
+                _flags |= Simulation::DIRTY_LINEAR_VELOCITY;
             }
         }
     }
@@ -1744,7 +1746,7 @@ void EntityItem::setDamping(float value) {
     withWriteLock([&] {
         if (_damping != clampedDamping) {
             _damping = clampedDamping;
-            _dirtyFlags |= Simulation::DIRTY_MATERIAL;
+            _flags |= Simulation::DIRTY_MATERIAL;
         }
     });
 }
@@ -1763,7 +1765,7 @@ void EntityItem::setGravity(const glm::vec3& value) {
                     } else {
                         _gravity = value;
                     }
-                    _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
+                    _flags |= Simulation::DIRTY_LINEAR_VELOCITY;
                 }
             }
         }
@@ -1788,7 +1790,7 @@ void EntityItem::setAngularVelocity(const glm::vec3& value) {
                     angularVelocity = value;
                 }
                 setLocalAngularVelocity(angularVelocity);
-                _dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY;
+                _flags |= Simulation::DIRTY_ANGULAR_VELOCITY;
             }
         }
     }
@@ -1799,7 +1801,7 @@ void EntityItem::setAngularDamping(float value) {
     withWriteLock([&] {
         if (_angularDamping != clampedDamping) {
             _angularDamping = clampedDamping;
-            _dirtyFlags |= Simulation::DIRTY_MATERIAL;
+            _flags |= Simulation::DIRTY_MATERIAL;
         }
     });
 }
@@ -1808,7 +1810,7 @@ void EntityItem::setCollisionless(bool value) {
     withWriteLock([&] {
         if (_collisionless != value) {
             _collisionless = value;
-            _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP;
+            _flags |= Simulation::DIRTY_COLLISION_GROUP;
         }
     });
 }
@@ -1817,7 +1819,7 @@ void EntityItem::setCollisionMask(uint8_t value) {
     withWriteLock([&] {
         if ((_collisionMask & ENTITY_COLLISION_MASK_DEFAULT) != (value & ENTITY_COLLISION_MASK_DEFAULT)) {
             _collisionMask = (value & ENTITY_COLLISION_MASK_DEFAULT);
-            _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP;
+            _flags |= Simulation::DIRTY_COLLISION_GROUP;
         }
     });
 }
@@ -1829,11 +1831,11 @@ void EntityItem::setDynamic(bool value) {
             if (value && getShapeType() == SHAPE_TYPE_STATIC_MESH) {
                 if (_dynamic) {
                     _dynamic = false;
-                    _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
+                    _flags |= Simulation::DIRTY_MOTION_TYPE;
                 }
             } else {
                 _dynamic = value;
-                _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
+                _flags |= Simulation::DIRTY_MOTION_TYPE;
             }
         });
     }
@@ -1844,7 +1846,7 @@ void EntityItem::setRestitution(float value) {
     withWriteLock([&] {
         if (_restitution != clampedValue) {
             _restitution = clampedValue;
-            _dirtyFlags |= Simulation::DIRTY_MATERIAL;
+            _flags |= Simulation::DIRTY_MATERIAL;
         }
     });
 
@@ -1855,7 +1857,7 @@ void EntityItem::setFriction(float value) {
     withWriteLock([&] {
         if (_friction != clampedValue) {
             _friction = clampedValue;
-            _dirtyFlags |= Simulation::DIRTY_MATERIAL;
+            _flags |= Simulation::DIRTY_MATERIAL;
         }
     });
 }
@@ -1864,7 +1866,7 @@ void EntityItem::setLifetime(float value) {
     withWriteLock([&] {
         if (_lifetime != value) {
             _lifetime = value;
-            _dirtyFlags |= Simulation::DIRTY_LIFETIME;
+            _flags |= Simulation::DIRTY_LIFETIME;
         }
     });
 }
@@ -1873,7 +1875,7 @@ void EntityItem::setCreated(quint64 value) {
     withWriteLock([&] {
         if (_created != value) {
             _created = value;
-            _dirtyFlags |= Simulation::DIRTY_LIFETIME;
+            _flags |= Simulation::DIRTY_LIFETIME;
         }
     });
 }
@@ -1902,7 +1904,7 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask
             }
         }
 
-        if ((bool)(_dirtyFlags & Simulation::NO_BOOTSTRAPPING)) {
+        if ((bool)(_flags & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
             userMask &= ~USER_COLLISION_GROUP_MY_AVATAR;
         }
         mask = Physics::getDefaultCollisionMask(group) & (int16_t)(userMask);
@@ -1997,17 +1999,18 @@ bool EntityItem::addActionInternal(EntitySimulationPointer simulation, EntityDyn
     serializeActions(success, newDataCache);
     if (success) {
         _allActionsDataCache = newDataCache;
-        _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
+        _flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
 
         auto actionType = action->getType();
         if (actionType == DYNAMIC_TYPE_HOLD || actionType == DYNAMIC_TYPE_FAR_GRAB) {
-            if (!(bool)(_dirtyFlags & Simulation::NO_BOOTSTRAPPING)) {
-                _dirtyFlags |= Simulation::NO_BOOTSTRAPPING;
-                _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
+            if (!(bool)(_flags & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
+                _flags |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
+                _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
                 forEachDescendant([&](SpatiallyNestablePointer child) {
                     if (child->getNestableType() == NestableType::Entity) {
                         EntityItemPointer entity = std::static_pointer_cast<EntityItem>(child);
-                        entity->markDirtyFlags(Simulation::NO_BOOTSTRAPPING | Simulation::DIRTY_COLLISION_GROUP);
+                        entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
+                        entity->markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
                     }
                 });
             }
@@ -2033,7 +2036,7 @@ bool EntityItem::updateAction(EntitySimulationPointer simulation, const QUuid& a
         if (success) {
             action->setIsMine(true);
             serializeActions(success, _allActionsDataCache);
-            _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
+            _flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
         } else {
             qCDebug(entities) << "EntityItem::updateAction failed";
         }
@@ -2091,17 +2094,17 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
         _objectActions.remove(actionID);
 
         if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) {
-            _dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING;
-            _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
+            _flags &= ~Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
+            _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
             forEachDescendant([&](SpatiallyNestablePointer child) {
                 if (child->getNestableType() == NestableType::Entity) {
                     EntityItemPointer entity = std::static_pointer_cast<EntityItem>(child);
                     entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
-                    entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
+                    entity->clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
                 }
             });
         } else {
-            // NO-OP: we assume NO_BOOTSTRAPPING bits and collision group are correct
+            // NO-OP: we assume SPECIAL_FLAGS_NO_BOOTSTRAPPING bits and collision group are correct
             // because they should have been set correctly when the action was added
             // and/or when children were linked
         }
@@ -2112,7 +2115,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
 
         bool success = true;
         serializeActions(success, _allActionsDataCache);
-        _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
+        _flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
         setDynamicDataNeedsTransmit(true);
         return success;
     }
@@ -2132,8 +2135,8 @@ bool EntityItem::clearActions(EntitySimulationPointer simulation) {
         // empty _serializedActions means no actions for the EntityItem
         _actionsToRemove.clear();
         _allActionsDataCache.clear();
-        _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
-        _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
+        _flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
+        _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
     });
     return true;
 }
@@ -2364,7 +2367,7 @@ QList<EntityDynamicPointer> EntityItem::getActionsOfType(EntityDynamicType typeT
 void EntityItem::locationChanged(bool tellPhysics) {
     requiresRecalcBoxes();
     if (tellPhysics) {
-        _dirtyFlags |= Simulation::DIRTY_TRANSFORM;
+        _flags |= Simulation::DIRTY_TRANSFORM;
         EntityTreePointer tree = getTree();
         if (tree) {
             tree->entityChanged(getThisPointer());
@@ -2832,7 +2835,7 @@ DEFINE_PROPERTY_ACCESSOR(quint32, StaticCertificateVersion, staticCertificateVer
 uint32_t EntityItem::getDirtyFlags() const {
     uint32_t result;
     withReadLock([&] {
-        result = _dirtyFlags;
+        result = _flags;
     });
     return result;
 }
@@ -2840,13 +2843,33 @@ uint32_t EntityItem::getDirtyFlags() const {
 
 void EntityItem::markDirtyFlags(uint32_t mask) {
     withWriteLock([&] {
-        _dirtyFlags |= mask;
+        _flags |= mask;
     });
 }
 
 void EntityItem::clearDirtyFlags(uint32_t mask) {
     withWriteLock([&] {
-        _dirtyFlags &= ~mask;
+        _flags &= ~mask;
+    });
+}
+
+uint32_t EntityItem::getSpecialFlags() const {
+    uint32_t result;
+    withReadLock([&] {
+        result = _flags;
+    });
+    return result;
+}
+
+void EntityItem::markSpecialFlags(uint32_t mask) {
+    withWriteLock([&] {
+        _flags |= mask;
+    });
+}
+
+void EntityItem::clearSpecialFlags(uint32_t mask) {
+    withWriteLock([&] {
+        _flags &= ~mask;
     });
 }
 
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 4c398b8a29..fb0f36c4d6 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -358,7 +358,11 @@ public:
 
     uint32_t getDirtyFlags() const;
     void markDirtyFlags(uint32_t mask);
-    void clearDirtyFlags(uint32_t mask = 0xffffffff);
+    void clearDirtyFlags(uint32_t mask = 0x0000ffff);
+
+    uint32_t getSpecialFlags() const;
+    void markSpecialFlags(uint32_t mask);
+    void clearSpecialFlags(uint32_t mask = 0xffff0000);
 
     bool isMoving() const;
     bool isMovingRelativeToParent() const;
@@ -385,7 +389,7 @@ public:
     void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
 
     void flagForOwnershipBid(uint8_t priority);
-    void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; }
+    void flagForMotionStateChange() { _flags |= Simulation::DIRTY_MOTION_TYPE; }
 
     QString actionsToDebugString();
     bool addAction(EntitySimulationPointer simulation, EntityDynamicPointer action);
@@ -572,7 +576,7 @@ protected:
     //
 
     // DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about.
-    uint32_t _dirtyFlags { 0 };   // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
+    uint32_t _flags { 0 };   // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
 
     // these backpointers are only ever set/cleared by friends:
     EntityTreeElementPointer _element; // set by EntityTreeElement
diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp
index a615beefa9..5d33e4c047 100644
--- a/libraries/entities/src/ModelEntityItem.cpp
+++ b/libraries/entities/src/ModelEntityItem.cpp
@@ -85,7 +85,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
     bool somethingChangedInAnimations = _animationProperties.setProperties(properties);
 
     if (somethingChangedInAnimations) {
-        _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+        _flags |= Simulation::DIRTY_UPDATEABLE;
     }
     somethingChanged = somethingChanged || somethingChangedInAnimations;
 
@@ -132,7 +132,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
     READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType);
 
     if (animationPropertiesChanged) {
-        _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+        _flags |= Simulation::DIRTY_UPDATEABLE;
         somethingChanged = true;
     }
 
@@ -305,10 +305,10 @@ void ModelEntityItem::setShapeType(ShapeType type) {
                 // dynamic and STATIC_MESH are incompatible
                 // since the shape is being set here we clear the dynamic bit
                 _dynamic = false;
-                _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
+                _flags |= Simulation::DIRTY_MOTION_TYPE;
             }
             _shapeType = type;
-            _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+            _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
         }
     });
 }
@@ -336,7 +336,7 @@ void ModelEntityItem::setModelURL(const QString& url) {
         if (_modelURL != url) {
             _modelURL = url;
             if (_shapeType == SHAPE_TYPE_STATIC_MESH) {
-                _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+                _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
             }
         }
     });
@@ -348,14 +348,14 @@ void ModelEntityItem::setCompoundShapeURL(const QString& url) {
             ShapeType oldType = computeTrueShapeType();
             _compoundShapeURL.set(url);
             if (oldType != computeTrueShapeType()) {
-                _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+                _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
             }
         }
     });
 }
 
 void ModelEntityItem::setAnimationURL(const QString& url) {
-    _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+    _flags |= Simulation::DIRTY_UPDATEABLE;
     withWriteLock([&] {
         _animationProperties.setURL(url);
     });
@@ -422,16 +422,16 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
         bool allowTranslation = settingsMap["allowTranslation"].toBool();
         setAnimationAllowTranslation(allowTranslation);
     }
-    _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+    _flags |= Simulation::DIRTY_UPDATEABLE;
 }
 
 void ModelEntityItem::setAnimationIsPlaying(bool value) {
-    _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+    _flags |= Simulation::DIRTY_UPDATEABLE;
     _animationProperties.setRunning(value);
 }
 
 void ModelEntityItem::setAnimationFPS(float value) {
-    _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+    _flags |= Simulation::DIRTY_UPDATEABLE;
     _animationProperties.setFPS(value);
 }
 
diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp
index c20572a491..7d27011c56 100644
--- a/libraries/entities/src/ParticleEffectEntityItem.cpp
+++ b/libraries/entities/src/ParticleEffectEntityItem.cpp
@@ -601,7 +601,7 @@ void ParticleEffectEntityItem::setShapeType(ShapeType type) {
     withWriteLock([&] {
         if (type != _shapeType) {
             _shapeType = type;
-            _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+            _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
         }
     });
 }
diff --git a/libraries/entities/src/SimulationFlags.h b/libraries/entities/src/SimulationFlags.h
index aaa92000e7..6f305ef1ff 100644
--- a/libraries/entities/src/SimulationFlags.h
+++ b/libraries/entities/src/SimulationFlags.h
@@ -27,7 +27,9 @@ namespace Simulation {
     const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine
     const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed
     const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed
-    const uint32_t NO_BOOTSTRAPPING = 0x4000;
+
+
+    const uint32_t SPECIAL_FLAGS_NO_BOOTSTRAPPING = 0x10000;
 
     const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION;
     const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY;

From 63371ff59c129184970435255ab2cc003bf85331 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Tue, 30 Jan 2018 17:17:22 -0800
Subject: [PATCH 30/57] Fix the android build

---
 .../gpu-gles/src/gpu/gl/GLBackendShader.cpp   | 35 -------------------
 1 file changed, 35 deletions(-)

diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
index 1d7636c159..350e95b46a 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
@@ -56,41 +56,6 @@ static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
     stereoVersion
 } };
 
-GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::CompilationHandler handler) {
-    // Any GLSLprogram ? normally yes...
-    const std::string& shaderSource = shader.getSource().getCode();
-    GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
-    GLShader::ShaderObjects shaderObjects;
-    Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
-
-    for (int version = 0; version < GLShader::NumVersions; version++) {
-        auto& shaderObject = shaderObjects[version];
-
-        std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version]
-        + "\n#extension GL_EXT_texture_buffer : enable"
-        + "\nprecision lowp float; // check precision 2"
-        + "\nprecision lowp samplerBuffer;"
-        + "\nprecision lowp sampler2DShadow;";
-        std::string error;
-
-#ifdef SEPARATE_PROGRAM
-        bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram, error);
-#else
-        bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, error);
-#endif
-        if (!result) {
-            qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << error.c_str();
-            return nullptr;
-        }
-    }
-
-    // So far so good, the shader is created successfully
-    GLShader* object = new GLShader(this->shared_from_this());
-    object->_shaderObjects = shaderObjects;
-
-    return object;
-}
-
 GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::CompilationHandler handler) {
     // Any GLSLprogram ? normally yes...
     const std::string& shaderSource = shader.getSource().getCode();

From 05fe33e417b6d2c9097ec6902305ae90404ea59c Mon Sep 17 00:00:00 2001
From: Zach Fox <fox@highfidelity.io>
Date: Tue, 30 Jan 2018 18:01:46 -0800
Subject: [PATCH 31/57] Initial work

---
 .../commerce/wallet/sendMoney/SendMoney.qml   | 25 +++++-
 scripts/system/commerce/wallet.js             | 81 +++++++++++++++++++
 2 files changed, 104 insertions(+), 2 deletions(-)

diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
index f66781c919..ea1c6670e9 100644
--- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
@@ -308,6 +308,22 @@ Item {
                     }
                 }
             }
+
+            // "Particle" button
+            HifiControlsUit.Button {
+                id: particle;
+                color: hifi.buttons.blue;
+                colorScheme: hifi.colorSchemes.dark;
+                anchors.horizontalCenter: parent.horizontalCenter;
+                anchors.top: nearbyButton.bottom;
+                anchors.topMargin: 24;
+                height: 50;
+                width: 160;
+                text: "Try Particles";
+                onClicked: {
+                    sendSignalToWallet({method: 'sendMoney_sendPublicly', recipient: "{d90f0952-20c0-46b7-8851-92184db83e1f}", amount: 2});
+                }
+            }
         }
     }
     // Send Money Home END
@@ -967,7 +983,7 @@ Item {
 
         HifiControlsUit.CheckBox {
             id: sendPubliclyCheckbox;
-            visible: false; // FIXME ONCE PARTICLE EFFECTS ARE IN
+            visible: true;
             text: "Send Publicly"
             // Anchors
             anchors.top: messageContainer.bottom;
@@ -1035,7 +1051,11 @@ Item {
                         if (sendMoneyStep.referrer === "connections") {
                             Commerce.transferHfcToUsername(sendMoneyStep.selectedRecipientUserName, parseInt(amountTextField.text), optionalMessage.text);
                         } else if (sendMoneyStep.referrer === "nearby") {
-                            Commerce.transferHfcToNode(sendMoneyStep.selectedRecipientNodeID, parseInt(amountTextField.text), optionalMessage.text);
+                            var transferAmount = parseInt(amountTextField.text);
+                            Commerce.transferHfcToNode(sendMoneyStep.selectedRecipientNodeID, transferAmount, optionalMessage.text);
+                            if (sendPubliclyCheckbox.checked) {
+                                sendSignalToWallet({method: 'sendMoney_sendPublicly', recipient: sendMoneyStep.selectedRecipientNodeID, amount: transferAmount});
+                            }
                         }
                     }
                 }
@@ -1533,6 +1553,7 @@ Item {
         sendMoneyStep.selectedRecipientProfilePic = "";
         amountTextField.text = "";
         optionalMessage.text = "";
+        sendPubliclyCheckbox.checked = false;
     }
 
     //
diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js
index ad864622ed..c1fae4715d 100644
--- a/scripts/system/commerce/wallet.js
+++ b/scripts/system/commerce/wallet.js
@@ -527,6 +527,69 @@
     //
     //***********************************************
 
+    var sendMoneyParticleEffectUpdateTimer;
+    var sendMoneyParticleEffectDeleteTimer;
+    var sendMoneyParticleEffect;
+    var SEND_MONEY_PARTICLE_TIMER_UPDATE = 250;
+    var SEND_MONEY_PARTICLE_TIMER_TIMEOUT = 4000;
+    var SEND_MONEY_PARTICLE_PROPERTIES = {
+        accelerationSpread: { x: 0, y: 0, z: 0 },
+        alpha: 1,
+        alphaFinish: 1,
+        alphaSpread: 0,
+        alphaStart: 1,
+        azimuthFinish: 0,
+        azimuthStart: -6,
+        color: { red: 143, green: 5, blue: 255 },
+        colorFinish: { red: 255, green: 0, blue: 204 },
+        colorSpread: { red: 0, green: 0, blue: 0 },
+        colorStart: { red: 0, green: 136, blue: 255 },
+        emitAcceleration: { x: 0, y: -3, z: 0 },
+        emitDimensions: { x: 0, y: 0, z: 0 },
+        emitOrientation: { x: 0, y: 0, z: 0 },
+        emitRate: 4.5,
+        emitSpeed: 2.1,
+        emitterShouldTrail: true,
+        isEmitting: 1,
+        lifespan: 3,
+        lifetime: 15,
+        maxParticles: 10,
+        name: 'hfc-particles',
+        particleRadius: 0.2,
+        polarFinish: 0,
+        polarStart: 0,
+        radiusFinish: 0,
+        radiusSpread: 0,
+        radiusStart: 0,
+        speedSpread: 0,
+        textures: "http://hifi-content.s3.amazonaws.com/alan/dev/Particles/Bokeh-Particle-HFC.png",
+        type: 'ParticleEffect'
+    };
+
+    function updateSendMoneyParticleEffect() {
+        if (sendMoneyParticleEffect) {
+            var accel = Vec3.subtract(AvatarList.getAvatar(recipient).position, MyAvatar.position);
+            accel.y -= 3.0;
+            Entities.editEntity(sendMoneyParticleEffect, {
+                emitAcceleration: accel
+            });
+        }
+    }
+
+    function deleteSendMoneyParticleEffect() {
+        if (sendMoneyParticleEffectDeleteTimer) {
+            Script.clearTimeout(sendMoneyParticleEffectDeleteTimer);
+            sendMoneyParticleEffectDeleteTimer = null;
+        }
+        if (sendMoneyParticleEffectUpdateTimer) {
+            Script.clearInterval(sendMoneyParticleEffectUpdateTimer);
+            sendMoneyParticleEffectUpdateTimer = null;
+        }
+        if (sendMoneyParticleEffect) {
+            sendMoneyParticleEffect = Entities.deleteEntity(sendMoneyParticleEffect);
+        }
+    }
+
     // Function Name: fromQml()
     //
     // Description:
@@ -534,6 +597,7 @@
     //    in the format "{method, params}", like json-rpc. See also sendToQml().
     var isHmdPreviewDisabled = true;
     var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js");
+
     function fromQml(message) {
         switch (message.method) {
             case 'passphrasePopup_cancelClicked':
@@ -605,6 +669,22 @@
                 }
                 removeOverlays();
                 break;
+            case 'sendMoney_sendPublicly':
+                var recipient = message.recipient;
+                var amount = message.amount;
+                var props = SEND_MONEY_PARTICLE_PROPERTIES;
+                if (sendMoneyParticleEffect) {
+                    deleteSendMoneyParticleEffect();
+                }
+                props.parentID = MyAvatar.sessionUUID;
+                props.emitAcceleration = Vec3.subtract(AvatarList.getAvatar(recipient).position, MyAvatar.position);
+                props.emitAcceleration.y -= 3.0;
+                props.position = MyAvatar.position;
+                props.position.y += 0.2;
+                sendMoneyParticleEffect = Entities.addEntity(props, true);
+                sendMoneyParticleEffectUpdateTimer = Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE);
+                sendMoneyParticleEffectDeleteTimer = Script.setTimeout(deleteSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_TIMEOUT);
+                break;
             default:
                 print('Unrecognized message from QML:', JSON.stringify(message));
         }
@@ -706,6 +786,7 @@
     function shutdown() {
         button.clicked.disconnect(onButtonClicked);
         tablet.removeButton(button);
+        deleteSendMoneyParticleEffect();
         if (tablet) {
             tablet.screenChanged.disconnect(onTabletScreenChanged);
             if (onWalletScreen) {

From f044cf76d6a35b65733fc20c54810042d6f6c8a5 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Tue, 30 Jan 2018 18:31:30 -0800
Subject: [PATCH 32/57] add the count of compilations of shaders to avoid
 recompiling them if ot needed

---
 .../src/display-plugins/hmd/HmdDisplayPlugin.cpp              | 1 -
 libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp               | 2 ++
 libraries/gpu/src/gpu/Shader.cpp                              | 4 ++++
 libraries/gpu/src/gpu/Shader.h                                | 4 ++++
 libraries/render/src/render/ShapePipeline.cpp                 | 2 +-
 5 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
index b64836627c..d35d5c5317 100644
--- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
@@ -398,7 +398,6 @@ void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
         auto vs = gpu::Shader::createVertex(std::string(hmd_ui_vert));
         auto ps = gpu::Shader::createPixel(std::string(hmd_ui_frag));
         auto program = gpu::Shader::createProgram(vs, ps);
-    //    gpu::gl::GLBackend::makeProgram(*program, gpu::Shader::BindingSet());
         gpu::Shader::makeProgram(*program, gpu::Shader::BindingSet());
         uniformsLocation = program->getUniformBuffers().findLocation("hudBuffer");
 
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
index 40b9c94610..e9d23b543f 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
@@ -62,6 +62,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::Compilat
     GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
     GLShader::ShaderObjects shaderObjects;
     Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
+    shader.incrementCompilationAttempt();
 
     for (int version = 0; version < GLShader::NumVersions; version++) {
         auto& shaderObject = shaderObjects[version];
@@ -108,6 +109,7 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, Shader::Compil
 
     GLShader::ShaderObjects programObjects;
 
+    program.incrementCompilationAttempt();
     Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
 
     for (int version = 0; version < GLShader::NumVersions; version++) {
diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp
index 35c9ad8ae2..b6b90e98fa 100755
--- a/libraries/gpu/src/gpu/Shader.cpp
+++ b/libraries/gpu/src/gpu/Shader.cpp
@@ -95,3 +95,7 @@ void Shader::setCompilationLogs(const CompilationLogs& logs) const {
         _compilationLogs.emplace_back(CompilationLog(log));
     }
 }
+
+void Shader::incrementCompilationAttempt() const {
+    _numCompilationAttempts++;
+}
\ No newline at end of file
diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h
index d78077a396..a489146e36 100755
--- a/libraries/gpu/src/gpu/Shader.h
+++ b/libraries/gpu/src/gpu/Shader.h
@@ -185,10 +185,12 @@ public:
     // Check the compilation state
     bool compilationHasFailed() const { return _compilationHasFailed; }
     const CompilationLogs& getCompilationLogs() const { return _compilationLogs; }
+    uint32_t getNumCompilationAttempts() const { return _numCompilationAttempts; }
 
     // Set COmpilation logs can only be called by the Backend layers
     void setCompilationHasFailed(bool compilationHasFailed) { _compilationHasFailed = compilationHasFailed; }
     void setCompilationLogs(const CompilationLogs& logs) const;
+    void incrementCompilationAttempt() const;
 
 
     const GPUObjectPointer gpuObject {};
@@ -219,6 +221,8 @@ protected:
     // The type of the shader, the master key
     Type _type;
 
+    // Number of attempts to compile the shader
+    mutable uint32_t _numCompilationAttempts{ 0 };
     // Compilation logs (one for each versions generated)
     mutable CompilationLogs _compilationLogs;
 
diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp
index 597a6a0fab..a6d73897ae 100644
--- a/libraries/render/src/render/ShapePipeline.cpp
+++ b/libraries/render/src/render/ShapePipeline.cpp
@@ -72,7 +72,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
         BatchSetter batchSetter, ItemSetter itemSetter) {
     ShapeKey key{ filter._flags };
 
-    if (program->getInputs().empty()) {
+    if (program->getNumCompilationAttempts() < 1) {
         gpu::Shader::BindingSet slotBindings;
         slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
         slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::BUFFER::SKINNING));

From 4429be23c0ca70e368d037d9e7f068c7f306003d Mon Sep 17 00:00:00 2001
From: Dante Ruiz <danteruiz102@gmail.com>
Date: Wed, 31 Jan 2018 09:13:11 -0800
Subject: [PATCH 33/57] add comment

---
 libraries/entities/src/SimulationFlags.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/entities/src/SimulationFlags.h b/libraries/entities/src/SimulationFlags.h
index 6f305ef1ff..da82916fe3 100644
--- a/libraries/entities/src/SimulationFlags.h
+++ b/libraries/entities/src/SimulationFlags.h
@@ -28,7 +28,7 @@ namespace Simulation {
     const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed
     const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed
 
-
+    // bits 17-32 are reservied for special flags
     const uint32_t SPECIAL_FLAGS_NO_BOOTSTRAPPING = 0x10000;
 
     const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION;

From c3b8565dea5f26035f0a98ac4fe049715fa1dc78 Mon Sep 17 00:00:00 2001
From: Dante Ruiz <danteruiz102@gmail.com>
Date: Wed, 31 Jan 2018 09:23:00 -0800
Subject: [PATCH 34/57] min diff

---
 libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 1134c385f2..9fcb7640ef 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1,4 +1,4 @@
- //
+//
 //  RenderableModelEntityItem.cpp
 //  interface/src
 //

From 9ff6e079ee7d4bcf2fab2261bd557140dfad4a4d Mon Sep 17 00:00:00 2001
From: Dante Ruiz <danteruiz102@gmail.com>
Date: Wed, 31 Jan 2018 10:09:23 -0800
Subject: [PATCH 35/57] fix functions

---
 libraries/entities/src/EntityItem.cpp | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 7e227c90d6..79f9f97aa4 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -2835,7 +2835,7 @@ DEFINE_PROPERTY_ACCESSOR(quint32, StaticCertificateVersion, staticCertificateVer
 uint32_t EntityItem::getDirtyFlags() const {
     uint32_t result;
     withReadLock([&] {
-        result = _flags;
+        result = _flags & 0x0000ffff;
     });
     return result;
 }
@@ -2843,12 +2843,14 @@ uint32_t EntityItem::getDirtyFlags() const {
 
 void EntityItem::markDirtyFlags(uint32_t mask) {
     withWriteLock([&] {
+        mask &= 0x0000ffff;
         _flags |= mask;
     });
 }
 
 void EntityItem::clearDirtyFlags(uint32_t mask) {
     withWriteLock([&] {
+        mask &= 0x0000ffff;
         _flags &= ~mask;
     });
 }
@@ -2856,19 +2858,21 @@ void EntityItem::clearDirtyFlags(uint32_t mask) {
 uint32_t EntityItem::getSpecialFlags() const {
     uint32_t result;
     withReadLock([&] {
-        result = _flags;
+        result = _flags & 0xffff0000;
     });
     return result;
 }
 
 void EntityItem::markSpecialFlags(uint32_t mask) {
     withWriteLock([&] {
+        mask &= 0xffff0000;
         _flags |= mask;
     });
 }
 
 void EntityItem::clearSpecialFlags(uint32_t mask) {
     withWriteLock([&] {
+        mask &= 0xffff0000;
         _flags &= ~mask;
     });
 }

From 01f8227fa25cc2cddd49dcf11e940a475223d17b Mon Sep 17 00:00:00 2001
From: Dante Ruiz <danteruiz102@gmail.com>
Date: Wed, 31 Jan 2018 10:41:08 -0800
Subject: [PATCH 36/57] remove stray prints

---
 libraries/entities/src/EntityItem.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 79f9f97aa4..ac349ad74d 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -1645,7 +1645,6 @@ void EntityItem::setParentID(const QUuid& value) {
         if ((bool)(oldParentNoBootstrapping ^ newParentNoBootstrapping)) {
             if ((bool)(newParentNoBootstrapping & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
                 markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
-                qDebug() << "setParentID" << QString::fromStdString(std::bitset<32>(_flags).to_string()) << " <--------";
                 forEachDescendant([&](SpatiallyNestablePointer object) {
                         if (object->getNestableType() == NestableType::Entity) {
                             EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);

From 90c2371f0c7086b03c74e02d38919fb66b302218 Mon Sep 17 00:00:00 2001
From: Zach Fox <fox@highfidelity.io>
Date: Wed, 31 Jan 2018 12:09:23 -0800
Subject: [PATCH 37/57] It's working!

---
 .../commerce/wallet/sendMoney/SendMoney.qml   |  2 +-
 scripts/system/commerce/wallet.js             | 52 +++++++++++--------
 2 files changed, 32 insertions(+), 22 deletions(-)

diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
index ea1c6670e9..63acf6bac8 100644
--- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
@@ -321,7 +321,7 @@ Item {
                 width: 160;
                 text: "Try Particles";
                 onClicked: {
-                    sendSignalToWallet({method: 'sendMoney_sendPublicly', recipient: "{d90f0952-20c0-46b7-8851-92184db83e1f}", amount: 2});
+                    sendSignalToWallet({method: 'sendMoney_sendPublicly', recipient: "{09f76bc2-c108-41e9-9a94-18bbda228ed2}", amount: 2});
                 }
             }
         }
diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js
index 939034ec6c..4e49ee324f 100644
--- a/scripts/system/commerce/wallet.js
+++ b/scripts/system/commerce/wallet.js
@@ -527,11 +527,13 @@
     //
     //***********************************************
 
+    var sendMoneyRecipient;
     var sendMoneyParticleEffectUpdateTimer;
-    var sendMoneyParticleEffectDeleteTimer;
+    var particleEffectTimestamp;
     var sendMoneyParticleEffect;
     var SEND_MONEY_PARTICLE_TIMER_UPDATE = 250;
-    var SEND_MONEY_PARTICLE_TIMER_TIMEOUT = 4000;
+    var SEND_MONEY_PARTICLE_EMITTING_DURATION = 3000;
+    var SEND_MONEY_PARTICLE_LIFETIME_SECONDS = 8;
     var SEND_MONEY_PARTICLE_PROPERTIES = {
         accelerationSpread: { x: 0, y: 0, z: 0 },
         alpha: 1,
@@ -544,43 +546,51 @@
         colorFinish: { red: 255, green: 0, blue: 204 },
         colorSpread: { red: 0, green: 0, blue: 0 },
         colorStart: { red: 0, green: 136, blue: 255 },
-        emitAcceleration: { x: 0, y: -3, z: 0 },
+        emitAcceleration: { x: 0, y: 0, z: 0 }, // Immediately gets updated to be accurate
         emitDimensions: { x: 0, y: 0, z: 0 },
         emitOrientation: { x: 0, y: 0, z: 0 },
-        emitRate: 4.5,
+        emitRate: 4,
         emitSpeed: 2.1,
         emitterShouldTrail: true,
         isEmitting: 1,
-        lifespan: 3,
-        lifetime: 15,
-        maxParticles: 10,
+        lifespan: SEND_MONEY_PARTICLE_LIFETIME_SECONDS + 1, // Immediately gets updated to be accurate
+        lifetime: SEND_MONEY_PARTICLE_LIFETIME_SECONDS + 1,
+        maxParticles: 20,
         name: 'hfc-particles',
         particleRadius: 0.2,
         polarFinish: 0,
         polarStart: 0,
-        radiusFinish: 0,
+        radiusFinish: 0.05,
         radiusSpread: 0,
-        radiusStart: 0,
+        radiusStart: 0.2,
         speedSpread: 0,
         textures: "http://hifi-content.s3.amazonaws.com/alan/dev/Particles/Bokeh-Particle-HFC.png",
         type: 'ParticleEffect'
     };
 
     function updateSendMoneyParticleEffect() {
-        if (sendMoneyParticleEffect) {
-            var accel = Vec3.subtract(AvatarList.getAvatar(recipient).position, MyAvatar.position);
-            accel.y -= 3.0;
+        var timestampNow = Date.now();
+        if ((timestampNow - particleEffectTimestamp) > (SEND_MONEY_PARTICLE_LIFETIME_SECONDS * 1000)) {
+            deleteSendMoneyParticleEffect();
+            return;
+        } else if ((timestampNow - particleEffectTimestamp) > SEND_MONEY_PARTICLE_EMITTING_DURATION) {
             Entities.editEntity(sendMoneyParticleEffect, {
-                emitAcceleration: accel
+                isEmitting: 0
+            });
+        } else if (sendMoneyParticleEffect) {
+            var recipientPosition = AvatarList.getAvatar(sendMoneyRecipient).position;
+            var distance = Vec3.distance(recipientPosition, MyAvatar.position);
+            var accel = Vec3.subtract(recipientPosition, MyAvatar.position);
+            accel.y -= 3.0;
+            var life = Math.sqrt(2 * distance / Vec3.length(accel));
+            Entities.editEntity(sendMoneyParticleEffect, {
+                emitAcceleration: accel,
+                lifespan: life
             });
         }
     }
 
     function deleteSendMoneyParticleEffect() {
-        if (sendMoneyParticleEffectDeleteTimer) {
-            Script.clearTimeout(sendMoneyParticleEffectDeleteTimer);
-            sendMoneyParticleEffectDeleteTimer = null;
-        }
         if (sendMoneyParticleEffectUpdateTimer) {
             Script.clearInterval(sendMoneyParticleEffectUpdateTimer);
             sendMoneyParticleEffectUpdateTimer = null;
@@ -588,6 +598,7 @@
         if (sendMoneyParticleEffect) {
             sendMoneyParticleEffect = Entities.deleteEntity(sendMoneyParticleEffect);
         }
+        sendMoneyRecipient = null;
     }
 
     // Function Name: fromQml()
@@ -670,20 +681,19 @@
                 removeOverlays();
                 break;
             case 'sendMoney_sendPublicly':
-                var recipient = message.recipient;
+                sendMoneyRecipient = message.recipient;
                 var amount = message.amount;
                 var props = SEND_MONEY_PARTICLE_PROPERTIES;
                 if (sendMoneyParticleEffect) {
                     deleteSendMoneyParticleEffect();
                 }
                 props.parentID = MyAvatar.sessionUUID;
-                props.emitAcceleration = Vec3.subtract(AvatarList.getAvatar(recipient).position, MyAvatar.position);
-                props.emitAcceleration.y -= 3.0;
                 props.position = MyAvatar.position;
                 props.position.y += 0.2;
                 sendMoneyParticleEffect = Entities.addEntity(props, true);
+                particleEffectTimestamp = Date.now();
+                updateSendMoneyParticleEffect();
                 sendMoneyParticleEffectUpdateTimer = Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE);
-                sendMoneyParticleEffectDeleteTimer = Script.setTimeout(deleteSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_TIMEOUT);
                 break;
             default:
                 print('Unrecognized message from QML:', JSON.stringify(message));

From 96b6e85745fff6e3bc31363bb07d5164fda91728 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Wed, 31 Jan 2018 12:24:23 -0800
Subject: [PATCH 38/57] formatting

---
 libraries/render/src/render/Item.cpp | 16 ++++++++--------
 libraries/render/src/render/Item.h   |  4 ++--
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp
index 1bf20ab510..612dba076b 100644
--- a/libraries/render/src/render/Item.cpp
+++ b/libraries/render/src/render/Item.cpp
@@ -34,15 +34,15 @@ const int Item::LAYER_3D = 1;
 const int Item::LAYER_3D_FRONT = 2;
 const int Item::LAYER_3D_HUD = 3;
 
-const uint8_t ItemKey::TAG_BITS_ALL{ 0xFF };
-const uint8_t ItemKey::TAG_BITS_NONE{ 0x00 };
-const uint8_t ItemKey::TAG_BITS_0{ 0x01 };
-const uint8_t ItemKey::TAG_BITS_1{ 0x02 };
-const uint8_t ItemKey::TAG_BITS_2{ 0x04 };
-const uint8_t ItemKey::TAG_BITS_3{ 0x08 };
+const uint8_t ItemKey::TAG_BITS_ALL { 0xFF };
+const uint8_t ItemKey::TAG_BITS_NONE { 0x00 };
+const uint8_t ItemKey::TAG_BITS_0 { 0x01 };
+const uint8_t ItemKey::TAG_BITS_1 { 0x02 };
+const uint8_t ItemKey::TAG_BITS_2 { 0x04 };
+const uint8_t ItemKey::TAG_BITS_3 { 0x08 };
 const uint8_t ItemKey::TAG_BITS_4 { 0x10 };
-const uint8_t ItemKey::TAG_BITS_5{ 0x20 };
-const uint8_t ItemKey::TAG_BITS_6{ 0x40 };
+const uint8_t ItemKey::TAG_BITS_5 { 0x20 };
+const uint8_t ItemKey::TAG_BITS_6 { 0x40 };
 const uint8_t ItemKey::TAG_BITS_7 { 0x80 };
 
 const uint32_t ItemKey::KEY_TAG_BITS_MASK = ((uint32_t) ItemKey::TAG_BITS_ALL) << FIRST_TAG_BIT;
diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h
index 4833bd2f42..ff4b3a0458 100644
--- a/libraries/render/src/render/Item.h
+++ b/libraries/render/src/render/Item.h
@@ -43,7 +43,7 @@ public:
     // An Item can be tagged and filtering can rely on the tags to keep or exclude items
     // ItemKey are not taged by default
     enum Tag : uint8_t {
-        TAG_0 = 0, // 8 Tags 
+        TAG_0 = 0, // 8 Tags
         TAG_1,
         TAG_2,
         TAG_3,
@@ -52,7 +52,7 @@ public:
         TAG_6,
         TAG_7,
 
-        NUM_TAGS,
+        NUM_TAGS
     };
     // Tag bits are derived from the Tag enum
     const static uint8_t TAG_BITS_ALL;

From 87ab8a5840dc5d55d7755afe7488eab230313a3d Mon Sep 17 00:00:00 2001
From: vladest <vladstelmahovsky@gmail.com>
Date: Wed, 31 Jan 2018 21:46:05 +0100
Subject: [PATCH 39/57] Image overlay uses bounds property

---
 scripts/system/progress.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/scripts/system/progress.js b/scripts/system/progress.js
index f4741c5b6a..db09d40608 100644
--- a/scripts/system/progress.js
+++ b/scripts/system/progress.js
@@ -300,7 +300,7 @@
 
         if (visible) {
             x = ((Date.now() / 1000) % ANIMATION_SECONDS_PER_REPEAT) / ANIMATION_SECONDS_PER_REPEAT;
-            if (isHMD) {
+            if (!isHMD) {
                 x = x * barDesktop.repeat;
             } else {
                 x = x * BAR_HMD_REPEAT;
@@ -309,9 +309,9 @@
             // Update progress bar
             Overlays.editOverlay(barDesktop.overlay, {
                 visible: !isHMD,
-                subImage: {
+                bounds: {
                     x: barDesktop.repeat - x,
-                    y: 0,
+                    y: windowHeight - barDesktop.height,
                     width: barDesktop.width - barDesktop.repeat,
                     height: barDesktop.height
                 }
@@ -319,9 +319,9 @@
 
             Overlays.editOverlay(barHMD.overlay, {
                 visible: isHMD,
-                subImage: {
+                bounds: {
                     x: BAR_HMD_REPEAT - x,
-                    y: 0,
+                    y: windowHeight - BAR_HMD_HEIGHT,
                     width: BAR_HMD_WIDTH - BAR_HMD_REPEAT,
                     height: BAR_HMD_HEIGHT
                 }

From f6029ed9dcabdf0634efdcb77ab8a5d4bebe839f Mon Sep 17 00:00:00 2001
From: Dante Ruiz <danteruiz102@gmail.com>
Date: Wed, 31 Jan 2018 15:21:22 -0800
Subject: [PATCH 40/57] made requested changes

---
 libraries/entities/src/EntityItem.cpp    | 12 ++++++------
 libraries/entities/src/SimulationFlags.h | 16 ++++++++++++++++
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index ac349ad74d..9ac24b4324 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -2834,7 +2834,7 @@ DEFINE_PROPERTY_ACCESSOR(quint32, StaticCertificateVersion, staticCertificateVer
 uint32_t EntityItem::getDirtyFlags() const {
     uint32_t result;
     withReadLock([&] {
-        result = _flags & 0x0000ffff;
+        result = _flags & ~Simulation::SPECIAL_FLAGS;
     });
     return result;
 }
@@ -2842,14 +2842,14 @@ uint32_t EntityItem::getDirtyFlags() const {
 
 void EntityItem::markDirtyFlags(uint32_t mask) {
     withWriteLock([&] {
-        mask &= 0x0000ffff;
+        mask &= ~Simulation::SPECIAL_FLAGS;
         _flags |= mask;
     });
 }
 
 void EntityItem::clearDirtyFlags(uint32_t mask) {
     withWriteLock([&] {
-        mask &= 0x0000ffff;
+        mask &= ~Simulation::SPECIAL_FLAGS;
         _flags &= ~mask;
     });
 }
@@ -2857,21 +2857,21 @@ void EntityItem::clearDirtyFlags(uint32_t mask) {
 uint32_t EntityItem::getSpecialFlags() const {
     uint32_t result;
     withReadLock([&] {
-        result = _flags & 0xffff0000;
+        result = _flags & ~Simulation::DIRTY_FLAGS;
     });
     return result;
 }
 
 void EntityItem::markSpecialFlags(uint32_t mask) {
     withWriteLock([&] {
-        mask &= 0xffff0000;
+        mask &= ~Simulation::DIRTY_FLAGS;
         _flags |= mask;
     });
 }
 
 void EntityItem::clearSpecialFlags(uint32_t mask) {
     withWriteLock([&] {
-        mask &= 0xffff0000;
+        mask &= ~Simulation::DIRTY_FLAGS;
         _flags &= ~mask;
     });
 }
diff --git a/libraries/entities/src/SimulationFlags.h b/libraries/entities/src/SimulationFlags.h
index da82916fe3..c45b333b29 100644
--- a/libraries/entities/src/SimulationFlags.h
+++ b/libraries/entities/src/SimulationFlags.h
@@ -33,6 +33,22 @@ namespace Simulation {
 
     const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION;
     const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY;
+    const uint32_t SPECIAL_FLAGS = SPECIAL_FLAGS_NO_BOOTSTRAPPING;
+
+    const uint32_t DIRTY_FLAGS = DIRTY_POSITION |
+      DIRTY_ROTATION |
+      DIRTY_LINEAR_VELOCITY |
+      DIRTY_ANGULAR_VELOCITY |
+      DIRTY_MASS |
+      DIRTY_COLLISION_GROUP |
+      DIRTY_MOTION_TYPE |
+      DIRTY_SHAPE |
+      DIRTY_LIFETIME |
+      DIRTY_UPDATEABLE |
+      DIRTY_MATERIAL |
+      DIRTY_PHYSICS_ACTIVATION |
+      DIRTY_SIMULATOR_ID |
+      DIRTY_SIMULATION_OWNERSHIP_PRIORITY;
 };
 
 #endif // hifi_SimulationFlags_h

From bd5fc65bfbaab291e0deba95d774a7cfc6aca273 Mon Sep 17 00:00:00 2001
From: Dante Ruiz <danteruiz102@gmail.com>
Date: Wed, 31 Jan 2018 16:19:14 -0800
Subject: [PATCH 41/57] fix getDirtyFlags & getSpecialFlags function

---
 libraries/entities/src/EntityItem.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 9ac24b4324..842e5cd7b4 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -2834,7 +2834,7 @@ DEFINE_PROPERTY_ACCESSOR(quint32, StaticCertificateVersion, staticCertificateVer
 uint32_t EntityItem::getDirtyFlags() const {
     uint32_t result;
     withReadLock([&] {
-        result = _flags & ~Simulation::SPECIAL_FLAGS;
+        result = _flags & Simulation::SPECIAL_FLAGS;
     });
     return result;
 }
@@ -2857,7 +2857,7 @@ void EntityItem::clearDirtyFlags(uint32_t mask) {
 uint32_t EntityItem::getSpecialFlags() const {
     uint32_t result;
     withReadLock([&] {
-        result = _flags & ~Simulation::DIRTY_FLAGS;
+        result = _flags & Simulation::DIRTY_FLAGS;
     });
     return result;
 }

From 89f4fe1c04a132fbd73093a657a4f42d60a6dd4c Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Wed, 31 Jan 2018 17:28:45 -0800
Subject: [PATCH 42/57] Adding the map of existing shaders and programs and
 ways to identify them to avoid recompiling them

---
 libraries/gpu/src/gpu/Shader.cpp | 114 +++++++++++++++++++++++--------
 libraries/gpu/src/gpu/Shader.h   |  50 +++++++++++++-
 2 files changed, 132 insertions(+), 32 deletions(-)

diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp
index b6b90e98fa..649e7d9e66 100755
--- a/libraries/gpu/src/gpu/Shader.cpp
+++ b/libraries/gpu/src/gpu/Shader.cpp
@@ -17,59 +17,112 @@
 
 using namespace gpu;
 
-Shader::Shader(Type type, const Source& source):
+std::atomic<uint32_t> Shader::_nextShaderID( 1 );
+Shader::DomainShaderMaps Shader::_domainShaderMaps;
+Shader::ProgramMap Shader::_programMap;
+
+
+Shader::Shader(Type type, const Source& source) :
     _source(source),
-    _type(type)
+    _type(type),
+    _ID(_nextShaderID++)
 {
 }
 
-Shader::Shader(Type type, const Pointer& vertex, const Pointer& pixel):
-    _type(type)
+Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel):
+    _type(type),
+    _ID(_nextShaderID++)
 {
-    _shaders.resize(2);
-    _shaders[VERTEX] = vertex;
-    _shaders[PIXEL] = pixel;
-}
-
-Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel) :
-_type(type) {
-    _shaders.resize(3);
-    _shaders[VERTEX] = vertex;
-    _shaders[GEOMETRY] = geometry;
-    _shaders[PIXEL] = pixel;
+    if (geometry) {
+        _shaders.resize(3);
+        _shaders[VERTEX] = vertex;
+        _shaders[GEOMETRY] = geometry;
+        _shaders[PIXEL] = pixel;
+    } else {
+        _shaders.resize(2);
+        _shaders[VERTEX] = vertex;
+        _shaders[PIXEL] = pixel;
+    }
 }
 
 Shader::~Shader()
 {
 }
 
+Shader::Pointer Shader::createOrReuseDomainShader(Type type, const Source& source) {
+    auto found = _domainShaderMaps[type].find(source);
+    if (found != _domainShaderMaps[type].end()) {
+        auto sharedShader = (*found).second.lock();
+        if (sharedShader) {
+            return sharedShader;
+        }
+    }
+    auto shader = Pointer(new Shader(type, source));
+    _domainShaderMaps[type].emplace(source, std::weak_ptr<Shader>(shader));
+    return shader;
+}
+
 Shader::Pointer Shader::createVertex(const Source& source) {
-    return Pointer(new Shader(VERTEX, source));
+    return createOrReuseDomainShader(VERTEX, source);
 }
 
 Shader::Pointer Shader::createPixel(const Source& source) {
-    return Pointer(new Shader(PIXEL, source));
+    return createOrReuseDomainShader(PIXEL, source);
 }
 
 Shader::Pointer Shader::createGeometry(const Source& source) {
-    return Pointer(new Shader(GEOMETRY, source));
+    return createOrReuseDomainShader(GEOMETRY, source);
 }
 
-Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
-    if (vertexShader && vertexShader->getType() == VERTEX &&
-        pixelShader && pixelShader->getType() == PIXEL) {
-        return Pointer(new Shader(PROGRAM, vertexShader, pixelShader));
+ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
+    ProgramMapKey key(0);
+
+    if (vertexShader && vertexShader->getType() == VERTEX) {
+        key.x = vertexShader->getID();
+    } else {
+        // Shader is not valid, exit
+        return Pointer();
     }
-    return Pointer();
+
+    if (pixelShader && pixelShader->getType() == PIXEL) {
+        key.y = pixelShader->getID();
+    } else {
+        // Shader is not valid, exit
+        return Pointer();
+    }
+
+    if (geometryShader) {
+        if (geometryShader->getType() == GEOMETRY) {
+            key.z = geometryShader->getID();
+        } else {
+            // Shader is not valid, exit
+            return Pointer();
+        }
+    }
+
+    // program key is defined, now try to reuse
+    auto found = _programMap.find(key);
+    if (found != _programMap.end()) {
+        auto sharedShader = (*found).second.lock();
+        if (sharedShader) {
+            return sharedShader;
+        }
+    }
+
+    // Program is a new one, let's create it
+    auto program = Pointer(new Shader(type, vertexShader, geometryShader, pixelShader));
+    _programMap.emplace(key, std::weak_ptr<Shader>(program));
+    return program;
+}
+
+
+Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
+    return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, pixelShader);
 }
 
 Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
-    if (vertexShader && vertexShader->getType() == VERTEX &&
-        geometryShader && geometryShader->getType() == GEOMETRY &&
-        pixelShader && pixelShader->getType() == PIXEL) {
-        return Pointer(new Shader(PROGRAM, vertexShader, geometryShader, pixelShader));
-    }
-    return Pointer();
+    return createOrReuseProgramShader(PROGRAM, vertexShader, geometryShader, pixelShader);
+
 }
 
 void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers, const SlotSet& resourceBuffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) {
@@ -98,4 +151,5 @@ void Shader::setCompilationLogs(const CompilationLogs& logs) const {
 
 void Shader::incrementCompilationAttempt() const {
     _numCompilationAttempts++;
-}
\ No newline at end of file
+}
+
diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h
index a489146e36..1e251e6f67 100755
--- a/libraries/gpu/src/gpu/Shader.h
+++ b/libraries/gpu/src/gpu/Shader.h
@@ -15,6 +15,7 @@
 #include <string>
 #include <memory>
 #include <set>
+#include <map>
 
 #include <QUrl>
  
@@ -22,6 +23,8 @@ namespace gpu {
 
 class Shader {
 public:
+    // unique identifier of a shader
+    using ID = uint32_t;
 
     typedef std::shared_ptr< Shader > Pointer;
     typedef std::vector< Pointer > Shaders;
@@ -39,6 +42,11 @@ public:
  
         virtual const std::string& getCode() const { return _code; }
 
+        class Less {
+        public:
+            bool operator() (const Source& x, const Source& y) const { if (x._lang == y._lang) { return x._code < y._code; } else { return (x._lang < y._lang); } }
+        };
+
     protected:
         std::string _code;
         Language _lang = GLSL;
@@ -134,6 +142,8 @@ public:
 
     ~Shader();
 
+    ID getID() const { return _ID; }
+
     Type getType() const { return _type; }
     bool isProgram() const { return getType() > NUM_DOMAINS; }
     bool isDomain() const { return getType() < NUM_DOMAINS; }
@@ -194,15 +204,15 @@ public:
 
 
     const GPUObjectPointer gpuObject {};
-    
+
 protected:
     Shader(Type type, const Source& source);
-    Shader(Type type, const Pointer& vertex, const Pointer& pixel);
     Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel);
 
     Shader(const Shader& shader); // deep copy of the sysmem shader
     Shader& operator=(const Shader& shader); // deep copy of the sysmem texture
 
+
     // Source contains the actual source code or nothing if the shader is a program
     Source _source;
 
@@ -221,6 +231,9 @@ protected:
     // The type of the shader, the master key
     Type _type;
 
+    // The unique identifier of a shader in the GPU lib
+    uint32_t _ID{ 0 };
+
     // Number of attempts to compile the shader
     mutable uint32_t _numCompilationAttempts{ 0 };
     // Compilation logs (one for each versions generated)
@@ -228,6 +241,39 @@ protected:
 
     // Whether or not the shader compilation failed
     bool _compilationHasFailed { false };
+
+
+    // Global maps of the shaders 
+    // Unique shader ID
+    static std::atomic<ID> _nextShaderID;
+
+    using ShaderMap =  std::map<Source, std::weak_ptr<Shader>, Source::Less>;
+    using DomainShaderMaps = std::array<ShaderMap, NUM_DOMAINS>;
+    static DomainShaderMaps _domainShaderMaps;
+
+    static ShaderPointer createOrReuseDomainShader(Type type, const Source& source);
+
+    using ProgramMapKey = glm::uvec3; // THe IDs of the shaders in a progrma make its key
+    class ProgramKeyLess {
+    public:
+        bool operator() (const ProgramMapKey& l, const ProgramMapKey& r) const {
+            if (l.x == r.x) {
+                if (l.y == r.y) {
+                    return (l.z < l.z);
+                }
+                else {
+                    return (l.y < l.y);
+                }
+            }
+            else {
+                return (l.x < r.x);
+            }
+        }
+    };
+    using ProgramMap = std::map<ProgramMapKey, std::weak_ptr<Shader>, ProgramKeyLess>;
+    static ProgramMap _programMap;
+
+    static ShaderPointer createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader);
 };
 
 typedef Shader::Pointer ShaderPointer;

From edb416d24eacc2046d46f1f13c16d54d408cc343 Mon Sep 17 00:00:00 2001
From: Sam Gateau <samuel.gateau@gmail.com>
Date: Wed, 31 Jan 2018 21:32:22 -0800
Subject: [PATCH 43/57] Fixing the program map sorting, good to go

---
 libraries/gpu/src/gpu/Shader.cpp | 1 -
 libraries/gpu/src/gpu/Shader.h   | 4 ++--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp
index 649e7d9e66..e428c758b1 100755
--- a/libraries/gpu/src/gpu/Shader.cpp
+++ b/libraries/gpu/src/gpu/Shader.cpp
@@ -122,7 +122,6 @@ Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer
 
 Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
     return createOrReuseProgramShader(PROGRAM, vertexShader, geometryShader, pixelShader);
-
 }
 
 void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers, const SlotSet& resourceBuffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) {
diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h
index 1e251e6f67..b7ca000d43 100755
--- a/libraries/gpu/src/gpu/Shader.h
+++ b/libraries/gpu/src/gpu/Shader.h
@@ -259,10 +259,10 @@ protected:
         bool operator() (const ProgramMapKey& l, const ProgramMapKey& r) const {
             if (l.x == r.x) {
                 if (l.y == r.y) {
-                    return (l.z < l.z);
+                    return (l.z < r.z);
                 }
                 else {
-                    return (l.y < l.y);
+                    return (l.y < r.y);
                 }
             }
             else {

From 60238fa644b4ae603a3011f2abbdf8818ed8f37c Mon Sep 17 00:00:00 2001
From: Sam Gateau <samuel.gateau@gmail.com>
Date: Wed, 31 Jan 2018 23:15:19 -0800
Subject: [PATCH 44/57] Fixing the android build

---
 libraries/gpu-gles/src/gpu/gl/GLShader.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/gpu-gles/src/gpu/gl/GLShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
index a626376e27..42d4fe3845 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
@@ -39,7 +39,7 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, Shader::Compi
     }
     // need to have a gpu object?
     if (shader.isProgram()) {
-        GLShader* tempObject = backend.compileBackendProgram(shader);
+        GLShader* tempObject = backend.compileBackendProgram(shader, handler);
         if (tempObject) {
             object = tempObject;
             Backend::setGPUObject(shader, object);

From a650c5bbc62c8fc5d61f87b843b83fc373131691 Mon Sep 17 00:00:00 2001
From: Sam Gateau <samuel.gateau@gmail.com>
Date: Wed, 31 Jan 2018 23:31:31 -0800
Subject: [PATCH 45/57] Move a define to resume watchdog a bit further

---
 interface/src/Application.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 808f6eb890..f7c30869c2 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2296,10 +2296,6 @@ void Application::initializeGL() {
 #endif
     _renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED);
 
-#ifdef Q_OS_OSX
-    DeadlockWatchdogThread::resume();
-#endif
-
     _renderEngine->load();
     _renderEngine->registerScene(_main3DScene);
 

From 351f619555c736a7ae878c06c4dcb6775c727284 Mon Sep 17 00:00:00 2001
From: Sam Gateau <samuel.gateau@gmail.com>
Date: Wed, 31 Jan 2018 23:35:16 -0800
Subject: [PATCH 46/57] Fixing a shader error on android

---
 libraries/render-utils/src/LightAmbient.slh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/render-utils/src/LightAmbient.slh b/libraries/render-utils/src/LightAmbient.slh
index acd30d527d..89d3f4faee 100644
--- a/libraries/render-utils/src/LightAmbient.slh
+++ b/libraries/render-utils/src/LightAmbient.slh
@@ -46,7 +46,7 @@ vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, SurfaceData surface) {
             float levels = getLightAmbientMapNumMips(ambient);
             float m = 12.0 / (1.0+11.0*surface.roughness);
             float lod = levels - m;
-            lod = max(lod, 0);
+            lod = max(lod, 0.0);
             specularLight = evalSkyboxLight(lightDir, lod).xyz;
         }
     <@endif@>

From ab20643ada020d58b196685f795e7570c1213bdc Mon Sep 17 00:00:00 2001
From: Dante Ruiz <danteruiz102@gmail.com>
Date: Thu, 1 Feb 2018 08:13:43 -0800
Subject: [PATCH 47/57] fix mistakes

---
 libraries/entities/src/EntityItem.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 842e5cd7b4..ed13a46414 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -2834,7 +2834,7 @@ DEFINE_PROPERTY_ACCESSOR(quint32, StaticCertificateVersion, staticCertificateVer
 uint32_t EntityItem::getDirtyFlags() const {
     uint32_t result;
     withReadLock([&] {
-        result = _flags & Simulation::SPECIAL_FLAGS;
+        result = _flags & Simulation::DIRTY_FLAGS;
     });
     return result;
 }
@@ -2842,14 +2842,14 @@ uint32_t EntityItem::getDirtyFlags() const {
 
 void EntityItem::markDirtyFlags(uint32_t mask) {
     withWriteLock([&] {
-        mask &= ~Simulation::SPECIAL_FLAGS;
+        mask &= Simulation::DIRTY_FLAGS;
         _flags |= mask;
     });
 }
 
 void EntityItem::clearDirtyFlags(uint32_t mask) {
     withWriteLock([&] {
-        mask &= ~Simulation::SPECIAL_FLAGS;
+        mask &= Simulation::DIRTY_FLAGS;
         _flags &= ~mask;
     });
 }
@@ -2857,21 +2857,21 @@ void EntityItem::clearDirtyFlags(uint32_t mask) {
 uint32_t EntityItem::getSpecialFlags() const {
     uint32_t result;
     withReadLock([&] {
-        result = _flags & Simulation::DIRTY_FLAGS;
+        result = _flags & Simulation::SPECIAL_FLAGS;
     });
     return result;
 }
 
 void EntityItem::markSpecialFlags(uint32_t mask) {
     withWriteLock([&] {
-        mask &= ~Simulation::DIRTY_FLAGS;
+        mask &= Simulation::SPECIAL_FLAGS;
         _flags |= mask;
     });
 }
 
 void EntityItem::clearSpecialFlags(uint32_t mask) {
     withWriteLock([&] {
-        mask &= ~Simulation::DIRTY_FLAGS;
+        mask &= Simulation::SPECIAL_FLAGS;
         _flags &= ~mask;
     });
 }

From bd26c9dfc0fc922a0e635af5641f4284112277c9 Mon Sep 17 00:00:00 2001
From: Zach Fox <fox@highfidelity.io>
Date: Wed, 31 Jan 2018 12:32:54 -0800
Subject: [PATCH 48/57] More improvements

---
 .../hifi/commerce/common/images/loader.gif    | Bin 0 -> 59412 bytes
 .../commerce/wallet/sendMoney/SendMoney.qml   |  34 ++++++------------
 scripts/system/commerce/wallet.js             |   4 +--
 3 files changed, 12 insertions(+), 26 deletions(-)
 create mode 100644 interface/resources/qml/hifi/commerce/common/images/loader.gif

diff --git a/interface/resources/qml/hifi/commerce/common/images/loader.gif b/interface/resources/qml/hifi/commerce/common/images/loader.gif
new file mode 100644
index 0000000000000000000000000000000000000000..0536bd1884f1cb4a814b729803b1996c8347d182
GIT binary patch
literal 59412
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
L8@}NiK8F7Q4CAa&

literal 0
HcmV?d00001

diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
index 63acf6bac8..8f7757963c 100644
--- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
@@ -57,6 +57,9 @@ Item {
 
             if (result.status === 'success') {
                 root.nextActiveView = 'paymentSuccess';
+                if (sendPubliclyCheckbox.checked && sendMoneyStep.referrer === "nearby") {
+                    sendSignalToWallet({method: 'sendMoney_sendPublicly', recipient: sendMoneyStep.selectedRecipientNodeID, amount: parseInt(amountTextField.text)});
+                }
             } else {
                 root.nextActiveView = 'paymentFailure';
             }
@@ -308,22 +311,6 @@ Item {
                     }
                 }
             }
-
-            // "Particle" button
-            HifiControlsUit.Button {
-                id: particle;
-                color: hifi.buttons.blue;
-                colorScheme: hifi.colorSchemes.dark;
-                anchors.horizontalCenter: parent.horizontalCenter;
-                anchors.top: nearbyButton.bottom;
-                anchors.topMargin: 24;
-                height: 50;
-                width: 160;
-                text: "Try Particles";
-                onClicked: {
-                    sendSignalToWallet({method: 'sendMoney_sendPublicly', recipient: "{09f76bc2-c108-41e9-9a94-18bbda228ed2}", amount: 2});
-                }
-            }
         }
     }
     // Send Money Home END
@@ -983,7 +970,8 @@ Item {
 
         HifiControlsUit.CheckBox {
             id: sendPubliclyCheckbox;
-            visible: true;
+            visible: sendMoneyStep.referrer === "nearby";
+            checked: Settings.getValue("sendMoneyNearbyPublicly", true);
             text: "Send Publicly"
             // Anchors
             anchors.top: messageContainer.bottom;
@@ -992,7 +980,10 @@ Item {
             anchors.leftMargin: 20;
             anchors.right: parent.right;
             anchors.rightMargin: 16;
-            boxSize: 24;
+            boxSize: 28;
+            onCheckedChanged: {
+                Settings.setValue("sendMoneyNearbyPublicly", checked);
+            }
         }
 
         Item {
@@ -1051,11 +1042,7 @@ Item {
                         if (sendMoneyStep.referrer === "connections") {
                             Commerce.transferHfcToUsername(sendMoneyStep.selectedRecipientUserName, parseInt(amountTextField.text), optionalMessage.text);
                         } else if (sendMoneyStep.referrer === "nearby") {
-                            var transferAmount = parseInt(amountTextField.text);
-                            Commerce.transferHfcToNode(sendMoneyStep.selectedRecipientNodeID, transferAmount, optionalMessage.text);
-                            if (sendPubliclyCheckbox.checked) {
-                                sendSignalToWallet({method: 'sendMoney_sendPublicly', recipient: sendMoneyStep.selectedRecipientNodeID, amount: transferAmount});
-                            }
+                            Commerce.transferHfcToNode(sendMoneyStep.selectedRecipientNodeID, parseInt(amountTextField.text), optionalMessage.text);
                         }
                     }
                 }
@@ -1554,6 +1541,7 @@ Item {
         amountTextField.text = "";
         optionalMessage.text = "";
         sendPubliclyCheckbox.checked = false;
+        sendMoneyStep.referrer = "";
     }
 
     //
diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js
index 4e49ee324f..b1eef8ca83 100644
--- a/scripts/system/commerce/wallet.js
+++ b/scripts/system/commerce/wallet.js
@@ -684,9 +684,7 @@
                 sendMoneyRecipient = message.recipient;
                 var amount = message.amount;
                 var props = SEND_MONEY_PARTICLE_PROPERTIES;
-                if (sendMoneyParticleEffect) {
-                    deleteSendMoneyParticleEffect();
-                }
+                deleteSendMoneyParticleEffect();
                 props.parentID = MyAvatar.sessionUUID;
                 props.position = MyAvatar.position;
                 props.position.y += 0.2;

From fd501cf3af75357cb1de1a5496e8ae9c58fb79e8 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 1 Feb 2018 10:37:54 -0800
Subject: [PATCH 49/57] Addressing review comments

---
 libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp   | 3 +++
 libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp | 3 +++
 libraries/gpu/src/gpu/Shader.h                    | 2 +-
 3 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
index e9d23b543f..42e95ba6c6 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
@@ -71,6 +71,9 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::Compilat
         if (handler) {
             bool retest = true;
             std::string currentSrc = shaderSource;
+            // When a Handler is specified, we can try multiple times to build the shader and let the handler change the source if the compilation fails.
+            // The retest bool is set to false as soon as the compilation succeed to wexit the while loop.
+            // The handler tells us if we should retry or not while returning a modified version of the source.
             while (retest) {
                 bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
                 compilationLogs[version].compiled = result;
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
index 350e95b46a..b799fb0037 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
@@ -74,6 +74,9 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::Compilat
         if (handler) {
             bool retest = true;
             std::string currentSrc = shaderSource;
+            // When a Handler is specified, we can try multiple times to build the shader and let the handler change the source if the compilation fails.
+            // The retest bool is set to false as soon as the compilation succeed to wexit the while loop.
+            // The handler tells us if we should retry or not while returning a modified version of the source.
             while (retest) {
                 bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
                 compilationLogs[version].compiled = result;
diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h
index b7ca000d43..07800fa14a 100755
--- a/libraries/gpu/src/gpu/Shader.h
+++ b/libraries/gpu/src/gpu/Shader.h
@@ -253,7 +253,7 @@ protected:
 
     static ShaderPointer createOrReuseDomainShader(Type type, const Source& source);
 
-    using ProgramMapKey = glm::uvec3; // THe IDs of the shaders in a progrma make its key
+    using ProgramMapKey = glm::uvec3; // The IDs of the shaders in a program make its key
     class ProgramKeyLess {
     public:
         bool operator() (const ProgramMapKey& l, const ProgramMapKey& r) const {

From ce79504f03a96de88603ecb1ad5244adfe3fc685 Mon Sep 17 00:00:00 2001
From: Zach Fox <fox@highfidelity.io>
Date: Thu, 1 Feb 2018 11:51:08 -0800
Subject: [PATCH 50/57] Fix checkbox

---
 .../resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
index 8f7757963c..765b2aecdb 100644
--- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
@@ -1540,7 +1540,7 @@ Item {
         sendMoneyStep.selectedRecipientProfilePic = "";
         amountTextField.text = "";
         optionalMessage.text = "";
-        sendPubliclyCheckbox.checked = false;
+        sendPubliclyCheckbox.checked = Settings.getValue("sendMoneyNearbyPublicly", true);
         sendMoneyStep.referrer = "";
     }
 

From 89e52561e39c0f117bdeb85825b9ee27532c99a6 Mon Sep 17 00:00:00 2001
From: Zach Fox <fox@highfidelity.io>
Date: Thu, 1 Feb 2018 11:53:27 -0800
Subject: [PATCH 51/57] Silly bugfix

---
 scripts/system/commerce/wallet.js           | 2 +-
 scripts/system/marketplaces/marketplaces.js | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js
index b1eef8ca83..cef61bdc53 100644
--- a/scripts/system/commerce/wallet.js
+++ b/scripts/system/commerce/wallet.js
@@ -681,10 +681,10 @@
                 removeOverlays();
                 break;
             case 'sendMoney_sendPublicly':
+                deleteSendMoneyParticleEffect();
                 sendMoneyRecipient = message.recipient;
                 var amount = message.amount;
                 var props = SEND_MONEY_PARTICLE_PROPERTIES;
-                deleteSendMoneyParticleEffect();
                 props.parentID = MyAvatar.sessionUUID;
                 props.position = MyAvatar.position;
                 props.position.y += 0.2;
diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js
index ee3a9ce7ec..facb932eb0 100644
--- a/scripts/system/marketplaces/marketplaces.js
+++ b/scripts/system/marketplaces/marketplaces.js
@@ -578,6 +578,7 @@ var selectionDisplay = null; // for gridTool.js to ignore
             case 'refreshConnections':
             case 'enable_ChooseRecipientNearbyMode':
             case 'disable_ChooseRecipientNearbyMode':
+            case 'sendMoney_sendPublicly':
                 // NOP
                 break;
             default:

From 9867b479fd30f2a3987bf3ef4c7df9703ff58d69 Mon Sep 17 00:00:00 2001
From: samcake <samuel.gateau@gmail.com>
Date: Thu, 1 Feb 2018 13:12:28 -0800
Subject: [PATCH 52/57] APplying review feedback

---
 libraries/gpu-gl/src/gpu/gl/GLBackend.cpp         |  2 +-
 libraries/gpu-gl/src/gpu/gl/GLBackend.h           |  6 +++---
 libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp   |  4 ++--
 libraries/gpu-gl/src/gpu/gl/GLShader.cpp          |  4 ++--
 libraries/gpu-gl/src/gpu/gl/GLShader.h            |  4 ++--
 libraries/gpu-gles/src/gpu/gl/GLBackend.cpp       |  2 +-
 libraries/gpu-gles/src/gpu/gl/GLBackend.h         |  6 +++---
 libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp |  4 ++--
 libraries/gpu-gles/src/gpu/gl/GLShader.cpp        |  4 ++--
 libraries/gpu-gles/src/gpu/gl/GLShader.h          |  4 ++--
 libraries/gpu/src/gpu/Context.cpp                 |  2 +-
 libraries/gpu/src/gpu/Context.h                   |  4 ++--
 libraries/gpu/src/gpu/Shader.cpp                  |  2 +-
 libraries/gpu/src/gpu/Shader.h                    | 11 +++++++++--
 libraries/gpu/src/gpu/null/NullBackend.h          |  2 +-
 15 files changed, 34 insertions(+), 27 deletions(-)

diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
index 2a052c5210..08bd20be66 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
@@ -68,7 +68,7 @@ GLBackend& getBackend() {
     return *INSTANCE;
 }
 
-bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler) {
+bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
     return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
 }
 
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h
index f0b74803e4..18916ac18c 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h
@@ -64,7 +64,7 @@ protected:
     explicit GLBackend(bool syncCache);
     GLBackend();
 public:
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler);
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler);
 
     virtual ~GLBackend();
 
@@ -423,8 +423,8 @@ protected:
     } _pipeline;
 
     // Backend dependant compilation of the shader
-    virtual GLShader* compileBackendProgram(const Shader& program, Shader::CompilationHandler handler);
-    virtual GLShader* compileBackendShader(const Shader& shader, Shader::CompilationHandler handler);
+    virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
+    virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
     virtual std::string getBackendShaderHeader() const;
     virtual void makeProgramBindings(ShaderObject& shaderObject);
     class ElementResource {
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
index 42e95ba6c6..93c9b0d2ff 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
@@ -56,7 +56,7 @@ static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
     stereoVersion
 } };
 
-GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::CompilationHandler handler) {
+GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) {
     // Any GLSLprogram ? normally yes...
     const std::string& shaderSource = shader.getSource().getCode();
     GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
@@ -105,7 +105,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::Compilat
     return object;
 }
 
-GLShader* GLBackend::compileBackendProgram(const Shader& program, Shader::CompilationHandler handler) {
+GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler) {
     if (!program.isProgram()) {
         return nullptr;
     }
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
index 42d4fe3845..010a7c479c 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
@@ -30,7 +30,7 @@ GLShader::~GLShader() {
     }
 }
 
-GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, Shader::CompilationHandler handler) {
+GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler) {
     GLShader* object = Backend::getGPUObject<GLShader>(shader);
 
     // If GPU object already created then good
@@ -56,7 +56,7 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, Shader::Compi
     return object;
 }
 
-bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler) {
+bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
 
     // First make sure the Shader has been compiled
     GLShader* object = sync(backend, shader, handler);
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h
index 8625b3e64a..3259982e93 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShader.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h
@@ -21,8 +21,8 @@ struct ShaderObject {
 
 class GLShader : public GPUObject {
 public:
-    static GLShader* sync(GLBackend& backend, const Shader& shader, Shader::CompilationHandler handler = nullptr);
-    static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler);
+    static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr);
+    static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler);
 
     enum Version {
         Mono = 0,
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp
index 8a118b7b71..fc1bc39929 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp
@@ -61,7 +61,7 @@ GLBackend& getBackend() {
     return *INSTANCE;
 }
 
-bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler) {
+bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
     return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
 }
 
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackend.h b/libraries/gpu-gles/src/gpu/gl/GLBackend.h
index 0db46985f7..3681fc0492 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackend.h
@@ -61,7 +61,7 @@ protected:
     explicit GLBackend(bool syncCache);
     GLBackend();
 public:
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet(), Shader::CompilationHandler handler = nullptr);
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet(), const Shader::CompilationHandler& handler = nullptr);
 
     virtual ~GLBackend();
 
@@ -420,8 +420,8 @@ protected:
     } _pipeline;
 
     // Backend dependant compilation of the shader
-    virtual GLShader* compileBackendProgram(const Shader& program, Shader::CompilationHandler handler);
-    virtual GLShader* compileBackendShader(const Shader& shader, Shader::CompilationHandler handler);
+    virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
+    virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
     virtual std::string getBackendShaderHeader() const;
     virtual void makeProgramBindings(ShaderObject& shaderObject);
     class ElementResource {
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
index b799fb0037..677bba97ca 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
@@ -56,7 +56,7 @@ static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
     stereoVersion
 } };
 
-GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::CompilationHandler handler) {
+GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) {
     // Any GLSLprogram ? normally yes...
     const std::string& shaderSource = shader.getSource().getCode();
     GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
@@ -108,7 +108,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, Shader::Compilat
     return object;
 }
 
-GLShader* GLBackend::compileBackendProgram(const Shader& program, Shader::CompilationHandler handler) {
+GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler) {
     if (!program.isProgram()) {
         return nullptr;
     }
diff --git a/libraries/gpu-gles/src/gpu/gl/GLShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
index 42d4fe3845..010a7c479c 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
@@ -30,7 +30,7 @@ GLShader::~GLShader() {
     }
 }
 
-GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, Shader::CompilationHandler handler) {
+GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler) {
     GLShader* object = Backend::getGPUObject<GLShader>(shader);
 
     // If GPU object already created then good
@@ -56,7 +56,7 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, Shader::Compi
     return object;
 }
 
-bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler) {
+bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
 
     // First make sure the Shader has been compiled
     GLShader* object = sync(backend, shader, handler);
diff --git a/libraries/gpu-gles/src/gpu/gl/GLShader.h b/libraries/gpu-gles/src/gpu/gl/GLShader.h
index 42d63f8dfb..f2a144a81c 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLShader.h
+++ b/libraries/gpu-gles/src/gpu/gl/GLShader.h
@@ -21,8 +21,8 @@ struct ShaderObject {
 
 class GLShader : public GPUObject {
 public:
-    static GLShader* sync(GLBackend& backend, const Shader& shader, Shader::CompilationHandler handler = nullptr);
-    static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler = nullptr);
+    static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr);
+    static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler = nullptr);
 
     enum Version {
         Mono = 0,
diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp
index 2399d3ddc3..d7d86c3ef7 100644
--- a/libraries/gpu/src/gpu/Context.cpp
+++ b/libraries/gpu/src/gpu/Context.cpp
@@ -127,7 +127,7 @@ void Context::executeFrame(const FramePointer& frame) const {
     _frameStats.evalDelta(beginStats, endStats);
 }
 
-bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings, Shader::CompilationHandler handler) {
+bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler) {
     // If we're running in another DLL context, we need to fetch the program callback out of the application
     // FIXME find a way to do this without reliance on Qt app properties
     if (!_makeProgramCallback) {
diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h
index e22cc57570..195565f438 100644
--- a/libraries/gpu/src/gpu/Context.h
+++ b/libraries/gpu/src/gpu/Context.h
@@ -143,7 +143,7 @@ class Context {
 public:
     using Size = Resource::Size;
     typedef BackendPointer (*CreateBackend)();
-    typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings, Shader::CompilationHandler handler);
+    typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler);
 
 
     // This one call must happen before any context is created or used (Shader::MakeProgram) in order to setup the Backend and any singleton data needed
@@ -262,7 +262,7 @@ protected:
     // makeProgramShader(...) make a program shader ready to be used in a Batch.
     // It compiles the sub shaders, link them and defines the Slots and their bindings.
     // If the shader passed is not a program, nothing happens. 
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings, Shader::CompilationHandler handler);
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler);
 
     static CreateBackend _createBackendCallback;
     static MakeProgram _makeProgramCallback;
diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp
index e428c758b1..aa7898569b 100755
--- a/libraries/gpu/src/gpu/Shader.cpp
+++ b/libraries/gpu/src/gpu/Shader.cpp
@@ -134,7 +134,7 @@ void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers,
     _outputs = outputs;
 }
 
-bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings, CompilationHandler handler) {
+bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings, const CompilationHandler& handler) {
     if (shader.isProgram()) {
         return Context::makeProgram(shader, bindings, handler);
     }
diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h
index 07800fa14a..4504337789 100755
--- a/libraries/gpu/src/gpu/Shader.h
+++ b/libraries/gpu/src/gpu/Shader.h
@@ -175,7 +175,14 @@ public:
                      const SlotSet& inputs,
                      const SlotSet& outputs);
 
-    typedef bool(*CompilationHandler)(const Shader& shader, const std::string& src, CompilationLog& log, std::string& newSrc);
+    // Compilation Handler can be passed while compiling a shader (in the makeProgram call) to be able to give the hand to
+    // the caller thread if the comilation fails and to prvide a different version of the source for it
+    // @param0 the Shader object that just failed to compile
+    // @param1 the original source code as submited to the compiler
+    // @param2 the compilation log containing the error message
+    // @param3 a new string ready to be filled with the new version of the source that could be proposed from the handler functor
+    // @return boolean true if the backend should keep trying to compile the shader with the new source returned or false to stop and fail that shader compilation
+    using CompilationHandler = std::function<bool (const Shader&, const std::string&, CompilationLog&, std::string&)>; 
 
     // makeProgram(...) make a program shader ready to be used in a Batch.
     // It compiles the sub shaders, link them and defines the Slots and their bindings.
@@ -190,7 +197,7 @@ public:
     // on a gl Context and the driver to compile the glsl shader. 
     // Hoppefully in a few years the shader compilation will be completely abstracted in a separate shader compiler library
     // independant of the graphics api in use underneath (looking at you opengl & vulkan).
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet(), CompilationHandler handler = nullptr);
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet(), const CompilationHandler& handler = nullptr);
 
     // Check the compilation state
     bool compilationHasFailed() const { return _compilationHasFailed; }
diff --git a/libraries/gpu/src/gpu/null/NullBackend.h b/libraries/gpu/src/gpu/null/NullBackend.h
index abaa24812f..57b8fbafbc 100644
--- a/libraries/gpu/src/gpu/null/NullBackend.h
+++ b/libraries/gpu/src/gpu/null/NullBackend.h
@@ -28,7 +28,7 @@ class Backend : public gpu::Backend {
     friend class gpu::Context;
     static void init() {}
     static gpu::Backend* createBackend() { return new Backend(); }
-    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, Shader::CompilationHandler handler) { return true; }
+    static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) { return true; }
 
 protected:
     explicit Backend(bool syncCache) : Parent() { }

From dd2b7eb10703b93550a4704e91e2f345d7429264 Mon Sep 17 00:00:00 2001
From: Zach Fox <fox@highfidelity.io>
Date: Thu, 1 Feb 2018 15:17:50 -0800
Subject: [PATCH 53/57] Send Money Effect & Lightbox

---
 .../commerce/wallet/sendMoney/SendMoney.qml   |  46 ++++++++++++++++--
 .../sendMoney/images/send-money-effect-sm.jpg | Bin 0 -> 22213 bytes
 2 files changed, 43 insertions(+), 3 deletions(-)
 create mode 100644 interface/resources/qml/hifi/commerce/wallet/sendMoney/images/send-money-effect-sm.jpg

diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
index 765b2aecdb..16b56407ac 100644
--- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
@@ -106,6 +106,12 @@ Item {
         }
     }
 
+    HifiCommerceCommon.CommerceLightbox {
+        id: lightboxPopup;
+        visible: false;
+        anchors.fill: parent;
+    }
+
     // Send Money Home BEGIN
     Item {
         id: sendMoneyHome;
@@ -972,19 +978,53 @@ Item {
             id: sendPubliclyCheckbox;
             visible: sendMoneyStep.referrer === "nearby";
             checked: Settings.getValue("sendMoneyNearbyPublicly", true);
-            text: "Send Publicly"
+            text: "Show Effect"
             // Anchors
             anchors.top: messageContainer.bottom;
             anchors.topMargin: 16;
             anchors.left: parent.left;
             anchors.leftMargin: 20;
-            anchors.right: parent.right;
-            anchors.rightMargin: 16;
+            width: 110;
             boxSize: 28;
             onCheckedChanged: {
                 Settings.setValue("sendMoneyNearbyPublicly", checked);
             }
         }
+        RalewaySemiBold {
+            id: sendPubliclyCheckboxHelp;
+            visible: sendPubliclyCheckbox.visible;
+            text: "[?]";
+            // Anchors
+            anchors.left: sendPubliclyCheckbox.right;
+            anchors.leftMargin: 8;
+            anchors.verticalCenter: sendPubliclyCheckbox.verticalCenter;
+            height: 30;
+            width: paintedWidth;
+            // Text size
+            size: 18;
+            // Style
+            color: hifi.colors.blueAccent;
+            MouseArea {
+                enabled: sendPubliclyCheckboxHelp.visible;
+                anchors.fill: parent;
+                hoverEnabled: true;
+                onEntered: {
+                    parent.color = hifi.colors.blueHighlight;
+                }
+                onExited: {
+                    parent.color = hifi.colors.blueAccent;
+                }
+                onClicked: {
+                    lightboxPopup.titleText = "Send Money Effect";
+                    lightboxPopup.bodyImageSource = "../wallet/sendMoney/images/send-money-effect-sm.jpg"; // Path relative to CommerceLightbox.qml
+                    lightboxPopup.bodyText = "Enabling this option will create a particle effect between you and " +
+                        "your recipient that is visible to everyone nearby.";
+                    lightboxPopup.button1text = "CLOSE";
+                    lightboxPopup.button1method = "root.visible = false;"
+                    lightboxPopup.visible = true;
+                }
+            }
+        }
 
         Item {
             id: bottomBarContainer;
diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/send-money-effect-sm.jpg b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/send-money-effect-sm.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..7cabf9414a1d9f9a28a983c2fdffeda72912897b
GIT binary patch
literal 22213
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

literal 0
HcmV?d00001


From 14d5029f4d4893664b0ec1d36953d0ccfa6bf38b Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Fri, 2 Feb 2018 08:56:11 -0800
Subject: [PATCH 54/57] only update cauterization of child entities when
 something relevant changes

---
 interface/src/avatar/MyAvatar.cpp           | 38 +++++++++++++++------
 interface/src/avatar/MyAvatar.h             |  7 ++++
 libraries/render-utils/src/LightPayload.cpp |  2 +-
 3 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 3cf7874b50..54bdd79de5 100755
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -504,6 +504,16 @@ void MyAvatar::updateEyeContactTarget(float deltaTime) {
 extern QByteArray avatarStateToFrame(const AvatarData* _avatar);
 extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
 
+void MyAvatar::beParentOfChild(SpatiallyNestablePointer newChild) const {
+    _cauterizationNeedsUpdate = true;
+    SpatiallyNestable::beParentOfChild(newChild);
+}
+
+void MyAvatar::forgetChild(SpatiallyNestablePointer newChild) const {
+    _cauterizationNeedsUpdate = true;
+    SpatiallyNestable::forgetChild(newChild);
+}
+
 void MyAvatar::updateChildCauterization(SpatiallyNestablePointer object) {
     if (object->getNestableType() == NestableType::Entity) {
         EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
@@ -516,16 +526,19 @@ void MyAvatar::simulate(float deltaTime) {
 
     animateScaleChanges(deltaTime);
 
-    const std::unordered_set<int>& headBoneSet = _skeletonModel->getCauterizeBoneSet();
-    forEachChild([&](SpatiallyNestablePointer object) {
-        bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
-        if (isChildOfHead) {
-            updateChildCauterization(object);
-            object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
-                updateChildCauterization(descendant);
-            });
-        }
-    });
+    if (_cauterizationNeedsUpdate) {
+        const std::unordered_set<int>& headBoneSet = _skeletonModel->getCauterizeBoneSet();
+        forEachChild([&](SpatiallyNestablePointer object) {
+            bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
+            if (isChildOfHead) {
+                updateChildCauterization(object);
+                object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
+                    updateChildCauterization(descendant);
+                });
+            }
+        });
+        _cauterizationNeedsUpdate = false;
+    }
 
     {
         PerformanceTimer perfTimer("transform");
@@ -1438,6 +1451,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
     Avatar::setSkeletonModelURL(skeletonModelURL);
     _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE);
     _headBoneSet.clear();
+    _cauterizationNeedsUpdate = true;
     emit skeletonChanged();
 
 }
@@ -1809,6 +1823,8 @@ void MyAvatar::initHeadBones() {
         }
         q.pop();
     }
+
+    _cauterizationNeedsUpdate = true;
 }
 
 QUrl MyAvatar::getAnimGraphOverrideUrl() const {
@@ -1879,6 +1895,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
         _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
         initAnimGraph();
         _isAnimatingScale = true;
+        _cauterizationNeedsUpdate = true;
     }
 
     if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) {
@@ -1967,6 +1984,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
     // toggle using the cauterizedBones depending on where the camera is and the rendering pass type.
     const bool shouldDrawHead = shouldRenderHead(renderArgs);
     if (shouldDrawHead != _prevShouldDrawHead) {
+        _cauterizationNeedsUpdate = true;
         _skeletonModel->setEnableCauterization(!shouldDrawHead);
 
         for (int i = 0; i < _attachmentData.size(); i++) {
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index c32013b8d1..97e82b87f5 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -633,6 +633,11 @@ signals:
 private slots:
     void leaveDomain();
 
+
+protected:
+    virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override;
+    virtual void forgetChild(SpatiallyNestablePointer newChild) const override;
+
 private:
 
     bool requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& positionOut);
@@ -812,6 +817,8 @@ private:
     bool _enableDebugDrawIKChains { false };
     bool _enableDebugDrawDetailedCollision { false };
 
+    mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state?
+
     AudioListenerMode _audioListenerMode;
     glm::vec3 _customListenPosition;
     glm::quat _customListenOrientation;
diff --git a/libraries/render-utils/src/LightPayload.cpp b/libraries/render-utils/src/LightPayload.cpp
index f1eef19498..79e0c1d94d 100644
--- a/libraries/render-utils/src/LightPayload.cpp
+++ b/libraries/render-utils/src/LightPayload.cpp
@@ -19,7 +19,7 @@ namespace render {
         ItemKey::Builder builder;
         builder.withTypeLight();
         builder.withTagBits(ItemKey::TAG_BITS_ALL);
-        if (!payload) {
+        if (payload) {
             if (!payload->isVisible()) {
                 builder.withInvisible();
             }

From 03daba9bacad4b82a3e6e79625608bd23af1cc06 Mon Sep 17 00:00:00 2001
From: Olivier Prat <olivier@zvork.fr>
Date: Fri, 2 Feb 2018 18:18:24 +0100
Subject: [PATCH 55/57] Removed duplicate shader include

---
 libraries/render-utils/src/RenderPipelines.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp
index ccfe28f698..eacd5b5b66 100644
--- a/libraries/render-utils/src/RenderPipelines.cpp
+++ b/libraries/render-utils/src/RenderPipelines.cpp
@@ -72,7 +72,6 @@
 #include "model_lightmap_normal_specular_map_frag.h"
 #include "model_lightmap_specular_map_frag.h"
 #include "model_translucent_frag.h"
-#include "model_translucent_normal_map_frag.h"
 #include "model_translucent_unlit_frag.h"
 #include "model_translucent_normal_map_frag.h"
 

From 19235b8d946f539f4e4fe36d9f71c8683a17e339 Mon Sep 17 00:00:00 2001
From: Zach Fox <fox@highfidelity.io>
Date: Fri, 2 Feb 2018 10:50:35 -0800
Subject: [PATCH 56/57] Fix a bug where hover events incorrectly propagate
 under popups

---
 interface/resources/qml/hifi/commerce/checkout/Checkout.qml  | 1 +
 .../resources/qml/hifi/commerce/common/CommerceLightbox.qml  | 1 +
 .../resources/qml/hifi/commerce/common/FirstUseTutorial.qml  | 1 +
 .../commerce/inspectionCertificate/InspectionCertificate.qml | 1 +
 .../resources/qml/hifi/commerce/purchases/PurchasedItem.qml  | 1 +
 .../resources/qml/hifi/commerce/wallet/PassphraseModal.qml   | 1 +
 .../qml/hifi/commerce/wallet/PassphraseSelection.qml         | 1 +
 interface/resources/qml/hifi/commerce/wallet/Security.qml    | 1 +
 interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml | 1 +
 .../qml/hifi/commerce/wallet/sendMoney/SendMoney.qml         | 5 +++++
 10 files changed, 14 insertions(+)

diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
index 4de09c1bf3..809f48361d 100644
--- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
+++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
@@ -571,6 +571,7 @@ Rectangle {
             MouseArea {
                 anchors.fill: parent;
                 propagateComposedEvents: false;
+                hoverEnabled: true;
             }
 
             RalewayBold {
diff --git a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml
index 145b78bdc4..8b0ec17232 100644
--- a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml
+++ b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml
@@ -45,6 +45,7 @@ Rectangle {
     MouseArea {
         anchors.fill: parent;
         propagateComposedEvents: false;
+        hoverEnabled: true;
     }
 
     Rectangle {
diff --git a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml
index 0d3f67ef7a..bcc641acd5 100644
--- a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml
+++ b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml
@@ -44,6 +44,7 @@ Rectangle {
     MouseArea {
         anchors.fill: parent;
         propagateComposedEvents: false;
+        hoverEnabled: true;
     }
 
     Item {
diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml
index c331532f5e..421fa4b074 100644
--- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml
+++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml
@@ -119,6 +119,7 @@ Rectangle {
     MouseArea {
         anchors.fill: parent;
         propagateComposedEvents: false;
+        hoverEnabled: true;
     }
 
     Image {
diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
index f7913e5b1e..05e280b839 100644
--- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
+++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
@@ -316,6 +316,7 @@ Item {
             MouseArea {
                 anchors.fill: parent;
                 propagateComposedEvents: false;
+                hoverEnabled: true;
             }
 
             RalewayBold {
diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml
index 87430246f3..c586af9e80 100644
--- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml
@@ -66,6 +66,7 @@ Item {
     MouseArea {
         anchors.fill: parent;
         propagateComposedEvents: false;
+        hoverEnabled: true;
     }
     
     // This will cause a bug -- if you bring up passphrase selection in HUD mode while
diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml
index 50e58f8cc4..50bea2a3cf 100644
--- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml
@@ -34,6 +34,7 @@ Item {
     MouseArea {
         anchors.fill: parent;
         propagateComposedEvents: false;
+        hoverEnabled: true;
     }
 
     Connections {
diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml
index 634a68d117..224b743c06 100644
--- a/interface/resources/qml/hifi/commerce/wallet/Security.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml
@@ -306,6 +306,7 @@ Item {
                 MouseArea {
                     anchors.fill: parent;
                     propagateComposedEvents: false;
+                    hoverEnabled: true;
                 }
 
                 RalewayBold {
diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml
index fd74b07465..fab27a29bb 100644
--- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml
@@ -394,6 +394,7 @@ Item {
         MouseArea {
             anchors.fill: parent;
             propagateComposedEvents: false;
+            hoverEnabled: true;
         }
 
         Image {
diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
index f66781c919..24b6c6b9a1 100644
--- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
@@ -43,6 +43,7 @@ Item {
         width: parent.width;
         height: (root.shouldShowTopAndBottomOfWallet || root.shouldShowTopOfWallet) ? parent.height : parent.height - root.parentAppTitleBarHeight - root.parentAppNavBarHeight;
         propagateComposedEvents: false;
+        hoverEnabled: true;
     }
 
     Connections {
@@ -326,6 +327,7 @@ Item {
         MouseArea {
             anchors.fill: parent;
             propagateComposedEvents: false;
+            hoverEnabled: true;
         }
         
         ListModel {
@@ -477,6 +479,7 @@ Item {
                             enabled: connectionsList.currentIndex !== index;
                             anchors.fill: parent;
                             propagateComposedEvents: false;
+                            hoverEnabled: true;
                             onClicked: {
                                 connectionsList.currentIndex = index;
                             }
@@ -505,6 +508,7 @@ Item {
         MouseArea {
             anchors.fill: parent;
             propagateComposedEvents: false;
+            hoverEnabled: true;
         }
 
         Rectangle {
@@ -1059,6 +1063,7 @@ Item {
         MouseArea {
             anchors.fill: parent;
             propagateComposedEvents: false;
+            hoverEnabled: true;
         }
                 
         AnimatedImage {

From f26477b3e16d00215593b51c296c05cef2e5c167 Mon Sep 17 00:00:00 2001
From: Zach Fox <fox@highfidelity.io>
Date: Fri, 2 Feb 2018 11:00:32 -0800
Subject: [PATCH 57/57] Slight wording change to Optional Message placeholder

---
 .../resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
index 16b56407ac..4ef80234dc 100644
--- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
@@ -926,7 +926,7 @@ Item {
                 id: optionalMessage;
                 property int maximumLength: 72;
                 property string previousText: text;
-                placeholderText: "<i>Optional Message (" + maximumLength + " character limit)</i>";
+                placeholderText: "<i>Optional Public Message (" + maximumLength + " character limit)</i>";
                 font.family: firaSansSemiBold.name;
                 font.pixelSize: 20;
                 // Anchors