diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index d79c2bd236..06853fa4ba 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -7,7 +7,7 @@ /*jslint bitwise: true */ -/* global Script, Entities, Overlays, Controller, Vec3, getControllerWorldLocation, RayPick, +/* global Script, Entities, Overlays, Controller, Vec3, Quat, getControllerWorldLocation, RayPick, controllerDispatcherPlugins, controllerDispatcherPluginsNeedSort, entityIsGrabbable, LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS */ @@ -212,6 +212,14 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); ]; // if the pickray hit something very nearby, put it into the nearby entities list for (h = LEFT_HAND; h <= RIGHT_HAND; h++) { + + // XXX find a way to extract searchRay from samuel's stuff + rayPicks[h].searchRay = { + origin: controllerLocations[h].position, + direction: Quat.getUp(controllerLocations[h].orientation), + length: 1000 + }; + var nearEntityID = rayPicks[h].entityID; if (nearEntityID) { // XXX check to make sure this one isn't already in nearbyEntityProperties? diff --git a/scripts/system/controllers/controllerDispatcherUtils.js b/scripts/system/controllers/controllerDispatcherUtils.js index e52c158219..cdf8729d9c 100644 --- a/scripts/system/controllers/controllerDispatcherUtils.js +++ b/scripts/system/controllers/controllerDispatcherUtils.js @@ -26,7 +26,10 @@ entityIsGrabbable, getControllerJointIndex, propsArePhysical, - controllerDispatcherPluginsNeedSort + controllerDispatcherPluginsNeedSort, + projectOntoXYPlane, + projectOntoEntityXYPlane, + projectOntoOverlayXYPlane */ MSECS_PER_SEC = 1000.0; @@ -162,3 +165,41 @@ propsArePhysical = function (props) { var isPhysical = (props.shapeType && props.shapeType != 'none'); return isPhysical; }; + +projectOntoXYPlane = function (worldPos, position, rotation, dimensions, registrationPoint) { + var invRot = Quat.inverse(rotation); + var localPos = Vec3.multiplyQbyV(invRot, Vec3.subtract(worldPos, position)); + var invDimensions = { x: 1 / dimensions.x, + y: 1 / dimensions.y, + z: 1 / dimensions.z }; + var normalizedPos = Vec3.sum(Vec3.multiplyVbyV(localPos, invDimensions), registrationPoint); + return { x: normalizedPos.x * dimensions.x, + y: (1 - normalizedPos.y) * dimensions.y }; // flip y-axis +} + +projectOntoEntityXYPlane = function (entityID, worldPos, props) { + return projectOntoXYPlane(worldPos, props.position, props.rotation, props.dimensions, props.registrationPoint); +} + +projectOntoOverlayXYPlane = function projectOntoOverlayXYPlane(overlayID, worldPos) { + var position = Overlays.getProperty(overlayID, "position"); + var rotation = Overlays.getProperty(overlayID, "rotation"); + var dimensions; + + var dpi = Overlays.getProperty(overlayID, "dpi"); + if (dpi) { + // Calculate physical dimensions for web3d overlay from resolution and dpi; "dimensions" property is used as a scale. + var resolution = Overlays.getProperty(overlayID, "resolution"); + resolution.z = 1; // Circumvent divide-by-zero. + var scale = Overlays.getProperty(overlayID, "dimensions"); + scale.z = 0.01; // overlay dimensions are 2D, not 3D. + dimensions = Vec3.multiplyVbyV(Vec3.multiply(resolution, INCHES_TO_METERS / dpi), scale); + } else { + dimensions = Overlays.getProperty(overlayID, "dimensions"); + if (dimensions.z) { + dimensions.z = 0.01; // overlay dimensions are 2D, not 3D. + } + } + + return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT); +} diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js index 8017f457fe..42859f3e19 100644 --- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js @@ -167,6 +167,8 @@ Script.include("/~/system/libraries/controllers.js"); return makeRunningValues(false, [], []); // let nearParentGrabEntity handle it } else { this.targetEntityID = targetProps.id; + ContextOverlay.entityWithContextOverlay = this.targetEntityID; + ContextOverlay.enabled = true; // XXX highlight this.targetEntityID here return makeRunningValues(true, [this.targetEntityID], []); } @@ -188,16 +190,35 @@ Script.include("/~/system/libraries/controllers.js"); var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "continueNearGrab", args); } else { - // still searching / highlighting + + // still searching / highlighting var readiness = this.isReady (controllerData); if (!readiness.active) { return readiness; } - if (controllerData.triggerClicks[this.hand] == 1) { - // stop highlighting, switch to grabbing - // XXX stop highlight here - var targetProps = this.getTargetProps(controllerData); - if (targetProps) { + + var targetProps = this.getTargetProps(controllerData); + if (targetProps) { + + // XXX + var rayPickInfo = controllerData.rayPicks[this.hand]; + var pointerEvent = { + type: "Move", + id: this.hand + 1, // 0 is reserved for hardware mouse + pos2D: projectOntoEntityXYPlane(rayPickInfo.entityID, rayPickInfo.intersection, targetProps), + pos3D: rayPickInfo.intersection, + normal: rayPickInfo.normal, + direction: rayPickInfo.searchRay.direction, + button: "Secondary" + }; + if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.entityID, pointerEvent)) { + } + // XXX + + + if (controllerData.triggerClicks[this.hand] == 1) { + // stop highlighting, switch to grabbing + // XXX stop highlight here this.startNearGrabAction(controllerData, targetProps); } }