From 32886d67d98b7d2b964b25e39ce1a821a05593fe Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Fri, 20 Jul 2018 17:17:36 -0700 Subject: [PATCH] optimizing near-/far- grabbable entities a bit --- .../controllers/controllerDispatcher.js | 74 +++---- .../system/controllers/controllerModules/' | 181 ++++++++++++++++++ .../controllerModules/webSurfaceLaserInput.js | 12 +- 3 files changed, 223 insertions(+), 44 deletions(-) create mode 100644 scripts/system/controllers/controllerModules/' diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 8dbf4a6789..399ccf0ba3 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -380,46 +380,46 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } _this.pointerManager.updatePointersRenderState(controllerData.triggerClicks, controllerData.triggerValues); - if (DEBUG_OVERLAY) { - if (!_this.debugOverlayID) { +/* if (DEBUG_OVERLAY) {*/ + //if (!_this.debugOverlayID) { - var textWidth = 0.4; - var textHeight = 0.3; - var numberOfLines = 15; - var textMargin = 0.02; - var lineHeight = (textHeight - (2 * textMargin)) / numberOfLines; + //var textWidth = 0.4; + //var textHeight = 0.3; + //var numberOfLines = 15; + //var textMargin = 0.02; + //var lineHeight = (textHeight - (2 * textMargin)) / numberOfLines; - _this.debugOverlayID = Overlays.addOverlay("text3d", { - localPosition: { x: 0.3, y: 0.2, z: 1.1 }, - localRotation: { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }, - parentID: MyAvatar.sessionUUID, - parentJointIndex: MyAvatar.getJointIndex("Head"), - dimensions: { x: textWidth, y: textHeight }, - backgroundColor: { red: 0, green: 0, blue: 0 }, - color: { red: 255, green: 255, blue: 255 }, - topMargin: textMargin, - leftMargin: textMargin, - bottomMargin: textMargin, - rightMargin: textMargin, - text: "", - lineHeight: lineHeight, - alpha: 0.9, - backgroundAlpha: 0.9, - ignoreRayIntersection: true, - visible: true, - isFacingAvatar: true - }); - } + //_this.debugOverlayID = Overlays.addOverlay("text3d", { + //localPosition: { x: 0.3, y: 0.2, z: 1.1 }, + //localRotation: { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }, + //parentID: MyAvatar.sessionUUID, + //parentJointIndex: MyAvatar.getJointIndex("Head"), + //dimensions: { x: textWidth, y: textHeight }, + //backgroundColor: { red: 0, green: 0, blue: 0 }, + //color: { red: 255, green: 255, blue: 255 }, + //topMargin: textMargin, + //leftMargin: textMargin, + //bottomMargin: textMargin, + //rightMargin: textMargin, + //text: "", + //lineHeight: lineHeight, + //alpha: 0.9, + //backgroundAlpha: 0.9, + //ignoreRayIntersection: true, + //visible: true, + //isFacingAvatar: true + //}); + //} - var debugText = ""; - Object.keys(_this.runningPluginNames).forEach(function (pluginName) { - if (_this.runningPluginNames[pluginName]) { - var plugin = controllerDispatcherPlugins[pluginName]; - debugText += pluginName + ": " + plugin.parameters.priority + "\n"; - } - }); - Overlays.editOverlay(_this.debugOverlayID, { text: debugText }); - } + //var debugText = ""; + //Object.keys(_this.runningPluginNames).forEach(function (pluginName) { + //if (_this.runningPluginNames[pluginName]) { + //var plugin = controllerDispatcherPlugins[pluginName]; + //debugText += pluginName + ": " + plugin.parameters.priority + "\n"; + //} + //}); + //Overlays.editOverlay(_this.debugOverlayID, { text: debugText }); + /*}*/ if (PROFILE) { Script.endProfileRange("dispatch.run"); diff --git a/scripts/system/controllers/controllerModules/' b/scripts/system/controllers/controllerModules/' new file mode 100644 index 0000000000..8217e0d022 --- /dev/null +++ b/scripts/system/controllers/controllerModules/' @@ -0,0 +1,181 @@ +"use strict"; + +// webSurfaceLaserInput.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, Entities, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, + makeRunningValues, Messages, Quat, Vec3, makeDispatcherModuleParameters, Overlays, ZERO_VEC, HMD, + INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, + COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE, + TRIGGER_OFF_VALUE, getEnabledModuleByName, PICK_MAX_DISTANCE, ContextOverlay, Picks, makeLaserParams +*/ + +Script.include("/~/system/libraries/controllerDispatcherUtils.js"); +Script.include("/~/system/libraries/controllers.js"); + +(function() { + function WebSurfaceLaserInput(hand) { + this.hand = hand; + this.otherHand = this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND; + this.running = false; + + this.parameters = makeDispatcherModuleParameters( + 160, + this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], + [], + 100, + makeLaserParams(hand, true)); + + this.grabModuleWantsNearbyOverlay = function(controllerData) { + if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { + var nearGrabName = this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"; + var nearGrabModule = getEnabledModuleByName(nearGrabName); + if (nearGrabModule) { + var candidateOverlays = controllerData.nearbyOverlayIDs[this.hand]; + var grabbableOverlays = candidateOverlays.filter(function(overlayID) { + return Overlays.getProperty(overlayID, "grabbable"); + }); + var target = nearGrabModule.getTargetID(grabbableOverlays, controllerData); + if (target) { + return true; + } + } + nearGrabName = this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity"; + nearGrabModule = getEnabledModuleByName(nearGrabName); + if (nearGrabModule && nearGrabModule.isReady(controllerData)) { + return nearGrabModule.isReady(controllerData).active; + } + nearGrabName = this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity"; + nearGrabModule = getEnabledModuleByName(nearGrabName); + if (nearGrabModule && nearGrabModule.isReady(controllerData)) { + return nearGrabModule.isReady(controllerData).active; + } + } + return false; + }; + + this.getOtherModule = function() { + return this.hand === RIGHT_HAND ? leftOverlayLaserInput : rightOverlayLaserInput; + }; + + this.isPointingAtNearGrabbableEntity = function(controllerData, triggerPressed) { + // we are searching for an entity that is not a web entity. We want to be able to + // grab a non-web entity if the ray-pick intersects one. + var intersection = controllerData.rayPicks[this.hand]; + if (intersection.type === Picks.INTERSECTED_ENTITY) { + // is pointing at an entity. + var entityProperties = Entities.getEntityProperties(intersection.objectID); + var entityType = entityProperties.type; + if (entityIsGrabbable(entityProperties) && entityType !== "Web") { + // check if entity is near grabbable. + var distance = Vec3.distance(entityProperties.position, controllerData.controllerLocations[this.hand].position); + if (distance >= NEAR_GRAB_RADIUS * MyAvatar.sensorToWorldScale) { + // far-grabbable, but still return it as true anyway + return true; + } + } + } + return false; + }; + + this.isPointingAtTriggerable = function(controllerData, triggerPressed) { + // allow pointing at tablet, unlocked web entities, or web overlays automatically without pressing trigger, + // but for pointing at locked web entities or non-web overlays user must be pressing trigger + var intersection = controllerData.rayPicks[this.hand]; + var objectID = intersection.objectID; + if (intersection.type === Picks.INTERSECTED_OVERLAY) { + if ((HMD.tabletID && objectID === HMD.tabletID) || + (HMD.tabletScreenID && objectID === HMD.tabletScreenID) || + (HMD.homeButtonID && objectID === HMD.homeButtonID)) { + return true; + } else { + var overlayType = Overlays.getOverlayType(objectID); + return overlayType === "web3d" || triggerPressed; + } + } else if (intersection.type === Picks.INTERSECTED_ENTITY) { + var entityProperty = Entities.getEntityProperties(objectID); + var entityType = entityProperty.type; + var isLocked = entityProperty.locked; + return (!isLocked || triggerPressed || entityType === "Web"); + } + return false; + }; + + this.deleteContextOverlay = function() { + var farGrabModule = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightFarActionGrabEntity" : "LeftFarActionGrabEntity"); + if (farGrabModule) { + var entityWithContextOverlay = farGrabModule.entityWithContextOverlay; + + if (entityWithContextOverlay) { + ContextOverlay.destroyContextOverlay(entityWithContextOverlay); + farGrabModule.entityWithContextOverlay = false; + } + } + }; + + this.updateAllwaysOn = function() { + var PREFER_STYLUS_OVER_LASER = "preferStylusOverLaser"; + this.parameters.handLaser.allwaysOn = !Settings.getValue(PREFER_STYLUS_OVER_LASER, false); + }; + + this.getDominantHand = function() { + return MyAvatar.getDominantHand() === "right" ? 1 : 0; + }; + + this.dominantHandOverride = false; + + this.isReady = function(controllerData) { + var otherModuleRunning = this.getOtherModule().running; + otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand. + var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE && + controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE; + var allowThisModule = !otherModuleRunning || isTriggerPressed; + if (allowThisModule && this.isPointingAtTriggerable(controllerData, isTriggerPressed) && + (controllerData.nearbyEntityProperties[this.hand] !== [])) { + this.updateAllwaysOn(); + if (isTriggerPressed) { + this.dominantHandOverride = true; // Override dominant hand. + this.getOtherModule().dominantHandOverride = false; + } + if (this.parameters.handLaser.allwaysOn || isTriggerPressed) { + return makeRunningValues(true, [], []); + } + } + return makeRunningValues(false, [], []); + }; + + this.run = function(controllerData, deltaTime) { + var otherModuleRunning = this.getOtherModule().running; + otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand. + otherModuleRunning = otherModuleRunning || this.getOtherModule().dominantHandOverride; // Override dominant hand. + var grabModuleNeedsToRun = this.grabModuleWantsNearbyOverlay(controllerData); + var allowThisModule = !otherModuleRunning && !grabModuleNeedsToRun; + var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE; + var laserOn = isTriggerPressed || this.parameters.handLaser.allwaysOn; + if (allowThisModule && (laserOn && this.isPointingAtTriggerable(controllerData, isTriggerPressed)) && + (controllerData.nearbyEntityProperties[this.hand] !== [] || (this.isPointingAtNearGrabbableEntity(controllerData, isTriggerPressed)))) { + this.running = true; + return makeRunningValues(true, [], []); + } + this.deleteContextOverlay(); + this.running = false; + this.dominantHandOverride = false; + return makeRunningValues(false, [], []); + }; + } + + var leftOverlayLaserInput = new WebSurfaceLaserInput(LEFT_HAND); + var rightOverlayLaserInput = new WebSurfaceLaserInput(RIGHT_HAND); + + enableDispatcherModule("LeftWebSurfaceLaserInput", leftOverlayLaserInput); + enableDispatcherModule("RightWebSurfaceLaserInput", rightOverlayLaserInput); + + function cleanup() { + disableDispatcherModule("LeftWebSurfaceLaserInput"); + disableDispatcherModule("RightWebSurfaceLaserInput"); + } + Script.scriptEnding.connect(cleanup); +}()); diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index 16cf2eef5c..dd7bccf667 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -60,7 +60,7 @@ Script.include("/~/system/libraries/controllers.js"); return this.hand === RIGHT_HAND ? leftOverlayLaserInput : rightOverlayLaserInput; }; - this.isPointingAtNearGrabbableEntity = function(controllerData, triggerPressed) { + this.isPointingAtFarGrabbableEntity = function(controllerData, triggerPressed) { // we are searching for an entity that is not a web entity. We want to be able to // grab a non-web entity if the ray-pick intersects one. var intersection = controllerData.rayPicks[this.hand]; @@ -71,9 +71,7 @@ Script.include("/~/system/libraries/controllers.js"); if (entityIsGrabbable(entityProperties) && entityType !== "Web") { // check if entity is near grabbable. var distance = Vec3.distance(entityProperties.position, controllerData.controllerLocations[this.hand].position); - if (distance <= NEAR_GRAB_RADIUS * MyAvatar.sensorToWorldScale) { - return triggerPressed; - } else { + if (distance >= NEAR_GRAB_RADIUS * MyAvatar.sensorToWorldScale) { // far-grabbable, but still return it as true anyway return true; } @@ -135,8 +133,8 @@ Script.include("/~/system/libraries/controllers.js"); var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE && controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE; var allowThisModule = !otherModuleRunning || isTriggerPressed; - if (allowThisModule && this.isPointingAtTriggerable(controllerData, isTriggerPressed) && - !this.isPointingAtNearGrabbableEntity(controllerData, isTriggerPressed)) { + if (allowThisModule && this.isPointingAtTriggerable(controllerData, isTriggerPressed) && + (controllerData.nearbyEntityProperties[this.hand] !== [])) { this.updateAllwaysOn(); if (isTriggerPressed) { this.dominantHandOverride = true; // Override dominant hand. @@ -158,7 +156,7 @@ Script.include("/~/system/libraries/controllers.js"); var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE; var laserOn = isTriggerPressed || this.parameters.handLaser.allwaysOn; if (allowThisModule && (laserOn && this.isPointingAtTriggerable(controllerData, isTriggerPressed)) && - !this.isPointingAtNearGrabbableEntity(controllerData, isTriggerPressed)) { + (controllerData.nearbyEntityProperties[this.hand] !== [] || !(this.isPointingAtFarGrabbableEntity(controllerData, isTriggerPressed)))) { this.running = true; return makeRunningValues(true, [], []); }