From f6681d4b3dd39424fa1478a07795dd4d1ac5038f Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Thu, 7 Jul 2016 13:07:43 -0700
Subject: [PATCH 1/8] remove unused cruft

---
 libraries/render-utils/src/GeometryCache.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h
index 1bfdc1798e..385f2c6fa4 100644
--- a/libraries/render-utils/src/GeometryCache.h
+++ b/libraries/render-utils/src/GeometryCache.h
@@ -402,8 +402,6 @@ private:
     QHash<Vec2FloatPairPair, GridBuffer> _gridBuffers;
     QHash<int, GridBuffer> _registeredGridBuffers;
 
-    QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
-    
     gpu::ShaderPointer _simpleShader;
     gpu::ShaderPointer _unlitShader;
     static render::ShapePipelinePointer _simplePipeline;

From 9f7d2cf2630832aa25f9af9a2e78539d9129c05f Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Thu, 7 Jul 2016 13:08:18 -0700
Subject: [PATCH 2/8] NetworkGeometry --> GeometryResourceWatcher

Model class gets render and collision geometries with watchers
also changed names for readability
---
 .../src/model-networking/ModelCache.cpp       | 76 +++++++++-------
 .../src/model-networking/ModelCache.h         | 87 +++++++++----------
 .../render-utils/src/MeshPartPayload.cpp      |  6 +-
 libraries/render-utils/src/Model.cpp          | 77 ++++++++--------
 libraries/render-utils/src/Model.h            | 33 ++++---
 5 files changed, 144 insertions(+), 135 deletions(-)

diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp
index 40388e6123..afe86e0d1e 100644
--- a/libraries/model-networking/src/model-networking/ModelCache.cpp
+++ b/libraries/model-networking/src/model-networking/ModelCache.cpp
@@ -70,7 +70,7 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
         auto modelCache = DependencyManager::get<ModelCache>();
         GeometryExtra extra{ mapping, _textureBaseUrl };
 
-        // Get the raw GeometryResource, not the wrapped NetworkGeometry
+        // Get the raw GeometryResource
         _geometryResource = modelCache->getResource(url, QUrl(), &extra).staticCast<GeometryResource>();
         // Avoid caching nested resources - their references will be held by the parent
         _geometryResource->_isCacheable = false;
@@ -90,8 +90,8 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
 
 void GeometryMappingResource::onGeometryMappingLoaded(bool success) {
     if (success && _geometryResource) {
-        _geometry = _geometryResource->_geometry;
-        _shapes = _geometryResource->_shapes;
+        _fbxGeometry = _geometryResource->_fbxGeometry;
+        _meshParts = _geometryResource->_meshParts;
         _meshes = _geometryResource->_meshes;
         _materials = _geometryResource->_materials;
 
@@ -200,31 +200,31 @@ void GeometryDefinitionResource::downloadFinished(const QByteArray& data) {
 
 void GeometryDefinitionResource::setGeometryDefinition(FBXGeometry::Pointer fbxGeometry) {
     // Assume ownership of the geometry pointer
-    _geometry = fbxGeometry;
+    _fbxGeometry = fbxGeometry;
 
     // Copy materials
     QHash<QString, size_t> materialIDAtlas;
-    for (const FBXMaterial& material : _geometry->materials) {
+    for (const FBXMaterial& material : _fbxGeometry->materials) {
         materialIDAtlas[material.materialID] = _materials.size();
         _materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
     }
 
-    std::shared_ptr<NetworkMeshes> meshes = std::make_shared<NetworkMeshes>();
-    std::shared_ptr<NetworkShapes> shapes = std::make_shared<NetworkShapes>();
+    std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
+    std::shared_ptr<GeometryMeshParts> shapes = std::make_shared<GeometryMeshParts>();
     int meshID = 0;
-    for (const FBXMesh& mesh : _geometry->meshes) {
+    for (const FBXMesh& mesh : _fbxGeometry->meshes) {
         // Copy mesh pointers
         meshes->emplace_back(mesh._mesh);
         int partID = 0;
         for (const FBXMeshPart& part : mesh.parts) {
             // Construct local shapes
-            shapes->push_back(std::make_shared<NetworkShape>(meshID, partID, (int)materialIDAtlas[part.materialID]));
+            shapes->push_back(std::make_shared<MeshPart>(meshID, partID, (int)materialIDAtlas[part.materialID]));
             partID++;
         }
         meshID++;
     }
     _meshes = meshes;
-    _shapes = shapes;
+    _meshParts = shapes;
 
     finishedLoading(true);
 }
@@ -250,17 +250,15 @@ QSharedPointer<Resource> ModelCache::createResource(const QUrl& url, const QShar
     return QSharedPointer<Resource>(resource, &Resource::deleter);
 }
 
-std::shared_ptr<NetworkGeometry> ModelCache::getGeometry(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) {
+GeometryResource::Pointer ModelCache::fetchResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) {
     GeometryExtra geometryExtra = { mapping, textureBaseUrl };
     GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra).staticCast<GeometryResource>();
     if (resource) {
         if (resource->isLoaded() && resource->shouldSetTextures()) {
             resource->setTextures();
         }
-        return std::make_shared<NetworkGeometry>(resource);
-    } else {
-        return NetworkGeometry::Pointer();
     }
+    return resource;
 }
 
 const QVariantMap Geometry::getTextures() const {
@@ -278,9 +276,9 @@ const QVariantMap Geometry::getTextures() const {
 
 // FIXME: The materials should only be copied when modified, but the Model currently caches the original
 Geometry::Geometry(const Geometry& geometry) {
-    _geometry = geometry._geometry;
+    _fbxGeometry = geometry._fbxGeometry;
     _meshes = geometry._meshes;
-    _shapes = geometry._shapes;
+    _meshParts = geometry._meshParts;
 
     _materials.reserve(geometry._materials.size());
     for (const auto& material : geometry._materials) {
@@ -337,8 +335,8 @@ bool Geometry::areTexturesLoaded() const {
 }
 
 const std::shared_ptr<const NetworkMaterial> Geometry::getShapeMaterial(int shapeID) const {
-    if ((shapeID >= 0) && (shapeID < (int)_shapes->size())) {
-        int materialID = _shapes->at(shapeID)->materialID;
+    if ((shapeID >= 0) && (shapeID < (int)_meshParts->size())) {
+        int materialID = _meshParts->at(shapeID)->materialID;
         if ((materialID >= 0) && (materialID < (int)_materials.size())) {
             return _materials[materialID];
         }
@@ -352,7 +350,7 @@ void GeometryResource::deleter() {
 }
 
 void GeometryResource::setTextures() {
-    for (const FBXMaterial& material : _geometry->materials) {
+    for (const FBXMaterial& material : _fbxGeometry->materials) {
         _materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
     }
 }
@@ -361,26 +359,40 @@ void GeometryResource::resetTextures() {
     _materials.clear();
 }
 
-NetworkGeometry::NetworkGeometry(const GeometryResource::Pointer& networkGeometry) : _resource(networkGeometry) {
-    connect(_resource.data(), &Resource::finished, this, &NetworkGeometry::resourceFinished);
-    connect(_resource.data(), &Resource::onRefresh, this, &NetworkGeometry::resourceRefreshed);
+void GeometryResourceWatcher::startWatching() {
+    connect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished);
+    connect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed);
     if (_resource->isLoaded()) {
         resourceFinished(!_resource->getURL().isEmpty());
     }
 }
 
-void NetworkGeometry::resourceFinished(bool success) {
-    // FIXME: Model is not set up to handle a refresh
-    if (_instance) {
-        return;
-    }
-    if (success) {
-        _instance = std::make_shared<Geometry>(*_resource);
-    }
-    emit finished(success);
+void GeometryResourceWatcher::stopWatching() {
+    disconnect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished);
+    disconnect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed);
 }
 
-void NetworkGeometry::resourceRefreshed() {
+void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) {
+    if (_resource) {
+        stopWatching();
+    }
+    _resource = resource;
+    if (_resource) {
+        if (_resource->isLoaded()) {
+            _geometryRef = std::make_shared<Geometry>(*_resource);
+        } else {
+            startWatching();
+        }
+    }
+}
+
+void GeometryResourceWatcher::resourceFinished(bool success) {
+    if (success) {
+        _geometryRef = std::make_shared<Geometry>(*_resource);
+    }
+}
+
+void GeometryResourceWatcher::resourceRefreshed() {
     // FIXME: Model is not set up to handle a refresh
     // _instance.reset();
 }
diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h
index f15e1106e2..c450f96846 100644
--- a/libraries/model-networking/src/model-networking/ModelCache.h
+++ b/libraries/model-networking/src/model-networking/ModelCache.h
@@ -22,52 +22,30 @@
 #include "TextureCache.h"
 
 // Alias instead of derive to avoid copying
-using NetworkMesh = model::Mesh;
 
 class NetworkTexture;
 class NetworkMaterial;
-class NetworkShape;
-class NetworkGeometry;
+class MeshPart;
 
 class GeometryMappingResource;
 
-/// Stores cached model geometries.
-class ModelCache : public ResourceCache, public Dependency {
-    Q_OBJECT
-    SINGLETON_DEPENDENCY
-
-public:
-    /// Loads a model geometry from the specified URL.
-    std::shared_ptr<NetworkGeometry> getGeometry(const QUrl& url,
-        const QVariantHash& mapping = QVariantHash(), const QUrl& textureBaseUrl = QUrl());
-
-protected:
-    friend class GeometryMappingResource;
-
-    virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
-        const void* extra);
-
-private:
-    ModelCache();
-    virtual ~ModelCache() = default;
-};
-
 class Geometry {
 public:
     using Pointer = std::shared_ptr<Geometry>;
+    using WeakPointer = std::weak_ptr<Geometry>;
 
     Geometry() = default;
     Geometry(const Geometry& geometry);
 
     // Immutable over lifetime
-    using NetworkMeshes = std::vector<std::shared_ptr<const NetworkMesh>>;
-    using NetworkShapes = std::vector<std::shared_ptr<const NetworkShape>>;
+    using GeometryMeshes = std::vector<std::shared_ptr<const model::Mesh>>;
+    using GeometryMeshParts = std::vector<std::shared_ptr<const MeshPart>>;
 
     // Mutable, but must retain structure of vector
     using NetworkMaterials = std::vector<std::shared_ptr<NetworkMaterial>>;
 
-    const FBXGeometry& getGeometry() const { return *_geometry; }
-    const NetworkMeshes& getMeshes() const { return *_meshes; }
+    const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; }
+    const GeometryMeshes& getMeshes() const { return *_meshes; }
     const std::shared_ptr<const NetworkMaterial> getShapeMaterial(int shapeID) const;
 
     const QVariantMap getTextures() const;
@@ -79,9 +57,9 @@ protected:
     friend class GeometryMappingResource;
 
     // Shared across all geometries, constant throughout lifetime
-    std::shared_ptr<const FBXGeometry> _geometry;
-    std::shared_ptr<const NetworkMeshes> _meshes;
-    std::shared_ptr<const NetworkShapes> _shapes;
+    std::shared_ptr<const FBXGeometry> _fbxGeometry;
+    std::shared_ptr<const GeometryMeshes> _meshes;
+    std::shared_ptr<const GeometryMeshParts> _meshParts;
 
     // Copied to each geometry, mutable throughout lifetime via setTextures
     NetworkMaterials _materials;
@@ -108,7 +86,7 @@ protected:
 
     // Geometries may not hold onto textures while cached - that is for the texture cache
     // Instead, these methods clear and reset textures from the geometry when caching/loading
-    bool shouldSetTextures() const { return _geometry && _materials.empty(); }
+    bool shouldSetTextures() const { return _fbxGeometry && _materials.empty(); }
     void setTextures();
     void resetTextures();
 
@@ -118,22 +96,21 @@ protected:
     bool _isCacheable { true };
 };
 
-class NetworkGeometry : public QObject {
+class GeometryResourceWatcher : public QObject {
     Q_OBJECT
 public:
-    using Pointer = std::shared_ptr<NetworkGeometry>;
+    using Pointer = std::shared_ptr<GeometryResourceWatcher>;
 
-    NetworkGeometry() = delete;
-    NetworkGeometry(const GeometryResource::Pointer& networkGeometry);
+    GeometryResourceWatcher() = delete;
+    GeometryResourceWatcher(Geometry::Pointer& geometryPtr) : _geometryRef(geometryPtr) {}
 
-    const QUrl& getURL() { return _resource->getURL(); }
+    void setResource(GeometryResource::Pointer resource);
 
-    /// Returns the geometry, if it is loaded (must be checked!)
-    const Geometry::Pointer& getGeometry() { return _instance; }
+    const QUrl& getURL() const { return _resource->getURL(); }
 
-signals:
-    /// Emitted when the NetworkGeometry loads (or fails to)
-    void finished(bool success);
+private:
+    void startWatching();
+    void stopWatching();
 
 private slots:
     void resourceFinished(bool success);
@@ -141,7 +118,27 @@ private slots:
 
 private:
     GeometryResource::Pointer _resource;
-    Geometry::Pointer _instance { nullptr };
+    Geometry::Pointer& _geometryRef;
+};
+
+/// Stores cached model geometries.
+class ModelCache : public ResourceCache, public Dependency {
+    Q_OBJECT
+    SINGLETON_DEPENDENCY
+
+public:
+    GeometryResource::Pointer fetchResource(const QUrl& url,
+        const QVariantHash& mapping = QVariantHash(), const QUrl& textureBaseUrl = QUrl());
+
+protected:
+    friend class GeometryMappingResource;
+
+    virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
+        const void* extra);
+
+private:
+    ModelCache();
+    virtual ~ModelCache() = default;
 };
 
 class NetworkMaterial : public model::Material {
@@ -185,9 +182,9 @@ private:
     bool _isOriginal { true };
 };
 
-class NetworkShape {
+class MeshPart {
 public:
-    NetworkShape(int mesh, int part, int material) : meshID { mesh }, partID { part }, materialID { material } {}
+    MeshPart(int mesh, int part, int material) : meshID { mesh }, partID { part }, materialID { material } {}
     int meshID { -1 };
     int partID { -1 };
     int materialID { -1 };
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index 08c8dc23b4..4746b5a0c5 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -310,7 +310,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int par
     _shapeID(shapeIndex) {
 
     assert(_model && _model->isLoaded());
-    auto& modelMesh = _model->getGeometry()->getGeometry()->getMeshes().at(_meshIndex);
+    auto& modelMesh = _model->getGeometry()->getMeshes().at(_meshIndex);
     updateMeshPart(modelMesh, partIndex);
 
     updateTransform(transform, offsetTransform);
@@ -331,7 +331,7 @@ void ModelMeshPartPayload::initCache() {
         _isBlendShaped = !mesh.blendshapes.isEmpty();
     }
 
-    auto networkMaterial = _model->getGeometry()->getGeometry()->getShapeMaterial(_shapeID);
+    auto networkMaterial = _model->getGeometry()->getShapeMaterial(_shapeID);
     if (networkMaterial) {
         _drawMaterial = networkMaterial;
     };
@@ -384,7 +384,7 @@ ItemKey ModelMeshPartPayload::getKey() const {
 ShapeKey ModelMeshPartPayload::getShapeKey() const {
     assert(_model->isLoaded());
     const FBXGeometry& geometry = _model->getFBXGeometry();
-    const auto& networkMeshes = _model->getGeometry()->getGeometry()->getMeshes();
+    const auto& networkMeshes = _model->getGeometry()->getMeshes();
 
     // guard against partially loaded meshes
     if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size()) {
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 43eced3107..ab9e0e7403 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -31,7 +31,7 @@
 using namespace std;
 
 int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>();
-int weakNetworkGeometryPointerTypeId = qRegisterMetaType<std::weak_ptr<NetworkGeometry> >();
+int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<Geometry::WeakPointer >();
 int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
 float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
 #define HTTP_INVALID_COM "http://invalid.com"
@@ -79,6 +79,10 @@ void initCollisionHullMaterials() {
 
 Model::Model(RigPointer rig, QObject* parent) :
     QObject(parent),
+    _renderGeometry(),
+    _collisionGeometry(),
+    _renderWatcher(_renderGeometry),
+    _collisionWatcher(_collisionGeometry),
     _translation(0.0f),
     _rotation(),
     _scale(1.0f, 1.0f, 1.0f),
@@ -98,7 +102,6 @@ Model::Model(RigPointer rig, QObject* parent) :
     _calculatedMeshTrianglesValid(false),
     _meshGroupsKnown(false),
     _isWireframe(false),
-    _renderCollisionHull(false),
     _rig(rig) {
     // we may have been created in the network thread, but we live in the main thread
     if (_viewState) {
@@ -116,7 +119,7 @@ AbstractViewStateInterface* Model::_viewState = NULL;
 
 bool Model::needsFixupInScene() const {
     if (readyToAddToScene()) {
-        if (_needsUpdateTextures && _geometry->getGeometry()->areTexturesLoaded()) {
+        if (_needsUpdateTextures && _renderGeometry->areTexturesLoaded()) {
             _needsUpdateTextures = false;
             return true;
         }
@@ -793,13 +796,13 @@ int Model::getLastFreeJointIndex(int jointIndex) const {
 void Model::setTextures(const QVariantMap& textures) {
     if (isLoaded()) {
         _needsUpdateTextures = true;
-        _geometry->getGeometry()->setTextures(textures);
+        _renderGeometry->setTextures(textures);
     }
 }
 
 void Model::setURL(const QUrl& url) {
     // don't recreate the geometry if it's the same URL
-    if (_url == url && _geometry && _geometry->getURL() == url) {
+    if (_url == url && _renderWatcher.getURL() == url) {
         return;
     }
 
@@ -818,7 +821,7 @@ void Model::setURL(const QUrl& url) {
     invalidCalculatedMeshBoxes();
     deleteGeometry();
 
-    _geometry = DependencyManager::get<ModelCache>()->getGeometry(url);
+    _renderWatcher.setResource(DependencyManager::get<ModelCache>()->fetchResource(url));
     onInvalidate();
 }
 
@@ -827,7 +830,7 @@ void Model::setCollisionModelURL(const QUrl& url) {
         return;
     }
     _collisionUrl = url;
-    _collisionGeometry = DependencyManager::get<ModelCache>()->getGeometry(url);
+    _collisionWatcher.setResource(DependencyManager::get<ModelCache>()->fetchResource(url));
 }
 
 bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const {
@@ -883,7 +886,7 @@ QStringList Model::getJointNames() const {
 class Blender : public QRunnable {
 public:
 
-    Blender(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
+    Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
         const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients);
 
     virtual void run();
@@ -892,12 +895,12 @@ private:
 
     ModelPointer _model;
     int _blendNumber;
-    std::weak_ptr<NetworkGeometry> _geometry;
+    Geometry::WeakPointer _geometry;
     QVector<FBXMesh> _meshes;
     QVector<float> _blendshapeCoefficients;
 };
 
-Blender::Blender(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
+Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
         const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients) :
     _model(model),
     _blendNumber(blendNumber),
@@ -940,7 +943,7 @@ void Blender::run() {
     // post the result to the geometry cache, which will dispatch to the model if still alive
     QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",
         Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber),
-        Q_ARG(const std::weak_ptr<NetworkGeometry>&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
+        Q_ARG(const Geometry::WeakPointer&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
         Q_ARG(const QVector<glm::vec3>&, normals));
 }
 
@@ -1151,7 +1154,7 @@ bool Model::maybeStartBlender() {
     if (isLoaded()) {
         const FBXGeometry& fbxGeometry = getFBXGeometry();
         if (fbxGeometry.hasBlendedMeshes()) {
-            QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _geometry,
+            QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _renderGeometry,
                 fbxGeometry.meshes, _blendshapeCoefficients));
             return true;
         }
@@ -1159,10 +1162,10 @@ bool Model::maybeStartBlender() {
     return false;
 }
 
-void Model::setBlendedVertices(int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
+void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
         const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
     auto geometryRef = geometry.lock();
-    if (!geometryRef || _geometry != geometryRef || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) {
+    if (!geometryRef || _renderGeometry != geometryRef || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) {
         return;
     }
     _appliedBlendNumber = blendNumber;
@@ -1205,27 +1208,23 @@ AABox Model::getRenderableMeshBound() const {
 }
 
 void Model::segregateMeshGroups() {
-    NetworkGeometry::Pointer networkGeometry;
+    Geometry::Pointer geometry;
     bool showingCollisionHull = false;
     if (_showCollisionHull && _collisionGeometry) {
         if (isCollisionLoaded()) {
-            networkGeometry = _collisionGeometry;
+            geometry = _collisionGeometry;
             showingCollisionHull = true;
         } else {
             return;
         }
     } else {
         assert(isLoaded());
-        networkGeometry = _geometry;
+        geometry = _renderGeometry;
     }
-    const FBXGeometry& geometry = networkGeometry->getGeometry()->getGeometry();
-    const auto& networkMeshes = networkGeometry->getGeometry()->getMeshes();
+    const auto& meshes = geometry->getMeshes();
 
     // all of our mesh vectors must match in size
-    auto geoMeshesSize = geometry.meshes.size();
-    if ((int)networkMeshes.size() != geoMeshesSize ||
-      //  geometry.meshes.size() != _meshStates.size()) {
-        geoMeshesSize > _meshStates.size()) {
+    if ((int)meshes.size() != _meshStates.size()) {
         qDebug() << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
         return;
     }
@@ -1249,23 +1248,25 @@ void Model::segregateMeshGroups() {
 
     // Run through all of the meshes, and place them into their segregated, but unsorted buckets
     int shapeID = 0;
-    for (int i = 0; i < (int)networkMeshes.size(); i++) {
-        const FBXMesh& mesh = geometry.meshes.at(i);
-        const auto& networkMesh = networkMeshes.at(i);
+    uint32_t numMeshes = (uint32_t)meshes.size();
+    for (uint32_t i = 0; i < numMeshes; i++) {
+        const auto& mesh = meshes.at(i);
+        if (mesh) {
 
-        // Create the render payloads
-        int totalParts = mesh.parts.size();
-        for (int partIndex = 0; partIndex < totalParts; partIndex++) {
-            if (showingCollisionHull) {
-                if (_collisionHullMaterials.empty()) {
-                    initCollisionHullMaterials();
+            // Create the render payloads
+            int numParts = (int)mesh->getNumParts();
+            for (int partIndex = 0; partIndex < numParts; partIndex++) {
+                if (showingCollisionHull) {
+                    if (_collisionHullMaterials.empty()) {
+                        initCollisionHullMaterials();
+                    }
+                    _collisionRenderItemsSet << std::make_shared<MeshPartPayload>(mesh, partIndex, _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS], transform, offset);
+                } else {
+                    _modelMeshRenderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
                 }
-                _collisionRenderItemsSet << std::make_shared<MeshPartPayload>(networkMesh, partIndex, _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS], transform, offset);
-            } else {
-                _modelMeshRenderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
-            }
 
-            shapeID++;
+                shapeID++;
+            }
         }
     }
     _meshGroupsKnown = true;
@@ -1328,7 +1329,7 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) {
 }
 
 void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber,
-        const std::weak_ptr<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
+        const Geometry::WeakPointer& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
     if (model) {
         model->setBlendedVertices(blendNumber, geometry, vertices, normals);
     }
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index 6a7c9ec560..aa0c49f720 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -97,7 +97,7 @@ public:
                     bool showCollisionHull = false);
     void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
     void renderSetup(RenderArgs* args);
-    bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && getGeometry()->getGeometry()->getMeshes().empty()); }
+    bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _renderGeometry->getMeshes().empty()); }
 
     bool isVisible() const { return _isVisible; }
 
@@ -107,11 +107,11 @@ public:
     bool maybeStartBlender();
 
     /// Sets blended vertices computed in a separate thread.
-    void setBlendedVertices(int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
+    void setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
         const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
 
-    bool isLoaded() const { return _geometry && _geometry->getGeometry(); }
-    bool isCollisionLoaded() const { return _collisionGeometry && _collisionGeometry->getGeometry(); }
+    bool isLoaded() const { return (bool)_renderGeometry; }
+    bool isCollisionLoaded() const { return (bool)_collisionGeometry; }
 
     void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; }
     bool isWireframe() const { return _isWireframe; }
@@ -128,18 +128,18 @@ public:
     virtual void updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation);
 
     /// Returns a reference to the shared geometry.
-    const NetworkGeometry::Pointer& getGeometry() const { return _geometry; }
+    const Geometry::Pointer& getGeometry() const { return _renderGeometry; }
     /// Returns a reference to the shared collision geometry.
-    const NetworkGeometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
+    const Geometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
 
-    const QVariantMap getTextures() const { assert(isLoaded()); return _geometry->getGeometry()->getTextures(); }
+    const QVariantMap getTextures() const { assert(isLoaded()); return _renderGeometry->getTextures(); }
     void setTextures(const QVariantMap& textures);
 
     /// Provided as a convenience, will crash if !isLoaded()
     // And so that getGeometry() isn't chained everywhere
-    const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return getGeometry()->getGeometry()->getGeometry(); }
+    const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return _renderGeometry->getFBXGeometry(); }
     /// Provided as a convenience, will crash if !isCollisionLoaded()
-    const FBXGeometry& getCollisionFBXGeometry() const { assert(isCollisionLoaded()); return getCollisionGeometry()->getGeometry()->getGeometry(); }
+    const FBXGeometry& getCollisionFBXGeometry() const { assert(isCollisionLoaded()); return _collisionGeometry->getFBXGeometry(); }
 
     // Set the model to use for collisions.
     // Should only be called from the model's rendering thread to avoid access violations of changed geometry.
@@ -263,7 +263,11 @@ protected:
     /// \return true if joint exists
     bool getJointPosition(int jointIndex, glm::vec3& position) const;
 
-    NetworkGeometry::Pointer _geometry;
+    Geometry::Pointer _renderGeometry; // only ever set by its watcher
+    Geometry::Pointer _collisionGeometry; // only ever set by its watcher
+
+    GeometryResourceWatcher _renderWatcher;
+    GeometryResourceWatcher _collisionWatcher;
 
     glm::vec3 _translation;
     glm::quat _rotation;
@@ -330,8 +334,6 @@ protected:
     void deleteGeometry();
     void initJointTransforms();
 
-    NetworkGeometry::Pointer _collisionGeometry;
-
     float _pupilDilation;
     QVector<float> _blendshapeCoefficients;
 
@@ -373,9 +375,6 @@ protected:
 
     static AbstractViewStateInterface* _viewState;
 
-    bool _renderCollisionHull;
-
-
     QSet<std::shared_ptr<MeshPartPayload>> _collisionRenderItemsSet;
     QMap<render::ItemID, render::PayloadPointer> _collisionRenderItems;
 
@@ -395,7 +394,7 @@ protected:
 };
 
 Q_DECLARE_METATYPE(ModelPointer)
-Q_DECLARE_METATYPE(std::weak_ptr<NetworkGeometry>)
+Q_DECLARE_METATYPE(Geometry::WeakPointer)
 
 /// Handle management of pending models that need blending
 class ModelBlender : public QObject, public Dependency {
@@ -408,7 +407,7 @@ public:
     void noteRequiresBlend(ModelPointer model);
 
 public slots:
-    void setBlendedVertices(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
+    void setBlendedVertices(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
         const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
 
 private:

From 25fdea6bac0693d4e74a2e69dcc70d2f8542e418 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Fri, 8 Jul 2016 23:02:05 -0700
Subject: [PATCH 3/8] fix for change of API after rebase

---
 .../src/RenderableModelEntityItem.cpp                | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index d63361538a..bef790299c 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -709,9 +709,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
         // compute meshPart local transforms
         QVector<glm::mat4> localTransforms;
         const FBXGeometry& fbxGeometry = _model->getFBXGeometry();
-        int32_t numMeshes = (int32_t)fbxGeometry.meshes.size();
-        int32_t totalNumVertices = 0;
-        for (int32_t i = 0; i < numMeshes; i++) {
+        int numFbxMeshes = fbxGeometry.meshes.size();
+        int totalNumVertices = 0;
+        for (int i = 0; i < numFbxMeshes; i++) {
             const FBXMesh& mesh = fbxGeometry.meshes.at(i);
             if (mesh.clusters.size() > 0) {
                 const FBXCluster& cluster = mesh.clusters.at(0);
@@ -730,10 +730,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
             return;
         }
 
-        auto& meshes = _model->getGeometry()->getGeometry()->getMeshes();
-
-        // the render geometry's mesh count should match that of the FBXGeometry
-        assert(numMeshes == (int32_t)(meshes.size()));
+        auto& meshes = _model->getGeometry()->getMeshes();
+        int32_t numMeshes = (int32_t)(meshes.size());
 
         ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
         pointCollection.clear();

From c50d41c532047a53445519c50efc996f4b8f9a80 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Fri, 8 Jul 2016 23:08:49 -0700
Subject: [PATCH 4/8] finish name changes as per PR feedback

---
 .../src/model-networking/ModelCache.cpp            | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp
index afe86e0d1e..442bf008e7 100644
--- a/libraries/model-networking/src/model-networking/ModelCache.cpp
+++ b/libraries/model-networking/src/model-networking/ModelCache.cpp
@@ -210,21 +210,21 @@ void GeometryDefinitionResource::setGeometryDefinition(FBXGeometry::Pointer fbxG
     }
 
     std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
-    std::shared_ptr<GeometryMeshParts> shapes = std::make_shared<GeometryMeshParts>();
+    std::shared_ptr<GeometryMeshParts> parts = std::make_shared<GeometryMeshParts>();
     int meshID = 0;
     for (const FBXMesh& mesh : _fbxGeometry->meshes) {
         // Copy mesh pointers
         meshes->emplace_back(mesh._mesh);
         int partID = 0;
         for (const FBXMeshPart& part : mesh.parts) {
-            // Construct local shapes
-            shapes->push_back(std::make_shared<MeshPart>(meshID, partID, (int)materialIDAtlas[part.materialID]));
+            // Construct local parts
+            parts->push_back(std::make_shared<MeshPart>(meshID, partID, (int)materialIDAtlas[part.materialID]));
             partID++;
         }
         meshID++;
     }
     _meshes = meshes;
-    _meshParts = shapes;
+    _meshParts = parts;
 
     finishedLoading(true);
 }
@@ -334,9 +334,9 @@ bool Geometry::areTexturesLoaded() const {
     return true;
 }
 
-const std::shared_ptr<const NetworkMaterial> Geometry::getShapeMaterial(int shapeID) const {
-    if ((shapeID >= 0) && (shapeID < (int)_meshParts->size())) {
-        int materialID = _meshParts->at(shapeID)->materialID;
+const std::shared_ptr<const NetworkMaterial> Geometry::getShapeMaterial(int partID) const {
+    if ((partID >= 0) && (partID < (int)_meshParts->size())) {
+        int materialID = _meshParts->at(partID)->materialID;
         if ((materialID >= 0) && (materialID < (int)_materials.size())) {
             return _materials[materialID];
         }

From 4bebb682dc2a7db701c7b2fe6ff8d93688a5b39c Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Mon, 11 Jul 2016 08:45:57 -0700
Subject: [PATCH 5/8] namechange: fetchResource --> getGeometryResource

---
 .../model-networking/src/model-networking/ModelCache.cpp      | 2 +-
 libraries/model-networking/src/model-networking/ModelCache.h  | 2 +-
 libraries/render-utils/src/Model.cpp                          | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp
index 442bf008e7..30794cf312 100644
--- a/libraries/model-networking/src/model-networking/ModelCache.cpp
+++ b/libraries/model-networking/src/model-networking/ModelCache.cpp
@@ -250,7 +250,7 @@ QSharedPointer<Resource> ModelCache::createResource(const QUrl& url, const QShar
     return QSharedPointer<Resource>(resource, &Resource::deleter);
 }
 
-GeometryResource::Pointer ModelCache::fetchResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) {
+GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) {
     GeometryExtra geometryExtra = { mapping, textureBaseUrl };
     GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra).staticCast<GeometryResource>();
     if (resource) {
diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h
index c450f96846..93eab6aa24 100644
--- a/libraries/model-networking/src/model-networking/ModelCache.h
+++ b/libraries/model-networking/src/model-networking/ModelCache.h
@@ -127,7 +127,7 @@ class ModelCache : public ResourceCache, public Dependency {
     SINGLETON_DEPENDENCY
 
 public:
-    GeometryResource::Pointer fetchResource(const QUrl& url,
+    GeometryResource::Pointer getGeometryResource(const QUrl& url,
         const QVariantHash& mapping = QVariantHash(), const QUrl& textureBaseUrl = QUrl());
 
 protected:
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index ab9e0e7403..485c578045 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -821,7 +821,7 @@ void Model::setURL(const QUrl& url) {
     invalidCalculatedMeshBoxes();
     deleteGeometry();
 
-    _renderWatcher.setResource(DependencyManager::get<ModelCache>()->fetchResource(url));
+    _renderWatcher.setResource(DependencyManager::get<ModelCache>()->getGeometryResource(url));
     onInvalidate();
 }
 
@@ -830,7 +830,7 @@ void Model::setCollisionModelURL(const QUrl& url) {
         return;
     }
     _collisionUrl = url;
-    _collisionWatcher.setResource(DependencyManager::get<ModelCache>()->fetchResource(url));
+    _collisionWatcher.setResource(DependencyManager::get<ModelCache>()->getGeometryResource(url));
 }
 
 bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const {

From 3e4385913927e69b1a9068139a8822d12c6c5917 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Mon, 11 Jul 2016 08:47:15 -0700
Subject: [PATCH 6/8] setCollisionModelURL() more symmetric with setURL()

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

diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 485c578045..e2363d0cca 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -826,7 +826,7 @@ void Model::setURL(const QUrl& url) {
 }
 
 void Model::setCollisionModelURL(const QUrl& url) {
-    if (_collisionUrl == url) {
+    if (_collisionUrl == url && _collisionWatcher.getURL() == url) {
         return;
     }
     _collisionUrl = url;

From c106f4c3a01578f24831a8dbb2b07cf402ee212f Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Tue, 12 Jul 2016 10:15:28 -0700
Subject: [PATCH 7/8] fix crash for null pointer

---
 libraries/model-networking/src/model-networking/ModelCache.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h
index 93eab6aa24..f513a21fbc 100644
--- a/libraries/model-networking/src/model-networking/ModelCache.h
+++ b/libraries/model-networking/src/model-networking/ModelCache.h
@@ -106,7 +106,7 @@ public:
 
     void setResource(GeometryResource::Pointer resource);
 
-    const QUrl& getURL() const { return _resource->getURL(); }
+    QUrl GeometryResourceWatcher::getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); }
 
 private:
     void startWatching();

From cba49be9eaa64b28a0af35df60114058dbad115b Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Tue, 12 Jul 2016 16:30:26 -0700
Subject: [PATCH 8/8] fix compile bug

---
 libraries/model-networking/src/model-networking/ModelCache.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h
index f513a21fbc..aa3ea78db3 100644
--- a/libraries/model-networking/src/model-networking/ModelCache.h
+++ b/libraries/model-networking/src/model-networking/ModelCache.h
@@ -106,7 +106,7 @@ public:
 
     void setResource(GeometryResource::Pointer resource);
 
-    QUrl GeometryResourceWatcher::getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); }
+    QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); }
 
 private:
     void startWatching();