From 57760bca7d1f3de23af220b2a10cdecee747d659 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Wed, 8 Jun 2016 16:35:38 -0700 Subject: [PATCH 01/35] sort ShapeInfo data members --- libraries/shared/src/ShapeInfo.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index c853666d90..ad7a76c6a4 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -74,12 +74,12 @@ public: const DoubleHashKey& getHash() const; protected: - ShapeType _type = SHAPE_TYPE_NONE; + QUrl _url; // url for model of convex collision hulls + QVector<QVector<glm::vec3>> _points; // points for convex collision hulls glm::vec3 _halfExtents = glm::vec3(0.0f); glm::vec3 _offset = glm::vec3(0.0f); DoubleHashKey _doubleHashKey; - QVector<QVector<glm::vec3>> _points; // points for convex collision hulls - QUrl _url; // url for model of convex collision hulls + ShapeType _type = SHAPE_TYPE_NONE; }; #endif // hifi_ShapeInfo_h From d64729372a1cedc9cfc99464e5b15787bd063650 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Thu, 9 Jun 2016 16:14:49 -0700 Subject: [PATCH 02/35] ShapeInfo name changes --- .../src/RenderableModelEntityItem.cpp | 22 ++++---- .../src/RenderablePolyVoxEntityItem.cpp | 18 +++---- .../src/RenderablePolyVoxEntityItem.h | 2 +- .../physics/src/PhysicalEntitySimulation.cpp | 2 +- libraries/physics/src/ShapeFactory.cpp | 6 +-- libraries/shared/src/ShapeInfo.cpp | 50 +++++++++++-------- libraries/shared/src/ShapeInfo.h | 19 ++++--- tests/physics/src/ShapeManagerTests.cpp | 10 ++-- 8 files changed, 70 insertions(+), 59 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7b3b3c3efe..07bcc05572 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -608,8 +608,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { const FBXGeometry& renderGeometry = _model->getFBXGeometry(); const FBXGeometry& collisionGeometry = _model->getCollisionFBXGeometry(); - QVector<QVector<glm::vec3>>& points = info.getPoints(); - points.clear(); + ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); + pointCollection.clear(); uint32_t i = 0; // the way OBJ files get read, each section under a "g" line is its own meshPart. We only expect @@ -619,8 +619,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { foreach (const FBXMesh& mesh, collisionGeometry.meshes) { // each meshPart is a convex hull foreach (const FBXMeshPart &meshPart, mesh.parts) { - points.push_back(QVector<glm::vec3>()); - QVector<glm::vec3>& pointsInPart = points[i]; + pointCollection.push_back(QVector<glm::vec3>()); + ShapeInfo::PointList& pointsInPart = pointCollection[i]; // run through all the triangles and (uniquely) add each point to the hull uint32_t numIndices = (uint32_t)meshPart.triangleIndices.size(); @@ -664,7 +664,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { if (pointsInPart.size() == 0) { qCDebug(entitiesrenderer) << "Warning -- meshPart has no faces"; - points.pop_back(); + pointCollection.pop_back(); continue; } ++i; @@ -681,16 +681,16 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { // multiply each point by scale before handing the point-set off to the physics engine. // also determine the extents of the collision model. AABox box; - for (int i = 0; i < points.size(); i++) { - for (int j = 0; j < points[i].size(); j++) { + for (int i = 0; i < pointCollection.size(); i++) { + for (int j = 0; j < pointCollection[i].size(); j++) { // compensate for registration - points[i][j] += _model->getOffset(); + pointCollection[i][j] += _model->getOffset(); // scale so the collision points match the model points - points[i][j] *= scale; + pointCollection[i][j] *= scale; // this next subtraction is done so we can give info the offset, which will cause // the shape-key to change. - points[i][j] -= _model->getOffset(); - box += points[i][j]; + pointCollection[i][j] -= _model->getOffset(); + box += pointCollection[i][j]; } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index ad35a1a00c..7d5f227558 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1198,7 +1198,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() { QtConcurrent::run([entity, voxelSurfaceStyle, voxelVolumeSize, mesh] { auto polyVoxEntity = std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity); - QVector<QVector<glm::vec3>> points; + QVector<QVector<glm::vec3>> pointCollection; AABox box; glm::mat4 vtoM = std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity)->voxelToLocalMatrix(); @@ -1241,9 +1241,9 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() { pointsInPart << p3Model; // add next convex hull QVector<glm::vec3> newMeshPoints; - points << newMeshPoints; + pointCollection << newMeshPoints; // add points to the new convex hull - points[i++] << pointsInPart; + pointCollection[i++] << pointsInPart; } } else { unsigned int i = 0; @@ -1299,19 +1299,19 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() { // add next convex hull QVector<glm::vec3> newMeshPoints; - points << newMeshPoints; + pointCollection << newMeshPoints; // add points to the new convex hull - points[i++] << pointsInPart; + pointCollection[i++] << pointsInPart; } }); } - polyVoxEntity->setCollisionPoints(points, box); + polyVoxEntity->setCollisionPoints(pointCollection, box); }); } -void RenderablePolyVoxEntityItem::setCollisionPoints(const QVector<QVector<glm::vec3>> points, AABox box) { +void RenderablePolyVoxEntityItem::setCollisionPoints(ShapeInfo::PointCollection pointCollection, AABox box) { // this catches the payload from computeShapeInfoWorker - if (points.isEmpty()) { + if (pointCollection.isEmpty()) { EntityItem::computeShapeInfo(_shapeInfo); return; } @@ -1325,7 +1325,7 @@ void RenderablePolyVoxEntityItem::setCollisionPoints(const QVector<QVector<glm:: QString::number(_registrationPoint.y) + "," + QString::number(_registrationPoint.z); _shapeInfo.setParams(SHAPE_TYPE_COMPOUND, collisionModelDimensions, shapeKey); - _shapeInfo.setConvexHulls(points); + _shapeInfo.setPointCollection(pointCollection); _meshDirty = false; }); } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index e5afb94afa..c46a26deb5 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -123,7 +123,7 @@ public: std::function<void(int, int, int, uint8_t)> thunk); void setMesh(model::MeshPointer mesh); - void setCollisionPoints(const QVector<QVector<glm::vec3>> points, AABox box); + void setCollisionPoints(ShapeInfo::PointCollection points, AABox box); PolyVox::SimpleVolume<uint8_t>* getVolData() { return _volData; } uint8_t getVoxelInternal(int x, int y, int z); diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 6806b3a398..c5134fc027 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -217,7 +217,7 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re } else if (entity->isReadyToComputeShape()) { ShapeInfo shapeInfo; entity->computeShapeInfo(shapeInfo); - int numPoints = shapeInfo.getMaxNumPoints(); + int numPoints = shapeInfo.getLargestSubshapePointCount(); if (numPoints > MAX_HULL_POINTS) { qWarning() << "convex hull with" << numPoints << "points for entity" << entity->getName() diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index d667d1075d..a23ef97007 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -179,15 +179,15 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { } break; case SHAPE_TYPE_COMPOUND: { - const QVector<QVector<glm::vec3>>& points = info.getPoints(); + const ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); uint32_t numSubShapes = info.getNumSubShapes(); if (numSubShapes == 1) { - shape = createConvexHull(info.getPoints()[0]); + shape = createConvexHull(pointCollection[0]); } else { auto compound = new btCompoundShape(); btTransform trans; trans.setIdentity(); - foreach (QVector<glm::vec3> hullPoints, points) { + foreach (const ShapeInfo::PointList& hullPoints, pointCollection) { btConvexHullShape* hull = createConvexHull(hullPoints); compound->addChildShape (trans, hull); } diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 9c1e5c3816..cd0cb6fe8a 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -16,9 +16,13 @@ #include "NumericalConstants.h" // for MILLIMETERS_PER_METER void ShapeInfo::clear() { - _type = SHAPE_TYPE_NONE; - _halfExtents = _offset = glm::vec3(0.0f); + _url.clear(); + _pointCollection.clear(); + _triangleIndices.clear(); + _halfExtents = glm::vec3(0.0f); + _offset = glm::vec3(0.0f); _doubleHashKey.clear(); + _type = SHAPE_TYPE_NONE; } void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) { @@ -61,9 +65,9 @@ void ShapeInfo::setSphere(float radius) { _doubleHashKey.clear(); } -void ShapeInfo::setConvexHulls(const QVector<QVector<glm::vec3>>& points) { - _points = points; - _type = (_points.size() > 0) ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; +void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) { + _pointCollection = pointCollection; + _type = (_pointCollection.size() > 0) ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; _doubleHashKey.clear(); } @@ -83,15 +87,15 @@ uint32_t ShapeInfo::getNumSubShapes() const { if (_type == SHAPE_TYPE_NONE) { return 0; } else if (_type == SHAPE_TYPE_COMPOUND) { - return _points.size(); + return _pointCollection.size(); } return 1; } -int ShapeInfo::getMaxNumPoints() const { +int ShapeInfo::getLargestSubshapePointCount() const { int numPoints = 0; - for (int i = 0; i < _points.size(); ++i) { - int n = _points[i].size(); + for (int i = 0; i < _pointCollection.size(); ++i) { + int n = _pointCollection[i].size(); if (n > numPoints) { numPoints = n; } @@ -187,23 +191,23 @@ const DoubleHashKey& ShapeInfo::getHash() const { // TODO?: provide lookup table for hash/hash2 of _type rather than recompute? uint32_t primeIndex = 0; key.computeHash((uint32_t)_type, primeIndex++); - - // compute hash1 + + // compute hash1 uint32_t hash = key.getHash(); for (int j = 0; j < 3; ++j) { // NOTE: 0.49f is used to bump the float up almost half a millimeter // so the cast to int produces a round() effect rather than a floor() hash ^= DoubleHashKey::hashFunction( - (uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f), + (uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f), primeIndex++); if (useOffset) { hash ^= DoubleHashKey::hashFunction( - (uint32_t)(_offset[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[j]) * 0.49f), + (uint32_t)(_offset[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[j]) * 0.49f), primeIndex++); } } key.setHash(hash); - + // compute hash2 hash = key.getHash2(); for (int j = 0; j < 3; ++j) { @@ -224,14 +228,16 @@ const DoubleHashKey& ShapeInfo::getHash() const { } key.setHash2(hash); - QString url = _url.toString(); - if (!url.isEmpty()) { - // fold the urlHash into both parts - QByteArray baUrl = url.toLocal8Bit(); - const char *cUrl = baUrl.data(); - uint32_t urlHash = qChecksum(cUrl, baUrl.count()); - key.setHash(key.getHash() ^ urlHash); - key.setHash2(key.getHash2() ^ urlHash); + if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_MESH) { + QString url = _url.toString(); + if (!url.isEmpty()) { + // fold the urlHash into both parts + QByteArray baUrl = url.toLocal8Bit(); + const char *cUrl = baUrl.data(); + uint32_t urlHash = qChecksum(cUrl, baUrl.count()); + key.setHash(key.getHash() ^ urlHash); + key.setHash2(key.getHash2() ^ urlHash); + } } } return _doubleHashKey; diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index ad7a76c6a4..7f178bb53a 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -38,18 +38,23 @@ enum ShapeType { SHAPE_TYPE_CYLINDER_X, SHAPE_TYPE_CYLINDER_Y, SHAPE_TYPE_CYLINDER_Z, - SHAPE_TYPE_STATIC_MESH + SHAPE_TYPE_MESH }; class ShapeInfo { public: + + using PointList = QVector<glm::vec3>; + using PointCollection = QVector<PointList>; + using TriangleIndices = QVector<uint32_t>; + void clear(); void setParams(ShapeType type, const glm::vec3& halfExtents, QString url=""); void setBox(const glm::vec3& halfExtents); void setSphere(float radius); - void setConvexHulls(const QVector<QVector<glm::vec3>>& points); + void setPointCollection(const PointCollection& pointCollection); void setCapsuleY(float radius, float halfHeight); void setOffset(const glm::vec3& offset); @@ -58,12 +63,11 @@ public: const glm::vec3& getHalfExtents() const { return _halfExtents; } const glm::vec3& getOffset() const { return _offset; } - QVector<QVector<glm::vec3>>& getPoints() { return _points; } - const QVector<QVector<glm::vec3>>& getPoints() const { return _points; } + PointCollection& getPointCollection() { return _pointCollection; } + const PointCollection& getPointCollection() const { return _pointCollection; } uint32_t getNumSubShapes() const; - void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; } - int getMaxNumPoints() const; + int getLargestSubshapePointCount() const; float computeVolume() const; @@ -75,7 +79,8 @@ public: protected: QUrl _url; // url for model of convex collision hulls - QVector<QVector<glm::vec3>> _points; // points for convex collision hulls + PointCollection _pointCollection; + TriangleIndices _triangleIndices; glm::vec3 _halfExtents = glm::vec3(0.0f); glm::vec3 _offset = glm::vec3(0.0f); DoubleHashKey _doubleHashKey; diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index 66ac9d0c4a..c8805132fa 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -194,23 +194,23 @@ void ShapeManagerTests::addCompoundShape() { int numHullPoints = tetrahedron.size(); // compute the points of the hulls - QVector< QVector<glm::vec3> > hulls; + ShapeInfo::PointCollection pointCollection; int numHulls = 5; glm::vec3 offsetNormal(1.0f, 0.0f, 0.0f); for (int i = 0; i < numHulls; ++i) { glm::vec3 offset = (float)(i - numHulls/2) * offsetNormal; - QVector<glm::vec3> hull; + ShapeInfo::PointList pointList; float radius = (float)(i + 1); for (int j = 0; j < numHullPoints; ++j) { glm::vec3 point = radius * tetrahedron[j] + offset; - hull.push_back(point); + pointList.push_back(point); } - hulls.push_back(hull); + pointCollection.push_back(pointList); } // create the ShapeInfo ShapeInfo info; - info.setConvexHulls(hulls); + info.setPointCollection(hulls); // create the shape ShapeManager shapeManager; From 5d5dc2837b09984a9d7bcfb324cea0d632812f36 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 14 Jun 2016 13:58:53 -0700 Subject: [PATCH 03/35] fix comment --- 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 ded1184c24..0470a238fc 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1002,7 +1002,7 @@ void Model::scaleToFit() { Extents modelMeshExtents = getUnscaledMeshExtents(); // size is our "target size in world space" - // we need to set our model scale so that the extents of the mesh, fit in a cube that size... + // we need to set our model scale so that the extents of the mesh, fit in a box that size... glm::vec3 meshDimensions = modelMeshExtents.maximum - modelMeshExtents.minimum; glm::vec3 rescaleDimensions = _scaleToFitDimensions / meshDimensions; setScaleInternal(rescaleDimensions); From 13bb174b8b6e84e4fb6ac735dfb6cfc6dec1dee8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 14 Jun 2016 14:16:49 -0700 Subject: [PATCH 04/35] small change to commented out debug code --- libraries/physics/src/PhysicalEntitySimulation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index c5134fc027..cdf33a6edb 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -231,7 +231,7 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re result.push_back(motionState); entityItr = _entitiesToAddToPhysics.erase(entityItr); } else { - //qDebug() << "Warning! Failed to generate new shape for entity." << entity->getName(); + //qWarning() << "Failed to generate new shape for entity." << entity->getName(); ++entityItr; } } else { From 9fc77ccfa2f048c61b956b5cd64796097c32a5ea Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 14 Jun 2016 14:19:45 -0700 Subject: [PATCH 05/35] use reference to avoid big copy --- libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 7d5f227558..eb6db2874f 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1207,7 +1207,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() { // pull each triangle in the mesh into a polyhedron which can be collided with unsigned int i = 0; - const gpu::BufferView vertexBufferView = mesh->getVertexBuffer(); + const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); gpu::BufferView::Iterator<const uint32_t> it = indexBufferView.cbegin<uint32_t>(); From a519b77ae7f2ca513bbc6f8456b4dd144dcbe56b Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 14 Jun 2016 14:22:28 -0700 Subject: [PATCH 06/35] add SHAPE_TYPE_MESH and build mesh shapes --- .../src/RenderableModelEntityItem.cpp | 102 +++++++++++++++++- libraries/physics/src/ShapeFactory.cpp | 97 ++++++++++++++++- libraries/physics/src/ShapeFactory.h | 15 ++- libraries/physics/src/ShapeManager.cpp | 18 ++-- libraries/shared/src/ShapeInfo.cpp | 23 ++-- libraries/shared/src/ShapeInfo.h | 12 ++- 6 files changed, 235 insertions(+), 32 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 07bcc05572..e7991eb638 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -599,13 +599,13 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ShapeType type = getShapeType(); + glm::vec3 dimensions = getDimensions(); if (type == SHAPE_TYPE_COMPOUND) { updateModelBounds(); // should never fall in here when collision model not fully loaded // hence we assert that all geometries exist and are loaded assert(_model->isLoaded() && _model->isCollisionLoaded()); - const FBXGeometry& renderGeometry = _model->getFBXGeometry(); const FBXGeometry& collisionGeometry = _model->getCollisionFBXGeometry(); ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); @@ -677,7 +677,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { // to the visual model and apply them to the collision model (without regard for the // collision model's extents). - glm::vec3 scale = getDimensions() / renderGeometry.getUnscaledMeshExtents().size(); + const FBXGeometry& renderGeometry = _model->getFBXGeometry(); + glm::vec3 scale = dimensions / renderGeometry.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. AABox box; @@ -697,9 +698,104 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 collisionModelDimensions = box.getDimensions(); info.setParams(type, collisionModelDimensions, _compoundShapeURL); info.setOffset(_model->getOffset()); + } else if (type == SHAPE_TYPE_MESH) { + updateModelBounds(); + + // should never fall in here when collision model not fully loaded + assert(_model->isLoaded()); + + ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); + pointCollection.clear(); + + ShapeInfo::PointList points; + ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices(); + auto& meshes = _model->getGeometry()->getGeometry()->getMeshes(); + + glm::vec3 modelOffset = _model->getOffset(); + for (auto& mesh : meshes) { + const gpu::BufferView& vertices = mesh->getVertexBuffer(); + const gpu::BufferView& indices = mesh->getIndexBuffer(); + const gpu::BufferView& parts = mesh->getPartBuffer(); + + // copy points + uint32_t meshIndexOffset = (uint32_t)points.size(); + gpu::BufferView::Iterator<const glm::vec3> vertexItr = vertices.cbegin<const glm::vec3>(); + points.reserve(points.size() + vertices.getNumElements()); + Extents extents; + while (vertexItr != vertices.cend<const glm::vec3>()) { + points.push_back(*vertexItr); + extents.addPoint(*vertexItr); + ++vertexItr; + } + + // scale points and shift by modelOffset + glm::vec3 extentsSize = extents.size(); + glm::vec3 scale = dimensions / extents.size(); + for (int i = 0; i < 3; ++i) { + if (extentsSize[i] < 1.0e-6f) { + scale[i] = 1.0f; + } + } + for (int i = 0; i < points.size(); ++i) { + points[i] = (points[i] * scale) + modelOffset; + } + + // copy triangleIndices + triangleIndices.reserve(triangleIndices.size() + indices.getNumElements()); + gpu::BufferView::Iterator<const model::Mesh::Part> partItr = parts.cbegin<const model::Mesh::Part>(); + while (partItr != parts.cend<const model::Mesh::Part>()) { + + if (partItr->_topology == model::Mesh::TRIANGLES) { + assert(partItr->_numIndices % 3 == 0); + auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex; + auto indexEnd = indexItr + partItr->_numIndices; + while (indexItr != indexEnd) { + triangleIndices.push_back(*indexItr + meshIndexOffset); + ++indexItr; + } + } else if (partItr->_topology == model::Mesh::TRIANGLE_STRIP) { + assert(partItr->_numIndices > 2); + uint32_t approxNumIndices = 3 * partItr->_numIndices; + if (approxNumIndices > (uint32_t)(triangleIndices.capacity() - triangleIndices.size())) { + // we underestimated the final size of triangleIndices so we pre-emptively expand it + triangleIndices.reserve(triangleIndices.size() + approxNumIndices); + } + + auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex; + auto indexEnd = indexItr + (partItr->_numIndices - 2); + + // first triangle uses the first three indices + triangleIndices.push_back(*indexItr + meshIndexOffset); + triangleIndices.push_back(*(++indexItr) + meshIndexOffset); + triangleIndices.push_back(*(indexItr + 1) + meshIndexOffset); + + // the rest use previous and next index + uint32_t triangleCount = 1; + while (indexItr != indexEnd) { + if (triangleCount % 2 == 0) { + // even triangles use first two indices in order + triangleIndices.push_back(*(indexItr) + meshIndexOffset); + triangleIndices.push_back(*(++indexItr) + meshIndexOffset); // yes pre-increment + } else { + // odd triangles swap order of first two indices + triangleIndices.push_back(*(indexItr + 1) + meshIndexOffset); + triangleIndices.push_back(*(indexItr++) + meshIndexOffset); // yes post-increment + } + triangleIndices.push_back(*(indexItr + 1) + meshIndexOffset); + ++triangleCount; + } + } else if (partItr->_topology == model::Mesh::QUADS) { + // TODO: support model::Mesh::QUADS + } + // TODO? support model::Mesh::QUAD_STRIP? + ++partItr; + } + } + pointCollection.push_back(points); + info.setParams(SHAPE_TYPE_MESH, 0.5f * dimensions, _modelURL); } else { ModelEntityItem::computeShapeInfo(info); - info.setParams(type, 0.5f * getDimensions()); + info.setParams(type, 0.5f * dimensions); adjustShapeInfoByRegistration(info); } } diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index a23ef97007..4d5f56853d 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -67,7 +67,8 @@ static const btVector3 _unitSphereDirections[NUM_UNIT_SPHERE_DIRECTIONS] = { }; -btConvexHullShape* ShapeFactory::createConvexHull(const QVector<glm::vec3>& points) { +// util method +btConvexHullShape* createConvexHull(const ShapeInfo::PointList& points) { assert(points.size() > 0); btConvexHullShape* hull = new btConvexHullShape(); @@ -158,6 +159,84 @@ btConvexHullShape* ShapeFactory::createConvexHull(const QVector<glm::vec3>& poin return hull; } +// util method +btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info) { + assert(info.getType() == SHAPE_TYPE_MESH); // should only get here for mesh shapes + + const ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); + assert(pointCollection.size() == 1); // should only have one mesh + + const ShapeInfo::PointList& pointList = pointCollection[0]; + assert(pointList.size() > 2); // should have at least one triangle's worth of points + + const ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices(); + assert(triangleIndices.size() > 2); // should have at least one triangle's worth of indices + + // allocate mesh buffers + btIndexedMesh mesh; + int32_t numIndices = triangleIndices.size(); + const int32_t VERTICES_PER_TRIANGLE = 3; + mesh.m_numTriangles = numIndices / VERTICES_PER_TRIANGLE; + if (numIndices < INT16_MAX) { + // small number of points so we can use 16-bit indices + mesh.m_triangleIndexBase = new unsigned char[sizeof(int16_t) * (size_t)numIndices]; + mesh.m_indexType = PHY_SHORT; + mesh.m_triangleIndexStride = VERTICES_PER_TRIANGLE * sizeof(int16_t); + } else { + mesh.m_triangleIndexBase = new unsigned char[sizeof(int32_t) * (size_t)numIndices]; + mesh.m_indexType = PHY_INTEGER; + mesh.m_triangleIndexStride = VERTICES_PER_TRIANGLE * sizeof(int32_t); + } + mesh.m_numVertices = pointList.size(); + mesh.m_vertexBase = new unsigned char[VERTICES_PER_TRIANGLE * sizeof(btScalar) * (size_t)mesh.m_numVertices]; + mesh.m_vertexStride = VERTICES_PER_TRIANGLE * sizeof(btScalar); + mesh.m_vertexType = PHY_FLOAT; + + // copy data into buffers + btScalar* vertexData = static_cast<btScalar*>((void*)(mesh.m_vertexBase)); + for (int32_t i = 0; i < mesh.m_numVertices; ++i) { + int32_t j = i * VERTICES_PER_TRIANGLE; + const glm::vec3& point = pointList[i]; + vertexData[j] = point.x; + vertexData[j + 1] = point.y; + vertexData[j + 2] = point.z; + } + if (numIndices < INT16_MAX) { + int16_t* indices = static_cast<int16_t*>((void*)(mesh.m_triangleIndexBase)); + for (int32_t i = 0; i < numIndices; ++i) { + indices[i] = triangleIndices[i]; + } + } else { + int32_t* indices = static_cast<int32_t*>((void*)(mesh.m_triangleIndexBase)); + for (int32_t i = 0; i < numIndices; ++i) { + indices[i] = triangleIndices[i]; + } + } + + // store buffers in a new dataArray and return the pointer + // (external StaticMeshShape will own all of the data that was allocated here) + btTriangleIndexVertexArray* dataArray = new btTriangleIndexVertexArray; + dataArray->addIndexedMesh(mesh, mesh.m_indexType); + return dataArray; +} + +// util method +void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) { + assert(dataArray); + IndexedMeshArray& meshes = dataArray->getIndexedMeshArray(); + for (int32_t i = 0; i < meshes.size(); ++i) { + btIndexedMesh mesh = meshes[i]; + mesh.m_numTriangles = 0; + delete [] mesh.m_triangleIndexBase; + mesh.m_triangleIndexBase = nullptr; + mesh.m_numVertices = 0; + delete [] mesh.m_vertexBase; + mesh.m_vertexBase = nullptr; + } + meshes.clear(); + delete dataArray; +} + btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; int type = info.getType(); @@ -195,6 +274,11 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { } } break; + case SHAPE_TYPE_MESH: { + btTriangleIndexVertexArray* dataArray = createStaticMeshArray(info); + shape = new StaticMeshShape(dataArray); + } + break; } if (shape) { if (glm::length2(info.getOffset()) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET) { @@ -228,3 +312,14 @@ void ShapeFactory::deleteShape(btCollisionShape* shape) { } delete shape; } + +// the dataArray must be created before we create the StaticMeshShape +ShapeFactory::StaticMeshShape::StaticMeshShape(btTriangleIndexVertexArray* dataArray) +: btBvhTriangleMeshShape(dataArray, true), _dataArray(dataArray) { + assert(dataArray); +} + +ShapeFactory::StaticMeshShape::~StaticMeshShape() { + deleteStaticMeshArray(_dataArray); + _dataArray = nullptr; +} diff --git a/libraries/physics/src/ShapeFactory.h b/libraries/physics/src/ShapeFactory.h index 1ba2bdb619..6202612eb9 100644 --- a/libraries/physics/src/ShapeFactory.h +++ b/libraries/physics/src/ShapeFactory.h @@ -20,9 +20,22 @@ // translates between ShapeInfo and btShape namespace ShapeFactory { - btConvexHullShape* createConvexHull(const QVector<glm::vec3>& points); btCollisionShape* createShapeFromInfo(const ShapeInfo& info); void deleteShape(btCollisionShape* shape); + + //btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info); + //void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray); + + class StaticMeshShape : public btBvhTriangleMeshShape { + public: + StaticMeshShape() = delete; + StaticMeshShape(btTriangleIndexVertexArray* dataArray); + ~StaticMeshShape(); + + private: + // the StaticMeshShape owns its vertex/index data + btTriangleIndexVertexArray* _dataArray; + }; }; #endif // hifi_ShapeFactory_h diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 4231d1eb60..4fa660239c 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -32,15 +32,13 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { if (info.getType() == SHAPE_TYPE_NONE) { return NULL; } - if (info.getType() != SHAPE_TYPE_COMPOUND) { - // Very small or large non-compound objects are not supported. - float diagonal = 4.0f * glm::length2(info.getHalfExtents()); - const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube - if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED) { - // qCDebug(physics) << "ShapeManager::getShape -- not making shape due to size" << diagonal; - return NULL; - } + const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube + if (4.0f * glm::length2(info.getHalfExtents()) < MIN_SHAPE_DIAGONAL_SQUARED) { + // tiny shapes are not supported + // qCDebug(physics) << "ShapeManager::getShape -- not making shape due to size" << diagonal; + return NULL; } + DoubleHashKey key = info.getHash(); ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { @@ -66,8 +64,8 @@ bool ShapeManager::releaseShapeByKey(const DoubleHashKey& key) { shapeRef->refCount--; if (shapeRef->refCount == 0) { _pendingGarbage.push_back(key); - const int MAX_GARBAGE_CAPACITY = 255; - if (_pendingGarbage.size() > MAX_GARBAGE_CAPACITY) { + const int MAX_SHAPE_GARBAGE_CAPACITY = 255; + if (_pendingGarbage.size() > MAX_SHAPE_GARBAGE_CAPACITY) { collectGarbage(); } } diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index cd0cb6fe8a..ed1a76ef99 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -41,9 +41,9 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString break; } case SHAPE_TYPE_COMPOUND: + case SHAPE_TYPE_MESH: _url = QUrl(url); - _halfExtents = halfExtents; - break; + // yes, fall through default: _halfExtents = halfExtents; break; @@ -182,18 +182,15 @@ const DoubleHashKey& ShapeInfo::getHash() const { // NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance. if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) { bool useOffset = glm::length2(_offset) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET; - // The key is not yet cached therefore we must compute it! To this end we bypass the const-ness - // of this method by grabbing a non-const pointer to "this" and a non-const reference to _doubleHashKey. - ShapeInfo* thisPtr = const_cast<ShapeInfo*>(this); - DoubleHashKey& key = thisPtr->_doubleHashKey; + // The key is not yet cached therefore we must compute it. // compute hash1 // TODO?: provide lookup table for hash/hash2 of _type rather than recompute? uint32_t primeIndex = 0; - key.computeHash((uint32_t)_type, primeIndex++); + _doubleHashKey.computeHash((uint32_t)_type, primeIndex++); // compute hash1 - uint32_t hash = key.getHash(); + uint32_t hash = _doubleHashKey.getHash(); for (int j = 0; j < 3; ++j) { // NOTE: 0.49f is used to bump the float up almost half a millimeter // so the cast to int produces a round() effect rather than a floor() @@ -206,10 +203,10 @@ const DoubleHashKey& ShapeInfo::getHash() const { primeIndex++); } } - key.setHash(hash); + _doubleHashKey.setHash(hash); // compute hash2 - hash = key.getHash2(); + hash = _doubleHashKey.getHash2(); for (int j = 0; j < 3; ++j) { // NOTE: 0.49f is used to bump the float up almost half a millimeter // so the cast to int produces a round() effect rather than a floor() @@ -226,7 +223,7 @@ const DoubleHashKey& ShapeInfo::getHash() const { hash += ~(floatHash << 10); hash = (hash << 16) | (hash >> 16); } - key.setHash2(hash); + _doubleHashKey.setHash2(hash); if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_MESH) { QString url = _url.toString(); @@ -235,8 +232,8 @@ const DoubleHashKey& ShapeInfo::getHash() const { QByteArray baUrl = url.toLocal8Bit(); const char *cUrl = baUrl.data(); uint32_t urlHash = qChecksum(cUrl, baUrl.count()); - key.setHash(key.getHash() ^ urlHash); - key.setHash2(key.getHash2() ^ urlHash); + _doubleHashKey.setHash(_doubleHashKey.getHash() ^ urlHash); + _doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ urlHash); } } } diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index 7f178bb53a..794f31a987 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -30,14 +30,15 @@ enum ShapeType { SHAPE_TYPE_NONE, SHAPE_TYPE_BOX, SHAPE_TYPE_SPHERE, - SHAPE_TYPE_PLANE, - SHAPE_TYPE_COMPOUND, SHAPE_TYPE_CAPSULE_X, SHAPE_TYPE_CAPSULE_Y, SHAPE_TYPE_CAPSULE_Z, SHAPE_TYPE_CYLINDER_X, SHAPE_TYPE_CYLINDER_Y, SHAPE_TYPE_CYLINDER_Z, + SHAPE_TYPE_HULL, + SHAPE_TYPE_PLANE, + SHAPE_TYPE_COMPOUND, SHAPE_TYPE_MESH }; @@ -62,10 +63,13 @@ public: const glm::vec3& getHalfExtents() const { return _halfExtents; } const glm::vec3& getOffset() const { return _offset; } + uint32_t getNumSubShapes() const; PointCollection& getPointCollection() { return _pointCollection; } const PointCollection& getPointCollection() const { return _pointCollection; } - uint32_t getNumSubShapes() const; + + TriangleIndices& getTriangleIndices() { return _triangleIndices; } + const TriangleIndices& getTriangleIndices() const { return _triangleIndices; } int getLargestSubshapePointCount() const; @@ -83,7 +87,7 @@ protected: TriangleIndices _triangleIndices; glm::vec3 _halfExtents = glm::vec3(0.0f); glm::vec3 _offset = glm::vec3(0.0f); - DoubleHashKey _doubleHashKey; + mutable DoubleHashKey _doubleHashKey; ShapeType _type = SHAPE_TYPE_NONE; }; From f41fb30aceb4f6c9a66013397fa899c17c84ad11 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 14 Jun 2016 14:59:52 -0700 Subject: [PATCH 07/35] add "Static Mesh" option to edit.js --- .../entities/src/EntityItemProperties.cpp | 23 +++++++++++++++---- scripts/system/html/entityProperties.html | 1 + 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 89bf9f1a21..c521962976 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -88,8 +88,21 @@ void EntityItemProperties::setLastEdited(quint64 usecTime) { _lastEdited = usecTime > _created ? usecTime : _created; } -const char* shapeTypeNames[] = {"none", "box", "sphere", "plane", "compound", "capsule-x", - "capsule-y", "capsule-z", "cylinder-x", "cylinder-y", "cylinder-z"}; +const char* shapeTypeNames[] = { + "none", + "box", + "sphere", + "capsule-x", + "capsule-y", + "capsule-z", + "cylinder-x", + "cylinder-y", + "cylinder-z", + "hull", + "plane", + "compound", + "static-mesh" +}; QHash<QString, ShapeType> stringToShapeTypeLookup; @@ -101,14 +114,16 @@ void buildStringToShapeTypeLookup() { addShapeType(SHAPE_TYPE_NONE); addShapeType(SHAPE_TYPE_BOX); addShapeType(SHAPE_TYPE_SPHERE); - addShapeType(SHAPE_TYPE_PLANE); - addShapeType(SHAPE_TYPE_COMPOUND); addShapeType(SHAPE_TYPE_CAPSULE_X); addShapeType(SHAPE_TYPE_CAPSULE_Y); addShapeType(SHAPE_TYPE_CAPSULE_Z); addShapeType(SHAPE_TYPE_CYLINDER_X); addShapeType(SHAPE_TYPE_CYLINDER_Y); addShapeType(SHAPE_TYPE_CYLINDER_Z); + addShapeType(SHAPE_TYPE_HULL); + addShapeType(SHAPE_TYPE_PLANE); + addShapeType(SHAPE_TYPE_COMPOUND); + addShapeType(SHAPE_TYPE_MESH); } QString getCollisionGroupAsString(uint8_t group) { diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 0af199ef56..121e38c340 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -1646,6 +1646,7 @@ <option value="box">Box</option> <option value="sphere">Sphere</option> <option value="compound">Compound</option> + <option value="static-mesh">Static Mesh</option> </select> </div> <div class="model-group model-section zone-section property url "> From 2f6e5ab2ee3bfcf30b1b98194e2ca2b60d39c849 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 14 Jun 2016 15:26:13 -0700 Subject: [PATCH 08/35] remove fall-through in switch/case logic --- libraries/shared/src/ShapeInfo.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index ed1a76ef99..af81a0f96b 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -27,12 +27,12 @@ void ShapeInfo::clear() { void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) { _type = type; + _halfExtents = halfExtents; switch(type) { case SHAPE_TYPE_NONE: _halfExtents = glm::vec3(0.0f); break; case SHAPE_TYPE_BOX: - _halfExtents = halfExtents; break; case SHAPE_TYPE_SPHERE: { // sphere radius is max of halfExtents @@ -43,9 +43,8 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString case SHAPE_TYPE_COMPOUND: case SHAPE_TYPE_MESH: _url = QUrl(url); - // yes, fall through + break; default: - _halfExtents = halfExtents; break; } _doubleHashKey.clear(); From d1752211e6181c29a4814151f29d10256e31e032 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 14 Jun 2016 15:52:41 -0700 Subject: [PATCH 09/35] make implicit casts explict --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e7991eb638..73c3c2e50c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -720,7 +720,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { // copy points uint32_t meshIndexOffset = (uint32_t)points.size(); gpu::BufferView::Iterator<const glm::vec3> vertexItr = vertices.cbegin<const glm::vec3>(); - points.reserve(points.size() + vertices.getNumElements()); + points.reserve((int32_t)((gpu::Size)points.size() + vertices.getNumElements())); Extents extents; while (vertexItr != vertices.cend<const glm::vec3>()) { points.push_back(*vertexItr); @@ -741,7 +741,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } // copy triangleIndices - triangleIndices.reserve(triangleIndices.size() + indices.getNumElements()); + triangleIndices.reserve((int32_t)((gpu::Size)(triangleIndices.size()) + indices.getNumElements())); gpu::BufferView::Iterator<const model::Mesh::Part> partItr = parts.cbegin<const model::Mesh::Part>(); while (partItr != parts.cend<const model::Mesh::Part>()) { From ab3548cac089189db0f4bf38c15b98f8872e4cf4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Wed, 15 Jun 2016 14:56:57 -0700 Subject: [PATCH 10/35] fix crash --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 73c3c2e50c..8f0c9f0a02 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -593,6 +593,8 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { // the model is still being downloaded. return false; + } else if (type == SHAPE_TYPE_MESH) { + return (_model && _model->isLoaded()); } return true; } From f444b70fdc6d018c2e634eaa90e06a6e9d80c123 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Wed, 15 Jun 2016 18:15:22 -0700 Subject: [PATCH 11/35] fix collision shape for scaled models --- .../src/RenderableModelEntityItem.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 8f0c9f0a02..c01ad8b92a 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -713,7 +713,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices(); auto& meshes = _model->getGeometry()->getGeometry()->getMeshes(); - glm::vec3 modelOffset = _model->getOffset(); + glm::vec3 scaledModelOffset = _model->getOffset() * _model->getScale(); for (auto& mesh : meshes) { const gpu::BufferView& vertices = mesh->getVertexBuffer(); const gpu::BufferView& indices = mesh->getIndexBuffer(); @@ -730,16 +730,16 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ++vertexItr; } - // scale points and shift by modelOffset + // scale and shift glm::vec3 extentsSize = extents.size(); - glm::vec3 scale = dimensions / extents.size(); + glm::vec3 scaleToFit = dimensions / extents.size(); for (int i = 0; i < 3; ++i) { if (extentsSize[i] < 1.0e-6f) { - scale[i] = 1.0f; + scaleToFit[i] = 1.0f; } } for (int i = 0; i < points.size(); ++i) { - points[i] = (points[i] * scale) + modelOffset; + points[i] = (points[i] * scaleToFit) + scaledModelOffset; } // copy triangleIndices From c0c77e90272a74afeea6556013468a12afe89d39 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Thu, 16 Jun 2016 09:26:33 -0700 Subject: [PATCH 12/35] optimize/cleanup compound/mesh shape computation --- .../src/RenderableModelEntityItem.cpp | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c01ad8b92a..13d757e9b4 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -618,6 +618,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { // to find one actual "mesh" (with one or more meshParts in it), but we loop over the meshes, just in case. const uint32_t TRIANGLE_STRIDE = 3; const uint32_t QUAD_STRIDE = 4; + Extents extents; foreach (const FBXMesh& mesh, collisionGeometry.meshes) { // each meshPart is a convex hull foreach (const FBXMeshPart &meshPart, mesh.parts) { @@ -631,14 +632,18 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 p0 = mesh.vertices[meshPart.triangleIndices[j]]; glm::vec3 p1 = mesh.vertices[meshPart.triangleIndices[j + 1]]; glm::vec3 p2 = mesh.vertices[meshPart.triangleIndices[j + 2]]; + if (!pointsInPart.contains(p0)) { pointsInPart << p0; + extents.addPoint(p0); } if (!pointsInPart.contains(p1)) { pointsInPart << p1; + extents.addPoint(p1); } if (!pointsInPart.contains(p2)) { pointsInPart << p2; + extents.addPoint(p2); } } @@ -652,15 +657,19 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 p3 = mesh.vertices[meshPart.quadIndices[j + 3]]; if (!pointsInPart.contains(p0)) { pointsInPart << p0; + extents.addPoint(p0); } if (!pointsInPart.contains(p1)) { pointsInPart << p1; + extents.addPoint(p1); } if (!pointsInPart.contains(p2)) { pointsInPart << p2; + extents.addPoint(p2); } if (!pointsInPart.contains(p3)) { pointsInPart << p3; + extents.addPoint(p3); } } @@ -673,33 +682,30 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } + glm::vec3 extentsSize = extents.size(); + glm::vec3 scaleToFit = dimensions / extentsSize; + for (int i = 0; i < 3; ++i) { + if (extentsSize[i] < 1.0e-6f) { + scaleToFit[i] = 1.0f; + } + } + // We expect that the collision model will have the same units and will be displaced // from its origin in the same way the visual model is. The visual model has // been centered and probably scaled. We take the scaling and offset which were applied // to the visual model and apply them to the collision model (without regard for the // collision model's extents). - const FBXGeometry& renderGeometry = _model->getFBXGeometry(); - glm::vec3 scale = dimensions / renderGeometry.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. - AABox box; + glm::vec3 scaledModelOffset = _model->getOffset() * _model->getScale(); for (int i = 0; i < pointCollection.size(); i++) { for (int j = 0; j < pointCollection[i].size(); j++) { - // compensate for registration - pointCollection[i][j] += _model->getOffset(); - // scale so the collision points match the model points - pointCollection[i][j] *= scale; - // this next subtraction is done so we can give info the offset, which will cause - // the shape-key to change. - pointCollection[i][j] -= _model->getOffset(); - box += pointCollection[i][j]; + pointCollection[i][j] = (pointCollection[i][j] * scaleToFit) + scaledModelOffset; } } - glm::vec3 collisionModelDimensions = box.getDimensions(); - info.setParams(type, collisionModelDimensions, _compoundShapeURL); - info.setOffset(_model->getOffset()); + info.setParams(type, dimensions, _compoundShapeURL); } else if (type == SHAPE_TYPE_MESH) { updateModelBounds(); @@ -713,6 +719,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices(); auto& meshes = _model->getGeometry()->getGeometry()->getMeshes(); + Extents extents; glm::vec3 scaledModelOffset = _model->getOffset() * _model->getScale(); for (auto& mesh : meshes) { const gpu::BufferView& vertices = mesh->getVertexBuffer(); @@ -723,25 +730,12 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { uint32_t meshIndexOffset = (uint32_t)points.size(); gpu::BufferView::Iterator<const glm::vec3> vertexItr = vertices.cbegin<const glm::vec3>(); points.reserve((int32_t)((gpu::Size)points.size() + vertices.getNumElements())); - Extents extents; while (vertexItr != vertices.cend<const glm::vec3>()) { points.push_back(*vertexItr); extents.addPoint(*vertexItr); ++vertexItr; } - // scale and shift - glm::vec3 extentsSize = extents.size(); - glm::vec3 scaleToFit = dimensions / extents.size(); - for (int i = 0; i < 3; ++i) { - if (extentsSize[i] < 1.0e-6f) { - scaleToFit[i] = 1.0f; - } - } - for (int i = 0; i < points.size(); ++i) { - points[i] = (points[i] * scaleToFit) + scaledModelOffset; - } - // copy triangleIndices triangleIndices.reserve((int32_t)((gpu::Size)(triangleIndices.size()) + indices.getNumElements())); gpu::BufferView::Iterator<const model::Mesh::Part> partItr = parts.cbegin<const model::Mesh::Part>(); @@ -793,6 +787,19 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ++partItr; } } + + // scale and shift + glm::vec3 extentsSize = extents.size(); + glm::vec3 scaleToFit = dimensions / extentsSize; + for (int i = 0; i < 3; ++i) { + if (extentsSize[i] < 1.0e-6f) { + scaleToFit[i] = 1.0f; + } + } + for (int i = 0; i < points.size(); ++i) { + points[i] = (points[i] * scaleToFit) + scaledModelOffset; + } + pointCollection.push_back(points); info.setParams(SHAPE_TYPE_MESH, 0.5f * dimensions, _modelURL); } else { From 5484b6fbb7e9a545007275a2da0129000c285529 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Thu, 16 Jun 2016 12:15:47 -0700 Subject: [PATCH 13/35] more correct extraction from triangle strips --- .../src/RenderableModelEntityItem.cpp | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 13d757e9b4..1adbd4fe1a 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -761,24 +761,27 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { auto indexEnd = indexItr + (partItr->_numIndices - 2); // first triangle uses the first three indices - triangleIndices.push_back(*indexItr + meshIndexOffset); - triangleIndices.push_back(*(++indexItr) + meshIndexOffset); - triangleIndices.push_back(*(indexItr + 1) + meshIndexOffset); + triangleIndices.push_back(*(indexItr++) + meshIndexOffset); + triangleIndices.push_back(*(indexItr++) + meshIndexOffset); + triangleIndices.push_back(*(indexItr++) + meshIndexOffset); // the rest use previous and next index uint32_t triangleCount = 1; while (indexItr != indexEnd) { - if (triangleCount % 2 == 0) { - // even triangles use first two indices in order - triangleIndices.push_back(*(indexItr) + meshIndexOffset); - triangleIndices.push_back(*(++indexItr) + meshIndexOffset); // yes pre-increment - } else { - // odd triangles swap order of first two indices - triangleIndices.push_back(*(indexItr + 1) + meshIndexOffset); - triangleIndices.push_back(*(indexItr++) + meshIndexOffset); // yes post-increment + if ((*indexItr) != model::Mesh::PRIMITIVE_RESTART_INDEX) { + if (triangleCount % 2 == 0) { + // even triangles use first two indices in order + triangleIndices.push_back(*(indexItr - 2) + meshIndexOffset); + triangleIndices.push_back(*(indexItr - 1) + meshIndexOffset); + } else { + // odd triangles swap order of first two indices + triangleIndices.push_back(*(indexItr - 1) + meshIndexOffset); + triangleIndices.push_back(*(indexItr - 2) + meshIndexOffset); + } + triangleIndices.push_back(*indexItr + meshIndexOffset); + ++triangleCount; } - triangleIndices.push_back(*(indexItr + 1) + meshIndexOffset); - ++triangleCount; + ++indexItr; } } else if (partItr->_topology == model::Mesh::QUADS) { // TODO: support model::Mesh::QUADS From f22a5613bd1b7a2ba0b86de3424e92edda0bd4e7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Mon, 20 Jun 2016 17:27:39 -0700 Subject: [PATCH 14/35] fix static mesh for model with per-mesh transforms --- .../src/RenderableModelEntityItem.cpp | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 1adbd4fe1a..7b1dddfcab 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -707,6 +707,22 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(type, dimensions, _compoundShapeURL); } else if (type == SHAPE_TYPE_MESH) { + // compute meshPart local transforms + QVector<glm::mat4> localTransforms; + const FBXGeometry& geometry = _model->getFBXGeometry(); + int numberOfMeshes = geometry.meshes.size(); + for (int i = 0; i < numberOfMeshes; i++) { + const FBXMesh& mesh = geometry.meshes.at(i); + if (mesh.clusters.size() > 0) { + const FBXCluster& cluster = mesh.clusters.at(0); + auto jointMatrix = _model->getRig()->getJointTransform(cluster.jointIndex); + localTransforms.push_back(jointMatrix * cluster.inverseBindMatrix); + } else { + glm::mat4 identity; + localTransforms.push_back(identity); + } + } + updateModelBounds(); // should never fall in here when collision model not fully loaded @@ -720,19 +736,21 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { auto& meshes = _model->getGeometry()->getGeometry()->getMeshes(); Extents extents; - glm::vec3 scaledModelOffset = _model->getOffset() * _model->getScale(); + int meshCount = 0; for (auto& mesh : meshes) { const gpu::BufferView& vertices = mesh->getVertexBuffer(); const gpu::BufferView& indices = mesh->getIndexBuffer(); const gpu::BufferView& parts = mesh->getPartBuffer(); // copy points + const glm::mat4& localTransform = localTransforms[meshCount]; uint32_t meshIndexOffset = (uint32_t)points.size(); gpu::BufferView::Iterator<const glm::vec3> vertexItr = vertices.cbegin<const glm::vec3>(); points.reserve((int32_t)((gpu::Size)points.size() + vertices.getNumElements())); while (vertexItr != vertices.cend<const glm::vec3>()) { - points.push_back(*vertexItr); - extents.addPoint(*vertexItr); + glm::vec3 point = extractTranslation(localTransform * glm::translate(*vertexItr)); + points.push_back(point); + extents.addPoint(point); ++vertexItr; } @@ -783,12 +801,10 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } ++indexItr; } - } else if (partItr->_topology == model::Mesh::QUADS) { - // TODO: support model::Mesh::QUADS } - // TODO? support model::Mesh::QUAD_STRIP? ++partItr; } + ++meshCount; } // scale and shift @@ -800,7 +816,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } for (int i = 0; i < points.size(); ++i) { - points[i] = (points[i] * scaleToFit) + scaledModelOffset; + points[i] = (points[i] * scaleToFit); } pointCollection.push_back(points); From 937bd0c1bea53ed3cd3954b91f138a8cce46f16c Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 21 Jun 2016 13:54:21 -0700 Subject: [PATCH 15/35] SHAPE_TYPE_MESH --> SHAPE_TYPE_STATIC_MESH --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 6 +++--- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/physics/src/ShapeFactory.cpp | 4 ++-- libraries/shared/src/ShapeInfo.cpp | 4 ++-- libraries/shared/src/ShapeInfo.h | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7b1dddfcab..ab91edd294 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -593,7 +593,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { // the model is still being downloaded. return false; - } else if (type == SHAPE_TYPE_MESH) { + } else if (type == SHAPE_TYPE_STATIC_MESH) { return (_model && _model->isLoaded()); } return true; @@ -706,7 +706,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } info.setParams(type, dimensions, _compoundShapeURL); - } else if (type == SHAPE_TYPE_MESH) { + } else if (type == SHAPE_TYPE_STATIC_MESH) { // compute meshPart local transforms QVector<glm::mat4> localTransforms; const FBXGeometry& geometry = _model->getFBXGeometry(); @@ -820,7 +820,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } pointCollection.push_back(points); - info.setParams(SHAPE_TYPE_MESH, 0.5f * dimensions, _modelURL); + info.setParams(SHAPE_TYPE_STATIC_MESH, 0.5f * dimensions, _modelURL); } else { ModelEntityItem::computeShapeInfo(info); info.setParams(type, 0.5f * dimensions); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index c521962976..a62f4b182a 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -123,7 +123,7 @@ void buildStringToShapeTypeLookup() { addShapeType(SHAPE_TYPE_HULL); addShapeType(SHAPE_TYPE_PLANE); addShapeType(SHAPE_TYPE_COMPOUND); - addShapeType(SHAPE_TYPE_MESH); + addShapeType(SHAPE_TYPE_STATIC_MESH); } QString getCollisionGroupAsString(uint8_t group) { diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 4d5f56853d..3afc170a8c 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -161,7 +161,7 @@ btConvexHullShape* createConvexHull(const ShapeInfo::PointList& points) { // util method btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info) { - assert(info.getType() == SHAPE_TYPE_MESH); // should only get here for mesh shapes + assert(info.getType() == SHAPE_TYPE_STATIC_MESH); // should only get here for mesh shapes const ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); assert(pointCollection.size() == 1); // should only have one mesh @@ -274,7 +274,7 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { } } break; - case SHAPE_TYPE_MESH: { + case SHAPE_TYPE_STATIC_MESH: { btTriangleIndexVertexArray* dataArray = createStaticMeshArray(info); shape = new StaticMeshShape(dataArray); } diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index af81a0f96b..e0f4cc18b2 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -41,7 +41,7 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString break; } case SHAPE_TYPE_COMPOUND: - case SHAPE_TYPE_MESH: + case SHAPE_TYPE_STATIC_MESH: _url = QUrl(url); break; default: @@ -224,7 +224,7 @@ const DoubleHashKey& ShapeInfo::getHash() const { } _doubleHashKey.setHash2(hash); - if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_MESH) { + if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_STATIC_MESH) { QString url = _url.toString(); if (!url.isEmpty()) { // fold the urlHash into both parts diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index 794f31a987..96132a4b23 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -39,7 +39,7 @@ enum ShapeType { SHAPE_TYPE_HULL, SHAPE_TYPE_PLANE, SHAPE_TYPE_COMPOUND, - SHAPE_TYPE_MESH + SHAPE_TYPE_STATIC_MESH }; class ShapeInfo { From 4c9ec7ca432bfac30bf84c0bf829845d111c6191 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 21 Jun 2016 13:55:11 -0700 Subject: [PATCH 16/35] protect physics against bad entity properties --- libraries/physics/src/EntityMotionState.cpp | 5 +++ libraries/physics/src/ObjectMotionState.cpp | 48 +++++++++++---------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 8f22c576f0..e0d355911a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -152,6 +152,11 @@ PhysicsMotionType EntityMotionState::computePhysicsMotionType() const { } assert(entityTreeIsLocked()); + if (_entity->getShapeType() == SHAPE_TYPE_STATIC_MESH + || (_body && _body->getCollisionShape()->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)) { + return MOTION_TYPE_STATIC; + } + if (_entity->getDynamic()) { if (!_entity->getParentID().isNull()) { // if something would have been dynamic but is a child of something else, force it to be kinematic, instead. diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index de435e80da..f915121718 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -203,35 +203,37 @@ void ObjectMotionState::handleEasyChanges(uint32_t& flags) { } } - if (flags & Simulation::DIRTY_LINEAR_VELOCITY) { - btVector3 newLinearVelocity = glmToBullet(getObjectLinearVelocity()); - if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) { - float delta = (newLinearVelocity - _body->getLinearVelocity()).length(); - if (delta > ACTIVATION_LINEAR_VELOCITY_DELTA) { - flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + if (_body->getCollisionShape()->getShapeType() != TRIANGLE_MESH_SHAPE_PROXYTYPE) { + if (flags & Simulation::DIRTY_LINEAR_VELOCITY) { + btVector3 newLinearVelocity = glmToBullet(getObjectLinearVelocity()); + if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) { + float delta = (newLinearVelocity - _body->getLinearVelocity()).length(); + if (delta > ACTIVATION_LINEAR_VELOCITY_DELTA) { + flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } } - } - _body->setLinearVelocity(newLinearVelocity); + _body->setLinearVelocity(newLinearVelocity); - btVector3 newGravity = glmToBullet(getObjectGravity()); - if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) { - float delta = (newGravity - _body->getGravity()).length(); - if (delta > ACTIVATION_GRAVITY_DELTA || - (delta > 0.0f && _body->getGravity().length2() == 0.0f)) { - flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + btVector3 newGravity = glmToBullet(getObjectGravity()); + if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) { + float delta = (newGravity - _body->getGravity()).length(); + if (delta > ACTIVATION_GRAVITY_DELTA || + (delta > 0.0f && _body->getGravity().length2() == 0.0f)) { + flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } } + _body->setGravity(newGravity); } - _body->setGravity(newGravity); - } - if (flags & Simulation::DIRTY_ANGULAR_VELOCITY) { - btVector3 newAngularVelocity = glmToBullet(getObjectAngularVelocity()); - if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) { - float delta = (newAngularVelocity - _body->getAngularVelocity()).length(); - if (delta > ACTIVATION_ANGULAR_VELOCITY_DELTA) { - flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + if (flags & Simulation::DIRTY_ANGULAR_VELOCITY) { + btVector3 newAngularVelocity = glmToBullet(getObjectAngularVelocity()); + if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) { + float delta = (newAngularVelocity - _body->getAngularVelocity()).length(); + if (delta > ACTIVATION_ANGULAR_VELOCITY_DELTA) { + flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } } + _body->setAngularVelocity(newAngularVelocity); } - _body->setAngularVelocity(newAngularVelocity); } if (flags & Simulation::DIRTY_MATERIAL) { From 702e83ba6a8a9d6db90eb4c40caf81caa1a005c4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 21 Jun 2016 14:03:21 -0700 Subject: [PATCH 17/35] prevent incompatible entity properties combos --- libraries/entities/src/EntityItem.cpp | 50 ++++++++++++++++++--------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 64b6a2c655..2abb9f12e2 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1602,14 +1602,20 @@ void EntityItem::updateMass(float mass) { void EntityItem::updateVelocity(const glm::vec3& value) { glm::vec3 velocity = getLocalVelocity(); if (velocity != value) { - const float MIN_LINEAR_SPEED = 0.001f; - if (glm::length(value) < MIN_LINEAR_SPEED) { - velocity = ENTITY_ITEM_ZERO_VEC3; + if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { + if (velocity != Vectors::ZERO) { + setLocalVelocity(Vectors::ZERO); + } } else { - velocity = value; + const float MIN_LINEAR_SPEED = 0.001f; + if (glm::length(value) < MIN_LINEAR_SPEED) { + velocity = ENTITY_ITEM_ZERO_VEC3; + } else { + velocity = value; + } + setLocalVelocity(velocity); + _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; } - setLocalVelocity(velocity); - _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; } } @@ -1630,22 +1636,30 @@ void EntityItem::updateDamping(float value) { void EntityItem::updateGravity(const glm::vec3& value) { if (_gravity != value) { - _gravity = value; - _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; + if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { + _gravity = Vectors::ZERO; + } else { + _gravity = value; + _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; + } } } void EntityItem::updateAngularVelocity(const glm::vec3& value) { glm::vec3 angularVelocity = getLocalAngularVelocity(); if (angularVelocity != value) { - const float MIN_ANGULAR_SPEED = 0.0002f; - if (glm::length(value) < MIN_ANGULAR_SPEED) { - angularVelocity = ENTITY_ITEM_ZERO_VEC3; + if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { + setLocalAngularVelocity(Vectors::ZERO); } else { - angularVelocity = value; + const float MIN_ANGULAR_SPEED = 0.0002f; + if (glm::length(value) < MIN_ANGULAR_SPEED) { + angularVelocity = ENTITY_ITEM_ZERO_VEC3; + } else { + angularVelocity = value; + } + setLocalAngularVelocity(angularVelocity); + _dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY; } - setLocalAngularVelocity(angularVelocity); - _dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY; } } @@ -1680,8 +1694,12 @@ void EntityItem::updateCollisionMask(uint8_t value) { void EntityItem::updateDynamic(bool value) { if (_dynamic != value) { - _dynamic = value; - _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { + _dynamic = false; + } else { + _dynamic = value; + _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + } } } From e88b264864807d7f8518ded3c447e8fe2f1fb64e Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Wed, 22 Jun 2016 09:30:44 -0700 Subject: [PATCH 18/35] revert compound hull shape generation --- .../src/RenderableModelEntityItem.cpp | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ab91edd294..366e365107 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -618,7 +618,6 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { // to find one actual "mesh" (with one or more meshParts in it), but we loop over the meshes, just in case. const uint32_t TRIANGLE_STRIDE = 3; const uint32_t QUAD_STRIDE = 4; - Extents extents; foreach (const FBXMesh& mesh, collisionGeometry.meshes) { // each meshPart is a convex hull foreach (const FBXMeshPart &meshPart, mesh.parts) { @@ -632,18 +631,14 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 p0 = mesh.vertices[meshPart.triangleIndices[j]]; glm::vec3 p1 = mesh.vertices[meshPart.triangleIndices[j + 1]]; glm::vec3 p2 = mesh.vertices[meshPart.triangleIndices[j + 2]]; - if (!pointsInPart.contains(p0)) { pointsInPart << p0; - extents.addPoint(p0); } if (!pointsInPart.contains(p1)) { pointsInPart << p1; - extents.addPoint(p1); } if (!pointsInPart.contains(p2)) { pointsInPart << p2; - extents.addPoint(p2); } } @@ -657,19 +652,15 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 p3 = mesh.vertices[meshPart.quadIndices[j + 3]]; if (!pointsInPart.contains(p0)) { pointsInPart << p0; - extents.addPoint(p0); } if (!pointsInPart.contains(p1)) { pointsInPart << p1; - extents.addPoint(p1); } if (!pointsInPart.contains(p2)) { pointsInPart << p2; - extents.addPoint(p2); } if (!pointsInPart.contains(p3)) { pointsInPart << p3; - extents.addPoint(p3); } } @@ -682,29 +673,23 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } - glm::vec3 extentsSize = extents.size(); - glm::vec3 scaleToFit = dimensions / extentsSize; - for (int i = 0; i < 3; ++i) { - if (extentsSize[i] < 1.0e-6f) { - scaleToFit[i] = 1.0f; - } - } - // We expect that the collision model will have the same units and will be displaced // from its origin in the same way the visual model is. The visual model has // been centered and probably scaled. We take the scaling and offset which were applied // to the visual model and apply them to the collision model (without regard for the // collision model's extents). + glm::vec3 scaleToFit = dimensions / _model->getFBXGeometry().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. - glm::vec3 scaledModelOffset = _model->getOffset() * _model->getScale(); for (int i = 0; i < pointCollection.size(); i++) { for (int j = 0; j < pointCollection[i].size(); j++) { - pointCollection[i][j] = (pointCollection[i][j] * scaleToFit) + scaledModelOffset; + // compensate for registration + pointCollection[i][j] += _model->getOffset(); + // scale so the collision points match the model points + pointCollection[i][j] *= scaleToFit; } } - info.setParams(type, dimensions, _compoundShapeURL); } else if (type == SHAPE_TYPE_STATIC_MESH) { // compute meshPart local transforms From b6b73af2b487b10e9cabe85299f498ef0b683df2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz <zach@highfidelity.io> Date: Fri, 17 Jun 2016 14:27:45 -0700 Subject: [PATCH 19/35] Clean up domain-server setup --- domain-server/src/DomainServer.cpp | 70 +++++++++++++----------------- domain-server/src/DomainServer.h | 2 +- 2 files changed, 32 insertions(+), 40 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 223cab61da..a4b57226ed 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -104,23 +104,25 @@ DomainServer::DomainServer(int argc, char* argv[]) : connect(&_settingsManager, &DomainServerSettingsManager::updateNodePermissions, &_gatekeeper, &DomainGatekeeper::updateNodePermissions); - if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth()) { - // we either read a certificate and private key or were not passed one - // and completed login or did not need to - - qDebug() << "Setting up LimitedNodeList and assignments."; - setupNodeListAndAssignments(); - - // setup automatic networking settings with data server - setupAutomaticNetworking(); - - // preload some user public keys so they can connect on first request - _gatekeeper.preloadAllowedUserPublicKeys(); - - optionallyGetTemporaryName(args); + // if we were given a certificate/private key or oauth credentials they must succeed + if (!(optionallyReadX509KeyAndCertificate() && optionallySetupOAuth())) { + return; } + qDebug() << "Setting up domain-server"; + setupNodeListAndAssignments(); + setupAutomaticNetworking(); + _gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request + _metadata = new DomainMetadata(this); + + // check for the temporary name parameter + const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; + if (args.contains(GET_TEMPORARY_NAME_SWITCH)) { + getTemporaryName(); + } + + qDebug() << "domain-server" << nullptr << "is running"; } DomainServer::~DomainServer() { @@ -233,34 +235,25 @@ bool DomainServer::optionallySetupOAuth() { static const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id"; -void DomainServer::optionallyGetTemporaryName(const QStringList& arguments) { - // check for the temporary name parameter - const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; +void DomainServer::getTemporaryName(bool force) { + // check if we already have a domain ID + const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH); - if (arguments.contains(GET_TEMPORARY_NAME_SWITCH)) { - - // make sure we don't already have a domain ID - const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH); - if (idValueVariant) { - qWarning() << "Temporary domain name requested but a domain ID is already present in domain-server settings." - << "Will not request temporary name."; + if (idValueVariant) { + qWarning() << "Temporary domain name requested but a domain ID is already present in domain-server settings."; + if (force) { + qWarning() << "Temporary domain name will be requested to replace it."; + } else { + qWarning() << "Temporary domain name will not be requested."; return; } - - // we've been asked to grab a temporary name from the API - // so fire off that request now - auto accountManager = DependencyManager::get<AccountManager>(); - - // get callbacks for temporary domain result - JSONCallbackParameters callbackParameters; - callbackParameters.jsonCallbackReceiver = this; - callbackParameters.jsonCallbackMethod = "handleTempDomainSuccess"; - callbackParameters.errorCallbackReceiver = this; - callbackParameters.errorCallbackMethod = "handleTempDomainError"; - - accountManager->sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None, - QNetworkAccessManager::PostOperation, callbackParameters); } + + // request a temporary name from the metaverse + auto accountManager = DependencyManager::get<AccountManager>(); + JSONCallbackParameters callbackParameters { this, "handleTempDomainSuccess", this, "handleTempDomainError" }; + accountManager->sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None, + QNetworkAccessManager::PostOperation, callbackParameters); } void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) { @@ -333,7 +326,6 @@ bool DomainServer::packetVersionMatch(const udt::Packet& packet) { void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { - const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port"; QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index c742dbc9b3..8a25591605 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -100,7 +100,7 @@ private: bool optionallySetupOAuth(); bool optionallyReadX509KeyAndCertificate(); - void optionallyGetTemporaryName(const QStringList& arguments); + void getTemporaryName(bool force = false); static bool packetVersionMatch(const udt::Packet& packet); From 3a36b0a2e5307094c106c73d4ddfb3cb5a289838 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz <zach@highfidelity.io> Date: Fri, 17 Jun 2016 18:31:23 -0700 Subject: [PATCH 20/35] add temporary domain info to account info --- libraries/networking/src/AccountManager.cpp | 5 +++++ libraries/networking/src/AccountManager.h | 3 +++ libraries/networking/src/DataServerAccountInfo.cpp | 13 ++++++++++--- libraries/networking/src/DataServerAccountInfo.h | 8 +++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 26b3801ec1..ac6d0cd4a0 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -471,6 +471,11 @@ void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken) persistAccountToFile(); } +void AccountManager::setTemporaryDomain(const QUuid& domainID, const QString& key) { + _accountInfo.setTemporaryDomain(domainID, key); + persistAccountToFile(); +} + void AccountManager::requestAccessToken(const QString& login, const QString& password) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 4803d2625f..dc3315eb45 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -88,6 +88,9 @@ public: void setSessionID(const QUuid& sessionID) { _sessionID = sessionID; } + void setTemporaryDomain(const QUuid& domainID, const QString& key); + const QString& getTemporaryDomainKey(const QUuid& domainID) { return _accountInfo.getTemporaryDomainKey(domainID); } + public slots: void requestAccessToken(const QString& login, const QString& password); diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index 211bfdccfa..6c6f3eb90c 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -25,6 +25,8 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif +const QString DataServerAccountInfo::EMPTY_KEY = QString(); + DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) : QObject() { _accessToken = otherInfo._accessToken; _username = otherInfo._username; @@ -33,6 +35,8 @@ DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherI _walletID = otherInfo._walletID; _privateKey = otherInfo._privateKey; _domainID = otherInfo._domainID; + _temporaryDomainID = otherInfo._temporaryDomainID; + _temporaryDomainApiKey = otherInfo._temporaryDomainApiKey; } DataServerAccountInfo& DataServerAccountInfo::operator=(const DataServerAccountInfo& otherInfo) { @@ -51,6 +55,8 @@ void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) { swap(_walletID, otherInfo._walletID); swap(_privateKey, otherInfo._privateKey); swap(_domainID, otherInfo._domainID); + swap(_temporaryDomainID, otherInfo._temporaryDomainID); + swap(_temporaryDomainApiKey, otherInfo._temporaryDomainApiKey); } void DataServerAccountInfo::setAccessTokenFromJSON(const QJsonObject& jsonObject) { @@ -145,13 +151,14 @@ QByteArray DataServerAccountInfo::signPlaintext(const QByteArray& plaintext) { QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) { out << info._accessToken << info._username << info._xmppPassword << info._discourseApiKey - << info._walletID << info._privateKey << info._domainID; - + << info._walletID << info._privateKey << info._domainID + << info._temporaryDomainID << info._temporaryDomainApiKey; return out; } QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info) { in >> info._accessToken >> info._username >> info._xmppPassword >> info._discourseApiKey - >> info._walletID >> info._privateKey >> info._domainID; + >> info._walletID >> info._privateKey >> info._domainID + >> info._temporaryDomainID >> info._temporaryDomainApiKey; return in; } diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index 6ee726efde..8cb416cf34 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -22,6 +22,7 @@ const float SATOSHIS_PER_CREDIT = 100000000.0f; class DataServerAccountInfo : public QObject { Q_OBJECT + const static QString EMPTY_KEY; public: DataServerAccountInfo() {}; DataServerAccountInfo(const DataServerAccountInfo& otherInfo); @@ -52,6 +53,9 @@ public: void setDomainID(const QUuid& domainID) { _domainID = domainID; } const QUuid& getDomainID() const { return _domainID; } + void setTemporaryDomain(const QUuid& domainID, const QString& key) { _temporaryDomainID = domainID; _temporaryDomainApiKey = key; } + const QString& getTemporaryDomainKey(const QUuid& domainID) { return domainID == _temporaryDomainID ? _temporaryDomainApiKey : EMPTY_KEY; } + bool hasProfile() const; void setProfileInfoFromJSON(const QJsonObject& jsonObject); @@ -67,7 +71,9 @@ private: QString _xmppPassword; QString _discourseApiKey; QUuid _walletID; - QUuid _domainID; // if this holds account info for a domain, this holds the ID of that domain + QUuid _domainID; + QUuid _temporaryDomainID; + QString _temporaryDomainApiKey; QByteArray _privateKey; }; From eebf8e91c6bdcca2308e64b75a4b8ee97b1b970b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz <zach@highfidelity.io> Date: Fri, 17 Jun 2016 19:02:27 -0700 Subject: [PATCH 21/35] add api_key to domains/public_key updates --- libraries/networking/src/AccountManager.cpp | 27 +++++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index ac6d0cd4a0..38f33da6ce 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -652,22 +652,33 @@ void AccountManager::processGeneratedKeypair() { const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key"; QString uploadPath; - if (keypairGenerator->getDomainID().isNull()) { + const auto& domainID = keypairGenerator->getDomainID(); + if (domainID.isNull()) { uploadPath = USER_PUBLIC_KEY_UPDATE_PATH; } else { - uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(keypairGenerator->getDomainID())); + uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(domainID)); } // setup a multipart upload to send up the public key QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); - QHttpPart keyPart; - keyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); - keyPart.setHeader(QNetworkRequest::ContentDispositionHeader, - QVariant("form-data; name=\"public_key\"; filename=\"public_key\"")); - keyPart.setBody(keypairGenerator->getPublicKey()); + QHttpPart publicKeyPart; + publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); - requestMultiPart->append(keyPart); + publicKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader, + QVariant("form-data; name=\"public_key\"; filename=\"public_key\"")); + publicKeyPart.setBody(keypairGenerator->getPublicKey()); + requestMultiPart->append(publicKeyPart); + + if (!domainID.isNull()) { + const auto& key = getTemporaryDomainKey(domainID); + QHttpPart apiKeyPart; + publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); + apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader, + QVariant("form-data; name=\"api_key\"")); + apiKeyPart.setBody(key.toUtf8()); + requestMultiPart->append(apiKeyPart); + } // setup callback parameters so we know once the keypair upload has succeeded or failed JSONCallbackParameters callbackParameters; From a6115cba6e981f17477edd98a0b6695770cc5c19 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz <zach@highfidelity.io> Date: Fri, 17 Jun 2016 19:04:03 -0700 Subject: [PATCH 22/35] update temporary domains to use api_key --- domain-server/src/DomainServer.cpp | 149 +++++++++++++++++++---------- domain-server/src/DomainServer.h | 10 +- 2 files changed, 105 insertions(+), 54 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index a4b57226ed..df1697af28 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -76,6 +76,8 @@ DomainServer::DomainServer(int argc, char* argv[]) : setApplicationVersion(BuildInfo::VERSION); QSettings::setDefaultFormat(QSettings::IniFormat); + qDebug() << "Setting up domain-server"; + // make sure we have a fresh AccountManager instance // (need this since domain-server can restart itself and maintain static variables) DependencyManager::set<AccountManager>(); @@ -109,20 +111,26 @@ DomainServer::DomainServer(int argc, char* argv[]) : return; } - qDebug() << "Setting up domain-server"; - setupNodeListAndAssignments(); - setupAutomaticNetworking(); - _gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request - - _metadata = new DomainMetadata(this); - // check for the temporary name parameter const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; if (args.contains(GET_TEMPORARY_NAME_SWITCH)) { getTemporaryName(); } - qDebug() << "domain-server" << nullptr << "is running"; + setupNodeListAndAssignments(); + setupAutomaticNetworking(); + if (!getID().isNull()) { + setupHeartbeatToMetaverse(); + // send the first heartbeat immediately + sendHeartbeatToMetaverse(); + } + + _gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request + + _metadata = new DomainMetadata(this); + + + qDebug() << "domain-server is running"; } DomainServer::~DomainServer() { @@ -150,6 +158,10 @@ void DomainServer::restart() { exit(DomainServer::EXIT_CODE_REBOOT); } +const QUuid& DomainServer::getID() { + return DependencyManager::get<LimitedNodeList>()->getSessionUUID(); +} + bool DomainServer::optionallyReadX509KeyAndCertificate() { const QString X509_CERTIFICATE_OPTION = "cert"; const QString X509_PRIVATE_KEY_OPTION = "key"; @@ -264,11 +276,13 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) { static const QString DOMAIN_KEY = "domain"; static const QString ID_KEY = "id"; static const QString NAME_KEY = "name"; + static const QString KEY_KEY = "api_key"; auto domainObject = jsonObject[DATA_KEY].toObject()[DOMAIN_KEY].toObject(); if (!domainObject.isEmpty()) { auto id = domainObject[ID_KEY].toString(); auto name = domainObject[NAME_KEY].toString(); + auto key = domainObject[KEY_KEY].toString(); qInfo() << "Received new temporary domain name" << name; qDebug() << "The temporary domain ID is" << id; @@ -284,9 +298,13 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) { // change our domain ID immediately DependencyManager::get<LimitedNodeList>()->setSessionUUID(QUuid { id }); - // change our automatic networking settings so that we're communicating with the ICE server - setupICEHeartbeatForFullNetworking(); + // store the new token to the account info + auto accountManager = DependencyManager::get<AccountManager>(); + accountManager->setTemporaryDomain(id, key); + // update our heartbeats to use the correct id + setupICEHeartbeatForFullNetworking(); + setupHeartbeatToMetaverse(); } else { qWarning() << "There were problems parsing the API response containing a temporary domain name. Please try again" << "via domain-server relaunch or from the domain-server settings."; @@ -325,7 +343,7 @@ bool DomainServer::packetVersionMatch(const udt::Packet& packet) { } -void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { +void DomainServer::setupNodeListAndAssignments() { const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port"; QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION); @@ -450,29 +468,20 @@ bool DomainServer::resetAccountManagerAccessToken() { } void DomainServer::setupAutomaticNetworking() { - auto nodeList = DependencyManager::get<LimitedNodeList>(); - + qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting; _automaticNetworkingSetting = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString(); + auto nodeList = DependencyManager::get<LimitedNodeList>(); + const QUuid& domainID = getID(); + if (_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) { setupICEHeartbeatForFullNetworking(); } - _hasAccessToken = resetAccountManagerAccessToken(); - - if (!_hasAccessToken) { - qDebug() << "Will not send heartbeat to Metaverse API without an access token."; - qDebug() << "If this is not a temporary domain add an access token to your config file or via the web interface."; - - return; - } - if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE || _automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) { - const QUuid& domainID = nodeList->getSessionUUID(); - if (!domainID.isNull()) { qDebug() << "domain-server" << _automaticNetworkingSetting << "automatic networking enabled for ID" << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); @@ -484,9 +493,6 @@ void DomainServer::setupAutomaticNetworking() { // have the LNL enable public socket updating via STUN nodeList->startSTUNPublicSocketUpdate(); - } else { - // send our heartbeat to data server so it knows what our network settings are - sendHeartbeatToMetaverse(); } } else { qDebug() << "Cannot enable domain-server automatic networking without a domain ID." @@ -494,18 +500,20 @@ void DomainServer::setupAutomaticNetworking() { return; } - } else { - sendHeartbeatToMetaverse(); } +} - qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting; - - // no matter the auto networking settings we should heartbeat to the data-server every 15s +void DomainServer::setupHeartbeatToMetaverse() { + // heartbeat to the data-server every 15s const int DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS = 15 * 1000; - QTimer* dataHeartbeatTimer = new QTimer(this); - connect(dataHeartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeatToMetaverse())); - dataHeartbeatTimer->start(DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS); + if (!_metaverseHeartbeatTimer) { + // setup a timer to heartbeat with the metaverse-server + _metaverseHeartbeatTimer = new QTimer { this }; + connect(_metaverseHeartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeatToMetaverse())); + // do not send a heartbeat immediately - this avoids flooding if the heartbeat fails with a 401 + _metaverseHeartbeatTimer->start(DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS); + } } void DomainServer::setupICEHeartbeatForFullNetworking() { @@ -524,22 +532,21 @@ void DomainServer::setupICEHeartbeatForFullNetworking() { limitedNodeList->startSTUNPublicSocketUpdate(); // to send ICE heartbeats we'd better have a private key locally with an uploaded public key - auto accountManager = DependencyManager::get<AccountManager>(); - auto domainID = accountManager->getAccountInfo().getDomainID(); - // if we have an access token and we don't have a private key or the current domain ID has changed // we should generate a new keypair - if (!accountManager->getAccountInfo().hasPrivateKey() || domainID != limitedNodeList->getSessionUUID()) { - accountManager->generateNewDomainKeypair(limitedNodeList->getSessionUUID()); + auto accountManager = DependencyManager::get<AccountManager>(); + if (!accountManager->getAccountInfo().hasPrivateKey() || accountManager->getAccountInfo().getDomainID() != getID()) { + accountManager->generateNewDomainKeypair(getID()); } // hookup to the signal from account manager that tells us when keypair is available connect(accountManager.data(), &AccountManager::newKeypair, this, &DomainServer::handleKeypairChange); if (!_iceHeartbeatTimer) { - // setup a timer to heartbeat with the ice-server every so often + // setup a timer to heartbeat with the ice-server _iceHeartbeatTimer = new QTimer { this }; connect(_iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHeartbeatToIceServer); + sendHeartbeatToIceServer(); _iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); } } @@ -1067,9 +1074,6 @@ void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr) } void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) { - auto nodeList = DependencyManager::get<LimitedNodeList>(); - const QUuid& domainID = nodeList->getSessionUUID(); - // Setup the domain object to send to the data server QJsonObject domainObject; @@ -1088,6 +1092,13 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) { NodePermissions anonymousPermissions = _settingsManager.getPermissionsForName(NodePermissions::standardNameAnonymous); domainObject[RESTRICTED_ACCESS_FLAG] = !anonymousPermissions.canConnectToDomain; + const auto& temporaryDomainKey = DependencyManager::get<AccountManager>()->getTemporaryDomainKey(getID()); + if (!temporaryDomainKey.isEmpty()) { + // add the temporary domain token + const QString KEY_KEY = "api_key"; + domainObject[KEY_KEY] = temporaryDomainKey; + } + if (_metadata) { // Add the metadata to the heartbeat static const QString DOMAIN_HEARTBEAT_KEY = "heartbeat"; @@ -1097,18 +1108,47 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) { QString domainUpdateJSON = QString("{\"domain\":%1}").arg(QString(QJsonDocument(domainObject).toJson(QJsonDocument::Compact))); static const QString DOMAIN_UPDATE = "/api/v1/domains/%1"; - DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), - AccountManagerAuth::Required, + DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(getID())), + AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), + JSONCallbackParameters(nullptr, QString(), this, "handleMetaverseHeartbeatError"), domainUpdateJSON.toUtf8()); } +void DomainServer::handleMetaverseHeartbeatError(QNetworkReply& requestReply) { + if (!_metaverseHeartbeatTimer) { + // avoid rehandling errors from the same issue + return; + } + + // if we have a temporary domain with a bad token, we will get a 401 + if (requestReply.error() == QNetworkReply::NetworkError::AuthenticationRequiredError) { + static const QString DATA_KEY = "data"; + static const QString TOKEN_KEY = "api_key"; + + QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); + auto tokenFailure = jsonObject[DATA_KEY].toObject()[TOKEN_KEY]; + + if (!tokenFailure.isNull()) { + qWarning() << "Temporary domain name lacks a valid API key, and is being reset."; + + // halt heartbeats until we have a token + _metaverseHeartbeatTimer->deleteLater(); + _metaverseHeartbeatTimer = nullptr; + + // give up eventually to avoid flooding traffic + static const int MAX_ATTEMPTS = 5; + static int attempt = 0; + if (++attempt < MAX_ATTEMPTS) { + // get a new temporary name and token + getTemporaryName(true); + } + } + } +} + void DomainServer::sendICEServerAddressToMetaverseAPI() { if (!_iceServerSocket.isNull()) { - auto nodeList = DependencyManager::get<LimitedNodeList>(); - const QUuid& domainID = nodeList->getSessionUUID(); - const QString ICE_SERVER_ADDRESS = "ice_server_address"; QJsonObject domainObject; @@ -1116,6 +1156,13 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() { // we're using full automatic networking and we have a current ice-server socket, use that now domainObject[ICE_SERVER_ADDRESS] = _iceServerSocket.getAddress().toString(); + const auto& temporaryDomainKey = DependencyManager::get<AccountManager>()->getTemporaryDomainKey(getID()); + if (!temporaryDomainKey.isEmpty()) { + // add the temporary domain token + const QString KEY_KEY = "api_key"; + domainObject[KEY_KEY] = temporaryDomainKey; + } + QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson())); // make sure we hear about failure so we can retry @@ -1127,7 +1174,7 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() { static const QString DOMAIN_ICE_ADDRESS_UPDATE = "/api/v1/domains/%1/ice_server_address"; - DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), + DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(getID())), AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation, callbackParameters, diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 8a25591605..138cb9ca2d 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -80,6 +80,8 @@ private slots: void handleTempDomainSuccess(QNetworkReply& requestReply); void handleTempDomainError(QNetworkReply& requestReply); + void handleMetaverseHeartbeatError(QNetworkReply& requestReply); + void queuedQuit(QString quitMessage, int exitCode); void handleKeypairChange(); @@ -96,7 +98,9 @@ signals: void userDisconnected(); private: - void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); + const QUuid& getID(); + + void setupNodeListAndAssignments(); bool optionallySetupOAuth(); bool optionallyReadX509KeyAndCertificate(); @@ -108,6 +112,7 @@ private: void setupAutomaticNetworking(); void setupICEHeartbeatForFullNetworking(); + void setupHeartbeatToMetaverse(); void sendHeartbeatToMetaverse(const QString& networkAddress); void randomizeICEServerAddress(bool shouldTriggerHostLookup); @@ -178,6 +183,7 @@ private: // These will be parented to this, they are not dangling DomainMetadata* _metadata { nullptr }; QTimer* _iceHeartbeatTimer { nullptr }; + QTimer* _metaverseHeartbeatTimer { nullptr }; QList<QHostAddress> _iceServerAddresses; QSet<QHostAddress> _failedIceServerAddresses; @@ -186,8 +192,6 @@ private: int _numHeartbeatDenials { 0 }; bool _connectedToICEServer { false }; - bool _hasAccessToken { false }; - friend class DomainGatekeeper; friend class DomainMetadata; }; From 4a30d549add061e408c95d692e2098ef6eb70207 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz <zach@highfidelity.io> Date: Fri, 17 Jun 2016 19:26:22 -0700 Subject: [PATCH 23/35] force temp domain reset on 404 too (401 already) --- domain-server/src/DomainServer.cpp | 51 +++++++++++++++++++----------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index df1697af28..192c0d26e6 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1121,29 +1121,42 @@ void DomainServer::handleMetaverseHeartbeatError(QNetworkReply& requestReply) { return; } - // if we have a temporary domain with a bad token, we will get a 401 - if (requestReply.error() == QNetworkReply::NetworkError::AuthenticationRequiredError) { - static const QString DATA_KEY = "data"; - static const QString TOKEN_KEY = "api_key"; + // check if we need to force a new temporary domain name + switch (requestReply.error()) { + // if we have a temporary domain with a bad token, we get a 401 + case QNetworkReply::NetworkError::AuthenticationRequiredError: { + static const QString DATA_KEY = "data"; + static const QString TOKEN_KEY = "api_key"; - QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); - auto tokenFailure = jsonObject[DATA_KEY].toObject()[TOKEN_KEY]; + QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); + auto tokenFailure = jsonObject[DATA_KEY].toObject()[TOKEN_KEY]; - if (!tokenFailure.isNull()) { - qWarning() << "Temporary domain name lacks a valid API key, and is being reset."; - - // halt heartbeats until we have a token - _metaverseHeartbeatTimer->deleteLater(); - _metaverseHeartbeatTimer = nullptr; - - // give up eventually to avoid flooding traffic - static const int MAX_ATTEMPTS = 5; - static int attempt = 0; - if (++attempt < MAX_ATTEMPTS) { - // get a new temporary name and token - getTemporaryName(true); + if (!tokenFailure.isNull()) { + qWarning() << "Temporary domain name lacks a valid API key, and is being reset."; } + break; } + // if the domain does not (or no longer) exists, we get a 404 + case QNetworkReply::NetworkError::ContentNotFoundError: + qWarning() << "Domain not found, getting a new temporary domain."; + break; + // otherwise, we erred on something else, and should not force a temporary domain + default: + return; + } + + // halt heartbeats until we have a token + _metaverseHeartbeatTimer->deleteLater(); + _metaverseHeartbeatTimer = nullptr; + + // give up eventually to avoid flooding traffic + static const int MAX_ATTEMPTS = 5; + static int attempt = 0; + if (++attempt < MAX_ATTEMPTS) { + // get a new temporary name and token + getTemporaryName(true); + } else { + qWarning() << "Already attempted too many temporary domain requests. Please set a domain ID manually or restart."; } } From 8009d23f7007fbf311ab80f593346d4cf5658764 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Wed, 22 Jun 2016 15:20:45 -0700 Subject: [PATCH 24/35] more STATIC_MESH and dynamic overlap prevention --- libraries/entities/src/EntityItem.cpp | 12 ++-- libraries/entities/src/EntityItem.h | 4 +- libraries/entities/src/ModelEntityItem.cpp | 57 ++++++++++++------- libraries/entities/src/ModelEntityItem.h | 6 +- .../entities/src/ParticleEffectEntityItem.cpp | 6 +- .../entities/src/ParticleEffectEntityItem.h | 4 +- libraries/entities/src/ZoneEntityItem.cpp | 4 +- libraries/entities/src/ZoneEntityItem.h | 6 +- 8 files changed, 61 insertions(+), 38 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 2abb9f12e2..f0a4d40860 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1693,9 +1693,13 @@ void EntityItem::updateCollisionMask(uint8_t value) { } void EntityItem::updateDynamic(bool value) { - if (_dynamic != value) { - if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { - _dynamic = false; + if (getDynamic() != value) { + // dynamic and STATIC_MESH are incompatible so we check for that case + if (value && getShapeType() == SHAPE_TYPE_STATIC_MESH) { + if (_dynamic) { + _dynamic = false; + _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + } } else { _dynamic = value; _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; @@ -1749,7 +1753,7 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask group = BULLET_COLLISION_GROUP_COLLISIONLESS; mask = 0; } else { - if (_dynamic) { + if (getDynamic()) { group = BULLET_COLLISION_GROUP_DYNAMIC; } else if (isMovingRelativeToParent() || hasActions()) { group = BULLET_COLLISION_GROUP_KINEMATIC; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 4a691462ab..9fa13690f1 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -283,7 +283,7 @@ public: void computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const; - bool getDynamic() const { return _dynamic; } + bool getDynamic() const { return SHAPE_TYPE_STATIC_MESH == getShapeType() ? false : _dynamic; } void setDynamic(bool value) { _dynamic = value; } virtual bool shouldBePhysical() const { return false; } @@ -348,7 +348,7 @@ public: void updateDynamic(bool value); void updateLifetime(float value); void updateCreated(uint64_t value); - virtual void updateShapeType(ShapeType type) { /* do nothing */ } + virtual void setShapeType(ShapeType type) { /* do nothing */ } uint32_t getDirtyFlags() const { return _dirtyFlags; } void clearDirtyFlags(uint32_t mask = 0xffffffff) { _dirtyFlags &= ~mask; } diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 40faf2c3c3..8e925b2f79 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -77,7 +77,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotationsSet, setJointRotationsSet); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotations, setJointRotations); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslationsSet, setJointTranslationsSet); @@ -145,7 +145,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, dataAt += bytesFromAnimation; } - READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, updateShapeType); + READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); if (animationPropertiesChanged) { _dirtyFlags |= Simulation::DIRTY_UPDATEABLE; @@ -257,37 +257,54 @@ void ModelEntityItem::debugDump() const { qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL(); } -void ModelEntityItem::updateShapeType(ShapeType type) { - // BEGIN_TEMPORARY_WORKAROUND - // we have allowed inconsistent ShapeType's to be stored in SVO files in the past (this was a bug) - // but we are now enforcing the entity properties to be consistent. To make the possible we're - // introducing a temporary workaround: we will ignore ShapeType updates that conflict with the - // _compoundShapeURL. - if (hasCompoundShapeURL()) { - type = SHAPE_TYPE_COMPOUND; - } - // END_TEMPORARY_WORKAROUND - +void ModelEntityItem::setShapeType(ShapeType type) { if (type != _shapeType) { + if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) { + // dynamic and STATIC_MESH are incompatible + // since the shape is being set here we clear the dynamic bit + _dynamic = false; + _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + } _shapeType = type; _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; } } -// virtual ShapeType ModelEntityItem::getShapeType() const { - if (_shapeType == SHAPE_TYPE_COMPOUND) { - return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE; - } else { - return _shapeType; + return computeTrueShapeType(); +} + +ShapeType ModelEntityItem::computeTrueShapeType() const { + ShapeType type = _shapeType; + if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) { + // dynamic is incompatible with STATIC_MESH + // shouldn't fall in here but just in case --> fall back to COMPOUND + type = SHAPE_TYPE_COMPOUND; + } + if (type == SHAPE_TYPE_COMPOUND && !hasCompoundShapeURL()) { + // no compoundURL set --> fall back to NONE + type = SHAPE_TYPE_NONE; + } + return type; +} + +void ModelEntityItem::setModelURL(const QString& url) { + if (_modelURL != url) { + _modelURL = url; + _parsedModelURL = QUrl(url); + if (_shapeType == SHAPE_TYPE_STATIC_MESH) { + _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; + } } } void ModelEntityItem::setCompoundShapeURL(const QString& url) { if (_compoundShapeURL != url) { + ShapeType oldType = computeTrueShapeType(); _compoundShapeURL = url; - _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; - _shapeType = _compoundShapeURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND; + if (oldType != computeTrueShapeType()) { + _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; + } } } diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 29730bf4df..7b7edaf945 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -50,9 +50,10 @@ public: virtual bool needsToCallUpdate() const; virtual void debugDump() const; - void updateShapeType(ShapeType type); + void setShapeType(ShapeType type); virtual ShapeType getShapeType() const; + // TODO: Move these to subclasses, or other appropriate abstraction // getters/setters applicable to models and particles @@ -76,7 +77,7 @@ public: } // model related properties - virtual void setModelURL(const QString& url) { _modelURL = url; _parsedModelURL = QUrl(url); } + virtual void setModelURL(const QString& url); virtual void setCompoundShapeURL(const QString& url); // Animation related items... @@ -130,6 +131,7 @@ public: private: void setAnimationSettings(const QString& value); // only called for old bitstream format + ShapeType computeTrueShapeType() const; protected: // these are used: diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index a7bd0038e6..c501737146 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -342,7 +342,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(maxParticles, setMaxParticles); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan); SET_ENTITY_PROPERTY_FROM_PROPERTIES(isEmitting, setIsEmitting); @@ -406,7 +406,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting); } - READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, updateShapeType); + READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles); READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan); READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate); @@ -584,7 +584,7 @@ void ParticleEffectEntityItem::debugDump() const { qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } -void ParticleEffectEntityItem::updateShapeType(ShapeType type) { +void ParticleEffectEntityItem::setShapeType(ShapeType type) { if (type != _shapeType) { _shapeType = type; _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 4538a1bb43..777f3b6cf6 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -95,8 +95,8 @@ public: void setAlphaSpread(float alphaSpread); float getAlphaSpread() const { return _alphaSpread; } - void updateShapeType(ShapeType type); - virtual ShapeType getShapeType() const { return _shapeType; } + void setShapeType(ShapeType type) override; + virtual ShapeType getShapeType() const override { return _shapeType; } virtual void debugDump() const; diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index a28b8210c2..0b99d0377f 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -73,7 +73,7 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChangedInStage = _stageProperties.setProperties(properties); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundMode, setBackgroundMode); @@ -117,7 +117,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, bytesRead += bytesFromStage; dataAt += bytesFromStage; - READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, updateShapeType); + READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); READ_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode); diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 56968aa9c9..599e70f83e 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -54,9 +54,9 @@ public: static bool getDrawZoneBoundaries() { return _drawZoneBoundaries; } static void setDrawZoneBoundaries(bool value) { _drawZoneBoundaries = value; } - virtual bool isReadyToComputeShape() { return false; } - void updateShapeType(ShapeType type) { _shapeType = type; } - virtual ShapeType getShapeType() const; + virtual bool isReadyToComputeShape() override { return false; } + void setShapeType(ShapeType type) override { _shapeType = type; } + virtual ShapeType getShapeType() const override; virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); } const QString getCompoundShapeURL() const { return _compoundShapeURL; } From e5b89ebd17aaa10fcb7253c10fcaa4ea0576d9ae Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Wed, 22 Jun 2016 15:33:44 -0700 Subject: [PATCH 25/35] bump version number --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 6ca50420f3..c74b10820d 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -49,7 +49,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_PROPERLY_ENCODE_SHAPE_EDITS; + return VERSION_MODEL_ENTITIES_SUPPORT_STATIC_MESH; case PacketType::AvatarIdentity: case PacketType::AvatarData: case PacketType::BulkAvatarData: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index ae54450fee..e484a06502 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -180,6 +180,7 @@ const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57; const PacketVersion VERSION_ENTITIES_NO_FLY_ZONES = 58; const PacketVersion VERSION_ENTITIES_MORE_SHAPES = 59; const PacketVersion VERSION_ENTITIES_PROPERLY_ENCODE_SHAPE_EDITS = 60; +const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_STATIC_MESH = 61; enum class AvatarMixerPacketVersion : PacketVersion { TranslationSupport = 17, From f495f5e3b56173d15977159300db9802fa46843d Mon Sep 17 00:00:00 2001 From: SamGondelman <samuel_gondelman@brown.edu> Date: Wed, 22 Jun 2016 16:05:55 -0700 Subject: [PATCH 26/35] removed mac hydra support --- plugins/hifiSixense/src/SixenseManager.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index 03028249a3..48d13a8eaf 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -66,14 +66,8 @@ const QString SHOW_DEBUG_RAW = "Debug Draw Raw Data"; const QString SHOW_DEBUG_CALIBRATED = "Debug Draw Calibrated Data"; bool SixenseManager::isSupported() const { -#ifdef HAVE_SIXENSE - -#if defined(Q_OS_OSX) - return QSysInfo::macVersion() <= QSysInfo::MV_MAVERICKS; -#else +#if defined(HAVE_SIXENSE) && !defined(Q_OS_OSX) return true; -#endif - #else return false; #endif From a9ed0b1c8386c530e08ef9e23845ca21580f05f7 Mon Sep 17 00:00:00 2001 From: SamGondelman <samuel_gondelman@brown.edu> Date: Wed, 22 Jun 2016 16:56:50 -0700 Subject: [PATCH 27/35] completely destroyed sixense on macs --- cmake/externals/sixense/CMakeLists.txt | 25 +-- cmake/macros/TargetSixense.cmake | 12 +- plugins/hifiSixense/src/SixenseManager.cpp | 2 + plugins/hifiSixense/src/SixenseSupportOSX.cpp | 155 ------------------ 4 files changed, 10 insertions(+), 184 deletions(-) delete mode 100644 plugins/hifiSixense/src/SixenseSupportOSX.cpp diff --git a/cmake/externals/sixense/CMakeLists.txt b/cmake/externals/sixense/CMakeLists.txt index 16f2850449..bd0d042c0b 100644 --- a/cmake/externals/sixense/CMakeLists.txt +++ b/cmake/externals/sixense/CMakeLists.txt @@ -57,30 +57,7 @@ if (WIN32) elseif(APPLE) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/lib/osx_x64/debug_dll/libsixensed_x64.dylib CACHE TYPE INTERNAL) - - set(_SIXENSE_LIB_DIR "${SOURCE_DIR}/lib/osx_x64") - ExternalProject_Add_Step( - ${EXTERNAL_NAME} - change-install-name-release - COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking" - COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SIXENSE_LIB_DIR}/release_dll -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake - DEPENDEES install - WORKING_DIRECTORY <SOURCE_DIR> - LOG 1 - ) - - set(_SIXENSE_LIB_DIR "${SOURCE_DIR}/lib/osx_x64") - ExternalProject_Add_Step( - ${EXTERNAL_NAME} - change-install-name-debug - COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking" - COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SIXENSE_LIB_DIR}/debug_dll -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake - DEPENDEES install - WORKING_DIRECTORY <SOURCE_DIR> - LOG 1 - ) + # We no longer support Sixense on Macs due to bugs in the Sixense DLL elseif(NOT ANDROID) diff --git a/cmake/macros/TargetSixense.cmake b/cmake/macros/TargetSixense.cmake index 6fd9cede1f..28128d8b79 100644 --- a/cmake/macros/TargetSixense.cmake +++ b/cmake/macros/TargetSixense.cmake @@ -6,9 +6,11 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # macro(TARGET_SIXENSE) - add_dependency_external_projects(sixense) - find_package(Sixense REQUIRED) - target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) - add_definitions(-DHAVE_SIXENSE) + if(NOT APPLE) + add_dependency_external_projects(sixense) + find_package(Sixense REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) + add_definitions(-DHAVE_SIXENSE) + endif() endmacro() diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index 48d13a8eaf..ade643ec72 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -131,6 +131,7 @@ void SixenseManager::setSixenseFilter(bool filter) { void SixenseManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { BAIL_IF_NOT_LOADED +#ifdef HAVE_SIXENSE static bool sixenseHasBeenConnected { false }; if (!sixenseHasBeenConnected && sixenseIsBaseConnected(0)) { sixenseHasBeenConnected = true; @@ -146,6 +147,7 @@ void SixenseManager::pluginUpdate(float deltaTime, const controller::InputCalibr _container->requestReset(); _inputDevice->_requestReset = false; } +#endif } void SixenseManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { diff --git a/plugins/hifiSixense/src/SixenseSupportOSX.cpp b/plugins/hifiSixense/src/SixenseSupportOSX.cpp deleted file mode 100644 index fce2ea023b..0000000000 --- a/plugins/hifiSixense/src/SixenseSupportOSX.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// -// SixenseSupportOSX.cpp -// libraries/input-plugins/src/input-plugins -// -// Created by Clement on 10/20/15. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// Mock implementation of sixense.h to hide dynamic linking on OS X -#if defined(__APPLE__) && defined(HAVE_SIXENSE) -#include <type_traits> - -#include <sixense.h> - -#include <QtCore/QCoreApplication> -#include <QtCore/QLibrary> -#include <QtCore/QDebug> - -#ifndef SIXENSE_LIB_FILENAME -#define SIXENSE_LIB_FILENAME QCoreApplication::applicationDirPath() + "/../Frameworks/libsixense_x64" -#endif - -using Library = std::unique_ptr<QLibrary>; -static Library SIXENSE; - -struct Callable { - template<typename... Args> - int operator() (Args&&... args){ - return reinterpret_cast<int(*)(Args...)>(function)(std::forward<Args>(args)...); - } - QFunctionPointer function; -}; - -Callable resolve(const Library& library, const char* name) { - Q_ASSERT_X(library && library->isLoaded(), __FUNCTION__, "Sixense library not loaded"); - auto function = library->resolve(name); - Q_ASSERT_X(function, __FUNCTION__, std::string("Could not resolve ").append(name).c_str()); - return Callable { function }; -} -#define FORWARD resolve(SIXENSE, __FUNCTION__) - - -void loadSixense() { - Q_ASSERT_X(!(SIXENSE && SIXENSE->isLoaded()), __FUNCTION__, "Sixense library already loaded"); - SIXENSE.reset(new QLibrary(SIXENSE_LIB_FILENAME)); - Q_CHECK_PTR(SIXENSE); - - if (SIXENSE->load()){ - qDebug() << "Loaded sixense library for hydra support -" << SIXENSE->fileName(); - } else { - qDebug() << "Sixense library at" << SIXENSE->fileName() << "failed to load:" << SIXENSE->errorString(); - qDebug() << "Continuing without hydra support."; - } -} -void unloadSixense() { - SIXENSE->unload(); -} - - -// sixense.h wrapper for OSX dynamic linking -int sixenseInit() { - loadSixense(); - if (!SIXENSE || !SIXENSE->isLoaded()) { - return SIXENSE_FAILURE; - } - return FORWARD(); -} -int sixenseExit() { - auto returnCode = FORWARD(); - unloadSixense(); - return returnCode; -} - -int sixenseGetMaxBases() { - return FORWARD(); -} -int sixenseSetActiveBase(int i) { - return FORWARD(i); -} -int sixenseIsBaseConnected(int i) { - return FORWARD(i); -} - -int sixenseGetMaxControllers() { - return FORWARD(); -} -int sixenseIsControllerEnabled(int which) { - return FORWARD(which); -} -int sixenseGetNumActiveControllers() { - return FORWARD(); -} - -int sixenseGetHistorySize() { - return FORWARD(); -} - -int sixenseGetData(int which, int index_back, sixenseControllerData* data) { - return FORWARD(which, index_back, data); -} -int sixenseGetAllData(int index_back, sixenseAllControllerData* data) { - return FORWARD(index_back, data); -} -int sixenseGetNewestData(int which, sixenseControllerData* data) { - return FORWARD(which, data); -} -int sixenseGetAllNewestData(sixenseAllControllerData* data) { - return FORWARD(data); -} - -int sixenseSetHemisphereTrackingMode(int which_controller, int state) { - return FORWARD(which_controller, state); -} -int sixenseGetHemisphereTrackingMode(int which_controller, int* state) { - return FORWARD(which_controller, state); -} -int sixenseAutoEnableHemisphereTracking(int which_controller) { - return FORWARD(which_controller); -} - -int sixenseSetHighPriorityBindingEnabled(int on_or_off) { - return FORWARD(on_or_off); -} -int sixenseGetHighPriorityBindingEnabled(int* on_or_off) { - return FORWARD(on_or_off); -} - -int sixenseTriggerVibration(int controller_id, int duration_100ms, int pattern_id) { - return FORWARD(controller_id, duration_100ms, pattern_id); -} - -int sixenseSetFilterEnabled(int on_or_off) { - return FORWARD(on_or_off); -} -int sixenseGetFilterEnabled(int* on_or_off) { - return FORWARD(on_or_off); -} - -int sixenseSetFilterParams(float near_range, float near_val, float far_range, float far_val) { - return FORWARD(near_range, near_val, far_range, far_val); -} -int sixenseGetFilterParams(float* near_range, float* near_val, float* far_range, float* far_val) { - return FORWARD(near_range, near_val, far_range, far_val); -} - -int sixenseSetBaseColor(unsigned char red, unsigned char green, unsigned char blue) { - return FORWARD(red, green, blue); -} -int sixenseGetBaseColor(unsigned char* red, unsigned char* green, unsigned char* blue) { - return FORWARD(red, green, blue); -} -#endif From 645ae3c21e96fe299ceac3c2499b218b9fc87213 Mon Sep 17 00:00:00 2001 From: SamGondelman <samuel_gondelman@brown.edu> Date: Wed, 22 Jun 2016 17:02:02 -0700 Subject: [PATCH 28/35] remove tabs --- cmake/macros/TargetSixense.cmake | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/macros/TargetSixense.cmake b/cmake/macros/TargetSixense.cmake index 28128d8b79..07dcfe67e4 100644 --- a/cmake/macros/TargetSixense.cmake +++ b/cmake/macros/TargetSixense.cmake @@ -6,11 +6,11 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # macro(TARGET_SIXENSE) - if(NOT APPLE) - add_dependency_external_projects(sixense) - find_package(Sixense REQUIRED) - target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) - add_definitions(-DHAVE_SIXENSE) - endif() + if(NOT APPLE) + add_dependency_external_projects(sixense) + find_package(Sixense REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) + add_definitions(-DHAVE_SIXENSE) + endif() endmacro() From 1d8d1240cad863ab853123b874d78d677ce26e07 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Thu, 23 Jun 2016 10:38:46 -0700 Subject: [PATCH 29/35] remove override to avoid new Jenkins OSX warnings --- libraries/entities/src/ParticleEffectEntityItem.h | 4 ++-- libraries/entities/src/ZoneEntityItem.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 777f3b6cf6..9ddda62c8b 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -95,8 +95,8 @@ public: void setAlphaSpread(float alphaSpread); float getAlphaSpread() const { return _alphaSpread; } - void setShapeType(ShapeType type) override; - virtual ShapeType getShapeType() const override { return _shapeType; } + void setShapeType(ShapeType type); + virtual ShapeType getShapeType() const { return _shapeType; } virtual void debugDump() const; diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 599e70f83e..f0f2a91d63 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -54,9 +54,9 @@ public: static bool getDrawZoneBoundaries() { return _drawZoneBoundaries; } static void setDrawZoneBoundaries(bool value) { _drawZoneBoundaries = value; } - virtual bool isReadyToComputeShape() override { return false; } - void setShapeType(ShapeType type) override { _shapeType = type; } - virtual ShapeType getShapeType() const override; + virtual bool isReadyToComputeShape() { return false; } + void setShapeType(ShapeType type) { _shapeType = type; } + virtual ShapeType getShapeType() const; virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); } const QString getCompoundShapeURL() const { return _compoundShapeURL; } From 1de1c632afbb4f6f124108d32265e2aa3ec25c53 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz <zach@highfidelity.io> Date: Thu, 23 Jun 2016 17:16:42 -0700 Subject: [PATCH 30/35] use private_description instead of description for domain settings --- domain-server/resources/web/settings/js/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index c2cb2ecb80..4188e86548 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -555,7 +555,7 @@ function createNewDomainID(description, justConnected) { // get the JSON object ready that we'll use to create a new domain var domainJSON = { "domain": { - "description": description + "private_description": description }, "access_token": $(Settings.ACCESS_TOKEN_SELECTOR).val() } @@ -748,8 +748,8 @@ function chooseFromHighFidelityDomains(clickedButton) { _.each(data.data.domains, function(domain){ var domainString = ""; - if (domain.description) { - domainString += '"' + domain.description + '" - '; + if (domain.private_description) { + domainString += '"' + domain.private_description + '" - '; } domainString += domain.id; From 13310923c4440ec6b0a97dbf89627dc63fe832ad Mon Sep 17 00:00:00 2001 From: Zach Pomerantz <zach@highfidelity.io> Date: Thu, 23 Jun 2016 19:38:23 -0700 Subject: [PATCH 31/35] reset to temp domain after logout --- .../resources/web/settings/js/settings.js | 2 ++ domain-server/src/DomainServer.cpp | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 4188e86548..4f153d6190 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -457,6 +457,8 @@ function disonnectHighFidelityAccount() { }, function(){ // we need to post to settings to clear the access-token $(Settings.ACCESS_TOKEN_SELECTOR).val('').change(); + // reset the domain id to get a new temporary name + $(Settings.DOMAIN_ID_SELECTOR).val('').change(); saveSettings(); }); } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 192c0d26e6..ca0d7728dd 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -111,12 +111,6 @@ DomainServer::DomainServer(int argc, char* argv[]) : return; } - // check for the temporary name parameter - const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; - if (args.contains(GET_TEMPORARY_NAME_SWITCH)) { - getTemporaryName(); - } - setupNodeListAndAssignments(); setupAutomaticNetworking(); if (!getID().isNull()) { @@ -125,6 +119,12 @@ DomainServer::DomainServer(int argc, char* argv[]) : sendHeartbeatToMetaverse(); } + // check for the temporary name parameter + const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; + if (args.contains(GET_TEMPORARY_NAME_SWITCH)) { + getTemporaryName(); + } + _gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request _metadata = new DomainMetadata(this); @@ -251,12 +251,13 @@ void DomainServer::getTemporaryName(bool force) { // check if we already have a domain ID const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH); + qInfo() << "Requesting temporary domain name"; if (idValueVariant) { - qWarning() << "Temporary domain name requested but a domain ID is already present in domain-server settings."; + qDebug() << "A domain ID is already present in domain-server settings:" << idValueVariant->toString(); if (force) { - qWarning() << "Temporary domain name will be requested to replace it."; + qDebug() << "Requesting temporary domain name to replace current ID:" << getID(); } else { - qWarning() << "Temporary domain name will not be requested."; + qInfo() << "Abandoning request of temporary domain name."; return; } } From b1b378a91feb062e160cf794002e59c13e5ed11b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz <zach@highfidelity.io> Date: Thu, 23 Jun 2016 19:38:41 -0700 Subject: [PATCH 32/35] add back access token to domain-server --- domain-server/src/DomainServer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index ca0d7728dd..6e5c1fd361 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -470,6 +470,9 @@ bool DomainServer::resetAccountManagerAccessToken() { void DomainServer::setupAutomaticNetworking() { qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting; + + resetAccountManagerAccessToken(); + _automaticNetworkingSetting = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString(); From 1fcd7aa0c44d714fa4505b9b97fdad698ed9a674 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz <zach@highfidelity.io> Date: Thu, 23 Jun 2016 19:54:34 -0700 Subject: [PATCH 33/35] add build version to heartbeat --- domain-server/src/DomainServer.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 223cab61da..d421c6554b 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1081,6 +1081,11 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) { // Setup the domain object to send to the data server QJsonObject domainObject; + // add the version + static const QString VERSION_KEY = "version"; + domainObject[VERSION_KEY] = BuildInfo::VERSION; + + // add networking if (!networkAddress.isEmpty()) { static const QString PUBLIC_NETWORK_ADDRESS_KEY = "network_address"; domainObject[PUBLIC_NETWORK_ADDRESS_KEY] = networkAddress; @@ -1089,10 +1094,10 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) { static const QString AUTOMATIC_NETWORKING_KEY = "automatic_networking"; domainObject[AUTOMATIC_NETWORKING_KEY] = _automaticNetworkingSetting; - // add a flag to indicate if this domain uses restricted access - for now that will exclude it from listings - const QString RESTRICTED_ACCESS_FLAG = "restricted"; - // consider the domain to have restricted access if "anonymous" connections can't connect to the domain. + // add access level for anonymous connections + // consider the domain to be "restricted" if anonymous connections are disallowed + static const QString RESTRICTED_ACCESS_FLAG = "restricted"; NodePermissions anonymousPermissions = _settingsManager.getPermissionsForName(NodePermissions::standardNameAnonymous); domainObject[RESTRICTED_ACCESS_FLAG] = !anonymousPermissions.canConnectToDomain; From a095da31fd8c1422058da1de0622554124f4f56c Mon Sep 17 00:00:00 2001 From: Brad Davis <bdavis@saintandreas.org> Date: Fri, 24 Jun 2016 11:48:55 -0700 Subject: [PATCH 34/35] Fix initial visibility of QML windows from scripts --- libraries/ui/src/QmlWindowClass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index b8834f0549..c0eba4abf3 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -118,7 +118,7 @@ void QmlWindowClass::initQml(QVariantMap properties) { } bool visible = !properties.contains(VISIBILE_PROPERTY) || properties[VISIBILE_PROPERTY].toBool(); - object->setProperty(VISIBILE_PROPERTY, visible); + object->setProperty(OFFSCREEN_VISIBILITY_PROPERTY, visible); object->setProperty(SOURCE_PROPERTY, _source); // Forward messages received from QML on to the script From 8bf72f28da84d177e67e920fa1e3f1b243a587b6 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" <tony@highfidelity.io> Date: Fri, 24 Jun 2016 12:06:02 -0700 Subject: [PATCH 35/35] Fix for grab script search ray length --- scripts/system/controllers/handControllerGrab.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 7706132c58..93d2269584 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1173,10 +1173,12 @@ function MyController(hand) { } var rayPickInfo = this.calcRayPickInfo(this.hand); - this.intersectionDistance = rayPickInfo.distance; if (rayPickInfo.entityID) { candidateEntities.push(rayPickInfo.entityID); this.entityPropertyCache.addEntity(rayPickInfo.entityID); + this.intersectionDistance = rayPickInfo.distance; + } else { + this.intersectionDistance = 0; } var grabbableEntities = candidateEntities.filter(function (entity) {