diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index e4c56dc419..d61e3c02f7 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -18,39 +18,77 @@ EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, cons return new RenderableZoneEntityItem(entityID, properties); } -bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& properties) { +template +void RenderableZoneEntityItem::changeProperties(Lambda setNewProperties) { QString oldShapeURL = getCompoundShapeURL(); - bool somethingChanged = ZoneEntityItem::setProperties(properties); - if (somethingChanged && oldShapeURL != getCompoundShapeURL()) { - _compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); + glm::vec3 oldPosition = getPosition(), oldDimensions = getDimensions(); + glm::quat oldRotation = getRotation(); + + setNewProperties(); + + if (oldShapeURL != getCompoundShapeURL()) { + if (!_model) { + _model = getModel(); + _needsInitialSimulation = true; + } + _model->setURL(getCompoundShapeURL(), QUrl(), true, true); } + if (oldPosition != getPosition() || + oldRotation != getRotation() || + oldDimensions != getDimensions()) { + _needsInitialSimulation = true; + } +} + +bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + changeProperties([&]() { + somethingChanged = this->ZoneEntityItem::setProperties(properties); + }); return somethingChanged; } int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { - QString oldShapeURL = getCompoundShapeURL(); - int bytesRead = ZoneEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead, - args, propertyFlags, overwriteLocalData); - if (oldShapeURL != getCompoundShapeURL()) { - _compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); - } + int bytesRead = 0; + changeProperties([&]() { + bytesRead = ZoneEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead, + args, propertyFlags, overwriteLocalData); + }); return bytesRead; } +Model* RenderableZoneEntityItem::getModel() { + Model* model = new Model(); + model->init(); + return model; +} + +void RenderableZoneEntityItem::initialSimulation() { + _model->setScaleToFit(true, getDimensions()); + _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); + _model->setRotation(getRotation()); + _model->setTranslation(getPosition()); + _model->simulate(0.0f); + _needsInitialSimulation = false; +} + bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { if (getShapeType() != SHAPE_TYPE_COMPOUND) { return EntityItem::contains(point); } - if (!_compoundShapeModel && hasCompoundShapeURL()) { - const_cast(this)->_compoundShapeModel = DependencyManager::get()->getGeometry(getCompoundShapeURL(), QUrl(), true); + + if (_model && !_model->isActive() && hasCompoundShapeURL()) { + // Since we have a delayload, we need to update the geometry if it has been downloaded + _model->setURL(getCompoundShapeURL(), QUrl(), true); } - if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) { - const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry(); - glm::vec3 meshDimensions = geometry.getUnscaledMeshExtents().maximum - geometry.getUnscaledMeshExtents().minimum; - return geometry.convexHullContains(worldToEntity(point) * meshDimensions); + if (_model && _model->isActive() && EntityItem::contains(point)) { + if (_needsInitialSimulation) { + const_cast(this)->initialSimulation(); + } + return _model->convexHullContains(point); } return false; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 8d8d8b4b3f..8a75a048d1 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -12,6 +12,7 @@ #ifndef hifi_RenderableZoneEntityItem_h #define hifi_RenderableZoneEntityItem_h +#include #include class NetworkGeometry; @@ -21,7 +22,9 @@ public: static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - ZoneEntityItem(entityItemID, properties) + ZoneEntityItem(entityItemID, properties), + _model(NULL), + _needsInitialSimulation(true) { } virtual bool setProperties(const EntityItemProperties& properties); @@ -32,8 +35,14 @@ public: virtual bool contains(const glm::vec3& point) const; private: + Model* getModel(); + void initialSimulation(); - QSharedPointer _compoundShapeModel; + template + void changeProperties(Lambda functor); + + Model* _model; + bool _needsInitialSimulation; }; #endif // hifi_RenderableZoneEntityItem_h \ No newline at end of file diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 37156a6c71..8ccbb65dbb 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -324,7 +324,7 @@ public: const FBXGeometry& getFBXGeometry() const { return _geometry; } const QVector& getMeshes() const { return _meshes; } -// + QVector getJointMappings(const AnimationPointer& animation); virtual void setLoadPriority(const QPointer& owner, float priority); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0114bc65f0..7528d1db4d 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -573,6 +573,61 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g 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)){ + if (!_calculatedMeshTrianglesValid) { + recalculateMeshBoxes(true); + } + + // If we are inside the models box, then consider the submeshes... + int subMeshIndex = 0; + foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { + if (subMeshBox.contains(point)) { + bool insideMesh = true; + // To be inside the sub mesh, we need to be behind every triangles' planes + const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; + foreach (const Triangle& triangle, meshTriangles) { + if (!isPointBehindTrianglesPlane(point, triangle.v0, triangle.v1, triangle.v2)) { + // it's not behind at least one so we bail + insideMesh = false; + break; + } + + } + if (insideMesh) { + // It's inside this mesh, return true. + return true; + } + } + subMeshIndex++; + } + } + // It wasn't in any mesh, return false. + return false; +} + // TODO: we seem to call this too often when things haven't actually changed... look into optimizing this void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; @@ -1047,7 +1102,7 @@ int Model::getLastFreeJointIndex(int jointIndex) const { void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bool delayLoad) { // don't recreate the geometry if it's the same URL - if (_url == url) { + if (_url == url && _geometry && _geometry->getURL() == url) { return; } _url = url; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index b91d2116f8..dba8f5277f 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -213,6 +213,7 @@ public: bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false); + bool convexHullContains(glm::vec3 point); protected: QSharedPointer _geometry;