mirror of
https://github.com/overte-org/overte.git
synced 2025-07-23 11:44:09 +02:00
use new-style far-grabbing code for mouse grabs
This commit is contained in:
parent
73a5f30350
commit
174c79d66d
2 changed files with 33 additions and 158 deletions
|
@ -3368,7 +3368,8 @@ void EntityItem::addGrab(GrabPointer grab) {
|
||||||
EntityDynamicType dynamicType;
|
EntityDynamicType dynamicType;
|
||||||
QVariantMap arguments;
|
QVariantMap arguments;
|
||||||
int grabParentJointIndex =grab->getParentJointIndex();
|
int grabParentJointIndex =grab->getParentJointIndex();
|
||||||
if (grabParentJointIndex == FARGRAB_RIGHTHAND_INDEX || grabParentJointIndex == FARGRAB_LEFTHAND_INDEX) {
|
if (grabParentJointIndex == FARGRAB_RIGHTHAND_INDEX || grabParentJointIndex == FARGRAB_LEFTHAND_INDEX ||
|
||||||
|
grabParentJointIndex == FARGRAB_MOUSE_INDEX) {
|
||||||
// add a far-grab action
|
// add a far-grab action
|
||||||
dynamicType = DYNAMIC_TYPE_FAR_GRAB;
|
dynamicType = DYNAMIC_TYPE_FAR_GRAB;
|
||||||
arguments["otherID"] = grab->getOwnerID();
|
arguments["otherID"] = grab->getOwnerID();
|
||||||
|
|
|
@ -14,79 +14,25 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
/* global MyAvatar, Entities, Script, HMD, Camera, Vec3, Reticle, Overlays, getEntityCustomData, Messages, Quat, Controller,
|
/* global MyAvatar, Entities, Script, HMD, Camera, Vec3, Reticle, Overlays, Messages, Quat, Controller,
|
||||||
isInEditMode, entityIsGrabbable, Picks, PickType, Pointers, unhighlightTargetEntity, DISPATCHER_PROPERTIES,
|
isInEditMode, entityIsGrabbable, Picks, PickType, Pointers, unhighlightTargetEntity, DISPATCHER_PROPERTIES,
|
||||||
entityIsGrabbable, entityIsEquipped, getMainTabletIDs
|
entityIsGrabbable, getMainTabletIDs
|
||||||
*/
|
*/
|
||||||
/* jslint bitwise: true */
|
/* jslint bitwise: true */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
Script.include("/~/system/libraries/utils.js");
|
Script.include("/~/system/libraries/utils.js");
|
||||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
|
|
||||||
|
var FAR_GRAB_JOINT = 65526; // FARGRAB_MOUSE_INDEX
|
||||||
|
|
||||||
var MAX_SOLID_ANGLE = 0.01; // objects that appear smaller than this can't be grabbed
|
var MAX_SOLID_ANGLE = 0.01; // objects that appear smaller than this can't be grabbed
|
||||||
|
|
||||||
var DELAY_FOR_30HZ = 33; // milliseconds
|
var DELAY_FOR_30HZ = 33; // milliseconds
|
||||||
|
|
||||||
var ZERO_VEC3 = {
|
var ZERO_VEC3 = { x: 0, y: 0, z: 0 };
|
||||||
x: 0,
|
var IDENTITY_QUAT = { x: 0, y: 0, z: 0, w: 1 };
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
};
|
|
||||||
var IDENTITY_QUAT = {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0,
|
|
||||||
w: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
var DEFAULT_GRABBABLE_DATA = {
|
|
||||||
grabbable: true,
|
|
||||||
invertSolidWhileHeld: false
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var ACTION_TTL = 10; // seconds
|
|
||||||
|
|
||||||
function getTag() {
|
|
||||||
return "grab-" + MyAvatar.sessionUUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position
|
|
||||||
var DISTANCE_HOLDING_UNITY_MASS = 1200; // The mass at which the distance holding action timeframe is unmodified
|
|
||||||
var DISTANCE_HOLDING_UNITY_DISTANCE = 6; // The distance at which the distance holding action timeframe is unmodified
|
|
||||||
|
|
||||||
function distanceGrabTimescale(mass, distance) {
|
|
||||||
var timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME * mass /
|
|
||||||
DISTANCE_HOLDING_UNITY_MASS * distance /
|
|
||||||
DISTANCE_HOLDING_UNITY_DISTANCE;
|
|
||||||
if (timeScale < DISTANCE_HOLDING_ACTION_TIMEFRAME) {
|
|
||||||
timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME;
|
|
||||||
}
|
|
||||||
return timeScale;
|
|
||||||
}
|
|
||||||
function getMass(dimensions, density) {
|
|
||||||
return (dimensions.x * dimensions.y * dimensions.z) * density;
|
|
||||||
}
|
|
||||||
|
|
||||||
function entityIsGrabbedByOther(entityID) {
|
|
||||||
// by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*.
|
|
||||||
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 == getTag()) {
|
|
||||||
// we see a grab-*uuid* shaped tag, but it's our tag, so that's okay.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (tag.slice(0, 5) == "grab-") {
|
|
||||||
// we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function
|
// helper function
|
||||||
function mouseIntersectionWithPlane(pointOnPlane, planeNormal, event, maxDistance) {
|
function mouseIntersectionWithPlane(pointOnPlane, planeNormal, event, maxDistance) {
|
||||||
|
@ -227,7 +173,6 @@ var beacon = {
|
||||||
function Grabber() {
|
function Grabber() {
|
||||||
this.isGrabbing = false;
|
this.isGrabbing = false;
|
||||||
this.entityID = null;
|
this.entityID = null;
|
||||||
this.actionID = null;
|
|
||||||
this.startPosition = ZERO_VEC3;
|
this.startPosition = ZERO_VEC3;
|
||||||
this.lastRotation = IDENTITY_QUAT;
|
this.lastRotation = IDENTITY_QUAT;
|
||||||
this.currentPosition = ZERO_VEC3;
|
this.currentPosition = ZERO_VEC3;
|
||||||
|
@ -253,9 +198,6 @@ function Grabber() {
|
||||||
z: 0
|
z: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
this.targetPosition = null;
|
|
||||||
this.targetRotation = null;
|
|
||||||
|
|
||||||
this.liftKey = false; // SHIFT
|
this.liftKey = false; // SHIFT
|
||||||
this.rotateKey = false; // CONTROL
|
this.rotateKey = false; // CONTROL
|
||||||
|
|
||||||
|
@ -305,7 +247,7 @@ Grabber.prototype.computeNewGrabPlane = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pointOnPlane = Vec3.sum(this.currentPosition, this.offset);
|
this.pointOnPlane = Vec3.subtract(this.currentPosition, this.offset);
|
||||||
var xzOffset = Vec3.subtract(this.pointOnPlane, Camera.getPosition());
|
var xzOffset = Vec3.subtract(this.pointOnPlane, Camera.getPosition());
|
||||||
xzOffset.y = 0;
|
xzOffset.y = 0;
|
||||||
this.xzDistanceToGrab = Vec3.length(xzOffset);
|
this.xzDistanceToGrab = Vec3.length(xzOffset);
|
||||||
|
@ -341,16 +283,11 @@ Grabber.prototype.pressEvent = function(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var props = Entities.getEntityProperties(pickResults.objectID, DISPATCHER_PROPERTIES);
|
var props = Entities.getEntityProperties(pickResults.objectID, DISPATCHER_PROPERTIES);
|
||||||
var isDynamic = props.dynamic;
|
|
||||||
if (!entityIsGrabbable(props)) {
|
if (!entityIsGrabbable(props)) {
|
||||||
// only grab grabbable objects
|
// only grab grabbable objects
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!props.grab.grabbable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pointers.setRenderState(this.mouseRayEntities, "grabbed");
|
Pointers.setRenderState(this.mouseRayEntities, "grabbed");
|
||||||
Pointers.setLockEndUUID(this.mouseRayEntities, pickResults.objectID, false);
|
Pointers.setLockEndUUID(this.mouseRayEntities, pickResults.objectID, false);
|
||||||
unhighlightTargetEntity(pickResults.objectID);
|
unhighlightTargetEntity(pickResults.objectID);
|
||||||
|
@ -361,7 +298,6 @@ Grabber.prototype.pressEvent = function(event) {
|
||||||
var entityProperties = Entities.getEntityProperties(clickedEntity, DISPATCHER_PROPERTIES);
|
var entityProperties = Entities.getEntityProperties(clickedEntity, DISPATCHER_PROPERTIES);
|
||||||
this.startPosition = entityProperties.position;
|
this.startPosition = entityProperties.position;
|
||||||
this.lastRotation = entityProperties.rotation;
|
this.lastRotation = entityProperties.rotation;
|
||||||
this.madeDynamic = false;
|
|
||||||
var cameraPosition = Camera.getPosition();
|
var cameraPosition = Camera.getPosition();
|
||||||
|
|
||||||
var objectBoundingDiameter = Vec3.length(entityProperties.dimensions);
|
var objectBoundingDiameter = Vec3.length(entityProperties.dimensions);
|
||||||
|
@ -373,21 +309,10 @@ Grabber.prototype.pressEvent = function(event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entityIsGrabbable(props) && !isDynamic) {
|
|
||||||
entityProperties.dynamic = true;
|
|
||||||
Entities.editEntity(clickedEntity, entityProperties);
|
|
||||||
this.madeDynamic = true;
|
|
||||||
}
|
|
||||||
// this.activateEntity(clickedEntity, entityProperties);
|
|
||||||
this.isGrabbing = true;
|
this.isGrabbing = true;
|
||||||
|
|
||||||
this.entityID = clickedEntity;
|
this.entityID = clickedEntity;
|
||||||
this.currentPosition = entityProperties.position;
|
this.currentPosition = entityProperties.position;
|
||||||
this.targetPosition = {
|
|
||||||
x: this.startPosition.x,
|
|
||||||
y: this.startPosition.y,
|
|
||||||
z: this.startPosition.z
|
|
||||||
};
|
|
||||||
|
|
||||||
// compute the grab point
|
// compute the grab point
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
@ -396,14 +321,13 @@ Grabber.prototype.pressEvent = function(event) {
|
||||||
nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction);
|
nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction);
|
||||||
this.pointOnPlane = Vec3.sum(cameraPosition, nearestPoint);
|
this.pointOnPlane = Vec3.sum(cameraPosition, nearestPoint);
|
||||||
|
|
||||||
// compute the grab offset (points from object center to point of grab)
|
MyAvatar.setJointTranslation(FAR_GRAB_JOINT, MyAvatar.worldToJointPoint(this.startPosition));
|
||||||
this.offset = Vec3.subtract(this.pointOnPlane, this.startPosition);
|
MyAvatar.setJointRotation(FAR_GRAB_JOINT, MyAvatar.worldToJointRotation(this.lastRotation));
|
||||||
|
|
||||||
|
this.offset = Vec3.subtract(this.startPosition, this.pointOnPlane); // offset in world-space
|
||||||
|
|
||||||
this.computeNewGrabPlane();
|
this.computeNewGrabPlane();
|
||||||
|
this.moveEvent(event);
|
||||||
if (!entityIsGrabbedByOther(this.entityID)) {
|
|
||||||
this.moveEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
var args = "mouse";
|
var args = "mouse";
|
||||||
Entities.callEntityMethod(this.entityID, "startDistanceGrab", args);
|
Entities.callEntityMethod(this.entityID, "startDistanceGrab", args);
|
||||||
|
@ -413,6 +337,8 @@ Grabber.prototype.pressEvent = function(event) {
|
||||||
grabbedEntity: this.entityID
|
grabbedEntity: this.entityID
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this.grabID = MyAvatar.grab(this.entityID, FAR_GRAB_JOINT, ZERO_VEC3, IDENTITY_QUAT);
|
||||||
|
|
||||||
// TODO: play sounds again when we aren't leaking AudioInjector threads
|
// TODO: play sounds again when we aren't leaking AudioInjector threads
|
||||||
//Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME });
|
//Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME });
|
||||||
};
|
};
|
||||||
|
@ -428,20 +354,7 @@ Grabber.prototype.releaseEvent = function(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isGrabbing) {
|
if (this.isGrabbing) {
|
||||||
// this.deactivateEntity(this.entityID);
|
|
||||||
this.isGrabbing = false;
|
this.isGrabbing = false;
|
||||||
if (this.actionID) {
|
|
||||||
Entities.deleteAction(this.entityID, this.actionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.madeDynamic) {
|
|
||||||
var entityProps = {};
|
|
||||||
entityProps.dynamic = false;
|
|
||||||
entityProps.localVelocity = {x: 0, y: 0, z: 0};
|
|
||||||
Entities.editEntity(this.entityID, entityProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.actionID = null;
|
|
||||||
|
|
||||||
Pointers.setRenderState(this.mouseRayEntities, "");
|
Pointers.setRenderState(this.mouseRayEntities, "");
|
||||||
Pointers.setLockEndUUID(this.mouseRayEntities, null, false);
|
Pointers.setLockEndUUID(this.mouseRayEntities, null, false);
|
||||||
|
@ -455,6 +368,13 @@ Grabber.prototype.releaseEvent = function(event) {
|
||||||
joint: "mouse"
|
joint: "mouse"
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (this.grabID) {
|
||||||
|
MyAvatar.releaseGrab(this.grabID);
|
||||||
|
this.grabID = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
MyAvatar.clearJointData(FAR_GRAB_JOINT);
|
||||||
|
|
||||||
// TODO: play sounds again when we aren't leaking AudioInjector threads
|
// TODO: play sounds again when we aren't leaking AudioInjector threads
|
||||||
//Audio.playSound(releaseSound, { position: entityProperties.position, volume: VOLUME });
|
//Audio.playSound(releaseSound, { position: entityProperties.position, volume: VOLUME });
|
||||||
}
|
}
|
||||||
|
@ -482,23 +402,12 @@ Grabber.prototype.moveEvent = function(event) {
|
||||||
|
|
||||||
Grabber.prototype.moveEventProcess = function() {
|
Grabber.prototype.moveEventProcess = function() {
|
||||||
this.moveEventTimer = null;
|
this.moveEventTimer = null;
|
||||||
// see if something added/restored gravity
|
|
||||||
var entityProperties = Entities.getEntityProperties(this.entityID, DISPATCHER_PROPERTIES);
|
var entityProperties = Entities.getEntityProperties(this.entityID, DISPATCHER_PROPERTIES);
|
||||||
if (!entityProperties || !entityProperties.gravity || HMD.active) {
|
if (!entityProperties || HMD.active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Vec3.length(entityProperties.gravity) !== 0.0) {
|
|
||||||
this.originalGravity = entityProperties.gravity;
|
|
||||||
}
|
|
||||||
this.currentPosition = entityProperties.position;
|
this.currentPosition = entityProperties.position;
|
||||||
this.mass = getMass(entityProperties.dimensions, entityProperties.density);
|
|
||||||
var cameraPosition = Camera.getPosition();
|
|
||||||
|
|
||||||
var actionArgs = {
|
|
||||||
tag: getTag(),
|
|
||||||
ttl: ACTION_TTL
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.mode === "rotate") {
|
if (this.mode === "rotate") {
|
||||||
var drag = mouse.getDrag();
|
var drag = mouse.getDrag();
|
||||||
|
@ -510,19 +419,9 @@ Grabber.prototype.moveEventProcess = function() {
|
||||||
var ROTATE_STRENGTH = 0.4; // magic number tuned by hand
|
var ROTATE_STRENGTH = 0.4; // magic number tuned by hand
|
||||||
var angle = ROTATE_STRENGTH * Math.sqrt((drag.x * drag.x) + (drag.y * drag.y));
|
var angle = ROTATE_STRENGTH * Math.sqrt((drag.x * drag.x) + (drag.y * drag.y));
|
||||||
var deltaQ = Quat.angleAxis(angle, axis);
|
var deltaQ = Quat.angleAxis(angle, axis);
|
||||||
// var qZero = entityProperties.rotation;
|
|
||||||
//var qZero = this.lastRotation;
|
|
||||||
this.lastRotation = Quat.multiply(deltaQ, this.lastRotation);
|
this.lastRotation = Quat.multiply(deltaQ, this.lastRotation);
|
||||||
|
MyAvatar.setJointRotation(FAR_GRAB_JOINT, MyAvatar.worldToJointRotation(this.lastRotation));
|
||||||
var distanceToCameraR = Vec3.length(Vec3.subtract(this.currentPosition, cameraPosition));
|
|
||||||
var angularTimeScale = distanceGrabTimescale(this.mass, distanceToCameraR);
|
|
||||||
|
|
||||||
actionArgs = {
|
|
||||||
targetRotation: this.lastRotation,
|
|
||||||
angularTimeScale: angularTimeScale,
|
|
||||||
tag: getTag(),
|
|
||||||
ttl: ACTION_TTL
|
|
||||||
};
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var newPointOnPlane;
|
var newPointOnPlane;
|
||||||
|
@ -534,17 +433,10 @@ Grabber.prototype.moveEventProcess = function() {
|
||||||
planeNormal = Vec3.normalize(planeNormal);
|
planeNormal = Vec3.normalize(planeNormal);
|
||||||
var pointOnCylinder = Vec3.multiply(planeNormal, this.xzDistanceToGrab);
|
var pointOnCylinder = Vec3.multiply(planeNormal, this.xzDistanceToGrab);
|
||||||
pointOnCylinder = Vec3.sum(Camera.getPosition(), pointOnCylinder);
|
pointOnCylinder = Vec3.sum(Camera.getPosition(), pointOnCylinder);
|
||||||
this.pointOnPlane = mouseIntersectionWithPlane(pointOnCylinder, planeNormal, mouse.current, this.maxDistance);
|
newPointOnPlane = mouseIntersectionWithPlane(pointOnCylinder, planeNormal, mouse.current, this.maxDistance);
|
||||||
newPointOnPlane = {
|
|
||||||
x: this.pointOnPlane.x,
|
|
||||||
y: this.pointOnPlane.y,
|
|
||||||
z: this.pointOnPlane.z
|
|
||||||
};
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
var cameraPosition = Camera.getPosition();
|
||||||
newPointOnPlane = mouseIntersectionWithPlane(
|
newPointOnPlane = mouseIntersectionWithPlane(this.pointOnPlane, this.planeNormal, mouse.current, this.maxDistance);
|
||||||
this.pointOnPlane, this.planeNormal, mouse.current, this.maxDistance);
|
|
||||||
var relativePosition = Vec3.subtract(newPointOnPlane, cameraPosition);
|
var relativePosition = Vec3.subtract(newPointOnPlane, cameraPosition);
|
||||||
var distance = Vec3.length(relativePosition);
|
var distance = Vec3.length(relativePosition);
|
||||||
if (distance > this.maxDistance) {
|
if (distance > this.maxDistance) {
|
||||||
|
@ -553,26 +445,8 @@ Grabber.prototype.moveEventProcess = function() {
|
||||||
newPointOnPlane = Vec3.sum(relativePosition, cameraPosition);
|
newPointOnPlane = Vec3.sum(relativePosition, cameraPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.targetPosition = Vec3.subtract(newPointOnPlane, this.offset);
|
|
||||||
|
|
||||||
var distanceToCameraL = Vec3.length(Vec3.subtract(this.targetPosition, cameraPosition));
|
MyAvatar.setJointTranslation(FAR_GRAB_JOINT, MyAvatar.worldToJointPoint(Vec3.sum(newPointOnPlane, this.offset)));
|
||||||
var linearTimeScale = distanceGrabTimescale(this.mass, distanceToCameraL);
|
|
||||||
|
|
||||||
actionArgs = {
|
|
||||||
targetPosition: this.targetPosition,
|
|
||||||
linearTimeScale: linearTimeScale,
|
|
||||||
tag: getTag(),
|
|
||||||
ttl: ACTION_TTL
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.actionID) {
|
|
||||||
if (!entityIsGrabbedByOther(this.entityID) && !entityIsEquipped(this.entityID)) {
|
|
||||||
this.actionID = Entities.addAction("far-grab", this.entityID, actionArgs);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Entities.updateAction(this.entityID, this.actionID, actionArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scheduleMouseMoveProcessor();
|
this.scheduleMouseMoveProcessor();
|
||||||
|
|
Loading…
Reference in a new issue