content/hifi-content/thoys/dev/2017/whiteboard-rev5/whiteboardToolAttacher_NoHandControllerGrab.js
2022-02-14 02:04:11 +01:00

319 lines
13 KiB
JavaScript

(function() {
Script.include("/~/system/libraries/utils.js");
Script.include("/~/system/libraries/Xform.js");
Script.include("/~/system/libraries/controllers.js");
var MARKER_SCRIPT_URL = Script.resolvePath('markerEntityScript.js');
var ERASER_SCRIPT_URL = Script.resolvePath('eraserEntityScript.js');
// For re-downloading already cached entity scripts
var SCRIPT_UPDATE_DATE = 1484867653634;
var CLIENT_ONLY = true;
var RIGHT_HAND = 1;
var LEFT_HAND = 0;
var HAND_COUNT = 2;
var ZERO_VEC = {
x: 0,
y: 0,
z: 0
};
var ONE_VEC = {
x: 1,
y: 1,
z: 1
};
var DEBUG = true;
// Only fetch property once per 5 sec
var PROPERTIES_FETCH_FREQUENCY = 0.2;
var REQUEST_PROPERTIES = ['position', 'rotation', 'dimensions', 'registrationPoint'];
var FORCE_FOLLOW_IK = DEBUG;
// TODO: put these in userdata
var HIGHLIGHT_SCALE = 1.1;
var GRAB_RANGE_SCALE = {x: 1.8, y: 1.8, z: 1.2};
var MIN_TRIGGER_FORCE = 0.5; // 50%
var HAPTIC_TEXTURE_STRENGTH = 0.3; // was 0.1
var HAPTIC_TEXTURE_DURATION = 3.0;
var _this = null;
var handToController = function(hand) {
return (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
};
var distanceBetweenPointAndBoundingBox = function(point, position, rotation, dimensions, registrationPoint) {
var entityXform = new Xform(rotation, position);
var localPoint = entityXform.inv().xformPoint(point);
var minOffset = Vec3.multiplyVbyV(registrationPoint, dimensions);
var maxOffset = Vec3.multiplyVbyV(Vec3.subtract(ONE_VEC, registrationPoint), dimensions);
var localMin = Vec3.subtract(entityXform.trans, minOffset);
var localMax = Vec3.sum(entityXform.trans, maxOffset);
var v = {x: localPoint.x, y: localPoint.y, z: localPoint.z};
v.x = Math.max(v.x, localMin.x);
v.x = Math.min(v.x, localMax.x);
v.y = Math.max(v.y, localMin.y);
v.y = Math.min(v.y, localMax.y);
v.z = Math.max(v.z, localMin.z);
v.z = Math.min(v.z, localMax.z);
return Vec3.distance(v, localPoint);
}
var distanceBetweenPointAndEntityBoundingBox = function(point, entityProps) {
var entityXform = new Xform(entityProps.rotation, entityProps.position);
var localPoint = entityXform.inv().xformPoint(point);
var minOffset = Vec3.multiplyVbyV(entityProps.registrationPoint, entityProps.dimensions);
var maxOffset = Vec3.multiplyVbyV(Vec3.subtract(ONE_VEC, entityProps.registrationPoint), entityProps.dimensions);
var localMin = Vec3.subtract(entityXform.trans, minOffset);
var localMax = Vec3.sum(entityXform.trans, maxOffset);
var v = {x: localPoint.x, y: localPoint.y, z: localPoint.z};
v.x = Math.max(v.x, localMin.x);
v.x = Math.min(v.x, localMax.x);
v.y = Math.max(v.y, localMin.y);
v.y = Math.min(v.y, localMax.y);
v.z = Math.max(v.z, localMin.z);
v.z = Math.min(v.z, localMax.z);
return Vec3.distance(v, localPoint);
}
function HandyAttacher() {
_this = this;
_this.overlay = null;
_this.entityID = null;
_this.mappingName = null;
_this.mapping = null;
_this.ignoreDistance = 0.2;
_this.triggerPress = [0.0, 0.0]; // both hands
_this.wasHandPreviouslyInBound = [false, false]; // both hands ..
_this.wasTriggeredWhileInBound = [false, false]; // both hands ...
}
HandyAttacher.prototype = {
preload: function(entityID) {
_this.entityID = entityID;
_this.overlayVisible = false;
_this.overlay = Overlays.addOverlay('model', {
parentID: _this.entityID,
localPosition: {x: 0.0, y: 0.0, z: 0.0},
localRotation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0},
dimensions: Vec3.multiply(Entities.getEntityProperties(_this.entityID, 'dimensions').dimensions, HIGHLIGHT_SCALE),
url: Entities.getEntityProperties(_this.entityID, 'modelURL').modelURL,
visible: _this.overlayVisible
});
_this.mappingName = 'io.highfidelity.attacherEntity_' + entityID;
_this.mapping = Controller.newMapping(_this.mappingName);
_this.mapping.from([Controller.Standard.LT]).peek().to(function(value) {
_this.triggerPress[LEFT_HAND] = value;
});
_this.mapping.from([Controller.Standard.RT]).peek().to(function(value) {
_this.triggerPress[RIGHT_HAND] = value;
});
var updateProperties = function() {
_this.properties = Entities.getEntityProperties(_this.entityID, REQUEST_PROPERTIES);
_this.ignoreDistance = Math.max(_this.properties.dimensions.x, _this.properties.dimensions.y, _this.properties.dimensions.z) * GRAB_RANGE_SCALE;
};
_this.propertiesUpdateTimer = Script.setInterval(updateProperties, 1000 / PROPERTIES_FETCH_FREQUENCY);
updateProperties();
Controller.enableMapping(_this.mappingName);
Script.update.connect(_this.update);
},
unload: function() {
// important to disconnect the update first, to prevent it from not disconnecting
Script.update.disconnect(_this.update);
Script.clearInterval(_this.propertiesUpdateTimer);
Overlays.deleteOverlay(_this.overlay);
Controller.disableMapping(_this.mappingName);
},
update: function(deltaTime) {
var shouldShow = false;
for (var hand = 0; hand < HAND_COUNT; hand++) {
var worldHandPosition = getControllerWorldLocation(handToController(hand), true).position;
if (Vec3.distance(_this.properties.position, worldHandPosition) > _this.ignoreDistance) {
//print(Vec3.distance(_this.properties.position, worldHandPosition) + '>' + _this.ignoreDistance)
continue;
}
var outerDistance = distanceBetweenPointAndBoundingBox(worldHandPosition, _this.properties.position,
_this.properties.rotation, Vec3.multiplyVbyV(_this.properties.dimensions, GRAB_RANGE_SCALE), _this.properties.registrationPoint);
// if hand near bound (scale bound x1.5)
if (outerDistance === 0) {
shouldShow = true;
//}
// if hand in bound
//var innerDistance = distanceBetweenPointAndEntityBoundingBox(worldHandPosition, properties);
//print("innerDistance = " + innerDistance);
//if (innerDistance === 0) {
if (!_this.wasHandPreviouslyInBound[hand]) {
Controller.triggerHapticPulse(HAPTIC_TEXTURE_STRENGTH, HAPTIC_TEXTURE_DURATION, hand);
}
_this.wasHandPreviouslyInBound[hand] = true;
if (!_this.wasTriggeredWhileInBound[hand] && _this.triggerPress[hand] >= MIN_TRIGGER_FORCE) {
_this.wasTriggeredWhileInBound[hand] = true;
Controller.triggerShortHapticPulse(1.0, hand);
_this.attachEntity(_this.entityID, hand === LEFT_HAND ? 'left' : 'right');
}
} else {
// reset while out of bounds
_this.wasHandPreviouslyInBound[hand] = false;
_this.wasTriggeredWhileInBound[hand] = false;
}
}
if (shouldShow !== _this.overlayVisible) {
Overlays.editOverlay(_this.overlay, {visible: shouldShow});
_this.overlayVisible = shouldShow;
}
},
createMarker: function(modelURL, markerColor) {
print ('cm modelURL = ' + modelURL)
var markerProperties = {
type: "Model",
modelURL: modelURL,
shapeType: "box",
name: "hifi_model_marker",
dimensions: {
x: 0.027,
y: 0.027,
z: 0.164
},
lifetime: 86400,
script: MARKER_SCRIPT_URL,
scriptTimestamp: SCRIPT_UPDATE_DATE,
userData: JSON.stringify({
grabbableKey: {
grabbable: true,
ignoreIK: FORCE_FOLLOW_IK
},
markerColor: markerColor,
equipHotspots: [{
position: {
x: 0,
y: 0,
z: 0
},
radius: 0.15,
joints: {
RightHand: [{
x: 0.001,
y: 0.139,
z: 0.050
},
{
x: -0.0432,
y: 0.7337,
z: 0.6693,
w: -0.1085
}],
LeftHand: [{
x: 0.007,
y: 0.151,
z: 0.061
},
{
x: 0.6313,
y: 0.4172,
z: 0.5253,
w: -0.3892
}]
}
}]
})
};
return Entities.addEntity(markerProperties, CLIENT_ONLY);
},
createEraser: function(modelURL) {
var eraserProps = {
type: "Model",
name: "hifi_model_whiteboardEraser",
modelURL: modelURL,
script: ERASER_SCRIPT_URL,
scriptTimestamp: SCRIPT_UPDATE_DATE,
shapeType: "box",
lifetime: 86400,
dimensions: {
x: 0.0858,
y: 0.0393,
z: 0.2083
},
userData: JSON.stringify({
grabbableKey: {
grabbable: true,
ignoreIK: FORCE_FOLLOW_IK
},
equipHotspots: [{
position: {
x: 0,
y: 0,
z: 0
},
radius: 0.15,
joints: {
RightHand: [{
x: 0.020,
y: 0.120,
z: 0.049
}, {
x: 0.1004,
y: 0.6424,
z: 0.717,
w: 0.250
}],
LeftHand: [{
x: -0.005,
y: 0.1101,
z: 0.053
}, {
x: 0.723,
y: 0.289,
z: 0.142,
w: 0.610
}]
}
}]
})
};
return Entities.addEntity(eraserProps, CLIENT_ONLY);
},
attachEntity: function(entityID, attachHand) {
var properties = Entities.getEntityProperties(entityID, ['userData', 'modelURL']);
var userData = JSON.parse(properties.userData);
var newEntity;
if (userData.type === 'marker') {
newEntity = _this.createMarker(properties.modelURL, userData.markerColor);
} else if (userData.type === 'eraser') {
newEntity = _this.createEraser(properties.modelURL);
} else {
return;
}
//Script.setTimeout(function() {
Messages.sendLocalMessage('Hifi-Hand-Grab', JSON.stringify({hand: attachHand, entityID: newEntity}));
//}, 1000);
}
/*,
startNearTrigger: function(entityID, args) {
print(' on startNearTrigger!!');
_this.attachEntity(entityID, args[0]);
}*/
};
return new HandyAttacher();
});