From 59971869f51af504bbc002c0c051bd0e03c8400c Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 10 Apr 2018 19:06:27 -0700 Subject: [PATCH 01/30] desktop equip --- .../controllerModules/equipEntity.js | 117 +++++++++++++++++- scripts/system/controllers/grab.js | 2 +- 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 252f6efa9e..33091696f3 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -21,6 +21,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var DEFAULT_SPHERE_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/equip-Fresnel-3.fbx"; var EQUIP_SPHERE_SCALE_FACTOR = 0.65; +var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}"; // Each overlayInfoSet describes a single equip hotspot. @@ -176,6 +177,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var TRIGGER_OFF_VALUE = 0.1; var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab var BUMPER_ON_VALUE = 0.5; + + var UNEQUIP_KEY = "u"; function getWearableData(props) { @@ -270,6 +273,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.shouldSendStart = false; this.equipedWithSecondary = false; this.handHasBeenRightsideUp = false; + this.mouseEquip = false; + this.mouseEquipAnimationHandler; this.parameters = makeDispatcherModuleParameters( 300, @@ -279,10 +284,11 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var equipHotspotBuddy = new EquipHotspotBuddy(); - this.setMessageGrabData = function(entityProperties) { + this.setMessageGrabData = function(entityProperties, mouseEquip) { if (entityProperties) { this.messageGrabEntity = true; this.grabEntityProps = entityProperties; + this.mouseEquip = mouseEquip; } }; @@ -552,6 +558,15 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa // 100 ms seems to be sufficient time to force the check even occur after the object has been initialized. Script.setTimeout(grabEquipCheck, 100); } + + if (this.mouseEquip) { + this.removeMouseEquipAnimation(); + if (this.hand === RIGHT_HAND) { + this.mouseEquipAnimationHandler = MyAvatar.addAnimationStateHandler(this.rightHandMouseEquipAnimation, []); + } else { + this.mouseEquipAnimationHandler = MyAvatar.addAnimationStateHandler(this.leftHandMouseEquipAnimation, []); + } + } }; this.endEquipEntity = function () { @@ -574,6 +589,11 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.targetEntityID = null; this.messageGrabEntity = false; this.grabEntityProps = null; + + if (this.mouseEquip) { + this.removeMouseEquipAnimation(); + this.mouseEquip = false; + } }; this.updateInputs = function (controllerData) { @@ -650,7 +670,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var timestamp = Date.now(); this.updateInputs(controllerData); - if (!this.isTargetIDValid(controllerData)) { + if (!this.mouseEquip && !this.isTargetIDValid(controllerData)) { this.endEquipEntity(); return makeRunningValues(false, [], []); } @@ -740,6 +760,40 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.endEquipEntity(); } }; + + this.removeMouseEquipAnimation = function() { + if (this.mouseEquipAnimationHandler) { + this.mouseEquipAnimationHandler = MyAvatar.removeAnimationStateHandler(this.mouseEquipAnimationHandler); + } + }; + + this.leftHandMouseEquipAnimation = function() { + var result = {}; + var leftHandPosition = MyAvatar.getJointPosition("LeftHand"); + var leftShoulderPosition = MyAvatar.getJointPosition("LeftShoulder"); + var cameraToLeftShoulder = Vec3.subtract(leftShoulderPosition, Camera.position); + var cameraToLeftShoulderNormalized = Vec3.normalize(cameraToLeftShoulder); + var leftHandPositionNew = Vec3.sum(leftShoulderPosition, cameraToLeftShoulderNormalized); + var leftHandPositionNewAvatarFrame = Vec3.subtract(leftHandPositionNew, MyAvatar.position); + result.leftHandType = 1; + result.leftHandPosition = leftHandPositionNewAvatarFrame; + result.leftHandRotation = Quat.multiply(Quat.lookAtSimple(leftHandPositionNew, Camera.position), Quat.fromPitchYawRollDegrees(90, 0, -90)); + return result; + }; + + this.rightHandMouseEquipAnimation = function() { + var result = {}; + var rightHandPosition = MyAvatar.getJointPosition("RightHand"); + var rightShoulderPosition = MyAvatar.getJointPosition("RightShoulder"); + var cameraToRightShoulder = Vec3.subtract(rightShoulderPosition, Camera.position); + var cameraToRightShoulderNormalized = Vec3.normalize(cameraToRightShoulder); + var rightHandPositionNew = Vec3.sum(rightShoulderPosition, cameraToRightShoulderNormalized); + var rightHandPositionNewAvatarFrame = Vec3.subtract(rightHandPositionNew, MyAvatar.position); + result.rightHandType = 1; + result.rightHandPosition = rightHandPositionNewAvatarFrame; + result.rightHandRotation = Quat.multiply(Quat.lookAtSimple(rightHandPositionNew, Camera.position), Quat.fromPitchYawRollDegrees(90, 0, 90)); + return result; + }; } var handleMessage = function(channel, message, sender) { @@ -751,7 +805,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var equipModule = (data.hand === "left") ? leftEquipEntity : rightEquipEntity; var entityProperties = Entities.getEntityProperties(data.entityID, DISPATCHER_PROPERTIES); entityProperties.id = data.entityID; - equipModule.setMessageGrabData(entityProperties); + var mouseEquip = false; + equipModule.setMessageGrabData(entityProperties, mouseEquip); } catch (e) { print("WARNING: equipEntity.js -- error parsing Hifi-Hand-Grab message: " + message); @@ -768,10 +823,63 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa } } }; + + var clearGrabActions = function(entityID) { + var actionIDs = Entities.getActionIDs(entityID); + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments.tag; + if (tag.slice(0, 5) == "grab-") { + Entities.deleteAction(entityID, actionID); + } + } + }; + + var onMousePress = function(event) { + if (isInEditMode()) { // ignore any mouse clicks on the entity while create/edit is open + return; + } + var pickRay = Camera.computePickRay(event.x, event.y); + var intersection = Entities.findRayIntersection(pickRay, true); + if (intersection.intersects) { + var entityProperties = Entities.getEntityProperties(intersection.entityID, DISPATCHER_PROPERTIES); + if (entityProperties.parentID === EMPTY_PARENT_ID) { + entityProperties.id = intersection.entityID; + var rightHandPosition = MyAvatar.getJointPosition("RightHand"); + var leftHandPosition = MyAvatar.getJointPosition("LeftHand"); + var distanceToRightHand = Vec3.distance(entityProperties.position, rightHandPosition); + var distanceToLeftHand = Vec3.distance(entityProperties.position, leftHandPosition); + var leftHandAvailable = leftEquipEntity.targetEntityID === null; + var rightHandAvailable = rightEquipEntity.targetEntityID === null; + var mouseEquip = true; + if (rightHandAvailable && (distanceToRightHand < distanceToLeftHand || !leftHandAvailable)) { + clearGrabActions(intersection.entityID); + rightEquipEntity.setMessageGrabData(entityProperties, mouseEquip); + } else if (leftHandAvailable && (distanceToLeftHand < distanceToRightHand || !rightHandAvailable)) { + clearGrabActions(intersection.entityID); + leftEquipEntity.setMessageGrabData(entityProperties, mouseEquip); + } + } + } + }; + + var onKeyPress = function(event) { + if (event.text === UNEQUIP_KEY) { + if (rightEquipEntity.mouseEquip) { + rightEquipEntity.endEquipEntity(); + } + if (leftEquipEntity.mouseEquip) { + leftEquipEntity.endEquipEntity(); + } + } + }; Messages.subscribe('Hifi-Hand-Grab'); Messages.subscribe('Hifi-Hand-Drop'); Messages.messageReceived.connect(handleMessage); + Controller.mousePressEvent.connect(onMousePress); + Controller.keyPressEvent.connect(onKeyPress); var leftEquipEntity = new EquipEntity(LEFT_HAND); var rightEquipEntity = new EquipEntity(RIGHT_HAND); @@ -785,6 +893,9 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa disableDispatcherModule("LeftEquipEntity"); disableDispatcherModule("RightEquipEntity"); clearAttachPoints(); + Messages.messageReceived.disconnect(handleMessage); + Controller.mousePressEvent.disconnect(onMousePress); + Controller.keyPressEvent.disconnect(onKeyPress); } Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 1171703847..b32c64d189 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -567,7 +567,7 @@ Grabber.prototype.moveEventProcess = function() { } if (!this.actionID) { - if (!entityIsGrabbedByOther(this.entityID)) { + if (!entityIsGrabbedByOther(this.entityID) ) && Entities.getEntityProperties(this.entityID, ['parentID']).parentID !== MyAvatar.SELF_ID) { this.actionID = Entities.addAction("far-grab", this.entityID, actionArgs); } } else { From 243b3637c4a702ed6b0a5669547fef65da42a4df Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 12 Apr 2018 12:41:36 -0700 Subject: [PATCH 02/30] fix grab.js change --- scripts/system/controllers/grab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index b32c64d189..4af2d97a8f 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -567,7 +567,7 @@ Grabber.prototype.moveEventProcess = function() { } if (!this.actionID) { - if (!entityIsGrabbedByOther(this.entityID) ) && Entities.getEntityProperties(this.entityID, ['parentID']).parentID !== MyAvatar.SELF_ID) { + if (!entityIsGrabbedByOther(this.entityID) && Entities.getEntityProperties(this.entityID, ['parentID']).parentID !== MyAvatar.SELF_ID) { this.actionID = Entities.addAction("far-grab", this.entityID, actionArgs); } } else { From 9f3a431c5d67e64411ac92b19fd59649142fbc21 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 12 Apr 2018 14:12:52 -0700 Subject: [PATCH 03/30] minimum entity dimension --- libraries/entities/src/EntityItem.cpp | 3 ++- libraries/render-utils/src/Model.cpp | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index fe88f21a23..91ad581b32 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1688,7 +1688,8 @@ void EntityItem::setScaledDimensions(const glm::vec3& value) { } void EntityItem::setUnscaledDimensions(const glm::vec3& value) { - glm::vec3 newDimensions = glm::max(value, glm::vec3(0.0f)); // can never have negative dimensions + const float MIN_ENTITY_DIMENSION = 0.01f; // this value cubed should == MIN_VOLUME in setMass + glm::vec3 newDimensions = glm::max(value, glm::vec3(MIN_ENTITY_DIMENSION)); if (getUnscaledDimensions() != newDimensions) { withWriteLock([&] { _unscaledDimensions = newDimensions; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 70f873734a..65b12ac0d4 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -182,9 +182,7 @@ const float SCALE_CHANGE_EPSILON = 0.0000001f; void Model::setScaleInternal(const glm::vec3& scale) { if (glm::distance(_scale, scale) > SCALE_CHANGE_EPSILON) { _scale = scale; - if (_scale.x == 0.0f || _scale.y == 0.0f || _scale.z == 0.0f) { - assert(false); - } + assert(_scale.x != 0.0f && scale.y != 0.0f && scale.z != 0.0f); simulate(0.0f, true); } } From b71a06a18ed75c0c6ba3e43d0e71069e3029f748 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 13 Apr 2018 15:26:37 -0700 Subject: [PATCH 04/30] min dim = 1 mm --- libraries/entities/src/EntityItem.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f50235e776..2034cb9a73 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -942,9 +942,9 @@ void EntityItem::setMass(float mass) { float volume = _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z; // compute new density - const float MIN_VOLUME = 1.0e-6f; // 0.001mm^3 + const float MIN_VOLUME = 1.0e-9f; // 1mm^3 float newDensity = 1.0f; - if (volume < 1.0e-6f) { + if (volume < MIN_VOLUME) { // avoid divide by zero newDensity = glm::min(mass / MIN_VOLUME, ENTITY_ITEM_MAX_DENSITY); } else { @@ -1688,7 +1688,7 @@ void EntityItem::setScaledDimensions(const glm::vec3& value) { } void EntityItem::setUnscaledDimensions(const glm::vec3& value) { - const float MIN_ENTITY_DIMENSION = 0.01f; // this value cubed should == MIN_VOLUME in setMass + const float MIN_ENTITY_DIMENSION = 0.001f; // this value cubed should == MIN_VOLUME in setMass glm::vec3 newDimensions = glm::max(value, glm::vec3(MIN_ENTITY_DIMENSION)); if (getUnscaledDimensions() != newDimensions) { withWriteLock([&] { From 78c0ec57700b41fc24594a748e03b0bd9c98df3c Mon Sep 17 00:00:00 2001 From: David Back Date: Mon, 16 Apr 2018 12:56:22 -0700 Subject: [PATCH 05/30] remove animations --- .../controllerModules/equipEntity.js | 60 ++----------------- 1 file changed, 5 insertions(+), 55 deletions(-) diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 33091696f3..7b9640047c 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -22,6 +22,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var DEFAULT_SPHERE_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/equip-Fresnel-3.fbx"; var EQUIP_SPHERE_SCALE_FACTOR = 0.65; var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}"; +var UNEQUIP_KEY = "u"; // Each overlayInfoSet describes a single equip hotspot. @@ -176,10 +177,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing var TRIGGER_OFF_VALUE = 0.1; var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab - var BUMPER_ON_VALUE = 0.5; - - var UNEQUIP_KEY = "u"; - + var BUMPER_ON_VALUE = 0.5 + function getWearableData(props) { var wearable = {}; @@ -274,7 +273,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.equipedWithSecondary = false; this.handHasBeenRightsideUp = false; this.mouseEquip = false; - this.mouseEquipAnimationHandler; this.parameters = makeDispatcherModuleParameters( 300, @@ -558,15 +556,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa // 100 ms seems to be sufficient time to force the check even occur after the object has been initialized. Script.setTimeout(grabEquipCheck, 100); } - - if (this.mouseEquip) { - this.removeMouseEquipAnimation(); - if (this.hand === RIGHT_HAND) { - this.mouseEquipAnimationHandler = MyAvatar.addAnimationStateHandler(this.rightHandMouseEquipAnimation, []); - } else { - this.mouseEquipAnimationHandler = MyAvatar.addAnimationStateHandler(this.leftHandMouseEquipAnimation, []); - } - } }; this.endEquipEntity = function () { @@ -575,7 +564,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa parentID: Uuid.NULL, parentJointIndex: -1 }); - +; var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "releaseEquip", args); @@ -589,11 +578,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.targetEntityID = null; this.messageGrabEntity = false; this.grabEntityProps = null; - - if (this.mouseEquip) { - this.removeMouseEquipAnimation(); - this.mouseEquip = false; - } }; this.updateInputs = function (controllerData) { @@ -760,40 +744,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.endEquipEntity(); } }; - - this.removeMouseEquipAnimation = function() { - if (this.mouseEquipAnimationHandler) { - this.mouseEquipAnimationHandler = MyAvatar.removeAnimationStateHandler(this.mouseEquipAnimationHandler); - } - }; - - this.leftHandMouseEquipAnimation = function() { - var result = {}; - var leftHandPosition = MyAvatar.getJointPosition("LeftHand"); - var leftShoulderPosition = MyAvatar.getJointPosition("LeftShoulder"); - var cameraToLeftShoulder = Vec3.subtract(leftShoulderPosition, Camera.position); - var cameraToLeftShoulderNormalized = Vec3.normalize(cameraToLeftShoulder); - var leftHandPositionNew = Vec3.sum(leftShoulderPosition, cameraToLeftShoulderNormalized); - var leftHandPositionNewAvatarFrame = Vec3.subtract(leftHandPositionNew, MyAvatar.position); - result.leftHandType = 1; - result.leftHandPosition = leftHandPositionNewAvatarFrame; - result.leftHandRotation = Quat.multiply(Quat.lookAtSimple(leftHandPositionNew, Camera.position), Quat.fromPitchYawRollDegrees(90, 0, -90)); - return result; - }; - - this.rightHandMouseEquipAnimation = function() { - var result = {}; - var rightHandPosition = MyAvatar.getJointPosition("RightHand"); - var rightShoulderPosition = MyAvatar.getJointPosition("RightShoulder"); - var cameraToRightShoulder = Vec3.subtract(rightShoulderPosition, Camera.position); - var cameraToRightShoulderNormalized = Vec3.normalize(cameraToRightShoulder); - var rightHandPositionNew = Vec3.sum(rightShoulderPosition, cameraToRightShoulderNormalized); - var rightHandPositionNewAvatarFrame = Vec3.subtract(rightHandPositionNew, MyAvatar.position); - result.rightHandType = 1; - result.rightHandPosition = rightHandPositionNewAvatarFrame; - result.rightHandRotation = Quat.multiply(Quat.lookAtSimple(rightHandPositionNew, Camera.position), Quat.fromPitchYawRollDegrees(90, 0, 90)); - return result; - }; } var handleMessage = function(channel, message, sender) { @@ -874,7 +824,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa } } }; - + Messages.subscribe('Hifi-Hand-Grab'); Messages.subscribe('Hifi-Hand-Drop'); Messages.messageReceived.connect(handleMessage); From ad85e2b053bdbdcaf53a73aa39a6bb3b2c2d7514 Mon Sep 17 00:00:00 2001 From: David Back Date: Mon, 16 Apr 2018 13:12:33 -0700 Subject: [PATCH 06/30] pre PR adjustments --- .../controllerModules/equipEntity.js | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 7b9640047c..ccd0c750df 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -21,8 +21,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var DEFAULT_SPHERE_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/equip-Fresnel-3.fbx"; var EQUIP_SPHERE_SCALE_FACTOR = 0.65; -var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}"; -var UNEQUIP_KEY = "u"; // Each overlayInfoSet describes a single equip hotspot. @@ -177,9 +175,13 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing var TRIGGER_OFF_VALUE = 0.1; var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab - var BUMPER_ON_VALUE = 0.5 - + var BUMPER_ON_VALUE = 0.5; + + var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}"; + + var UNEQUIP_KEY = "u"; + function getWearableData(props) { var wearable = {}; try { @@ -564,7 +566,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa parentID: Uuid.NULL, parentJointIndex: -1 }); -; + var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "releaseEquip", args); @@ -780,14 +782,14 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var actionID = actionIDs[actionIndex]; var actionArguments = Entities.getActionArguments(entityID, actionID); var tag = actionArguments.tag; - if (tag.slice(0, 5) == "grab-") { + if (tag.slice(0, 5) === "grab-") { Entities.deleteAction(entityID, actionID); } } }; var onMousePress = function(event) { - if (isInEditMode()) { // ignore any mouse clicks on the entity while create/edit is open + if (isInEditMode()) { // don't consider any mouse clicks on the entity while in edit return; } var pickRay = Camera.computePickRay(event.x, event.y); @@ -804,9 +806,11 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var rightHandAvailable = rightEquipEntity.targetEntityID === null; var mouseEquip = true; if (rightHandAvailable && (distanceToRightHand < distanceToLeftHand || !leftHandAvailable)) { + // clear any existing grab actions on the entity now (their later removal could affect bootstrapping flags) clearGrabActions(intersection.entityID); rightEquipEntity.setMessageGrabData(entityProperties, mouseEquip); - } else if (leftHandAvailable && (distanceToLeftHand < distanceToRightHand || !rightHandAvailable)) { + } else if (leftHandAvailable && (distanceToLeftHand < distanceToRightHand || !rightHandAvailable)) + // clear any existing grab actions on the entity now (their later removal could affect bootstrapping flags) clearGrabActions(intersection.entityID); leftEquipEntity.setMessageGrabData(entityProperties, mouseEquip); } @@ -824,7 +828,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa } } }; - + Messages.subscribe('Hifi-Hand-Grab'); Messages.subscribe('Hifi-Hand-Drop'); Messages.messageReceived.connect(handleMessage); From e86ef1c2d6781b4a97a3a5a224c134767611b518 Mon Sep 17 00:00:00 2001 From: David Back Date: Mon, 16 Apr 2018 13:33:17 -0700 Subject: [PATCH 07/30] fix bracket --- scripts/system/controllers/controllerModules/equipEntity.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index ccd0c750df..00fc1e581a 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -181,7 +181,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var UNEQUIP_KEY = "u"; - function getWearableData(props) { var wearable = {}; try { @@ -809,7 +808,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa // clear any existing grab actions on the entity now (their later removal could affect bootstrapping flags) clearGrabActions(intersection.entityID); rightEquipEntity.setMessageGrabData(entityProperties, mouseEquip); - } else if (leftHandAvailable && (distanceToLeftHand < distanceToRightHand || !rightHandAvailable)) + } else if (leftHandAvailable && (distanceToLeftHand < distanceToRightHand || !rightHandAvailable)) { // clear any existing grab actions on the entity now (their later removal could affect bootstrapping flags) clearGrabActions(intersection.entityID); leftEquipEntity.setMessageGrabData(entityProperties, mouseEquip); From 527d71c379b560d1dfe1a4865f5a42257ed80b19 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 17 Apr 2018 10:58:54 -0700 Subject: [PATCH 08/30] CR --- libraries/entities/src/EntityItem.cpp | 8 +++----- libraries/entities/src/EntityItemPropertiesDefaults.h | 2 ++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 2034cb9a73..585b0b63eb 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -942,11 +942,10 @@ void EntityItem::setMass(float mass) { float volume = _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z; // compute new density - const float MIN_VOLUME = 1.0e-9f; // 1mm^3 float newDensity = 1.0f; - if (volume < MIN_VOLUME) { + if (volume < ENTITY_ITEM_MIN_VOLUME) { // avoid divide by zero - newDensity = glm::min(mass / MIN_VOLUME, ENTITY_ITEM_MAX_DENSITY); + newDensity = glm::min(mass / ENTITY_ITEM_MIN_VOLUME, ENTITY_ITEM_MAX_DENSITY); } else { newDensity = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); } @@ -1688,8 +1687,7 @@ void EntityItem::setScaledDimensions(const glm::vec3& value) { } void EntityItem::setUnscaledDimensions(const glm::vec3& value) { - const float MIN_ENTITY_DIMENSION = 0.001f; // this value cubed should == MIN_VOLUME in setMass - glm::vec3 newDimensions = glm::max(value, glm::vec3(MIN_ENTITY_DIMENSION)); + glm::vec3 newDimensions = glm::max(value, glm::vec3(ENTITY_ITEM_MIN_DIMENSION)); if (getUnscaledDimensions() != newDimensions) { withWriteLock([&] { _unscaledDimensions = newDimensions; diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 0e0c2994cd..d2ddd687dd 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -60,8 +60,10 @@ const float ENTITY_ITEM_DEFAULT_LIFETIME = ENTITY_ITEM_IMMORTAL_LIFETIME; const glm::vec3 ENTITY_ITEM_DEFAULT_POSITION = ENTITY_ITEM_ZERO_VEC3; const glm::quat ENTITY_ITEM_DEFAULT_ROTATION; const float ENTITY_ITEM_DEFAULT_WIDTH = 0.1f; +const float ENTITY_ITEM_MIN_DIMENSION = 0.001f; const glm::vec3 ENTITY_ITEM_DEFAULT_DIMENSIONS = glm::vec3(ENTITY_ITEM_DEFAULT_WIDTH); const float ENTITY_ITEM_DEFAULT_VOLUME = ENTITY_ITEM_DEFAULT_WIDTH * ENTITY_ITEM_DEFAULT_WIDTH * ENTITY_ITEM_DEFAULT_WIDTH; +const float ENTITY_ITEM_MIN_VOLUME = ENTITY_ITEM_MIN_DIMENSION * ENTITY_ITEM_MIN_DIMENSION * ENTITY_ITEM_MIN_DIMENSION; const float ENTITY_ITEM_MAX_DENSITY = 10000.0f; // kg/m^3 density of silver const float ENTITY_ITEM_MIN_DENSITY = 100.0f; // kg/m^3 density of balsa wood From 9e4914975b801d9d5a263c8553f9cba1c72bf1dd Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 17 Apr 2018 16:13:10 -0700 Subject: [PATCH 09/30] missing reset flag on end equip, remove mouseEquip check on unequip via U --- .../system/controllers/controllerModules/equipEntity.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 00fc1e581a..4e960c37f1 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -579,6 +579,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.targetEntityID = null; this.messageGrabEntity = false; this.grabEntityProps = null; + this.mouseEquip = false; }; this.updateInputs = function (controllerData) { @@ -796,7 +797,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa if (intersection.intersects) { var entityProperties = Entities.getEntityProperties(intersection.entityID, DISPATCHER_PROPERTIES); if (entityProperties.parentID === EMPTY_PARENT_ID) { - entityProperties.id = intersection.entityID; + entityProperties.id = intersection.entityID; var rightHandPosition = MyAvatar.getJointPosition("RightHand"); var leftHandPosition = MyAvatar.getJointPosition("LeftHand"); var distanceToRightHand = Vec3.distance(entityProperties.position, rightHandPosition); @@ -819,10 +820,10 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var onKeyPress = function(event) { if (event.text === UNEQUIP_KEY) { - if (rightEquipEntity.mouseEquip) { + if (rightEquipEntity.targetEntityID) { rightEquipEntity.endEquipEntity(); } - if (leftEquipEntity.mouseEquip) { + if (leftEquipEntity.targetEntityID) { leftEquipEntity.endEquipEntity(); } } From 278a6b763fb03e9950b5704cf3fd4748d767b1a2 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 17 Apr 2018 16:26:33 -0700 Subject: [PATCH 10/30] ensure target mouse entity has equip data --- scripts/system/controllers/controllerModules/equipEntity.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 4e960c37f1..6406b8593f 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -796,7 +796,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects) { var entityProperties = Entities.getEntityProperties(intersection.entityID, DISPATCHER_PROPERTIES); - if (entityProperties.parentID === EMPTY_PARENT_ID) { + var hasEquipData = getWearableData(entityProperties).joints || getEquipHotspotsData(entityProperties).length > 0; + if (hasEquipData && entityProperties.parentID === EMPTY_PARENT_ID) { entityProperties.id = intersection.entityID; var rightHandPosition = MyAvatar.getJointPosition("RightHand"); var leftHandPosition = MyAvatar.getJointPosition("LeftHand"); From 4a37c4ba18450221a7151a87a176fc6c575c184d Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 18 Apr 2018 15:00:10 -0700 Subject: [PATCH 11/30] add entityIsEquipped utils for grab.js check --- scripts/system/controllers/grab.js | 2 +- scripts/system/libraries/controllerDispatcherUtils.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 0ebe5cf86f..0f8cc72e64 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -568,7 +568,7 @@ Grabber.prototype.moveEventProcess = function() { } if (!this.actionID) { - if (!entityIsGrabbedByOther(this.entityID) && Entities.getEntityProperties(this.entityID, ['parentID']).parentID !== MyAvatar.SELF_ID) { + if (!entityIsGrabbedByOther(this.entityID) && !entityIsEquipped(this.entityID)) { this.actionID = Entities.addAction("far-grab", this.entityID, actionArgs); } } else { diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index 75e1d6668b..41b4458bc5 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -384,6 +384,14 @@ distanceBetweenPointAndEntityBoundingBox = function(point, entityProps) { return Vec3.distance(v, localPoint); }; +entityIsEquipped = function(entityID) { + var rightEquipEntity = getEnabledModuleByName("RightEquipEntity"); + var leftEquipEntity = getEnabledModuleByName("LeftEquipEntity"); + var equippedInRightHand = rightEquipEntity ? rightEquipEntity.targetEntityID === entityID : false; + var equippedInLeftHand = leftEquipEntity ? leftEquipEntity.targetEntityID === entityID : false; + return equippedInRightHand || equippedInLeftHand; +}; + if (typeof module !== 'undefined') { module.exports = { makeDispatcherModuleParameters: makeDispatcherModuleParameters, From 666653dd96e5db9f1ccd25c9c1b15d230453418d Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 18 Apr 2018 15:01:14 -0700 Subject: [PATCH 12/30] tabs --- scripts/system/libraries/controllerDispatcherUtils.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index 41b4458bc5..61b54ca156 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -385,11 +385,11 @@ distanceBetweenPointAndEntityBoundingBox = function(point, entityProps) { }; entityIsEquipped = function(entityID) { - var rightEquipEntity = getEnabledModuleByName("RightEquipEntity"); - var leftEquipEntity = getEnabledModuleByName("LeftEquipEntity"); - var equippedInRightHand = rightEquipEntity ? rightEquipEntity.targetEntityID === entityID : false; - var equippedInLeftHand = leftEquipEntity ? leftEquipEntity.targetEntityID === entityID : false; - return equippedInRightHand || equippedInLeftHand; + var rightEquipEntity = getEnabledModuleByName("RightEquipEntity"); + var leftEquipEntity = getEnabledModuleByName("LeftEquipEntity"); + var equippedInRightHand = rightEquipEntity ? rightEquipEntity.targetEntityID === entityID : false; + var equippedInLeftHand = leftEquipEntity ? leftEquipEntity.targetEntityID === entityID : false; + return equippedInRightHand || equippedInLeftHand; }; if (typeof module !== 'undefined') { From bf21a4cf563921a237506550dc3b917a9f519627 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 18 Apr 2018 15:05:29 -0700 Subject: [PATCH 13/30] tabs --- scripts/system/controllers/controllerModules/equipEntity.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 6406b8593f..5807465abb 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -579,7 +579,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.targetEntityID = null; this.messageGrabEntity = false; this.grabEntityProps = null; - this.mouseEquip = false; + this.mouseEquip = false; }; this.updateInputs = function (controllerData) { @@ -796,7 +796,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects) { var entityProperties = Entities.getEntityProperties(intersection.entityID, DISPATCHER_PROPERTIES); - var hasEquipData = getWearableData(entityProperties).joints || getEquipHotspotsData(entityProperties).length > 0; + var hasEquipData = getWearableData(entityProperties).joints || getEquipHotspotsData(entityProperties).length > 0; if (hasEquipData && entityProperties.parentID === EMPTY_PARENT_ID) { entityProperties.id = intersection.entityID; var rightHandPosition = MyAvatar.getJointPosition("RightHand"); From 8cbe0f463330182a0ed322423988feaef64e879e Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 19 Apr 2018 11:17:26 -0700 Subject: [PATCH 14/30] safer clear grab actions --- scripts/system/controllers/controllerModules/equipEntity.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 67fe9068b6..7532ca07c3 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -784,11 +784,12 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var clearGrabActions = function(entityID) { var actionIDs = Entities.getActionIDs(entityID); + var myGrabTag = "grab-" + MyAvatar.sessionUUID; for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { var actionID = actionIDs[actionIndex]; var actionArguments = Entities.getActionArguments(entityID, actionID); var tag = actionArguments.tag; - if (tag.slice(0, 5) === "grab-") { + if (tag === myGrabTag) { Entities.deleteAction(entityID, actionID); } } From 663af09605c57c7ebf7994879b1c3972c138d599 Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 19 Apr 2018 20:43:48 +0200 Subject: [PATCH 15/30] Fix SpinBox. attempt 1 --- interface/resources/qml/controls-uit/SpinBox.qml | 7 ++++++- interface/src/ui/PreferencesDialog.cpp | 2 +- libraries/shared/src/Preferences.h | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml index 83c30ce162..9af5ee1ae9 100644 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -20,6 +20,7 @@ SpinBox { property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme === hifi.colorSchemes.light property string label: "" + property string suffix: "" property string labelInside: "" property color colorLabelInside: hifi.colors.white property real controlHeight: height + (spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0) @@ -34,6 +35,8 @@ SpinBox { property real realTo: 100.0 property real realStepSize: 1.0 + signal editingFinished() + implicitHeight: height implicitWidth: width @@ -88,12 +91,14 @@ SpinBox { : (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGrayText) selectedTextColor: hifi.colors.black selectionColor: hifi.colors.primaryHighlight - text: spinBox.textFromValue(spinBox.value, spinBox.locale) + text: spinBox.textFromValue(spinBox.value, spinBox.locale) + suffix verticalAlignment: Qt.AlignVCenter leftPadding: spinBoxLabelInside.visible ? 30 : hifi.dimensions.textPadding //rightPadding: hifi.dimensions.spinnerSize width: spinBox.width - hifi.dimensions.spinnerSize + onEditingFinished: spinBox.editingFinished() } + up.indicator: Item { x: spinBox.width - implicitWidth - 5 y: 1 diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 4c233b986c..8067a27fb0 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -298,7 +298,7 @@ void setupPreferences() { { static const int MIN_PORT_NUMBER { 0 }; static const int MAX_PORT_NUMBER { 65535 }; - auto getter = [nodelist] { return static_cast(nodelist->getSocketLocalPort()); }; + auto getter = [nodelist] { qWarning() << "vladest: port" << static_cast(nodelist->getSocketLocalPort()); return static_cast(nodelist->getSocketLocalPort()); }; auto setter = [nodelist](int preset) { nodelist->setSocketLocalPort(static_cast(preset)); }; auto preference = new IntSpinnerPreference(NETWORKING, "Listening Port", getter, setter); preference->setMin(MIN_PORT_NUMBER); diff --git a/libraries/shared/src/Preferences.h b/libraries/shared/src/Preferences.h index a243a6d58d..76d61fe3f6 100644 --- a/libraries/shared/src/Preferences.h +++ b/libraries/shared/src/Preferences.h @@ -198,6 +198,7 @@ class IntPreference : public TypedPreference { Q_PROPERTY(float min READ getMin CONSTANT) Q_PROPERTY(float max READ getMax CONSTANT) Q_PROPERTY(float step READ getStep CONSTANT) + Q_PROPERTY(int decimals READ getDecimals CONSTANT) public: IntPreference(const QString& category, const QString& name, Getter getter, Setter setter) @@ -212,6 +213,9 @@ public: float getStep() const { return _step; } void setStep(float step) { _step = step; }; + int getDecimals() const { return _decimals; } + void setDecimals(int decimals) { _decimals = decimals; }; + signals: void valueChanged(); @@ -221,6 +225,7 @@ protected: int _min { std::numeric_limits::min() }; int _max { std::numeric_limits::max() }; int _step { 1 }; + int _decimals { 0 }; }; class StringPreference : public TypedPreference { From 8950c31378e6833e95046b238a4cb04db0e8ea8a Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 19 Apr 2018 16:29:49 -0700 Subject: [PATCH 16/30] fix mouse equipping while someone else far grabbing --- .../controllerModules/equipEntity.js | 11 +++++----- .../libraries/controllerDispatcherUtils.js | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 7532ca07c3..6f3169f5cf 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -802,10 +802,11 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects) { - var entityProperties = Entities.getEntityProperties(intersection.entityID, DISPATCHER_PROPERTIES); + var entityID = intersection.entityID; + var entityProperties = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); var hasEquipData = getWearableData(entityProperties).joints || getEquipHotspotsData(entityProperties).length > 0; - if (hasEquipData && entityProperties.parentID === EMPTY_PARENT_ID) { - entityProperties.id = intersection.entityID; + if (hasEquipData && entityProperties.parentID === EMPTY_PARENT_ID && !entityIsFarGrabbedByOther(entityID)) { + entityProperties.id = entityID; var rightHandPosition = MyAvatar.getJointPosition("RightHand"); var leftHandPosition = MyAvatar.getJointPosition("LeftHand"); var distanceToRightHand = Vec3.distance(entityProperties.position, rightHandPosition); @@ -815,11 +816,11 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var mouseEquip = true; if (rightHandAvailable && (distanceToRightHand < distanceToLeftHand || !leftHandAvailable)) { // clear any existing grab actions on the entity now (their later removal could affect bootstrapping flags) - clearGrabActions(intersection.entityID); + clearGrabActions(entityID); rightEquipEntity.setMessageGrabData(entityProperties, mouseEquip); } else if (leftHandAvailable && (distanceToLeftHand < distanceToRightHand || !rightHandAvailable)) { // clear any existing grab actions on the entity now (their later removal could affect bootstrapping flags) - clearGrabActions(intersection.entityID); + clearGrabActions(entityID); leftEquipEntity.setMessageGrabData(entityProperties, mouseEquip); } } diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index de5fad2ff9..71dc5e4273 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -423,6 +423,26 @@ entityIsEquipped = function(entityID) { return equippedInRightHand || equippedInLeftHand; }; +entityIsFarGrabbedByOther = function(entityID) { + // by convention, a far grab sets the tag of its action to be far-grab-*owner-session-id*. + var actionIDs = Entities.getActionIDs(entityID); + var myFarGrabTag = "far-grab-" + MyAvatar.sessionUUID; + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments.tag; + if (tag == myFarGrabTag) { + // we see a far-grab-*uuid* shaped tag, but it's our tag, so that's okay. + continue; + } + if (tag.slice(0, 9) == "far-grab-") { + // we see a far-grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. + return true; + } + } + return false; +}; + if (typeof module !== 'undefined') { module.exports = { makeDispatcherModuleParameters: makeDispatcherModuleParameters, From 7ecc279e00061eb7e2bd8b031c3e48fe2c8fa127 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 19 Apr 2018 16:43:11 -0700 Subject: [PATCH 17/30] show default or campaigned slideshow during install --- cmake/templates/NSIS.template.in | 84 ++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 28ac320e42..6ede94b900 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -87,6 +87,10 @@ ;-------------------------------- ;-------------------------------- ;General + + ; hide install details since we show an image slideshow in their place + ShowInstDetails nevershow + ; leverage the UAC NSIS plugin to promote uninstaller to elevated privileges !include UAC.nsh @@ -446,6 +450,7 @@ SectionEnd Page custom PostInstallOptionsPage ReadPostInstallOptions !define MUI_PAGE_CUSTOMFUNCTION_PRE PageInstallFilesPre + !define MUI_PAGE_CUSTOMFUNCTION_SHOW StartInstallSlideshow !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_UNPAGE_CONFIRM @@ -544,11 +549,33 @@ Var Express ${EndIf} !macroend +!macro DownloadSlideshowImages + InitPluginsDir + + Push $0 + + ; figure out where to download installer slideshow images from + StrCpy $0 "http://cdn.highfidelity.com/installer/slideshow" + + ${If} $CampaignName == "" + StrCpy $0 "$0/default" + ${Else} + StrCpy $0 "$0/$CampaignName" + ${EndIf} + + NSISdl::download_quiet $0/1.jpg "$PLUGINSDIR\1.jpg" + NSISdl::download_quiet $0/2.jpg "$PLUGINSDIR\2.jpg" + NSISdl::download_quiet $0/3.jpg "$PLUGINSDIR\3.jpg" + + Pop $0 +!macroend + Function OnUserAbort !insertmacro GoogleAnalytics "Installer" "Abort" "User Abort" "" FunctionEnd Function PageWelcomePre !insertmacro GoogleAnalytics "Installer" "Welcome" "" "" + !insertmacro DownloadSlideshowImages FunctionEnd Function PageLicensePre !insertmacro GoogleAnalytics "Installer" "License" "" "" @@ -640,6 +667,56 @@ Function ChangeCustomLabel Pop $R1 FunctionEnd +!macro AddImageToSlideshowFile ImageFilename + ${If} ${FileExists} "$PLUGINSDIR\${ImageFilename}.jpg" + FileWrite $0 "= ${ImageFilename}.jpg,500,5000,$\"$\"$\r$\n" + StrCpy $1 "1" + ${EndIf} +!macroend + +Function StartInstallSlideshow + ; create a slideshow file based on what files we have available + + ; stash $0 and $1 + Push $0 + Push $1 + + ; start $1 as 0, indicating we have no images present + StrCpy $1 "0" + + FileOpen $0 "$PLUGINSDIR\slideshow.dat" w + + ; write the language value to the slideshow file for english + FileWrite $0 "[1033]$\r$\n" + + ; for each of 1.jpg, 2.jpg, 3.jpg + ; if the image is present add it to the dat file and set our flag + ; to show we found at least one image + !insertmacro AddImageToSlideshowFile "1" + !insertmacro AddImageToSlideshowFile "2" + !insertmacro AddImageToSlideshowFile "3" + + FileClose $0 + + ; NOTE: something inside of nsisSlideshow::show isn't keeping the stack clean + ; so we need to push things back BEFORE we call it + + ${If} $1 == "1" + Pop $1 + Pop $0 + + ; show the slideshow using the created data file + nsisSlideshow::show /NOUNLOAD "/auto=$PLUGINSDIR\slideshow.dat" + ${Else} + Pop $1 + Pop $0 + + ; show the install details because we didn't end up with slideshow images to show + SetDetailsView show + ${EndIf} + +FunctionEnd + Function PostInstallOptionsPage !insertmacro MaybeSkipPage !insertmacro GoogleAnalytics "Installer" "Post Install Options" "" "" @@ -932,6 +1009,7 @@ FunctionEnd ;Installer Sections Section "-Core installation" + ;The following delete blocks are temporary and can be removed once users who had the initial installer have updated ;Delete any server-console files installed before it was placed in sub-folder @@ -983,11 +1061,13 @@ Section "-Core installation" WriteRegStr HKLM "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR ;Write some information about this install to the installation folder + Push $0 FileOpen $0 "$INSTDIR\installer.ini" w FileWrite $0 "type=@INSTALLER_TYPE@$\r$\n" FileWrite $0 "campaign=$CampaignName$\r$\n" FileWrite $0 "exepath=$EXEPATH$\r$\n" FileClose $0 + Pop $0 ;Package the signed uninstaller produced by the inner loop !ifndef INNER @@ -1082,6 +1162,10 @@ Section "-Core installation" Call HandlePostInstallOptions !insertmacro GoogleAnalytics "Installer" "Done" "" "" + + ; stop the image slideshow and display install details + nsisSlideshow::stop + SetDetailsView show SectionEnd !include nsProcess.nsh From 752d8368cc4748a24fe67b73a9739a8523dccacb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 19 Apr 2018 18:16:44 -0700 Subject: [PATCH 18/30] add slideshow plugin to list of requirements in install doc --- INSTALL.md | 1 + 1 file changed, 1 insertion(+) diff --git a/INSTALL.md b/INSTALL.md index e07d28a43d..ac210c887f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -19,6 +19,7 @@ To produce an executable installer on Windows, the following are required: - [nsProcess Plug-in for Nullsoft](http://nsis.sourceforge.net/NsProcess_plugin) - 1.6 - [Inetc Plug-in for Nullsoft](http://nsis.sourceforge.net/Inetc_plug-in) - 1.0 - [NSISpcre Plug-in for Nullsoft](http://nsis.sourceforge.net/NSISpcre_plug-in) - 1.0 +- [nsisSlideshow Plug-in for Nullsoft](http://nsis.sourceforge.net/NsisSlideshow_plug-in) - 1.7 Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System. From 0da51672bbf61c648b902055616f7ccb5f3559c4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 19 Apr 2018 18:52:45 -0700 Subject: [PATCH 19/30] don't stop image slideshow when install concludes --- cmake/templates/NSIS.template.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 6ede94b900..bfedccdd2e 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1162,10 +1162,6 @@ Section "-Core installation" Call HandlePostInstallOptions !insertmacro GoogleAnalytics "Installer" "Done" "" "" - - ; stop the image slideshow and display install details - nsisSlideshow::stop - SetDetailsView show SectionEnd !include nsProcess.nsh From 0e28e41107bac8670c020c41d28dbe1a806b8412 Mon Sep 17 00:00:00 2001 From: vladest Date: Fri, 20 Apr 2018 19:15:29 +0200 Subject: [PATCH 20/30] Fix various issues with SpinBox-es and Sliders --- .../resources/qml/controls-uit/Slider.qml | 1 + .../resources/qml/controls-uit/SpinBox.qml | 8 ++-- .../dialogs/preferences/SpinBoxPreference.qml | 4 +- .../preferences/SpinnerSliderPreference.qml | 14 +++--- .../hifi/dialogs/attachments/Attachment.qml | 8 ++-- .../qml/hifi/dialogs/attachments/Vector3.qml | 22 ++++----- .../qml/hifi/tablet/OpenVrConfiguration.qml | 48 +++++++++---------- 7 files changed, 53 insertions(+), 52 deletions(-) diff --git a/interface/resources/qml/controls-uit/Slider.qml b/interface/resources/qml/controls-uit/Slider.qml index 3726d3f260..5ddd97f3f6 100644 --- a/interface/resources/qml/controls-uit/Slider.qml +++ b/interface/resources/qml/controls-uit/Slider.qml @@ -24,6 +24,7 @@ Slider { property alias minimumValue: slider.from property alias maximumValue: slider.to + property bool tickmarksEnabled: false height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. y: sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0 diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml index 9af5ee1ae9..29f1de3dd7 100644 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -71,16 +71,16 @@ SpinBox { } validator: DoubleValidator { - bottom: Math.min(spinBox.from, spinBox.to)*spinBox.factor - top: Math.max(spinBox.from, spinBox.to)*spinBox.factor + bottom: Math.min(spinBox.from, spinBox.to) + top: Math.max(spinBox.from, spinBox.to) } textFromValue: function(value, locale) { - return parseFloat(value*1.0/factor).toFixed(decimals); + return parseFloat(value/factor).toFixed(decimals); } valueFromText: function(text, locale) { - return Number.fromLocaleString(locale, text); + return Number.fromLocaleString(locale, text)*factor; } diff --git a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml index e670cd37c4..89e1096a04 100644 --- a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml @@ -18,11 +18,11 @@ Preference { height: control.height + hifi.dimensions.controlInterlineHeight Component.onCompleted: { - spinner.value = preference.value; + spinner.realValue = preference.value; } function save() { - preference.value = spinner.value; + preference.value = spinner.realValue; preference.save(); } diff --git a/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml b/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml index 3cba67bc82..731acc7e5b 100644 --- a/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml @@ -21,7 +21,7 @@ Preference { Component.onCompleted: { slider.value = preference.value; - spinner.value = preference.value; + spinner.realValue = preference.value; } function save() { @@ -60,7 +60,7 @@ Preference { maximumValue: MyAvatar.getDomainMaxScale() stepSize: preference.step onValueChanged: { - spinner.value = value + spinner.realValue = value } anchors { right: spinner.left @@ -73,12 +73,12 @@ Preference { SpinBox { id: spinner decimals: preference.decimals - value: preference.value + realValue: preference.value minimumValue: MyAvatar.getDomainMinScale() maximumValue: MyAvatar.getDomainMaxScale() width: 100 onValueChanged: { - slider.value = value; + slider.value = realValue; } anchors { right: button.left @@ -92,10 +92,10 @@ Preference { id: button onClicked: { if (spinner.maximumValue >= 1) { - spinner.value = 1 + spinner.realValue = 1 slider.value = 1 } else { - spinner.value = spinner.maximumValue + spinner.realValue = spinner.maximumValue slider.value = spinner.maximumValue } } @@ -108,4 +108,4 @@ Preference { colorScheme: hifi.colorSchemes.dark } } -} \ No newline at end of file +} diff --git a/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml b/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml index d93e077b5a..30e03bd02e 100644 --- a/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml +++ b/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml @@ -181,11 +181,11 @@ Item { minimumValue: 0.01 maximumValue: 10 realStepSize: 0.05; - value: attachment ? attachment.scale : 1.0 + realValue: attachment ? attachment.scale : 1.0 colorScheme: hifi.colorSchemes.dark - onValueChanged: { - if (completed && attachment && attachment.scale !== value) { - attachment.scale = value; + onRealValueChanged: { + if (completed && attachment && attachment.scale !== realValue) { + attachment.scale = realValue; updateAttachment(); } } diff --git a/interface/resources/qml/hifi/dialogs/attachments/Vector3.qml b/interface/resources/qml/hifi/dialogs/attachments/Vector3.qml index 228d71fe6f..311492858b 100644 --- a/interface/resources/qml/hifi/dialogs/attachments/Vector3.qml +++ b/interface/resources/qml/hifi/dialogs/attachments/Vector3.qml @@ -51,7 +51,7 @@ Item { id: xspinner width: root.spinboxWidth anchors { left: parent.left } - value: root.vector.x + realValue: root.vector.x labelInside: "X:" colorScheme: hifi.colorSchemes.dark colorLabelInside: hifi.colors.redHighlight @@ -72,17 +72,17 @@ Item { id: yspinner width: root.spinboxWidth anchors { horizontalCenter: parent.horizontalCenter } - value: root.vector.y + realValue: root.vector.y labelInside: "Y:" colorLabelInside: hifi.colors.greenHighlight colorScheme: hifi.colorSchemes.dark decimals: root.decimals - stepSize: root.stepSize + realStepSize: root.stepSize maximumValue: root.maximumValue minimumValue: root.minimumValue - onValueChanged: { - if (value !== vector.y) { - vector.y = value + onRealValueChanged: { + if (realValue !== vector.y) { + vector.y = realValue root.valueChanged(); } } @@ -93,17 +93,17 @@ Item { id: zspinner width: root.spinboxWidth anchors { right: parent.right; } - value: root.vector.z + realValue: root.vector.z labelInside: "Z:" colorLabelInside: hifi.colors.primaryHighlight colorScheme: hifi.colorSchemes.dark decimals: root.decimals - stepSize: root.stepSize + realStepSize: root.stepSize maximumValue: root.maximumValue minimumValue: root.minimumValue - onValueChanged: { - if (value !== vector.z) { - vector.z = value + onRealValueChanged: { + if (realValue !== vector.z) { + vector.z = realValue root.valueChanged(); } } diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index bd3a95bca0..572d3a55f0 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -178,8 +178,8 @@ Rectangle { label: "Y Offset" suffix: " cm" minimumValue: -10 - stepSize: 1 - value: -5 + realStepSize: 1 + realValue: -5 colorScheme: hifi.colorSchemes.dark onEditingFinished: { @@ -193,10 +193,10 @@ Rectangle { width: 112 label: "Z Offset" minimumValue: -10 - stepSize: 1 + realStepSize: 1 decimals: 1 suffix: " cm" - value: -5 + realValue: -5 colorScheme: hifi.colorSchemes.dark onEditingFinished: { @@ -288,7 +288,7 @@ Rectangle { suffix: " cm" label: "Y Offset" minimumValue: -10 - stepSize: 1 + realStepSize: 1 colorScheme: hifi.colorSchemes.dark onEditingFinished: { @@ -303,7 +303,7 @@ Rectangle { label: "Z Offset" suffix: " cm" minimumValue: -10 - stepSize: 1 + realStepSize: 1 decimals: 1 colorScheme: hifi.colorSchemes.dark @@ -535,9 +535,9 @@ Rectangle { suffix: " cm" label: "Arm Circumference" minimumValue: 0 - stepSize: 1.0 + realStepSize: 1.0 colorScheme: hifi.colorSchemes.dark - value: 33.0 + realValue: 33.0 onEditingFinished: { sendConfigurationSettings(); @@ -550,10 +550,10 @@ Rectangle { label: "Shoulder Width" suffix: " cm" minimumValue: 0 - stepSize: 1.0 + realStepSize: 1.0 decimals: 1 colorScheme: hifi.colorSchemes.dark - value: 48 + realValue: 48 onEditingFinished: { sendConfigurationSettings(); @@ -659,13 +659,13 @@ Rectangle { InputConfiguration.uncalibratePlugin(pluginName); updateCalibrationButton(); } else { - calibrationTimer.interval = timeToCalibrate.value * 1000 - openVrConfiguration.countDown = timeToCalibrate.value; + calibrationTimer.interval = timeToCalibrate.realValue * 1000 + openVrConfiguration.countDown = timeToCalibrate.realValue; var calibratingScreen = screen.createObject(); stack.push(calibratingScreen); calibratingScreen.canceled.connect(cancelCalibration); calibratingScreen.restart.connect(restartCalibration); - calibratingScreen.start(calibrationTimer.interval, timeToCalibrate.value); + calibratingScreen.start(calibrationTimer.interval, timeToCalibrate.realValue); calibrationTimer.start(); } } @@ -728,12 +728,12 @@ Rectangle { anchors.leftMargin: leftMargin minimumValue: 5 - value: 5 + realValue: 5 colorScheme: hifi.colorSchemes.dark onEditingFinished: { - calibrationTimer.interval = value * 1000; - openVrConfiguration.countDown = value; + calibrationTimer.interval = realValue * 1000; + openVrConfiguration.countDown = realValue; numberAnimation.duration = calibrationTimer.interval; } } @@ -910,8 +910,8 @@ Rectangle { var desktopMode = settings["desktopMode"]; var hmdDesktopPosition = settings["hmdDesktopTracking"]; - armCircumference.value = settings.armCircumference; - shoulderWidth.value = settings.shoulderWidth; + armCircumference.realValue = settings.armCircumference; + shoulderWidth.realValue = settings.shoulderWidth; if (HmdHead) { headBox.checked = true; @@ -1075,22 +1075,22 @@ Rectangle { var headObject = { "override": overrideHead, - "Y": headYOffset.value, - "Z": headZOffset.value + "Y": headYOffset.realValue, + "Z": headZOffset.realValue } var handObject = { "override": overrideHandController, - "Y": handYOffset.value, - "Z": handZOffset.value + "Y": handYOffset.realValue, + "Z": handZOffset.realValue } var settingsObject = { "bodyConfiguration": trackerConfiguration, "headConfiguration": headObject, "handConfiguration": handObject, - "armCircumference": armCircumference.value, - "shoulderWidth": shoulderWidth.value, + "armCircumference": armCircumference.realValue, + "shoulderWidth": shoulderWidth.realValue, "desktopMode": viveInDesktop.checked, "hmdDesktopTracking": hmdInDesktop.checked } From d84ea6bf0f1e243da97fa80c8fe2c7d0b4d8fc1f Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 20 Apr 2018 16:09:20 -0700 Subject: [PATCH 21/30] Don't populate user list in pal until you connect the events up --- scripts/system/pal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index c24e34cc1b..0a01007ee9 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -715,7 +715,6 @@ function onTabletScreenChanged(type, url) { ContextOverlay.enabled = false; Users.requestsDomainListData = true; - populateNearbyUserList(); audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); @@ -726,6 +725,7 @@ function onTabletScreenChanged(type, url) { Users.usernameFromIDReply.connect(usernameFromIDReply); triggerMapping.enable(); triggerPressMapping.enable(); + populateNearbyUserList(); } else { off(); ContextOverlay.enabled = true; From 60115752ad3fc9be0c3ae9cb0ad6801baf1f3563 Mon Sep 17 00:00:00 2001 From: vladest Date: Sat, 21 Apr 2018 20:18:24 +0200 Subject: [PATCH 22/30] Fixed saving after editing --- interface/resources/qml/controls-uit/SpinBox.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml index 29f1de3dd7..9d63122dbc 100644 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -39,6 +39,7 @@ SpinBox { implicitHeight: height implicitWidth: width + editable: true padding: 0 leftPadding: 0 From cf070e6e92c7b954f92694306567f87ac4d51e76 Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 23 Apr 2018 18:56:16 +0200 Subject: [PATCH 23/30] Cleanup --- interface/src/ui/PreferencesDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 8067a27fb0..4c233b986c 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -298,7 +298,7 @@ void setupPreferences() { { static const int MIN_PORT_NUMBER { 0 }; static const int MAX_PORT_NUMBER { 65535 }; - auto getter = [nodelist] { qWarning() << "vladest: port" << static_cast(nodelist->getSocketLocalPort()); return static_cast(nodelist->getSocketLocalPort()); }; + auto getter = [nodelist] { return static_cast(nodelist->getSocketLocalPort()); }; auto setter = [nodelist](int preset) { nodelist->setSocketLocalPort(static_cast(preset)); }; auto preference = new IntSpinnerPreference(NETWORKING, "Listening Port", getter, setter); preference->setMin(MIN_PORT_NUMBER); From ea6585a0b905cd7dac7f18fa6155d20d884999a0 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 23 Apr 2018 11:53:35 -0700 Subject: [PATCH 24/30] Corrected tosRGBFloat() computation. --- libraries/shared/src/ColorUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/ColorUtils.h b/libraries/shared/src/ColorUtils.h index fd0bbdd8ab..e113449db3 100644 --- a/libraries/shared/src/ColorUtils.h +++ b/libraries/shared/src/ColorUtils.h @@ -102,7 +102,7 @@ inline float ColorUtils::tosRGBFloat(const float &linear) { } else if (0 < linear && linear < SRGB_ELBOW_INV) { sRGBValue = 12.92f * linear; } else if (SRGB_ELBOW_INV <= linear && linear < 1) { - sRGBValue = 1.055f * powf(linear, 0.41666f - 0.055f); + sRGBValue = 1.055f * powf(linear, 0.41666f) - 0.055f; } else { sRGBValue = 1.0f; } From 1deb38f06d61b25aa873bb0ac0a75772a36df2f4 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 23 Apr 2018 12:05:30 -0700 Subject: [PATCH 25/30] fix copy error --- interface/src/scripting/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index 387900b2ae..b27cc344c3 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -147,7 +147,7 @@ void Audio::setInputVolume(float volume) { } float Audio::getInputLevel() const { - return resultWithReadLock([&] { + return resultWithReadLock([&] { return _inputLevel; }); } From 2f72b789a33abd37c293ae25ba8b060efd273a4e Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 23 Apr 2018 12:13:31 -0700 Subject: [PATCH 26/30] Fix for null sourceNode use --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index ac157979bb..baeac043e4 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -617,7 +617,7 @@ bool DomainServer::isPacketVerified(const udt::Packet& packet) { } } else { HIFI_FDEBUG("Packet of type" << headerType - << "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceNode->getUUID())); + << "received from unknown node with Local ID" << localSourceID); return false; } } From f849d6f937ec17dd6b4a78fc9cb92745d7828515 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 23 Apr 2018 12:26:02 -0700 Subject: [PATCH 27/30] Change packetSourceAndHashMatchAndTrackBandwidth logging in same manner --- libraries/networking/src/LimitedNodeList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index aaf1b58a0a..8d177ca534 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -358,7 +358,7 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe } else { HIFI_FCDEBUG(networking(), - "Packet of type" << headerType << "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceID)); + "Packet of type" << headerType << "received from unknown node with Local ID" << sourceLocalID); } } From 779386fbc4ffbb336d22a9ef56687e0015624003 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 23 Apr 2018 12:27:30 -0700 Subject: [PATCH 28/30] fix setting of domain local ID from domain list --- libraries/networking/src/NodeList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index cfe81a58af..04e32f50cb 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -638,7 +638,7 @@ void NodeList::processDomainServerList(QSharedPointer message) // if this was the first domain-server list from this domain, we've now connected if (!_domainHandler.isConnected()) { - _domainHandler.setLocalID(newLocalID); + _domainHandler.setLocalID(domainLocalID); _domainHandler.setUUID(domainUUID); _domainHandler.setIsConnected(true); From 861200db27c0bbbd0ae41ab21808156b62258884 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 23 Apr 2018 12:29:41 -0700 Subject: [PATCH 29/30] Attempt to shutdown web surfaces more consistently --- interface/src/Application.cpp | 13 ++++- interface/src/Application.h | 7 ++- interface/src/ui/overlays/Web3DOverlay.cpp | 12 ++-- .../src/RenderableWebEntityItem.cpp | 39 +++++++------ libraries/qml/src/qml/OffscreenSurface.cpp | 7 +-- .../qml/src/qml/impl/RenderEventHandler.cpp | 11 ++-- libraries/qml/src/qml/impl/SharedObject.cpp | 56 +++++++++++++------ .../src/AbstractViewStateInterface.h | 19 +++++-- 8 files changed, 99 insertions(+), 65 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a171de87bc..6d4c82d4bf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4741,7 +4741,7 @@ void Application::updateLOD(float deltaTime) const { } } -void Application::pushPostUpdateLambda(void* key, std::function func) { +void Application::pushPostUpdateLambda(void* key, const std::function& func) { std::unique_lock guard(_postUpdateLambdasLock); _postUpdateLambdas[key] = func; } @@ -7351,7 +7351,7 @@ void Application::windowMinimizedChanged(bool minimized) { } } -void Application::postLambdaEvent(std::function f) { +void Application::postLambdaEvent(const std::function& f) { if (this->thread() == QThread::currentThread()) { f(); } else { @@ -7359,6 +7359,15 @@ void Application::postLambdaEvent(std::function f) { } } +void Application::sendLambdaEvent(const std::function& f) { + if (this->thread() == QThread::currentThread()) { + f(); + } else { + LambdaEvent event(f); + QCoreApplication::sendEvent(this, &event); + } +} + void Application::initPlugins(const QStringList& arguments) { QCommandLineOption display("display", "Preferred displays", "displays"); QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "displays"); diff --git a/interface/src/Application.h b/interface/src/Application.h index 769658b0d6..74b0e5a110 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -136,7 +136,8 @@ public: Application(int& argc, char** argv, QElapsedTimer& startup_time, bool runningMarkerExisted); ~Application(); - void postLambdaEvent(std::function f) override; + void postLambdaEvent(const std::function& f) override; + void sendLambdaEvent(const std::function& f) override; QString getPreviousScriptLocation(); void setPreviousScriptLocation(const QString& previousScriptLocation); @@ -240,7 +241,7 @@ public: qint64 getCurrentSessionRuntime() const { return _sessionRunTimer.elapsed(); } - bool isAboutToQuit() const override { return _aboutToQuit; } + bool isAboutToQuit() const { return _aboutToQuit; } bool isPhysicsEnabled() const { return _physicsEnabled; } // the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display @@ -264,7 +265,7 @@ public: render::EnginePointer getRenderEngine() override { return _renderEngine; } gpu::ContextPointer getGPUContext() const { return _gpuContext; } - virtual void pushPostUpdateLambda(void* key, std::function func) override; + virtual void pushPostUpdateLambda(void* key, const std::function& func) override; void updateMyAvatarLookAtPosition(); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 10050c94d0..d574e08a94 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -65,14 +65,10 @@ const QString Web3DOverlay::TYPE = "web3d"; const QString Web3DOverlay::QML = "Web3DOverlay.qml"; static auto qmlSurfaceDeleter = [](OffscreenQmlSurface* surface) { - AbstractViewStateInterface::instance()->postLambdaEvent([surface] { - if (AbstractViewStateInterface::instance()->isAboutToQuit()) { - // WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown - // if the application has already stopped its event loop, delete must be explicit - delete surface; - } else { - surface->deleteLater(); - } + AbstractViewStateInterface::instance()->sendLambdaEvent([surface] { + // WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown + // if the application has already stopped its event loop, delete must be explicit + delete surface; }); }; diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index f647082d73..2b87cbae58 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -25,7 +25,7 @@ #include #include "EntitiesRendererLogging.h" - +#include using namespace render; using namespace render::entities; @@ -45,6 +45,7 @@ static int DEFAULT_MAX_FPS = 10; static int YOUTUBE_MAX_FPS = 30; static QTouchDevice _touchDevice; +static const char* URL_PROPERTY = "url"; WebEntityRenderer::ContentType WebEntityRenderer::getContentType(const QString& urlString) { if (urlString.isEmpty()) { @@ -52,7 +53,7 @@ WebEntityRenderer::ContentType WebEntityRenderer::getContentType(const QString& } const QUrl url(urlString); - if (url.scheme() == "http" || url.scheme() == "https" || + if (url.scheme() == URL_SCHEME_HTTP || url.scheme() == URL_SCHEME_HTTPS || urlString.toLower().endsWith(".htm") || urlString.toLower().endsWith(".html")) { return ContentType::HtmlContent; } @@ -164,6 +165,8 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene if (urlChanged) { if (newContentType != ContentType::HtmlContent || currentContentType != ContentType::HtmlContent) { destroyWebSurface(); + // If we destroyed the surface, the URL change will be implicitly handled by the re-creation + urlChanged = false; } withWriteLock([&] { @@ -185,8 +188,8 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene return; } - if (urlChanged) { - _webSurface->getRootItem()->setProperty("url", _lastSourceUrl); + if (urlChanged && _contentType == ContentType::HtmlContent) { + _webSurface->getRootItem()->setProperty(URL_PROPERTY, _lastSourceUrl); } if (_contextPosition != entity->getWorldPosition()) { @@ -254,6 +257,14 @@ bool WebEntityRenderer::hasWebSurface() { return (bool)_webSurface && _webSurface->getRootItem(); } +static const auto WebSurfaceDeleter = [](OffscreenQmlSurface* webSurface) { + AbstractViewStateInterface::instance()->sendLambdaEvent([webSurface] { + // WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown + // if the application has already stopped its event loop, delete must be explicit + delete webSurface; + }); +}; + bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) { qWarning() << "Too many concurrent web views to create new view"; @@ -261,20 +272,9 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { } ++_currentWebCount; - auto deleter = [](OffscreenQmlSurface* webSurface) { - AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] { - if (AbstractViewStateInterface::instance()->isAboutToQuit()) { - // WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown - // if the application has already stopped its event loop, delete must be explicit - delete webSurface; - } else { - webSurface->deleteLater(); - } - }); - }; // FIXME use the surface cache instead of explicit creation - _webSurface = QSharedPointer(new OffscreenQmlSurface(), deleter); + _webSurface = QSharedPointer(new OffscreenQmlSurface(), WebSurfaceDeleter); // FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces // and the current rendering load) _webSurface->setMaxFps(DEFAULT_MAX_FPS); @@ -302,7 +302,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { _webSurface->setMaxFps(DEFAULT_MAX_FPS); } _webSurface->load("controls/WebEntityView.qml", [this](QQmlContext* context, QObject* item) { - item->setProperty("url", _lastSourceUrl); + item->setProperty(URL_PROPERTY, _lastSourceUrl); }); } else if (_contentType == ContentType::QmlContent) { _webSurface->load(_lastSourceUrl, [this](QQmlContext* context, QObject* item) { @@ -327,6 +327,11 @@ void WebEntityRenderer::destroyWebSurface() { if (webSurface) { --_currentWebCount; QQuickItem* rootItem = webSurface->getRootItem(); + // Explicitly set the web URL to an empty string, in an effort to get a + // faster shutdown of any chromium processes interacting with audio + if (rootItem && _contentType == ContentType::HtmlContent) { + rootItem->setProperty(URL_PROPERTY, ""); + } if (rootItem && rootItem->objectName() == "tabletRoot") { auto tabletScriptingInterface = DependencyManager::get(); diff --git a/libraries/qml/src/qml/OffscreenSurface.cpp b/libraries/qml/src/qml/OffscreenSurface.cpp index 2da1c41340..53a8998977 100644 --- a/libraries/qml/src/qml/OffscreenSurface.cpp +++ b/libraries/qml/src/qml/OffscreenSurface.cpp @@ -66,14 +66,11 @@ OffscreenSurface::OffscreenSurface() } OffscreenSurface::~OffscreenSurface() { - disconnect(qApp); - _sharedObject->destroy(); + delete _sharedObject; + const_cast(_sharedObject) = nullptr; } bool OffscreenSurface::fetchTexture(TextureAndFence& textureAndFence) { - if (!_sharedObject) { - return false; - } hifi::qml::impl::TextureAndFence typedTextureAndFence; bool result = _sharedObject->fetchTexture(typedTextureAndFence); textureAndFence = typedTextureAndFence; diff --git a/libraries/qml/src/qml/impl/RenderEventHandler.cpp b/libraries/qml/src/qml/impl/RenderEventHandler.cpp index 6b66ce9314..945a469611 100644 --- a/libraries/qml/src/qml/impl/RenderEventHandler.cpp +++ b/libraries/qml/src/qml/impl/RenderEventHandler.cpp @@ -49,8 +49,8 @@ RenderEventHandler::RenderEventHandler(SharedObject* shared, QThread* targetThre qFatal("Unable to create new offscreen GL context"); } - moveToThread(targetThread); _canvas.moveToThreadWithContext(targetThread); + moveToThread(targetThread); } void RenderEventHandler::onInitalize() { @@ -160,11 +160,8 @@ void RenderEventHandler::onQuit() { } _shared->shutdownRendering(_canvas, _currentSize); - // Release the reference to the shared object. This will allow it to - // be destroyed (should happen on it's own thread). - _shared->deleteLater(); - - deleteLater(); - + _canvas.doneCurrent(); + _canvas.moveToThreadWithContext(qApp->thread()); + moveToThread(qApp->thread()); QThread::currentThread()->quit(); } diff --git a/libraries/qml/src/qml/impl/SharedObject.cpp b/libraries/qml/src/qml/impl/SharedObject.cpp index b2057117f6..9253c41b39 100644 --- a/libraries/qml/src/qml/impl/SharedObject.cpp +++ b/libraries/qml/src/qml/impl/SharedObject.cpp @@ -72,26 +72,35 @@ SharedObject::SharedObject() { QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &SharedObject::onAboutToQuit); } + SharedObject::~SharedObject() { - if (_quickWindow) { - _quickWindow->destroy(); - _quickWindow = nullptr; + // After destroy returns, the rendering thread should be gone + destroy(); + + // _renderTimer is created with `this` as the parent, so need no explicit destruction + + // Destroy the event hand + if (_renderObject) { + delete _renderObject; + _renderObject = nullptr; } if (_renderControl) { - _renderControl->deleteLater(); + delete _renderControl; _renderControl = nullptr; } - if (_renderThread) { - _renderThread->quit(); - _renderThread->deleteLater(); + if (_quickWindow) { + _quickWindow->destroy(); + delete _quickWindow; + _quickWindow = nullptr; } - if (_rootItem) { - _rootItem->deleteLater(); - _rootItem = nullptr; - } + // _rootItem is parented to the quickWindow, so needs no explicit destruction + //if (_rootItem) { + // delete _rootItem; + // _rootItem = nullptr; + //} releaseEngine(_qmlContext->engine()); } @@ -119,6 +128,10 @@ void SharedObject::create(OffscreenSurface* surface) { } void SharedObject::setRootItem(QQuickItem* rootItem) { + if (_quit) { + return; + } + _rootItem = rootItem; _rootItem->setSize(_quickWindow->size()); @@ -127,7 +140,6 @@ void SharedObject::setRootItem(QQuickItem* rootItem) { _renderThread->setObjectName(objectName()); _renderThread->start(); - // Create event handler for the render thread _renderObject = new RenderEventHandler(this, _renderThread); QCoreApplication::postEvent(this, new OffscreenEvent(OffscreenEvent::Initialize)); @@ -137,35 +149,43 @@ void SharedObject::setRootItem(QQuickItem* rootItem) { } void SharedObject::destroy() { + // `destroy` is idempotent, it can be called multiple times without issues if (_quit) { return; } if (!_rootItem) { - deleteLater(); return; } - _paused = true; if (_renderTimer) { + _renderTimer->stop(); QObject::disconnect(_renderTimer); - _renderTimer->deleteLater(); } - QObject::disconnect(_renderControl); + if (_renderControl) { + QObject::disconnect(_renderControl); + } + QObject::disconnect(qApp); { QMutexLocker lock(&_mutex); _quit = true; - QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::Quit), Qt::HighEventPriority); + if (_renderObject) { + QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::Quit), Qt::HighEventPriority); + } } // Block until the rendering thread has stopped // FIXME this is undesirable because this is blocking the main thread, // but I haven't found a reliable way to do this only at application // shutdown - _renderThread->wait(); + if (_renderThread) { + _renderThread->wait(); + delete _renderThread; + _renderThread = nullptr; + } } diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index 96e9f4d222..54fdc903ca 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -37,15 +37,25 @@ public: virtual glm::vec3 getAvatarPosition() const = 0; - virtual bool isAboutToQuit() const = 0; - virtual void postLambdaEvent(std::function f) = 0; + // Unfortunately, having this here is a bad idea. Lots of objects connect to + // the aboutToQuit signal, and it's impossible to know the order in which + // the receivers will be called, so this might return false negatives + //virtual bool isAboutToQuit() const = 0; + + // Queue code to execute on the main thread. + // If called from the main thread, the lambda will execute synchronously + virtual void postLambdaEvent(const std::function& f) = 0; + // Synchronously execute code on the main thread. This function will + // not return until the code is executed, regardles of which thread it + // is called from + virtual void sendLambdaEvent(const std::function& f) = 0; virtual qreal getDevicePixelRatio() = 0; virtual render::ScenePointer getMain3DScene() = 0; virtual render::EnginePointer getRenderEngine() = 0; - virtual void pushPostUpdateLambda(void* key, std::function func) = 0; + virtual void pushPostUpdateLambda(void* key, const std::function& func) = 0; virtual bool isHMDMode() const = 0; @@ -54,5 +64,4 @@ public: static void setInstance(AbstractViewStateInterface* instance); }; - -#endif // hifi_AbstractViewStateInterface_h +#endif // hifi_AbstractViewStateInterface_h From ecaf162afb1c0e7a5abda6c4bde1e034ea28e061 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 23 Apr 2018 20:41:36 -0700 Subject: [PATCH 30/30] Fixing PR build --- libraries/qml/src/qml/OffscreenSurface.cpp | 1 - tests/render-perf/src/main.cpp | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/qml/src/qml/OffscreenSurface.cpp b/libraries/qml/src/qml/OffscreenSurface.cpp index 53a8998977..688f3fdb5f 100644 --- a/libraries/qml/src/qml/OffscreenSurface.cpp +++ b/libraries/qml/src/qml/OffscreenSurface.cpp @@ -67,7 +67,6 @@ OffscreenSurface::OffscreenSurface() OffscreenSurface::~OffscreenSurface() { delete _sharedObject; - const_cast(_sharedObject) = nullptr; } bool OffscreenSurface::fetchTexture(TextureAndFence& textureAndFence) { diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 93672cc5a2..9249b3d957 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -453,8 +453,8 @@ protected: return vec3(); } - bool isAboutToQuit() const override { return false; } - void postLambdaEvent(std::function f) override {} + void postLambdaEvent(const std::function& f) override {} + void sendLambdaEvent(const std::function& f) override {} qreal getDevicePixelRatio() override { return 1.0f; @@ -469,7 +469,7 @@ protected: } std::map> _postUpdateLambdas; - void pushPostUpdateLambda(void* key, std::function func) override { + void pushPostUpdateLambda(void* key, const std::function& func) override { _postUpdateLambdas[key] = func; }