618 lines
18 KiB
JavaScript
Raw Normal View History

2016-07-01 17:26:52 -07:00
// by james b. pollack @imgntn on 7/2/2016
2016-07-05 17:48:30 -07:00
///BUG: there is currently something going on when you try to adjust the dimensions of a second overlay model, it seems to be off by a factor of 10 or already changed or something weird.
2016-06-30 17:05:16 -07:00
//v1
//check if trigger is down xxx
//if trigger is down, check if thumb is down xxx
//if both are down, enter 'teleport mode' xxx
//aim controller to change landing spot xxx
//visualize aim + spot (line + circle) xxx
//release trigger to teleport then exit teleport mode xxx
//if thumb is release, exit teleport mode xxx
2016-06-29 15:59:51 -07:00
2016-06-30 17:05:16 -07:00
//v2
2016-07-01 15:19:37 -07:00
// try just thumb to teleport xxx
2016-06-30 17:05:16 -07:00
2016-07-05 17:48:30 -07:00
//v3
//fade in/out
2016-07-05 17:48:30 -07:00
//stretchy beam instead of GL line xxx
2016-06-30 17:05:16 -07:00
//try moving to final destination in 4 steps: 50% 75% 90% 100% (arrival)
2016-07-05 17:48:30 -07:00
//v?: haptic feedback
//v?: show room boundaries when choosing a place to teleport
2016-07-01 17:26:52 -07:00
2016-06-30 16:05:44 -07:00
var inTeleportMode = false;
2016-06-29 15:59:51 -07:00
2016-07-05 10:31:47 -07:00
var currentFadeSphereOpacity = 1;
var fadeSphereInterval = null;
//milliseconds between fading one-tenth -- so this is a half second fade total
var FADE_IN_INTERVAL = 50;
var FADE_OUT_INTERVAL = 50;
2016-07-05 10:31:47 -07:00
var BEAM_MODEL_URL = "http://hifi-content.s3.amazonaws.com/james/teleporter/teleportBeam.fbx";
var BEAM_MODEL_URL_NO_INTERSECTION = "http://hifi-content.s3.amazonaws.com/james/teleporter/teleportBeam2.fbx";
2016-07-05 10:31:47 -07:00
2016-07-01 11:12:20 -07:00
var STRETCHY_BEAM_DIMENSIONS_X = 0.04;
var STRETCHY_BEAM_DIMENSIONS_Y = 0.04;
var STRETCHY_BEAM_DIMENSIONS_Z_NO_INTESECTION = 20;
var TARGET_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/teleporter/Tele-destiny.fbx';
2016-07-01 15:19:37 -07:00
var TARGET_MODEL_DIMENSIONS = {
2016-07-01 17:26:52 -07:00
x: 1.15,
2016-07-05 09:22:19 -07:00
y: 0.5,
2016-07-01 17:26:52 -07:00
z: 1.15
2016-07-01 15:19:37 -07:00
};
//swirly thing, not sure we'll get to use it
// var TARGET_MODEL_URL='http://hifi-content.s3.amazonaws.com/alan/dev/Cyclone-4.fbx';
// var TARGET_MODEL_DIMENSIONS = {
// x: 0.93,
// y: 0.93,
// z: 1.22
// };
2016-06-30 16:05:44 -07:00
function ThumbPad(hand) {
this.hand = hand;
var _this = this;
2016-06-29 15:59:51 -07:00
2016-06-30 16:05:44 -07:00
this.buttonPress = function(value) {
print('jbp pad press: ' + value + " on: " + _this.hand)
_this.buttonValue = value;
};
2016-06-29 15:59:51 -07:00
2016-06-30 16:05:44 -07:00
this.down = function() {
return _this.buttonValue === 1 ? 1.0 : 0.0;
};
}
2016-06-29 15:59:51 -07:00
2016-06-30 16:05:44 -07:00
function Trigger(hand) {
this.hand = hand;
var _this = this;
2016-06-29 15:59:51 -07:00
2016-06-30 16:05:44 -07:00
this.buttonPress = function(value) {
_this.buttonValue = value;
2016-06-29 15:59:51 -07:00
2016-06-30 16:05:44 -07:00
};
2016-06-29 15:59:51 -07:00
2016-06-30 16:05:44 -07:00
this.down = function() {
return _this.buttonValue === 1 ? 1.0 : 0.0;
};
2016-06-29 15:59:51 -07:00
}
2016-06-30 16:05:44 -07:00
function Teleporter() {
var _this = this;
this.intersection = null;
2016-06-30 16:05:44 -07:00
this.targetProps = null;
this.targetOverlay = null;
this.stretchyBeam = null;
this.noIntersectionStretchyBeam = null;
this.updateConnected = null;
2016-06-30 16:05:44 -07:00
this.initialize = function() {
print('jbp initialize')
this.createMappings();
this.disableGrab();
};
2016-07-01 15:19:37 -07:00
this.createTargetOverlay = function() {
print('creating target overlay')
2016-07-01 15:19:37 -07:00
var cameraEuler = Quat.safeEulerAngles(Camera.orientation);
var towardsMe = Quat.angleAxis(cameraEuler.y + 180, {
x: 0,
y: 1,
z: 0
2016-06-30 16:05:44 -07:00
});
2016-07-01 15:19:37 -07:00
var targetOverlayProps = {
url: TARGET_MODEL_URL,
position: MyAvatar.position,
rotation: towardsMe,
dimensions: TARGET_MODEL_DIMENSIONS,
visible: true,
2016-07-01 15:19:37 -07:00
};
_this.targetOverlay = Overlays.addOverlay("model", targetOverlayProps);
2016-06-30 16:05:44 -07:00
};
2016-06-29 15:59:51 -07:00
2016-06-30 16:05:44 -07:00
this.createMappings = function() {
print('jbp create mappings internal');
// peek at the trigger and thumbs to store their values
2016-07-01 00:48:29 -07:00
teleporter.telporterMappingInternalName = 'Hifi-Teleporter-Internal-Dev-' + Math.random();
teleporter.teleportMappingInternal = Controller.newMapping(teleporter.telporterMappingInternalName);
2016-06-30 16:05:44 -07:00
Controller.enableMapping(teleporter.telporterMappingInternalName);
};
2016-06-29 18:28:39 -07:00
2016-06-30 16:05:44 -07:00
this.disableMappings = function() {
print('jbp disable mappings internal')
Controller.disableMapping(teleporter.telporterMappingInternalName);
};
2016-06-29 18:28:39 -07:00
2016-06-30 16:05:44 -07:00
this.enterTeleportMode = function(hand) {
if (inTeleportMode === true) {
return;
}
2016-06-30 16:05:44 -07:00
print('jbp hand on entering teleport mode: ' + hand);
inTeleportMode = true;
this.teleportHand = hand;
this.initialize();
this.updateConnected = true;
2016-07-01 15:19:37 -07:00
Script.update.connect(this.update);
2016-07-01 11:12:20 -07:00
2016-06-30 16:05:44 -07:00
};
2016-06-29 15:59:51 -07:00
this.findMidpoint = function(handPosition, intersection) {
var xy = Vec3.sum(handPosition, intersection.intersection);
var midpoint = Vec3.multiply(0.5, xy);
return midpoint
};
this.createStretchyBeam = function(handPosition, intersection, rotation) {
2016-07-05 10:31:47 -07:00
var beamProps = {
url: BEAM_MODEL_URL,
position: _this.findMidpoint(handPosition, intersection),
dimensions: {
x: STRETCHY_BEAM_DIMENSIONS_X,
y: STRETCHY_BEAM_DIMENSIONS_Y,
z: 0.1
},
ignoreRayIntersection: true,
2016-07-05 10:31:47 -07:00
};
_this.stretchyBeam = Overlays.addOverlay("model", beamProps);
};
this.updateStretchyBeam = function(handPosition, intersection, rotation) {
var dimensions = {
x: STRETCHY_BEAM_DIMENSIONS_X,
y: STRETCHY_BEAM_DIMENSIONS_Y,
z: Vec3.distance(handPosition, intersection.intersection)
};
var position = _this.findMidpoint(handPosition, intersection);
Overlays.editOverlay(_this.stretchyBeam, {
dimensions: dimensions,
position: position,
rotation: Quat.multiply(rotation, Quat.angleAxis(180, {
x: 0,
y: 1,
z: 0
}))
})
};
this.deleteStretchyBeam = function() {
if (_this.stretchyBeam !== null) {
Overlays.deleteOverlay(_this.stretchyBeam);
_this.stretchyBeam = null;
}
};
this.createNoIntersectionStretchyBeam = function(handPosition, direction, rotation) {
var howBig = STRETCHY_BEAM_DIMENSIONS_Z_NO_INTESECTION;
var ahead = Vec3.sum(handPosition, Vec3.multiply(howBig, direction));
var midpoint = this.findMidpoint(handPosition, {
intersection: ahead
});
var dimensions = {
x: 0.04,
y: 0.04,
2016-07-05 17:48:30 -07:00
z: 0.1
};
var finalRotation = Quat.multiply(rotation, Quat.angleAxis(180, {
x: 0,
y: 1,
z: 0
}));
var beamProps = {
2016-07-05 17:48:30 -07:00
// dimensions: dimensions,
url: BEAM_MODEL_URL_NO_INTERSECTION,
position: midpoint,
rotation: finalRotation,
ignoreRayIntersection: true,
};
this.noIntersectionStretchyBeam = Overlays.addOverlay("model", beamProps);
};
this.updateNoIntersectionStretchyBeam = function(handPosition, direction, rotation) {
var howBig = STRETCHY_BEAM_DIMENSIONS_Z_NO_INTESECTION;
var ahead = Vec3.sum(handPosition, Vec3.multiply(howBig, direction));
var midpoint = this.findMidpoint(handPosition, {
intersection: ahead
});
var dimensions = {
x: STRETCHY_BEAM_DIMENSIONS_X,
y: STRETCHY_BEAM_DIMENSIONS_Y,
z: Vec3.distance(handPosition, ahead)
};
2016-07-05 17:48:30 -07:00
dimensions = Vec3.multiply(10, dimensions)
print('dimensions in update:: ' + JSON.stringify(dimensions));
var finalRotation = Quat.multiply(rotation, Quat.angleAxis(180, {
x: 0,
y: 1,
z: 0
}));
var goodEdit = Overlays.editOverlay(_this.noIntersectionStretchyBeam, {
dimensions: dimensions,
position: midpoint,
rotation: rotation
})
2016-07-05 10:31:47 -07:00
};
this.deleteNoIntersectionStretchyBeam = function() {
if (_this.noIntersectionStretchyBeam !== null) {
Overlays.deleteOverlay(_this.noIntersectionStretchyBeam);
_this.noIntersectionStretchyBeam = null;
}
};
2016-07-05 10:31:47 -07:00
this.createFadeSphere = function(avatarHead) {
var sphereProps = {
position: avatarHead,
size: 0.25,
color: {
red: 0,
green: 0,
blue: 0,
},
alpha: 1,
solid: true,
visible: true,
ignoreRayIntersection: true,
drawInFront: true
};
currentFadeSphereOpacity = 1;
_this.fadeSphere = Overlays.addOverlay("sphere", sphereProps);
Script.update.connect(_this.updateFadeSphere);
2016-07-05 10:31:47 -07:00
};
this.fadeSphereOut = function() {
fadeSphereInterval = Script.setInterval(function() {
if (currentFadeSphereOpacity === 0) {
Script.clearInterval(fadeSphereInterval);
_this.deleteFadeSphere();
2016-07-05 10:31:47 -07:00
fadeSphereInterval = null;
return;
}
if (currentFadeSphereOpacity > 0) {
currentFadeSphereOpacity -= 0.1;
}
Overlays.editOverlay(_this.fadeSphere, {
alpha: currentFadeSphereOpacity
2016-07-05 10:31:47 -07:00
})
}, FADE_OUT_INTERVAL);
2016-07-05 10:31:47 -07:00
};
this.fadeSphereIn = function() {
fadeSphereInterval = Script.setInterval(function() {
if (currentFadeSphereOpacity === 1) {
Script.clearInterval(fadeSphereInterval);
_this.deleteFadeSphere();
2016-07-05 10:31:47 -07:00
fadeSphereInterval = null;
return;
}
if (currentFadeSphereOpacity < 1) {
currentFadeSphereOpacity += 0.1;
}
Overlays.editOverlay(_this.fadeSphere, {
alpha: currentFadeSphereOpacity
2016-07-05 10:31:47 -07:00
})
}, FADE_IN_INTERVAL);
};
this.updateFadeSphere = function() {
var headPosition = MyAvatar.getHeadPosition();
Overlays.editOverlay(_this.fadeSphere, {
position: headPosition
})
2016-07-05 10:31:47 -07:00
};
this.deleteFadeSphere = function() {
Script.update.disconnect(_this.updateFadeSphere);
Overlays.deleteOverlay(_this.fadeSphere);
2016-07-05 10:31:47 -07:00
};
this.deleteTargetOverlay = function() {
Overlays.deleteOverlay(this.targetOverlay);
this.intersection = null;
this.targetOverlay = null;
}
2016-06-30 16:05:44 -07:00
this.exitTeleportMode = function(value) {
print('jbp value on exit: ' + value);
2016-07-01 15:19:37 -07:00
Script.update.disconnect(this.update);
this.updateConnected = null;
2016-06-30 16:05:44 -07:00
this.disableMappings();
this.deleteStretchyBeam();
this.deleteNoIntersectionStretchyBeam();
this.deleteTargetOverlay();
2016-06-30 16:05:44 -07:00
this.enableGrab();
2016-07-01 15:19:37 -07:00
Script.setTimeout(function() {
inTeleportMode = false;
}, 100);
2016-06-30 16:05:44 -07:00
};
2016-07-01 15:19:37 -07:00
this.update = function() {
2016-07-01 11:12:20 -07:00
if (teleporter.teleportHand === 'left') {
teleporter.leftRay();
if (leftPad.buttonValue === 0) {
_this.teleport();
return;
}
} else {
teleporter.rightRay();
if (rightPad.buttonValue === 0) {
_this.teleport();
return;
}
}
};
2016-06-30 16:05:44 -07:00
this.rightRay = function() {
var rightPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getPoseValue(Controller.Standard.RightHand).translation), MyAvatar.position);
var rightRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(Controller.Standard.RightHand).rotation)
2016-06-30 16:05:44 -07:00
var rightPickRay = {
origin: rightPosition,
direction: Quat.getUp(rightRotation),
};
var rightFinal = Quat.multiply(rightRotation, Quat.angleAxis(90, {
x: 1,
y: 0,
z: 0
}));
2016-06-30 16:05:44 -07:00
this.rightPickRay = rightPickRay;
var location = Vec3.sum(rightPickRay.origin, Vec3.multiply(rightPickRay.direction, 500));
2016-06-30 16:05:44 -07:00
var rightIntersection = Entities.findRayIntersection(teleporter.rightPickRay, true, [], [this.targetEntity]);
if (rightIntersection.intersects) {
this.deleteNoIntersectionStretchyBeam();
if (this.targetOverlay !== null) {
this.updateTargetOverlay(rightIntersection);
} else {
this.createTargetOverlay();
}
if (this.stretchyBeam !== null) {
this.updateStretchyBeam(rightPickRay.origin, rightIntersection, rightFinal);
} else {
this.createStretchyBeam(rightPickRay.origin, rightIntersection, rightFinal);
}
2016-07-01 17:26:52 -07:00
} else {
this.deleteTargetOverlay();
this.deleteStretchyBeam();
if (this.noIntersectionStretchyBeam !== null) {
this.updateNoIntersectionStretchyBeam(rightPickRay.origin, rightPickRay.direction, rightFinal);
} else {
this.createNoIntersectionStretchyBeam(rightPickRay.origin, rightPickRay.direction, rightFinal);
}
2016-07-01 17:26:52 -07:00
}
}
2016-06-30 16:05:44 -07:00
this.leftRay = function() {
var leftPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getPoseValue(Controller.Standard.LeftHand).translation), MyAvatar.position);
var leftRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(Controller.Standard.LeftHand).rotation)
2016-06-30 16:05:44 -07:00
var leftPickRay = {
origin: leftPosition,
direction: Quat.getUp(leftRotation),
};
var leftFinal = Quat.multiply(leftRotation, Quat.angleAxis(90, {
x: 1,
y: 0,
z: 0
}));
2016-06-30 16:05:44 -07:00
this.leftPickRay = leftPickRay;
var location = Vec3.sum(leftPickRay.origin, Vec3.multiply(leftPickRay.direction, 500));
var leftIntersection = Entities.findRayIntersection(teleporter.leftPickRay, true, [], [this.targetEntity]);
2016-06-30 16:05:44 -07:00
if (leftIntersection.intersects) {
this.deleteNoIntersectionStretchyBeam();
if (this.targetOverlay !== null) {
this.updateTargetOverlay(leftIntersection);
} else {
this.createTargetOverlay();
}
if (this.stretchyBeam !== null) {
this.updateStretchyBeam(leftPickRay.origin, leftIntersection, leftFinal);
} else {
this.createStretchyBeam(leftPickRay.origin, leftIntersection, leftFinal);
2016-06-30 16:05:44 -07:00
}
2016-06-30 16:05:44 -07:00
} else {
this.deleteTargetOverlay();
this.deleteStretchyBeam();
if (this.noIntersectionStretchyBeam !== null) {
this.updateNoIntersectionStretchyBeam(leftPickRay.origin, leftPickRay.direction, leftFinal);
} else {
this.createNoIntersectionStretchyBeam(leftPickRay.origin, leftPickRay.direction, leftFinal);
}
2016-06-30 16:05:44 -07:00
}
};
2016-07-01 15:19:37 -07:00
this.updateTargetOverlay = function(intersection) {
2016-07-01 15:19:53 -07:00
this.intersection = intersection;
2016-06-30 16:05:44 -07:00
var position = {
x: intersection.intersection.x,
y: intersection.intersection.y + TARGET_MODEL_DIMENSIONS.y + 0.1,
2016-06-30 16:05:44 -07:00
z: intersection.intersection.z
}
2016-07-01 15:19:37 -07:00
Overlays.editOverlay(this.targetOverlay, {
2016-07-01 17:26:52 -07:00
position: position,
visible: true
2016-06-30 16:05:44 -07:00
});
2016-07-01 15:19:53 -07:00
2016-06-30 16:05:44 -07:00
};
this.disableGrab = function() {
Messages.sendLocalMessage('Hifi-Hand-Disabler', 'both');
};
this.enableGrab = function() {
Messages.sendLocalMessage('Hifi-Hand-Disabler', 'none');
};
this.teleport = function(value) {
2016-06-29 18:28:39 -07:00
2016-07-01 15:19:37 -07:00
print('TELEPORT CALLED');
2016-06-30 16:05:44 -07:00
2016-07-01 15:19:37 -07:00
var offset = getAvatarFootOffset();
if (_this.intersection !== null) {
_this.intersection.intersection.y += offset;
MyAvatar.position = _this.intersection.intersection;
}
2016-06-30 16:05:44 -07:00
this.exitTeleportMode();
};
2016-06-29 18:28:39 -07:00
}
2016-06-29 15:59:51 -07:00
2016-06-30 16:05:44 -07:00
//related to repositioning the avatar after you teleport
2016-06-29 18:28:39 -07:00
function getAvatarFootOffset() {
var data = getJointData();
var upperLeg, lowerLeg, foot, toe, toeTop;
data.forEach(function(d) {
var jointName = d.joint;
if (jointName === "RightUpLeg") {
upperLeg = d.translation.y;
}
if (jointName === "RightLeg") {
lowerLeg = d.translation.y;
}
if (jointName === "RightFoot") {
foot = d.translation.y;
}
if (jointName === "RightToeBase") {
toe = d.translation.y;
}
if (jointName === "RightToe_End") {
toeTop = d.translation.y
}
})
var myPosition = MyAvatar.position;
var offset = upperLeg + lowerLeg + foot + toe + toeTop;
offset = offset / 100;
return offset
};
function getJointData() {
var allJointData = [];
var jointNames = MyAvatar.jointNames;
jointNames.forEach(function(joint, index) {
var translation = MyAvatar.getJointTranslation(index);
var rotation = MyAvatar.getJointRotation(index)
allJointData.push({
joint: joint,
index: index,
translation: translation,
rotation: rotation
});
});
return allJointData;
};
2016-07-01 11:12:20 -07:00
2016-06-30 16:05:44 -07:00
var leftPad = new ThumbPad('left');
var rightPad = new ThumbPad('right');
var leftTrigger = new Trigger('left');
var rightTrigger = new Trigger('right');
//create a controller mapping and make sure to disable it when the script is stopped
2016-07-01 11:12:20 -07:00
var mappingName, teleportMapping;
2016-07-01 17:26:52 -07:00
function registerMappings() {
2016-07-01 11:12:20 -07:00
mappingName = 'Hifi-Teleporter-Dev-' + Math.random();
teleportMapping = Controller.newMapping(mappingName);
teleportMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(rightPad.buttonPress);
teleportMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(leftPad.buttonPress);
teleportMapping.from(leftPad.down).to(function() {
teleporter.enterTeleportMode('left')
});
teleportMapping.from(rightPad.down).to(function() {
teleporter.enterTeleportMode('right')
});
}
2016-06-30 16:05:44 -07:00
2016-07-01 17:26:52 -07:00
registerMappings();
2016-06-30 16:05:44 -07:00
var teleporter = new Teleporter();
Controller.enableMapping(mappingName);
Script.scriptEnding.connect(cleanup);
function cleanup() {
teleportMapping.disable();
teleporter.disableMappings();
teleporter.deleteStretchyBeam();
teleporter.deleteTargetOverlay();
teleporter.deleteNoIntersectionStretchyBeam();
2016-06-30 16:05:44 -07:00
if (teleporter.updateConnected !== null) {
Script.update.disconnect(teleporter.update);
}
}