diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 9af44f6a1b..4636c61367 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -74,6 +74,14 @@ } ] }, + { + "name": "maximum_user_capacity", + "label": "Maximum User Capacity", + "help": "The limit on how many avatars can be connected at once. 0 means no limit.", + "placeholder": "0", + "default": "0", + "advanced": false + }, { "name": "allowed_editors", "type": "table", diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 7af9ffd85c..2e3505dd4d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -44,6 +44,7 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io"; const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users"; +const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity"; const QString ALLOWED_EDITORS_SETTINGS_KEYPATH = "security.allowed_editors"; @@ -667,9 +668,22 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock } +unsigned int DomainServer::countConnectedUsers() { + unsigned int result = 0; + auto nodeList = DependencyManager::get(); + nodeList->eachNode([&](const SharedNodePointer& otherNode){ + if (otherNode->getType() == NodeType::Agent) { + result++; + } + }); + return result; +} + + bool DomainServer::shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature, const HifiSockAddr& senderSockAddr) { + const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_USERS_SETTINGS_KEYPATH); QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList(); @@ -679,6 +693,18 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username, || senderSockAddr.getAddress() == QHostAddress::LocalHost) { return true; } + + const QVariant* maximumUserCapacityVariant = valueForKeyPath(_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY); + unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0; + if (maximumUserCapacity > 0) { + unsigned int connectedUsers = countConnectedUsers(); + if (connectedUsers >= maximumUserCapacity) { + // too many users, deny the new connection. + qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection."; + return false; + } + qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, perhaps allowing new connection."; + } if (allowedUsers.count() > 0) { if (allowedUsers.contains(username, Qt::CaseInsensitive)) { diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index f910534eb1..7052cd65a8 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -83,6 +83,7 @@ private: void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); void handleConnectRequest(const QByteArray& packet, const HifiSockAddr& senderSockAddr); + unsigned int countConnectedUsers(); bool shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature, const HifiSockAddr& senderSockAddr); diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 05ffb0bd3f..f52d6be87e 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -18,3 +18,4 @@ Script.load("lobby.js"); Script.load("notifications.js"); Script.load("look.js"); Script.load("users.js"); +Script.load("utilities/LODWarning.js"); diff --git a/examples/example/ui/LODManagerExample.js b/examples/example/ui/LODManagerExample.js new file mode 100644 index 0000000000..b3d2444412 --- /dev/null +++ b/examples/example/ui/LODManagerExample.js @@ -0,0 +1,16 @@ + +LODManager.LODIncreased.connect(function() { + print("LOD has been increased. You can now see " + + LODManager.getLODFeedbackText() + + ", fps:" + LODManager.getFPSAverage() + + ", fast fps:" + LODManager.getFastFPSAverage() + ); +}); + +LODManager.LODDecreased.connect(function() { + print("LOD has been decreased. You can now see " + + LODManager.getLODFeedbackText() + + ", fps:" + LODManager.getFPSAverage() + + ", fast fps:" + LODManager.getFastFPSAverage() + ); +}); \ No newline at end of file diff --git a/examples/hmdDefaults.js b/examples/hmdDefaults.js index 0096b11777..1e96d41713 100644 --- a/examples/hmdDefaults.js +++ b/examples/hmdDefaults.js @@ -13,4 +13,5 @@ Script.load("progress.js"); Script.load("lobby.js"); Script.load("notifications.js"); Script.load("controllers/oculus/goTo.js"); +Script.load("utilities/LODWarning.js"); //Script.load("scripts.js"); // Not created yet diff --git a/examples/utilities/LODWarning.js b/examples/utilities/LODWarning.js new file mode 100644 index 0000000000..644d98ebf4 --- /dev/null +++ b/examples/utilities/LODWarning.js @@ -0,0 +1,115 @@ +// LODWarning.js +// examples +// +// Created by Brad Hefta-Gaub on 3/17/15. +// Copyright 2015 High Fidelity, Inc. +// +// This script will display a warning when the LOD is adjusted to do scene complexity. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var DISPLAY_WARNING_FOR = 3; // in seconds +var DISTANCE_FROM_CAMERA = 2; +var SHOW_LOD_UP_MESSAGE = false; // By default we only display the LOD message when reducing LOD + + +var warningIsVisible = false; // initially the warning is hidden +var warningShownAt = 0; +var billboardPosition = Vec3.sum(Camera.getPosition(), + Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation()))); + +var warningOverlay = Overlays.addOverlay("text3d", { + position: billboardPosition, + dimensions: { x: 2, y: 1.25 }, + width: 2, + height: 1.25, + backgroundColor: { red: 0, green: 0, blue: 0 }, + color: { red: 255, green: 255, blue: 255}, + topMargin: 0.1, + leftMargin: 0.1, + lineHeight: 0.07, + text: "", + alpha: 0.5, + backgroundAlpha: 0.7, + isFacingAvatar: true, + visible: warningIsVisible, + }); + +// Handle moving the billboard to remain in front of the camera +var billboardNeedsMoving = false; +Script.update.connect(function() { + + if (warningIsVisible) { + var bestBillboardPosition = Vec3.sum(Camera.getPosition(), + Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation()))); + + var MAX_DISTANCE = 0.5; + var CLOSE_ENOUGH = 0.01; + if (!billboardNeedsMoving && Vec3.distance(bestBillboardPosition, billboardPosition) > MAX_DISTANCE) { + billboardNeedsMoving = true; + } + + if (billboardNeedsMoving && Vec3.distance(bestBillboardPosition, billboardPosition) <= CLOSE_ENOUGH) { + billboardNeedsMoving = false; + } + + if (billboardNeedsMoving) { + // slurp the billboard to the best location + moveVector = Vec3.multiply(0.05, Vec3.subtract(bestBillboardPosition, billboardPosition)); + billboardPosition = Vec3.sum(billboardPosition, moveVector); + Overlays.editOverlay(warningOverlay, { position: billboardPosition }); + } + + var now = new Date(); + var sinceWarningShown = now - warningShownAt; + if (sinceWarningShown > 1000 * DISPLAY_WARNING_FOR) { + warningIsVisible = false; + Overlays.editOverlay(warningOverlay, { visible: warningIsVisible }); + } + } +}); + +LODManager.LODIncreased.connect(function() { + if (SHOW_LOD_UP_MESSAGE) { + // if the warning wasn't visible, then move it before showing it. + if (!warningIsVisible) { + billboardPosition = Vec3.sum(Camera.getPosition(), + Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation()))); + Overlays.editOverlay(warningOverlay, { position: billboardPosition }); + } + + warningShownAt = new Date(); + warningIsVisible = true; + warningText = "Level of detail has been increased. \n" + + "You can now see: \n" + + LODManager.getLODFeedbackText(); + + Overlays.editOverlay(warningOverlay, { visible: warningIsVisible, text: warningText }); + } +}); + +LODManager.LODDecreased.connect(function() { + // if the warning wasn't visible, then move it before showing it. + if (!warningIsVisible) { + billboardPosition = Vec3.sum(Camera.getPosition(), + Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation()))); + Overlays.editOverlay(warningOverlay, { position: billboardPosition }); + } + + warningShownAt = new Date(); + warningIsVisible = true; + warningText = "\n" + + "Due to the complexity of the content, the \n" + + "level of detail has been decreased. \n" + + "You can now see: \n" + + LODManager.getLODFeedbackText(); + + Overlays.editOverlay(warningOverlay, { visible: warningIsVisible, text: warningText }); +}); + + +Script.scriptEnding.connect(function() { + Overlays.deleteOverlay(warningOverlay); +}); \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c95030ed79..55d453fde8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3561,6 +3561,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("UndoStack", &_undoStackScriptingInterface); + scriptEngine->registerGlobalObject("LODManager", DependencyManager::get().data()); + QScriptValue hmdInterface = scriptEngine->registerGlobalObject("HMD", &HMDScriptingInterface::getInstance()); scriptEngine->registerFunction(hmdInterface, "getHUDLookAtPosition2D", HMDScriptingInterface::getHUDLookAtPosition2D, 0); scriptEngine->registerFunction(hmdInterface, "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0); diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index c47b6180c7..063ba13492 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -75,7 +75,9 @@ void LODManager::autoAdjustLOD(float currentFPS) { changed = true; _lastAdjust = now; qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() - << "_octreeSizeScale=" << _octreeSizeScale; + << "_octreeSizeScale=" << _octreeSizeScale; + + emit LODDecreased(); } if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > ADJUST_LOD_UP_FPS @@ -87,7 +89,9 @@ void LODManager::autoAdjustLOD(float currentFPS) { changed = true; _lastAdjust = now; qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() - << "_octreeSizeScale=" << _octreeSizeScale; + << "_octreeSizeScale=" << _octreeSizeScale; + + emit LODIncreased(); } if (changed) { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index b67b9ebc97..61c24bf5af 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -21,13 +21,16 @@ const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; const float DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS = 30.0f; -const quint64 ADJUST_LOD_DOWN_DELAY = 1000 * 1000 * 5; +const quint64 ADJUST_LOD_DOWN_DELAY = 1000 * 1000 * 0.5; // Consider adjusting LOD down after half a second const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2; const float ADJUST_LOD_DOWN_BY = 0.9f; const float ADJUST_LOD_UP_BY = 1.1f; -const float ADJUST_LOD_MIN_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE * 0.25f; +// This controls how low the auto-adjust LOD will go a value of 1 means it will adjust to a point where you must be 0.25 +// meters away from an object of TREE_SCALE before you can see it (which is effectively completely blind). The default value +// DEFAULT_OCTREE_SIZE_SCALE means you can be 400 meters away from a 1 meter object in order to see it (which is ~20:20 vision). +const float ADJUST_LOD_MIN_SIZE_SCALE = 1.0f; const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f; @@ -38,7 +41,8 @@ const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; -class LODManager : public Dependency { +class LODManager : public QObject, public Dependency { + Q_OBJECT SINGLETON_DEPENDENCY public: @@ -52,21 +56,27 @@ public: float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; } // User Tweakable LOD Items - QString getLODFeedbackText(); - void setOctreeSizeScale(float sizeScale); - float getOctreeSizeScale() const { return _octreeSizeScale; } + Q_INVOKABLE QString getLODFeedbackText(); + Q_INVOKABLE void setOctreeSizeScale(float sizeScale); + Q_INVOKABLE float getOctreeSizeScale() const { return _octreeSizeScale; } - void setBoundaryLevelAdjust(int boundaryLevelAdjust); - int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } + Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust); + Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } void autoAdjustLOD(float currentFPS); - void resetLODAdjust(); + Q_INVOKABLE void resetLODAdjust(); + Q_INVOKABLE float getFPSAverage() const { return _fpsAverage.getAverage(); } + Q_INVOKABLE float getFastFPSAverage() const { return _fastFPSAverage.getAverage(); } bool shouldRenderMesh(float largestDimension, float distanceToCamera); void loadSettings(); void saveSettings(); +signals: + void LODIncreased(); + void LODDecreased(); + private: LODManager() {} diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7e57323d68..210fa70b65 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -303,7 +303,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { _points << mesh.vertices; } - info.setParams(getShapeType(), 0.5f * getDimensions(), NULL, _collisionModelURL); + info.setParams(getShapeType(), 0.5f * getDimensions(), _collisionModelURL); info.setConvexHull(_points); } } diff --git a/libraries/octree/src/OctreeConstants.h b/libraries/octree/src/OctreeConstants.h index 9300ff98c0..a975469053 100644 --- a/libraries/octree/src/OctreeConstants.h +++ b/libraries/octree/src/OctreeConstants.h @@ -21,6 +21,8 @@ const int TREE_SCALE = 16384; // ~10 miles.. This is the number of meters of t // This controls the LOD. Larger number will make smaller voxels visible at greater distance. const float DEFAULT_OCTREE_SIZE_SCALE = TREE_SCALE * 400.0f; + +// This is used in the LOD Tools to translate between the size scale slider and the values used to set the OctreeSizeScale const float MAX_LOD_SIZE_MULTIPLIER = 2000.0f; const int NUMBER_OF_CHILDREN = 8; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index c7b3d60e41..8ae85ba67a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -63,7 +63,6 @@ void PhysicsEngine::addEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { - qDebug() << "PhysicsEngine::addEntityInternal(" << entity; if (entity->isReadyToComputeShape()) { ShapeInfo shapeInfo; entity->computeShapeInfo(shapeInfo); @@ -343,7 +342,6 @@ void PhysicsEngine::stepSimulation() { } unlock(); - _avatarData->unlock(); _entityTree->unlock(); computeCollisionEvents(); @@ -506,10 +504,8 @@ void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { btRigidBody* body = motionState->getRigidBody(); if (body) { const btCollisionShape* shape = body->getCollisionShape(); - ShapeInfo shapeInfo; - ShapeInfoUtil::collectInfoFromShape(shape, shapeInfo); _dynamicsWorld->removeRigidBody(body); - _shapeManager.releaseShape(shapeInfo); + _shapeManager.releaseShape(shape); // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. motionState->setRigidBody(NULL); delete body; diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index d92decad2a..61432830e7 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -19,10 +19,9 @@ void ShapeInfo::clear() { _type = SHAPE_TYPE_NONE; _halfExtents = glm::vec3(0.0f); _doubleHashKey.clear(); - _externalData = NULL; } -void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QVector* data, QString url) { +void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) { _type = type; switch(type) { case SHAPE_TYPE_NONE: @@ -45,7 +44,6 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QVector< _halfExtents = halfExtents; break; } - _externalData = data; } void ShapeInfo::setBox(const glm::vec3& halfExtents) { @@ -109,91 +107,53 @@ float ShapeInfo::computeVolume() const { } const DoubleHashKey& ShapeInfo::getHash() const { - // NOTE: we cache the hash so we only ever need to compute it once for any valid ShapeInfo instance. + // 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) { - // cast this to non-const pointer so we can do our dirty work + // 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(this); + DoubleHashKey& key = thisPtr->_doubleHashKey; + // compute hash1 // TODO?: provide lookup table for hash/hash2 of _type rather than recompute? uint32_t primeIndex = 0; - thisPtr->_doubleHashKey.computeHash((uint32_t)_type, primeIndex++); + key.computeHash((uint32_t)_type, primeIndex++); - const QVector* data = getData(); - if (data) { - // if externalData exists we use it to continue the hash - - // compute hash - uint32_t hash = _doubleHashKey.getHash(); + // 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() + uint32_t floatHash = + DoubleHashKey::hashFunction((uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f), primeIndex++); + hash ^= floatHash; + } + key.setHash(hash); - glm::vec3 tmpData; - int numData = data->size(); - for (int i = 0; i < numData; ++i) { - tmpData = (*data)[i]; - 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() - uint32_t floatHash = - DoubleHashKey::hashFunction((uint32_t)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f), primeIndex++); - hash ^= floatHash; - } - } - thisPtr->_doubleHashKey.setHash(hash); - - // compute hash2 + // compute hash2 + hash = key.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() + uint32_t floatHash = + DoubleHashKey::hashFunction2((uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f)); + hash += ~(floatHash << 17); + hash ^= (floatHash >> 11); + hash += (floatHash << 4); + hash ^= (floatHash >> 7); + hash += ~(floatHash << 10); + hash = (hash << 16) | (hash >> 16); + } + key.setHash2(hash); - QString url = _url.toString(); - - if (url == "") { - hash = _doubleHashKey.getHash2(); - for (int i = 0; i < numData; ++i) { - tmpData = (*data)[i]; - 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() - uint32_t floatHash = - DoubleHashKey::hashFunction2((uint32_t)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f)); - hash += ~(floatHash << 17); - hash ^= (floatHash >> 11); - hash += (floatHash << 4); - hash ^= (floatHash >> 7); - hash += ~(floatHash << 10); - hash = (hash << 16) | (hash >> 16); - } - } - } else { - QByteArray baUrl = url.toLocal8Bit(); - const char *cUrl = baUrl.data(); - hash = qChecksum(cUrl, baUrl.count()); - } - thisPtr->_doubleHashKey.setHash2(hash); - } else { - // this shape info has no external data so type+extents should be enough to generate a unique hash - // compute hash1 - 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() - uint32_t floatHash = - DoubleHashKey::hashFunction((uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f), primeIndex++); - hash ^= floatHash; - } - thisPtr->_doubleHashKey.setHash(hash); - - // compute hash2 - 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() - uint32_t floatHash = - DoubleHashKey::hashFunction2((uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f)); - hash += ~(floatHash << 17); - hash ^= (floatHash >> 11); - hash += (floatHash << 4); - hash ^= (floatHash >> 7); - hash += ~(floatHash << 10); - hash = (hash << 16) | (hash >> 16); - } - thisPtr->_doubleHashKey.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); } } return _doubleHashKey; diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index ff0b5ca8ff..0a55f7c51d 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -40,7 +40,7 @@ class ShapeInfo { public: void clear(); - void setParams(ShapeType type, const glm::vec3& halfExtents, QVector* data = NULL, QString url=""); + void setParams(ShapeType type, const glm::vec3& halfExtents, QString url=""); void setBox(const glm::vec3& halfExtents); void setSphere(float radius); void setEllipsoid(const glm::vec3& halfExtents); @@ -51,9 +51,6 @@ public: const glm::vec3& getHalfExtents() const { return _halfExtents; } - void setData(const QVector* data) { _externalData = data; } - const QVector* getData() const { return _externalData; } - const QVector& getPoints() const { return _points; } void clearPoints () { _points.clear(); } @@ -67,7 +64,6 @@ protected: ShapeType _type = SHAPE_TYPE_NONE; glm::vec3 _halfExtents = glm::vec3(0.0f); DoubleHashKey _doubleHashKey; - const QVector* _externalData = NULL; QVector _points; // points for convex collision hull QUrl _url; // url for model of convex collision hull };