From 0072684d98c5037e5aad89b61dc6e70eba53bd1a Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Mon, 19 Nov 2018 17:26:00 -0800
Subject: [PATCH 01/12] remove cruft and fix error in transform to mesh frame

---
 .../src/RenderableModelEntityItem.cpp         |  4 +-
 libraries/render-utils/src/Model.cpp          | 57 ++-----------------
 libraries/render-utils/src/Model.h            |  2 +-
 3 files changed, 9 insertions(+), 54 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index dcad562ba7..3c4aeb2686 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -726,7 +726,9 @@ int RenderableModelEntityItem::avatarJointIndex(int modelJointIndex) {
 bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
     auto model = getModel();
     if (EntityItem::contains(point) && model && _compoundShapeResource && _compoundShapeResource->isLoaded()) {
-        return _compoundShapeResource->getHFMModel().convexHullContains(worldToEntity(point));
+        glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
+        glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
+        return _compoundShapeResource->getHFMModel().convexHullContains(hfmPoint);
     }
 
     return false;
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 9cefbf65a8..ec29fb009e 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -614,58 +614,11 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
     return intersectedSomething;
 }
 
-bool Model::convexHullContains(glm::vec3 point) {
-    // if we aren't active, we can't compute that yet...
-    if (!isActive()) {
-        return false;
-    }
-
-    // extents is the entity relative, scaled, centered extents of the entity
-    glm::vec3 position = _translation;
-    glm::mat4 rotation = glm::mat4_cast(_rotation);
-    glm::mat4 translation = glm::translate(position);
-    glm::mat4 modelToWorldMatrix = translation * rotation;
-    glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix);
-
-    Extents modelExtents = getMeshExtents(); // NOTE: unrotated
-
-    glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum;
-    glm::vec3 corner = -(dimensions * _registrationPoint);
-    AABox modelFrameBox(corner, dimensions);
-
-    glm::vec3 modelFramePoint = glm::vec3(worldToModelMatrix * glm::vec4(point, 1.0f));
-
-    // we can use the AABox's contains() by mapping our point into the model frame
-    // and testing there.
-    if (modelFrameBox.contains(modelFramePoint)){
-        QMutexLocker locker(&_mutex);
-
-        if (!_triangleSetsValid) {
-            calculateTriangleSets(getHFMModel());
-        }
-
-        // If we are inside the models box, then consider the submeshes...
-        glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
-        glm::mat4 meshToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation) * meshToModelMatrix;
-        glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix);
-        glm::vec3 meshFramePoint = glm::vec3(worldToMeshMatrix * glm::vec4(point, 1.0f));
-
-        for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) {
-            for (auto &partTriangleSet : meshTriangleSets) {
-                const AABox& box = partTriangleSet.getBounds();
-                if (box.contains(meshFramePoint)) {
-                    if (partTriangleSet.convexHullContains(meshFramePoint)) {
-                        // It's inside this mesh, return true.
-                        return true;
-                    }
-                }
-            }
-        }
-
-
-    }
-    // It wasn't in any mesh, return false.
-    return false;
+glm::mat4 Model::getWorldToHFMMatrix() const {
+    glm::mat4 hfmToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
+    glm::mat4 modelToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation);
+    glm::mat4 worldToHFMMatrix = glm::inverse(modelToWorldMatrix * hfmToModelMatrix);
+    return worldToHFMMatrix;
 }
 
 // TODO: deprecate and remove
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index 93a0626d28..0f8eb782c3 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -192,7 +192,7 @@ public:
     bool didVisualGeometryRequestFail() const { return _visualGeometryRequestFailed; }
     bool didCollisionGeometryRequestFail() const { return _collisionGeometryRequestFailed; }
 
-    bool convexHullContains(glm::vec3 point);
+    glm::mat4 getWorldToHFMMatrix() const;
 
     QStringList getJointNames() const;
 

From 1fabaf0db43b3f1d5a64502ab76dc64bf6938eb7 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Mon, 19 Nov 2018 17:27:18 -0800
Subject: [PATCH 02/12] rename getCollisionGeometryResource to
 fetchCollisionGeometryResource

---
 .../src/RenderableModelEntityItem.cpp                  | 10 +++++-----
 .../entities-renderer/src/RenderableModelEntityItem.h  |  3 +--
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 3c4aeb2686..5693778e3a 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -279,7 +279,7 @@ bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3
         face, surfaceNormal, extraInfo, precisionPicking, false);
 }
 
-void RenderableModelEntityItem::getCollisionGeometryResource() {
+void RenderableModelEntityItem::fetchCollisionGeometryResource() {
     QUrl hullURL(getCollisionShapeURL());
     QUrlQuery queryArgs(hullURL);
     queryArgs.addQueryItem("collision-hull", "");
@@ -289,7 +289,7 @@ void RenderableModelEntityItem::getCollisionGeometryResource() {
 
 bool RenderableModelEntityItem::computeShapeFailedToLoad() {
     if (!_compoundShapeResource) {
-        getCollisionGeometryResource();
+        fetchCollisionGeometryResource();
     }
 
     return (_compoundShapeResource && _compoundShapeResource->isFailed());
@@ -300,7 +300,7 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) {
     auto shapeType = getShapeType();
     if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
         if (!_compoundShapeResource && !getCollisionShapeURL().isEmpty()) {
-            getCollisionGeometryResource();
+            fetchCollisionGeometryResource();
         }
     } else if (_compoundShapeResource && !getCompoundShapeURL().isEmpty()) {
         // the compoundURL has been set but the shapeType does not agree
@@ -317,7 +317,7 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
     ModelEntityItem::setCompoundShapeURL(url);
     if (getCompoundShapeURL() != currentCompoundShapeURL || !getModel()) {
         if (getShapeType() == SHAPE_TYPE_COMPOUND) {
-            getCollisionGeometryResource();
+            fetchCollisionGeometryResource();
         }
     }
 }
@@ -340,7 +340,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() const {
 
         if (model->isLoaded()) {
             if (!shapeURL.isEmpty() && !_compoundShapeResource) {
-                const_cast<RenderableModelEntityItem*>(this)->getCollisionGeometryResource();
+                const_cast<RenderableModelEntityItem*>(this)->fetchCollisionGeometryResource();
             }
 
             if (_compoundShapeResource && _compoundShapeResource->isLoaded()) {
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h
index ba185dee96..725c1d96c3 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h
@@ -122,7 +122,7 @@ private:
     void autoResizeJointArrays();
     void copyAnimationJointDataToModel();
     bool readyToAnimate() const;
-    void getCollisionGeometryResource();
+    void fetchCollisionGeometryResource();
 
     GeometryResource::Pointer _compoundShapeResource;
     std::vector<int> _jointMap;
@@ -179,7 +179,6 @@ private:
 
     bool _hasModel { false };
     ModelPointer _model;
-    GeometryResource::Pointer _compoundShapeResource;
     QString _lastTextures;
     bool _texturesLoaded { false };
     int _lastKnownCurrentFrame { -1 };

From b4807204095dffc31752f15d05cacc9a4c50f810 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Mon, 19 Nov 2018 17:32:28 -0800
Subject: [PATCH 03/12] proper shape support for EntityItem::contains(point)

---
 libraries/entities/src/EntityItem.cpp | 57 ++++++++++++++++++++++-----
 1 file changed, 48 insertions(+), 9 deletions(-)

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index bfa238d695..5000a8c2ea 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -1680,15 +1680,54 @@ void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const {
 }
 
 bool EntityItem::contains(const glm::vec3& point) const {
-    if (getShapeType() == SHAPE_TYPE_COMPOUND) {
-        bool success;
-        bool result = getAABox(success).contains(point);
-        return result && success;
-    } else {
-        ShapeInfo info;
-        info.setParams(getShapeType(), glm::vec3(0.5f));
-        adjustShapeInfoByRegistration(info);
-        return info.contains(worldToEntity(point));
+    // we transform into the "normalized entity-frame" where the bounding box is centered on the origin
+    // and has dimensions <1,1,1>
+    glm::vec3 localPoint = glm::vec3(glm::inverse(getEntityToWorldMatrix()) * glm::vec4(point, 1.0f));
+
+    const float NORMALIZED_HALF_SIDE = 0.5f;
+    const float NORMALIZED_RADIUS_SQUARED = NORMALIZED_HALF_SIDE * NORMALIZED_HALF_SIDE;
+    ShapeType shapeType = getShapeType();
+    switch(shapeType) {
+        case SHAPE_TYPE_NONE:
+            return false;
+        case SHAPE_TYPE_CAPSULE_X:
+        case SHAPE_TYPE_CAPSULE_Y:
+        case SHAPE_TYPE_CAPSULE_Z:
+        case SHAPE_TYPE_HULL:
+        case SHAPE_TYPE_PLANE:
+        case SHAPE_TYPE_COMPOUND:
+        case SHAPE_TYPE_SIMPLE_HULL:
+        case SHAPE_TYPE_SIMPLE_COMPOUND:
+        case SHAPE_TYPE_STATIC_MESH:
+        case SHAPE_TYPE_CIRCLE:
+        // the above cases not yet supported --> fall through to BOX case
+        case SHAPE_TYPE_BOX: {
+            localPoint = glm::abs(localPoint);
+            return localPoint.x <= NORMALIZED_HALF_SIDE &&
+                localPoint.y <= NORMALIZED_HALF_SIDE &&
+                localPoint.z <= NORMALIZED_HALF_SIDE;
+        }
+        case SHAPE_TYPE_SPHERE:
+        case SHAPE_TYPE_ELLIPSOID: {
+            return glm::length2(localPoint) <= NORMALIZED_RADIUS_SQUARED;
+        }
+        case SHAPE_TYPE_CYLINDER_X:
+            if (fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE) {
+                return (localPoint.y * localPoint.y + localPoint.z * localPoint.z <= NORMALIZED_RADIUS_SQUARED);
+            }
+            return false;
+        case SHAPE_TYPE_CYLINDER_Y:
+            if (fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE) {
+                return (localPoint.z * localPoint.z + localPoint.x * localPoint.x <= NORMALIZED_RADIUS_SQUARED);
+            }
+            return false;
+        case SHAPE_TYPE_CYLINDER_Z:
+            if (fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE) {
+                return (localPoint.x * localPoint.x + localPoint.y * localPoint.y <= NORMALIZED_RADIUS_SQUARED);
+            }
+            return false;
+        default:
+            return false;
     }
 }
 

From bb15b3a5d594fa96b558cdc38871b16ef89ce52d Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Mon, 19 Nov 2018 17:33:45 -0800
Subject: [PATCH 04/12] remove ShapeInfo::contains() which was a Bad Idea

---
 libraries/shared/src/ShapeInfo.cpp | 44 ------------------------------
 libraries/shared/src/ShapeInfo.h   |  4 ---
 2 files changed, 48 deletions(-)

diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp
index df8e61114d..3118fce891 100644
--- a/libraries/shared/src/ShapeInfo.cpp
+++ b/libraries/shared/src/ShapeInfo.cpp
@@ -250,50 +250,6 @@ float ShapeInfo::computeVolume() const {
     return volume;
 }
 
-bool ShapeInfo::contains(const glm::vec3& point) const {
-    switch(_type) {
-        case SHAPE_TYPE_SPHERE:
-            return glm::length(point) <= _halfExtents.x;
-        case SHAPE_TYPE_CYLINDER_X:
-            return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z;
-        case SHAPE_TYPE_CYLINDER_Y:
-            return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.x;
-        case SHAPE_TYPE_CYLINDER_Z:
-            return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y;
-        case SHAPE_TYPE_CAPSULE_X: {
-            if (glm::abs(point.x) <= _halfExtents.x - _halfExtents.y) {
-                return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.y;
-            } else {
-                glm::vec3 absPoint = glm::abs(point) - glm::vec3(_halfExtents.x, 0.0f, 0.0f);
-                return glm::length(absPoint) <= _halfExtents.y;
-            }
-        }
-        case SHAPE_TYPE_CAPSULE_Y: {
-            if (glm::abs(point.y) <= _halfExtents.y - _halfExtents.z) {
-                return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.z;
-            } else {
-                glm::vec3 absPoint = glm::abs(point) - glm::vec3(0.0f, _halfExtents.y, 0.0f);
-                return glm::length(absPoint) <= _halfExtents.z;
-            }
-        }
-        case SHAPE_TYPE_CAPSULE_Z: {
-            if (glm::abs(point.z) <= _halfExtents.z - _halfExtents.x) {
-                return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.x;
-            } else {
-                glm::vec3 absPoint = glm::abs(point) - glm::vec3(0.0f, 0.0f, _halfExtents.z);
-                return glm::length(absPoint) <= _halfExtents.x;
-            }
-        }
-        case SHAPE_TYPE_BOX:
-        default: {
-            glm::vec3 absPoint = glm::abs(point);
-            return absPoint.x <= _halfExtents.x
-            && absPoint.y <= _halfExtents.y
-            && absPoint.z <= _halfExtents.z;
-        }
-    }
-}
-
 const HashKey& ShapeInfo::getHash() const {
     // NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance.
     if (_hashKey.isNull() && _type != SHAPE_TYPE_NONE) {
diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h
index 16e260d9db..a2092c7f00 100644
--- a/libraries/shared/src/ShapeInfo.h
+++ b/libraries/shared/src/ShapeInfo.h
@@ -86,10 +86,6 @@ public:
 
     float computeVolume() const;
 
-    /// Returns whether point is inside the shape
-    /// For compound shapes it will only return whether it is inside the bounding box
-    bool contains(const glm::vec3& point) const;
-
     const HashKey& getHash() const;
 
 protected:

From a8325b5c00d850f8f91c76b3fc200cb635328e5d Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Mon, 19 Nov 2018 17:35:35 -0800
Subject: [PATCH 05/12] add ZoneEntityItem::contains() and support for shapes

---
 assignment-client/CMakeLists.txt              |  1 +
 .../src/entities/EntityServer.cpp             |  1 +
 libraries/entities/CMakeLists.txt             |  2 +-
 libraries/entities/src/ZoneEntityItem.cpp     | 87 ++++++++++++++++---
 libraries/entities/src/ZoneEntityItem.h       | 13 ++-
 libraries/physics/CMakeLists.txt              |  7 +-
 6 files changed, 94 insertions(+), 17 deletions(-)

diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt
index 229e3641d0..f28dc90b7d 100644
--- a/assignment-client/CMakeLists.txt
+++ b/assignment-client/CMakeLists.txt
@@ -14,6 +14,7 @@ link_hifi_libraries(
   audio avatars octree gpu graphics shaders fbx hfm entities
   networking animation recording shared script-engine embedded-webserver
   controllers physics plugins midi image
+  model-networking ktx shaders
 )
 
 add_dependencies(${TARGET_NAME} oven)
diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp
index 089fb3e52f..22308071eb 100644
--- a/assignment-client/src/entities/EntityServer.cpp
+++ b/assignment-client/src/entities/EntityServer.cpp
@@ -45,6 +45,7 @@ EntityServer::EntityServer(ReceivedMessage& message) :
 
     DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
     DependencyManager::set<AssignmentDynamicFactory>();
+    DependencyManager::set<ModelCache>();
 
     auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
     packetReceiver.registerListenerForTypes({ PacketType::EntityAdd,
diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt
index c51ae28d5f..542f6eb0e2 100644
--- a/libraries/entities/CMakeLists.txt
+++ b/libraries/entities/CMakeLists.txt
@@ -6,4 +6,4 @@ include_hifi_library_headers(fbx)
 include_hifi_library_headers(gpu)
 include_hifi_library_headers(image)
 include_hifi_library_headers(ktx)
-link_hifi_libraries(shared shaders networking octree avatars graphics model-networking)
\ No newline at end of file
+link_hifi_libraries(shared shaders networking octree model-networking avatars graphics model-networking)
diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp
index a265fe16cd..4c379f7290 100644
--- a/libraries/entities/src/ZoneEntityItem.cpp
+++ b/libraries/entities/src/ZoneEntityItem.cpp
@@ -11,7 +11,9 @@
 
 #include "ZoneEntityItem.h"
 
+#include <glm/gtx/transform.hpp>
 #include <QDebug>
+#include <QUrlQuery>
 
 #include <ByteCountCoding.h>
 
@@ -275,22 +277,53 @@ void ZoneEntityItem::debugDump() const {
     _bloomProperties.debugDump();
 }
 
-ShapeType ZoneEntityItem::getShapeType() const {
-    // Zones are not allowed to have a SHAPE_TYPE_NONE... they are always at least a SHAPE_TYPE_BOX
-    if (_shapeType == SHAPE_TYPE_COMPOUND) {
-        return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : DEFAULT_SHAPE_TYPE;
+void ZoneEntityItem::setShapeType(ShapeType type) {
+    //ShapeType typeArgument = type;
+    ShapeType oldShapeType = _shapeType;
+    switch(type) {
+        case SHAPE_TYPE_NONE:
+        case SHAPE_TYPE_CAPSULE_X:
+        case SHAPE_TYPE_CAPSULE_Y:
+        case SHAPE_TYPE_CAPSULE_Z:
+        case SHAPE_TYPE_HULL:
+        case SHAPE_TYPE_PLANE:
+        case SHAPE_TYPE_SIMPLE_HULL:
+        case SHAPE_TYPE_SIMPLE_COMPOUND:
+        case SHAPE_TYPE_STATIC_MESH:
+        case SHAPE_TYPE_CIRCLE:
+            // these types are unsupported for ZoneEntity
+            type = DEFAULT_SHAPE_TYPE;
+            break;
+        default:
+            break;
+    }
+    _shapeType = type;
+
+    if (type == SHAPE_TYPE_COMPOUND) {
+        if (type != oldShapeType) {
+            fetchCollisionGeometryResource();
+        }
     } else {
-        return _shapeType == SHAPE_TYPE_NONE ? DEFAULT_SHAPE_TYPE : _shapeType;
+        _shapeResource.reset();
     }
 }
 
+ShapeType ZoneEntityItem::getShapeType() const {
+    return _shapeType;
+}
+
 void ZoneEntityItem::setCompoundShapeURL(const QString& url) {
+    QString oldCompoundShapeURL = _compoundShapeURL;
     withWriteLock([&] {
         _compoundShapeURL = url;
-        if (_compoundShapeURL.isEmpty() && _shapeType == SHAPE_TYPE_COMPOUND) {
-            _shapeType = DEFAULT_SHAPE_TYPE;
-        }
     });
+    if (oldCompoundShapeURL != url) {
+        if (_shapeType == SHAPE_TYPE_COMPOUND) {
+            fetchCollisionGeometryResource();
+        } else {
+            _shapeResource.reset();
+        }
+    }
 }
 
 bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@@ -307,6 +340,28 @@ bool ZoneEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, c
     return _zonesArePickable;
 }
 
+bool ZoneEntityItem::contains(const glm::vec3& point) const {
+    GeometryResource::Pointer resource = _shapeResource;
+    if (_shapeType == SHAPE_TYPE_COMPOUND && resource) {
+        if (resource->isLoaded()) {
+            const HFMModel& hfmModel = resource->getHFMModel();
+
+            glm::vec3 minimum = glm::vec3(hfmModel.offset * glm::vec4(hfmModel.meshExtents.minimum, 1.0f));
+            glm::vec3 maximum = glm::vec3(hfmModel.offset * glm::vec4(hfmModel.meshExtents.maximum, 1.0f));
+            glm::vec3 modelExtentsDiagonal = maximum - minimum;
+            glm::vec3 offset = -minimum - (modelExtentsDiagonal * getRegistrationPoint());
+            glm::vec3 scale(getScaledDimensions() / modelExtentsDiagonal);
+
+            glm::mat4 hfmToEntityMatrix = glm::scale(scale) * glm::translate(offset);
+            glm::mat4 entityToWorldMatrix = getTransform().getMatrix();
+            glm::mat4 worldToHFMMatrix = glm::inverse(entityToWorldMatrix * hfmToEntityMatrix);
+
+            return hfmModel.convexHullContains(glm::vec3(worldToHFMMatrix * glm::vec4(point, 1.0f)));
+        }
+    }
+    return EntityItem::contains(point);
+}
+
 void ZoneEntityItem::setFilterURL(QString url) {
     withWriteLock([&] {
         _filterURL = url;
@@ -326,10 +381,6 @@ QString ZoneEntityItem::getFilterURL() const {
     return result;
 }
 
-bool ZoneEntityItem::hasCompoundShapeURL() const { 
-    return !getCompoundShapeURL().isEmpty();
-}
-
 QString ZoneEntityItem::getCompoundShapeURL() const { 
     QString result;
     withReadLock([&] {
@@ -403,3 +454,15 @@ void ZoneEntityItem::setSkyboxMode(const uint32_t value) {
 uint32_t ZoneEntityItem::getSkyboxMode() const {
     return _skyboxMode;
 }
+
+void ZoneEntityItem::fetchCollisionGeometryResource() {
+    QUrl hullURL(getCompoundShapeURL());
+    if (hullURL.isEmpty()) {
+        _shapeResource.reset();
+    } else {
+        QUrlQuery queryArgs(hullURL);
+        queryArgs.addQueryItem("collision-hull", "");
+        hullURL.setQuery(queryArgs);
+        _shapeResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(hullURL);
+    }
+}
diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h
index c2f4542aa6..813115add9 100644
--- a/libraries/entities/src/ZoneEntityItem.h
+++ b/libraries/entities/src/ZoneEntityItem.h
@@ -12,6 +12,9 @@
 #ifndef hifi_ZoneEntityItem_h
 #define hifi_ZoneEntityItem_h
 
+#include <ComponentMode.h>
+#include <model-networking/ModelCache.h>
+
 #include "KeyLightPropertyGroup.h"
 #include "AmbientLightPropertyGroup.h"
 #include "EntityItem.h"
@@ -19,7 +22,6 @@
 #include "SkyboxPropertyGroup.h"
 #include "HazePropertyGroup.h"
 #include "BloomPropertyGroup.h"
-#include <ComponentMode.h>
 
 class ZoneEntityItem : public EntityItem {
 public:
@@ -58,10 +60,9 @@ public:
     static void setDrawZoneBoundaries(bool value) { _drawZoneBoundaries = value; }
 
     virtual bool isReadyToComputeShape() const override { return false; }
-    void setShapeType(ShapeType type) override { withWriteLock([&] { _shapeType = type; }); }
+    virtual void setShapeType(ShapeType type) override;
     virtual ShapeType getShapeType() const override;
 
-    virtual bool hasCompoundShapeURL() const;
     QString getCompoundShapeURL() const;
     virtual void setCompoundShapeURL(const QString& url);
 
@@ -115,6 +116,8 @@ public:
                          BoxFace& face, glm::vec3& surfaceNormal,
                          QVariantMap& extraInfo, bool precisionPicking) const override;
 
+    bool contains(const glm::vec3& point) const override;
+
     virtual void debugDump() const override;
 
     static const ShapeType DEFAULT_SHAPE_TYPE;
@@ -156,6 +159,10 @@ protected:
 
     static bool _drawZoneBoundaries;
     static bool _zonesArePickable;
+
+    void fetchCollisionGeometryResource();
+    GeometryResource::Pointer _shapeResource;
+
 };
 
 #endif // hifi_ZoneEntityItem_h
diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt
index 96a55c8477..5249ed2950 100644
--- a/libraries/physics/CMakeLists.txt
+++ b/libraries/physics/CMakeLists.txt
@@ -1,11 +1,16 @@
 set(TARGET_NAME physics)
 setup_hifi_library()
-link_hifi_libraries(shared task workload fbx entities graphics)
+link_hifi_libraries(shared task workload fbx entities graphics shaders)
 include_hifi_library_headers(networking)
 include_hifi_library_headers(gpu)
 include_hifi_library_headers(avatars)
 include_hifi_library_headers(audio)
 include_hifi_library_headers(octree)
 include_hifi_library_headers(animation)
+include_hifi_library_headers(model-networking)
+include_hifi_library_headers(image)
+include_hifi_library_headers(ktx)
+include_hifi_library_headers(gpu)
+include_hifi_library_headers(hfm)
 
 target_bullet()

From 7625aebaa8be5aed5c1e2ec0aa3f5bd982f1ad56 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Wed, 21 Nov 2018 12:09:07 -0800
Subject: [PATCH 06/12] remove reduntant model-networking link dependency

---
 libraries/entities/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt
index 542f6eb0e2..fcbe563f88 100644
--- a/libraries/entities/CMakeLists.txt
+++ b/libraries/entities/CMakeLists.txt
@@ -6,4 +6,4 @@ include_hifi_library_headers(fbx)
 include_hifi_library_headers(gpu)
 include_hifi_library_headers(image)
 include_hifi_library_headers(ktx)
-link_hifi_libraries(shared shaders networking octree model-networking avatars graphics model-networking)
+link_hifi_libraries(shared shaders networking octree avatars graphics model-networking)

From 65e920039c04b4224453ffcbe24adeaec3f6c6ee Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Wed, 21 Nov 2018 12:30:30 -0800
Subject: [PATCH 07/12] cleaner return logic for EntityItem::contains()
 cylinder cases

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

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 5000a8c2ea..0b6f4c0cf5 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -1712,20 +1712,14 @@ bool EntityItem::contains(const glm::vec3& point) const {
             return glm::length2(localPoint) <= NORMALIZED_RADIUS_SQUARED;
         }
         case SHAPE_TYPE_CYLINDER_X:
-            if (fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE) {
-                return (localPoint.y * localPoint.y + localPoint.z * localPoint.z <= NORMALIZED_RADIUS_SQUARED);
-            }
-            return false;
+            return fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE &&
+                localPoint.y * localPoint.y + localPoint.z * localPoint.z <= NORMALIZED_RADIUS_SQUARED;
         case SHAPE_TYPE_CYLINDER_Y:
-            if (fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE) {
-                return (localPoint.z * localPoint.z + localPoint.x * localPoint.x <= NORMALIZED_RADIUS_SQUARED);
-            }
-            return false;
+            return fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE &&
+                localPoint.z * localPoint.z + localPoint.x * localPoint.x <= NORMALIZED_RADIUS_SQUARED;
         case SHAPE_TYPE_CYLINDER_Z:
-            if (fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE) {
-                return (localPoint.x * localPoint.x + localPoint.y * localPoint.y <= NORMALIZED_RADIUS_SQUARED);
-            }
-            return false;
+            return fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE &&
+                localPoint.x * localPoint.x + localPoint.y * localPoint.y <= NORMALIZED_RADIUS_SQUARED;
         default:
             return false;
     }

From a656ea723e0fc9c0ecd60038269a5e1379200b28 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Mon, 26 Nov 2018 09:14:08 -0800
Subject: [PATCH 08/12] special handling of SPHERE case in
 EntityItem::contains()

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

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 0b6f4c0cf5..76dd130f70 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -1680,13 +1680,24 @@ void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const {
 }
 
 bool EntityItem::contains(const glm::vec3& point) const {
+    ShapeType shapeType = getShapeType();
+
+    if (shapeType == SHAPE_TYPE_SPHERE) {
+        // SPHERE case is special:
+        // anything with shapeType == SPHERE must collide as a bounding sphere in the world-frame regardless of dimensions
+        // therefore we must do math using an unscaled localPoint relative to sphere center
+        glm::vec3 dimensions = getScaledDimensions();
+        glm::vec3 localPoint = point - (getWorldPosition() + getWorldOrientation() * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())));
+        const float HALF_SQUARED = 0.25f;
+        return glm::length2(localPoint) < HALF_SQUARED * glm::length2(dimensions);
+    }
+
     // we transform into the "normalized entity-frame" where the bounding box is centered on the origin
     // and has dimensions <1,1,1>
     glm::vec3 localPoint = glm::vec3(glm::inverse(getEntityToWorldMatrix()) * glm::vec4(point, 1.0f));
 
     const float NORMALIZED_HALF_SIDE = 0.5f;
     const float NORMALIZED_RADIUS_SQUARED = NORMALIZED_HALF_SIDE * NORMALIZED_HALF_SIDE;
-    ShapeType shapeType = getShapeType();
     switch(shapeType) {
         case SHAPE_TYPE_NONE:
             return false;
@@ -1707,8 +1718,8 @@ bool EntityItem::contains(const glm::vec3& point) const {
                 localPoint.y <= NORMALIZED_HALF_SIDE &&
                 localPoint.z <= NORMALIZED_HALF_SIDE;
         }
-        case SHAPE_TYPE_SPHERE:
         case SHAPE_TYPE_ELLIPSOID: {
+            // since we've transformed into the normalized space this is just a sphere-point intersection test
             return glm::length2(localPoint) <= NORMALIZED_RADIUS_SQUARED;
         }
         case SHAPE_TYPE_CYLINDER_X:

From a642af23b79b5deaf229a9baedde36e28435947a Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Tue, 27 Nov 2018 08:44:40 -0800
Subject: [PATCH 09/12] enable shapeType=ellipsoid and expose zone shapeType to
 UI

---
 .../entities/src/EntityItemProperties.cpp     |  1 +
 libraries/entities/src/ZoneEntityItem.cpp     |  1 -
 libraries/shared/src/ShapeInfo.cpp            |  3 ++-
 scripts/system/edit.js                        |  1 +
 scripts/system/html/js/entityProperties.js    | 20 ++++++++++++++++++-
 5 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index 1745658cf1..282e86c4d4 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -117,6 +117,7 @@ void buildStringToShapeTypeLookup() {
     addShapeType(SHAPE_TYPE_SIMPLE_HULL);
     addShapeType(SHAPE_TYPE_SIMPLE_COMPOUND);
     addShapeType(SHAPE_TYPE_STATIC_MESH);
+    addShapeType(SHAPE_TYPE_ELLIPSOID);
 }
 
 QHash<QString, MaterialMappingMode> stringToMaterialMappingModeLookup;
diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp
index 4c379f7290..61f07808f6 100644
--- a/libraries/entities/src/ZoneEntityItem.cpp
+++ b/libraries/entities/src/ZoneEntityItem.cpp
@@ -278,7 +278,6 @@ void ZoneEntityItem::debugDump() const {
 }
 
 void ZoneEntityItem::setShapeType(ShapeType type) {
-    //ShapeType typeArgument = type;
     ShapeType oldShapeType = _shapeType;
     switch(type) {
         case SHAPE_TYPE_NONE:
diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp
index 3118fce891..3426a79782 100644
--- a/libraries/shared/src/ShapeInfo.cpp
+++ b/libraries/shared/src/ShapeInfo.cpp
@@ -58,7 +58,8 @@ const char* shapeTypeNames[] = {
     "compound",
     "simple-hull",
     "simple-compound",
-    "static-mesh"
+    "static-mesh",
+    "ellipsoid"
 };
 
 static const size_t SHAPETYPE_NAME_COUNT = (sizeof(shapeTypeNames) / sizeof((shapeTypeNames)[0]));
diff --git a/scripts/system/edit.js b/scripts/system/edit.js
index 36f9af0ea7..28309ee98d 100644
--- a/scripts/system/edit.js
+++ b/scripts/system/edit.js
@@ -372,6 +372,7 @@ const DEFAULT_ENTITY_PROPERTIES = {
                 blue: 179
             },
         },
+        shapeType: "box",
         bloomMode: "inherit"
     },
     Model: {
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js
index 78ef8ac313..3554b7e5bf 100644
--- a/scripts/system/html/js/entityProperties.js
+++ b/scripts/system/html/js/entityProperties.js
@@ -1288,6 +1288,24 @@ const GROUPS = [
             },
         ]
     },
+    {
+        id: "zone_shape",
+        label: "ZONE SHAPE",
+        properties: [
+            {
+                label: "Shape Type",
+                type: "dropdown",
+                options: { "box": "Box", "sphere": "Sphere", "ellipsoid": "Ellipsoid", 
+                           "cylinder-y": "Cylinder", "compound": "Use Compound Shape URL" },
+                propertyID: "shapeType",
+            },
+            {
+                label: "Compound Shape URL",
+                type: "string",
+                propertyID: "compoundShapeURL",
+            },
+        ]
+    },
     {
         id: "physics",
         label: "PHYSICS",
@@ -1384,7 +1402,7 @@ const GROUPS_PER_TYPE = {
   None: [ 'base', 'spatial', 'behavior', 'collision', 'physics' ],
   Shape: [ 'base', 'shape', 'spatial', 'behavior', 'collision', 'physics' ],
   Text: [ 'base', 'text', 'spatial', 'behavior', 'collision', 'physics' ],
-  Zone: [ 'base', 'zone', 'spatial', 'behavior', 'collision', 'physics' ],
+  Zone: [ 'base', 'zone', 'spatial', 'behavior', 'zone_shape', 'physics' ],
   Model: [ 'base', 'model', 'spatial', 'behavior', 'collision', 'physics' ],
   Image: [ 'base', 'image', 'spatial', 'behavior', 'collision', 'physics' ],
   Web: [ 'base', 'web', 'spatial', 'behavior', 'collision', 'physics' ],

From 13a3982b5af70df361c607feb2331e3b17ead418 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Fri, 4 Jan 2019 12:31:29 -0800
Subject: [PATCH 10/12] fix ZoneEntityItem::contains() for model shapes

---
 .../src/RenderableModelEntityItem.cpp         | 21 +++++++++++--------
 .../src/RenderableZoneEntityItem.cpp          | 19 -----------------
 libraries/entities/src/ZoneEntityItem.cpp     |  9 ++++----
 libraries/hfm/src/hfm/HFM.cpp                 |  9 +++-----
 libraries/hfm/src/hfm/HFM.h                   |  1 +
 libraries/physics/src/EntityMotionState.cpp   |  1 -
 6 files changed, 20 insertions(+), 40 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 5693778e3a..aa449b8919 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -367,8 +367,6 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
     const uint32_t QUAD_STRIDE = 4;
 
     ShapeType type = getShapeType();
-    glm::vec3 dimensions = getScaledDimensions();
-    auto model = getModel();
     if (type == SHAPE_TYPE_COMPOUND) {
         updateModelBounds();
 
@@ -450,6 +448,11 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
         // to the visual model and apply them to the collision model (without regard for the
         // collision model's extents).
 
+        auto model = getModel();
+        // assert we never fall in here when model not fully loaded
+        assert(model && model->isLoaded());
+
+        glm::vec3 dimensions = getScaledDimensions();
         glm::vec3 scaleToFit = dimensions / model->getHFMModel().getUnscaledMeshExtents().size();
         // multiply each point by scale before handing the point-set off to the physics engine.
         // also determine the extents of the collision model.
@@ -461,11 +464,12 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
             }
         }
         shapeInfo.setParams(type, dimensions, getCompoundShapeURL());
+        adjustShapeInfoByRegistration(shapeInfo);
     } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
-        // TODO: assert we never fall in here when model not fully loaded
-        // assert(_model && _model->isLoaded());
-
         updateModelBounds();
+        auto model = getModel();
+        // assert we never fall in here when model not fully loaded
+        assert(model && model->isLoaded());
         model->updateGeometry();
 
         // compute meshPart local transforms
@@ -473,6 +477,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
         const HFMModel& hfmModel = model->getHFMModel();
         int numHFMMeshes = hfmModel.meshes.size();
         int totalNumVertices = 0;
+        glm::vec3 dimensions = getScaledDimensions();
         glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
         for (int i = 0; i < numHFMMeshes; i++) {
             const HFMMesh& mesh = hfmModel.meshes.at(i);
@@ -695,12 +700,10 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
         }
 
         shapeInfo.setParams(type, 0.5f * dimensions, getModelURL());
+        adjustShapeInfoByRegistration(shapeInfo);
     } else {
-        ModelEntityItem::computeShapeInfo(shapeInfo);
-        shapeInfo.setParams(type, 0.5f * dimensions);
+        EntityItem::computeShapeInfo(shapeInfo);
     }
-    // finally apply the registration offset to the shapeInfo
-    adjustShapeInfoByRegistration(shapeInfo);
 }
 
 void RenderableModelEntityItem::setJointMap(std::vector<int> jointMap) {
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
index 232e6efa67..57ff8ed8c2 100644
--- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
@@ -546,22 +546,3 @@ void ZoneEntityRenderer::setProceduralUserData(const QString& userData) {
     }
 }
 
-#if 0
-bool RenderableZoneEntityItem::contains(const glm::vec3& point) const {
-    if (getShapeType() != SHAPE_TYPE_COMPOUND) {
-        return EntityItem::contains(point);
-    }
-    const_cast<RenderableZoneEntityItem*>(this)->updateGeometry();
-
-    if (_model && _model->isActive() && EntityItem::contains(point)) {
-        return _model->convexHullContains(point);
-    }
-
-    return false;
-}
-
-void RenderableZoneEntityItem::notifyBoundChanged() {
-    notifyChangedRenderItem();
-}
-
-#endif
diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp
index 61f07808f6..7f7f6170d4 100644
--- a/libraries/entities/src/ZoneEntityItem.cpp
+++ b/libraries/entities/src/ZoneEntityItem.cpp
@@ -345,11 +345,10 @@ bool ZoneEntityItem::contains(const glm::vec3& point) const {
         if (resource->isLoaded()) {
             const HFMModel& hfmModel = resource->getHFMModel();
 
-            glm::vec3 minimum = glm::vec3(hfmModel.offset * glm::vec4(hfmModel.meshExtents.minimum, 1.0f));
-            glm::vec3 maximum = glm::vec3(hfmModel.offset * glm::vec4(hfmModel.meshExtents.maximum, 1.0f));
-            glm::vec3 modelExtentsDiagonal = maximum - minimum;
-            glm::vec3 offset = -minimum - (modelExtentsDiagonal * getRegistrationPoint());
-            glm::vec3 scale(getScaledDimensions() / modelExtentsDiagonal);
+            Extents meshExtents = hfmModel.getMeshExtents();
+            glm::vec3 meshExtentsDiagonal = meshExtents.maximum - meshExtents.minimum;
+            glm::vec3 offset = -meshExtents.minimum- (meshExtentsDiagonal * getRegistrationPoint());
+            glm::vec3 scale(getScaledDimensions() / meshExtentsDiagonal);
 
             glm::mat4 hfmToEntityMatrix = glm::scale(scale) * glm::translate(offset);
             glm::mat4 entityToWorldMatrix = getTransform().getMatrix();
diff --git a/libraries/hfm/src/hfm/HFM.cpp b/libraries/hfm/src/hfm/HFM.cpp
index 8f01956f17..b9e630456d 100644
--- a/libraries/hfm/src/hfm/HFM.cpp
+++ b/libraries/hfm/src/hfm/HFM.cpp
@@ -189,20 +189,17 @@ bool HFMModel::hasBlendedMeshes() const {
 }
 
 Extents HFMModel::getUnscaledMeshExtents() const {
-    const Extents& extents = meshExtents;
-
     // even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which
     // is captured in the offset matrix
-    glm::vec3 minimum = glm::vec3(offset * glm::vec4(extents.minimum, 1.0f));
-    glm::vec3 maximum = glm::vec3(offset * glm::vec4(extents.maximum, 1.0f));
+    glm::vec3 minimum = glm::vec3(offset * glm::vec4(meshExtents.minimum, 1.0f));
+    glm::vec3 maximum = glm::vec3(offset * glm::vec4(meshExtents.maximum, 1.0f));
     Extents scaledExtents = { minimum, maximum };
-
     return scaledExtents;
 }
 
 // TODO: Move to graphics::Mesh when Sam's ready
 bool HFMModel::convexHullContains(const glm::vec3& point) const {
-    if (!getUnscaledMeshExtents().containsPoint(point)) {
+    if (!meshExtents.containsPoint(point)) {
         return false;
     }
 
diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h
index 9846e7e891..78f608d72e 100644
--- a/libraries/hfm/src/hfm/HFM.h
+++ b/libraries/hfm/src/hfm/HFM.h
@@ -310,6 +310,7 @@ public:
 
     /// Returns the unscaled extents of the model's mesh
     Extents getUnscaledMeshExtents() const;
+    const Extents& getMeshExtents() const { return meshExtents; }
 
     bool convexHullContains(const glm::vec3& point) const;
 
diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp
index 4b635ef0be..dd906fe5c1 100644
--- a/libraries/physics/src/EntityMotionState.cpp
+++ b/libraries/physics/src/EntityMotionState.cpp
@@ -91,7 +91,6 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
     _serverRotation = localTransform.getRotation();
     _serverAcceleration = _entity->getAcceleration();
     _serverActionData = _entity->getDynamicData();
-
 }
 
 EntityMotionState::~EntityMotionState() {

From 3303bb70170c673f08d8749b4f38d4b72fa1068f Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Fri, 4 Jan 2019 12:36:45 -0800
Subject: [PATCH 11/12] EntityServer now depends on ModelFormatRegistry

---
 assignment-client/src/entities/EntityServer.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp
index 22308071eb..581d854909 100644
--- a/assignment-client/src/entities/EntityServer.cpp
+++ b/assignment-client/src/entities/EntityServer.cpp
@@ -23,6 +23,7 @@
 #include <EntityEditFilters.h>
 #include <NetworkingConstants.h>
 #include <AddressManager.h>
+#include <hfm/ModelFormatRegistry.h>
 
 #include "../AssignmentDynamicFactory.h"
 #include "AssignmentParentFinder.h"
@@ -45,6 +46,7 @@ EntityServer::EntityServer(ReceivedMessage& message) :
 
     DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
     DependencyManager::set<AssignmentDynamicFactory>();
+    DependencyManager::set<ModelFormatRegistry>(); // ModelFormatRegistry must be defined before ModelCache. See the ModelCache ctor
     DependencyManager::set<ModelCache>();
 
     auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();

From 5c750b40c9ee6049f6f0a18d577f9cbd39dbb353 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Sat, 5 Jan 2019 08:03:29 -0800
Subject: [PATCH 12/12] fix copy-n-paste errors in EntityItem::contains() for
 cylinders

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

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 76dd130f70..d05f087fdb 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -20,6 +20,7 @@
 #include <QtNetwork/QNetworkRequest>
 
 #include <glm/gtx/transform.hpp>
+#include <glm/gtx/component_wise.hpp>
 
 #include <BufferParser.h>
 #include <ByteCountCoding.h>
@@ -1714,9 +1715,7 @@ bool EntityItem::contains(const glm::vec3& point) const {
         // the above cases not yet supported --> fall through to BOX case
         case SHAPE_TYPE_BOX: {
             localPoint = glm::abs(localPoint);
-            return localPoint.x <= NORMALIZED_HALF_SIDE &&
-                localPoint.y <= NORMALIZED_HALF_SIDE &&
-                localPoint.z <= NORMALIZED_HALF_SIDE;
+            return glm::any(glm::lessThanEqual(localPoint, glm::vec3(NORMALIZED_HALF_SIDE)));
         }
         case SHAPE_TYPE_ELLIPSOID: {
             // since we've transformed into the normalized space this is just a sphere-point intersection test
@@ -1726,10 +1725,10 @@ bool EntityItem::contains(const glm::vec3& point) const {
             return fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE &&
                 localPoint.y * localPoint.y + localPoint.z * localPoint.z <= NORMALIZED_RADIUS_SQUARED;
         case SHAPE_TYPE_CYLINDER_Y:
-            return fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE &&
+            return fabsf(localPoint.y) <= NORMALIZED_HALF_SIDE &&
                 localPoint.z * localPoint.z + localPoint.x * localPoint.x <= NORMALIZED_RADIUS_SQUARED;
         case SHAPE_TYPE_CYLINDER_Z:
-            return fabsf(localPoint.x) <= NORMALIZED_HALF_SIDE &&
+            return fabsf(localPoint.z) <= NORMALIZED_HALF_SIDE &&
                 localPoint.x * localPoint.x + localPoint.y * localPoint.y <= NORMALIZED_RADIUS_SQUARED;
         default:
             return false;