From 9fb1835a26433817fef0958903575f3a6297f572 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 12 Aug 2017 12:38:36 -0700 Subject: [PATCH] grabbing overlays works, again --- .../controllers/controllerDispatcher.js | 32 +++- .../nearParentGrabOverlay.js | 167 ++++++++++++++++++ .../system/controllers/controllerScripts.js | 1 + 3 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 scripts/system/controllers/controllerModules/nearParentGrabOverlay.js diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 6283b3c583..d2b6418ee9 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -5,7 +5,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global Script, Entities, controllerDispatcherPlugins, Controller, Vec3, getControllerWorldLocation, +/* global Script, Entities, Overlays, controllerDispatcherPlugins, Controller, Vec3, getControllerWorldLocation, LEFT_HAND, RIGHT_HAND */ controllerDispatcherPlugins = {}; @@ -48,7 +48,7 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); var highVarianceCount = 0; var veryhighVarianceCount = 0; - // a module can occupy one or more slots while it's running. If all the required slots for a module are + // a module can occupy one or more "activity" slots while it's running. If all the required slots for a module are // not set to false (not in use), a module cannot start. When a module is using a slot, that module's name // is stored as the value, rather than false. this.activitySlots = { @@ -56,7 +56,7 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); rightHand: false }; - this.slotsAreAvailable = function (plugin) { + this.slotsAreAvailableForPlugin = function (plugin) { for (var i = 0; i < plugin.parameters.activitySlots.length; i++) { if (_this.activitySlots[plugin.parameters.activitySlots[i]]) { return false; // something is already using a slot which _this plugin requires @@ -140,8 +140,28 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); var controllerLocations = [_this.dataGatherers.leftControllerLocation(), _this.dataGatherers.rightControllerLocation()]; + // find 3d overlays near each hand + var nearbyOverlayIDs = []; + var h; + for (h = LEFT_HAND; h <= RIGHT_HAND; h++) { + // todo: check controllerLocations[h].valid + var nearbyOverlays = Overlays.findOverlays(controllerLocations[h].position, NEAR_MIN_RADIUS); + var makeOverlaySorter = function (handIndex) { + return function (a, b) { + var aPosition = Overlays.getProperty(a, "position"); + var aDistance = Vec3.distance(aPosition, controllerLocations[handIndex]); + var bPosition = Overlays.getProperty(b, "position"); + var bDistance = Vec3.distance(bPosition, controllerLocations[handIndex]); + return aDistance - bDistance; + }; + }; + nearbyOverlays.sort(makeOverlaySorter(h)); + nearbyOverlayIDs.push(nearbyOverlays); + } + + // find entities near each hand var nearbyEntityProperties = [[], []]; - for (var h = LEFT_HAND; h <= RIGHT_HAND; h++) { + for (h = LEFT_HAND; h <= RIGHT_HAND; h++) { // todo: check controllerLocations[h].valid var controllerPosition = controllerLocations[h].position; var nearbyEntityIDs = Entities.findEntities(controllerPosition, NEAR_MIN_RADIUS); @@ -165,11 +185,13 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); nearbyEntityProperties[h].sort(makeSorter(h)); } + // bundle up all the data about the current situation var controllerData = { triggerValues: [_this.leftTriggerValue, _this.rightTriggerValue], triggerClicks: [_this.leftTriggerClicked, _this.rightTriggerClicked], controllerLocations: controllerLocations, nearbyEntityProperties: nearbyEntityProperties, + nearbyOverlayIDs: nearbyOverlayIDs }; // print("QQQ dispatcher " + JSON.stringify(_this.runningPluginNames) + " : " + JSON.stringify(_this.activitySlots)); @@ -179,7 +201,7 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); // TODO sort names by plugin.priority if (controllerDispatcherPlugins.hasOwnProperty(pluginName)) { var candidatePlugin = controllerDispatcherPlugins[pluginName]; - if (_this.slotsAreAvailable(candidatePlugin) && candidatePlugin.isReady(controllerData, deltaTime)) { + if (_this.slotsAreAvailableForPlugin(candidatePlugin) && candidatePlugin.isReady(controllerData, deltaTime)) { // this plugin will start. add it to the list of running plugins and mark the // activity-slots which this plugin consumes as "in use" _this.runningPluginNames[pluginName] = true; diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js new file mode 100644 index 0000000000..4a70b31820 --- /dev/null +++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js @@ -0,0 +1,167 @@ +"use strict"; + +// nearParentGrabOverlay.js +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + + +/* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, AVATAR_SELF_ID, + getControllerJointIndex, NULL_UUID, enableDispatcherModule, disableDispatcherModule, + Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, + makeDispatcherModuleParameters, Overlays +*/ + +Script.include("/~/system/controllers/controllerDispatcherUtils.js"); + +(function() { + + // XXX this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true; + // XXX this.kinematicGrab = (grabbableData.kinematic !== undefined) ? grabbableData.kinematic : NEAR_GRABBING_KINEMATIC; + + function NearParentingGrabOverlay(hand) { + this.hand = hand; + this.grabbedThingID = null; + this.previousParentID = {}; + this.previousParentJointIndex = {}; + this.previouslyUnhooked = {}; + + this.parameters = makeDispatcherModuleParameters( + 500, + this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], + [], + 100); + + + // XXX does handJointIndex change if the avatar changes? + this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); + this.controllerJointIndex = getControllerJointIndex(this.hand); + + this.thisHandIsParent = function(props) { + if (props.parentID !== MyAvatar.sessionUUID && props.parentID !== AVATAR_SELF_ID) { + return false; + } + + var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); + if (props.parentJointIndex == handJointIndex) { + return true; + } + + var controllerJointIndex = this.controllerJointIndex; + if (props.parentJointIndex == controllerJointIndex) { + return true; + } + + var controllerCRJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? + "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : + "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"); + if (props.parentJointIndex == controllerCRJointIndex) { + return true; + } + + return false; + }; + + this.startNearParentingGrabOverlay = function (controllerData) { + Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); + + var handJointIndex; + // if (this.ignoreIK) { + // handJointIndex = this.controllerJointIndex; + // } else { + // handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); + // } + handJointIndex = this.controllerJointIndex; + + var grabbedProperties = { + position: Overlays.getProperty(this.grabbedThingID, "position"), + rotation: Overlays.getProperty(this.grabbedThingID, "rotation"), + parentID: Overlays.getProperty(this.grabbedThingID, "parentID"), + parentJointIndex: Overlays.getProperty(this.grabbedThingID, "parentJointIndex"), + dynamic: false, + shapeType: "none" + }; + + var reparentProps = { + parentID: AVATAR_SELF_ID, + parentJointIndex: handJointIndex, + velocity: {x: 0, y: 0, z: 0}, + angularVelocity: {x: 0, y: 0, z: 0} + }; + + if (this.thisHandIsParent(grabbedProperties)) { + // this should never happen, but if it does, don't set previous parent to be this hand. + // this.previousParentID[this.grabbedThingID] = NULL; + // this.previousParentJointIndex[this.grabbedThingID] = -1; + } else { + this.previousParentID[this.grabbedThingID] = grabbedProperties.parentID; + this.previousParentJointIndex[this.grabbedThingID] = grabbedProperties.parentJointIndex; + } + Overlays.editOverlay(this.grabbedThingID, reparentProps); + + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'grab', + grabbedEntity: this.grabbedThingID, + joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" + })); + }; + + this.endNearParentingGrabOverlay = function (controllerData) { + if (this.previousParentID[this.grabbedThingID] === NULL_UUID) { + Overlays.editOverlay(this.grabbedThingID, { + parentID: NULL_UUID, + parentJointIndex: -1 + }); + } else { + // before we grabbed it, overlay was a child of something; put it back. + Overlays.editOverlay(this.grabbedThingID, { + parentID: this.previousParentID[this.grabbedThingID], + parentJointIndex: this.previousParentJointIndex[this.grabbedThingID], + }); + } + + this.grabbedThingID = null; + }; + + this.isReady = function (controllerData) { + if (controllerData.triggerClicks[this.hand] == 0) { + return false; + } + + this.grabbedThingID = null; + + var candidateOverlays = controllerData.nearbyOverlayIDs[this.hand]; + print("candidateOverlays.length = " + candidateOverlays.length); + var grabbableOverlays = candidateOverlays.filter(function(overlayID) { + return Overlays.getProperty(overlayID, "grabbable"); + }); + print("grabbableOverlays.length = " + grabbableOverlays.length); + + if (grabbableOverlays.length > 0) { + this.grabbedThingID = grabbableOverlays[0]; + this.startNearParentingGrabOverlay(controllerData); + return true; + } else { + return false; + } + }; + + this.run = function (controllerData) { + if (controllerData.triggerClicks[this.hand] == 0) { + this.endNearParentingGrabOverlay(controllerData); + return false; + } else { + return true; + } + }; + } + + enableDispatcherModule("LeftNearParentingGrabOverlay", new NearParentingGrabOverlay(LEFT_HAND)); + enableDispatcherModule("RightNearParentingGrabOverlay", new NearParentingGrabOverlay(RIGHT_HAND)); + + this.cleanup = function () { + disableDispatcherModule("LeftNearParentingGrabOverlay"); + disableDispatcherModule("RightNearParentingGrabOverlay"); + }; + Script.scriptEnding.connect(this.cleanup); +}()); diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index 31c464ee49..5a067e44c6 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -20,6 +20,7 @@ var CONTOLLER_SCRIPTS = [ "ControllerDispatcher.js", "controllerModules/nearParentGrabEntity.js", + "controllerModules/nearParentGrabOverlay.js", "controllerModules/nearActionGrabEntity.js", "controllerModules/tabletStylusInput.js" ];