mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-26 01:55:08 +02:00
250 lines
7.8 KiB
JavaScript
250 lines
7.8 KiB
JavaScript
//
|
|
// hand.js
|
|
//
|
|
// Created by David Rowe on 21 Jul 2017.
|
|
// Copyright 2017 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
/* global Hand:true */
|
|
|
|
Hand = function (side) {
|
|
|
|
"use strict";
|
|
|
|
// Hand controller input.
|
|
var handController,
|
|
controllerTrigger,
|
|
controllerTriggerClicked,
|
|
controllerGrip,
|
|
|
|
isGripClicked = false,
|
|
isGripClickedHandled = false,
|
|
GRIP_ON_VALUE = 0.99,
|
|
GRIP_OFF_VALUE = 0.95,
|
|
|
|
isTriggerPressed,
|
|
isTriggerClicked,
|
|
TRIGGER_ON_VALUE = 0.15, // Per controllerDispatcherUtils.js.
|
|
TRIGGER_OFF_VALUE = 0.1, // Per controllerDispatcherUtils.js.
|
|
TRIGGER_CLICKED_VALUE = 1.0,
|
|
|
|
NEAR_GRAB_RADIUS = 0.05, // Different from controllerDispatcherUtils.js.
|
|
NEAR_HOVER_RADIUS = 0.025,
|
|
|
|
LEFT_HAND = 0,
|
|
HALF_TREE_SCALE = 16384,
|
|
|
|
handPose,
|
|
handPosition,
|
|
handOrientation,
|
|
palmPosition,
|
|
|
|
handleOverlayIDs = [],
|
|
intersection = {};
|
|
|
|
if (!(this instanceof Hand)) {
|
|
return new Hand(side);
|
|
}
|
|
|
|
if (side === LEFT_HAND) {
|
|
handController = Controller.Standard.LeftHand;
|
|
controllerTrigger = Controller.Standard.LT;
|
|
controllerTriggerClicked = Controller.Standard.LTClick;
|
|
controllerGrip = Controller.Standard.LeftGrip;
|
|
} else {
|
|
handController = Controller.Standard.RightHand;
|
|
controllerTrigger = Controller.Standard.RT;
|
|
controllerTriggerClicked = Controller.Standard.RTClick;
|
|
controllerGrip = Controller.Standard.RightGrip;
|
|
}
|
|
|
|
function setHandleOverlays(overlayIDs) {
|
|
handleOverlayIDs = overlayIDs;
|
|
}
|
|
|
|
function valid() {
|
|
return handPose.valid;
|
|
}
|
|
|
|
function position() {
|
|
return handPosition;
|
|
}
|
|
|
|
function orientation() {
|
|
return handOrientation;
|
|
}
|
|
|
|
function getPalmPosition() {
|
|
return palmPosition;
|
|
}
|
|
|
|
function triggerPressed() {
|
|
return isTriggerPressed;
|
|
}
|
|
|
|
function triggerClicked() {
|
|
return isTriggerClicked;
|
|
}
|
|
|
|
function gripClicked() {
|
|
return isGripClicked;
|
|
}
|
|
|
|
function setGripClickedHandled() {
|
|
isGripClicked = false;
|
|
isGripClickedHandled = true;
|
|
}
|
|
|
|
function getIntersection() {
|
|
return intersection;
|
|
}
|
|
|
|
function getNearGrabRadius() {
|
|
return NEAR_GRAB_RADIUS;
|
|
}
|
|
|
|
function update() {
|
|
var gripValue,
|
|
overlayID,
|
|
overlayIDs,
|
|
overlayDistance,
|
|
intersectionPosition,
|
|
distance,
|
|
entityID,
|
|
entityIDs,
|
|
entitySize,
|
|
size,
|
|
i,
|
|
length;
|
|
|
|
|
|
// Hand pose.
|
|
handPose = Controller.getPoseValue(handController);
|
|
if (!handPose.valid) {
|
|
intersection = {};
|
|
return;
|
|
}
|
|
handPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, handPose.translation), MyAvatar.position);
|
|
handOrientation = Quat.multiply(MyAvatar.orientation, handPose.rotation);
|
|
|
|
// Controller trigger.
|
|
isTriggerPressed = Controller.getValue(controllerTrigger) > (isTriggerPressed
|
|
? TRIGGER_OFF_VALUE : TRIGGER_ON_VALUE);
|
|
isTriggerClicked = Controller.getValue(controllerTriggerClicked) === TRIGGER_CLICKED_VALUE;
|
|
|
|
// Controller grip.
|
|
gripValue = Controller.getValue(controllerGrip);
|
|
if (isGripClicked) {
|
|
isGripClicked = gripValue > GRIP_OFF_VALUE;
|
|
} else {
|
|
isGripClicked = gripValue > GRIP_ON_VALUE;
|
|
}
|
|
// Grip clicked may be being handled by UI.
|
|
if (isGripClicked) {
|
|
isGripClicked = !isGripClickedHandled;
|
|
} else {
|
|
isGripClickedHandled = false;
|
|
}
|
|
|
|
// Hand-overlay intersection, if any handle overlays.
|
|
overlayID = null;
|
|
palmPosition = side === LEFT_HAND ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition();
|
|
if (handleOverlayIDs.length > 0) {
|
|
overlayIDs = Overlays.findOverlays(palmPosition, NEAR_HOVER_RADIUS);
|
|
if (overlayIDs.length > 0) {
|
|
// Typically, there will be only one overlay; optimize for that case.
|
|
overlayID = overlayIDs[0];
|
|
if (overlayIDs.length > 1) {
|
|
// Find closest overlay.
|
|
overlayDistance = Vec3.length(Vec3.subtract(Overlays.getProperty(overlayID, "position"), palmPosition));
|
|
for (i = 1, length = overlayIDs.length; i < length; i++) {
|
|
distance =
|
|
Vec3.length(Vec3.subtract(Overlays.getProperty(overlayIDs[i], "position"), palmPosition));
|
|
if (distance > overlayDistance) {
|
|
overlayID = overlayIDs[i];
|
|
overlayDistance = distance;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (overlayID && handleOverlayIDs.indexOf(overlayID) === -1) {
|
|
overlayID = null;
|
|
}
|
|
if (overlayID) {
|
|
intersectionPosition = Overlays.getProperty(overlayID, "position");
|
|
}
|
|
}
|
|
|
|
// Hand-entity intersection, if any editable, if overlay not intersected.
|
|
entityID = null;
|
|
if (overlayID === null) {
|
|
// palmPosition is set above.
|
|
entityIDs = Entities.findEntities(palmPosition, NEAR_GRAB_RADIUS);
|
|
if (entityIDs.length > 0) {
|
|
// Typically, there will be only one entity; optimize for that case.
|
|
if (Entities.hasEditableRoot(entityIDs[0])) {
|
|
entityID = entityIDs[0];
|
|
}
|
|
if (entityIDs.length > 1) {
|
|
// Find smallest, editable entity.
|
|
entitySize = HALF_TREE_SCALE;
|
|
for (i = 0, length = entityIDs.length; i < length; i++) {
|
|
if (Entities.hasEditableRoot(entityIDs[i])) {
|
|
size = Vec3.length(Entities.getEntityProperties(entityIDs[i], "dimensions").dimensions);
|
|
if (size < entitySize) {
|
|
entityID = entityIDs[i];
|
|
entitySize = size;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (entityID) {
|
|
intersectionPosition = Entities.getEntityProperties(entityID, "position").position;
|
|
if (Vec3.distance(palmPosition, intersectionPosition) > NEAR_GRAB_RADIUS) {
|
|
intersectionPosition = Vec3.sum(palmPosition,
|
|
Vec3.multiply(NEAR_GRAB_RADIUS, Vec3.normalize(Vec3.subtract(intersectionPosition, palmPosition))));
|
|
}
|
|
}
|
|
}
|
|
|
|
intersection = {
|
|
intersects: overlayID !== null || entityID !== null,
|
|
overlayID: overlayID,
|
|
entityID: entityID,
|
|
handIntersected: overlayID !== null || entityID !== null,
|
|
editableEntity: entityID !== null,
|
|
intersection: intersectionPosition
|
|
};
|
|
}
|
|
|
|
function clear() {
|
|
// Nothing to do.
|
|
}
|
|
|
|
function destroy() {
|
|
// Nothing to do.
|
|
}
|
|
|
|
return {
|
|
setHandleOverlays: setHandleOverlays,
|
|
valid: valid,
|
|
position: position,
|
|
orientation: orientation,
|
|
palmPosition: getPalmPosition,
|
|
triggerPressed: triggerPressed,
|
|
triggerClicked: triggerClicked,
|
|
gripClicked: gripClicked,
|
|
setGripClickedHandled: setGripClickedHandled,
|
|
intersection: getIntersection,
|
|
getNearGrabRadius: getNearGrabRadius,
|
|
update: update,
|
|
clear: clear,
|
|
destroy: destroy
|
|
};
|
|
};
|
|
|
|
Hand.prototype = {};
|