overte/examples/controllers/hydra/hydraGrab.js

752 lines
30 KiB
JavaScript

//
// hydraGrab.js
// examples
//
// Created by Clément Brisset on 4/24/14.
// Copyright 2014 High Fidelity, Inc.
//
// This script allows you to edit models either with the razor hydras or with your mouse
//
// Using the hydras :
// grab models with the triggers, you can then move the models around or scale them with both hands.
// You can switch mode using the bumpers so that you can move models around more easily.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/entityPropertyDialogBox.js");
var entityPropertyDialogBox = EntityPropertyDialogBox;
var MIN_ANGULAR_SIZE = 2;
var MAX_ANGULAR_SIZE = 45;
var allowLargeModels = true;
var allowSmallModels = true;
var wantEntityGlow = false;
var LEFT = 0;
var RIGHT = 1;
var jointList = MyAvatar.getJointNames();
var LASER_WIDTH = 3;
var LASER_COLOR = { red: 50, green: 150, blue: 200 };
var DROP_COLOR = { red: 200, green: 200, blue: 200 };
var DROP_WIDTH = 4;
var DROP_DISTANCE = 5.0;
var LASER_LENGTH_FACTOR = 500;
var velocity = { x: 0, y: 0, z: 0 };
var lastAccurateIntersection = null;
var accurateIntersections = 0;
var totalIntersections = 0;
var inaccurateInARow = 0;
var maxInaccurateInARow = 0;
function getRayIntersection(pickRay) { // pickRay : { origin : {xyz}, direction : {xyz} }
if (lastAccurateIntersection === null) {
lastAccurateIntersection = Entities.findRayIntersectionBlocking(pickRay);
} else {
var intersection = Entities.findRayIntersection(pickRay);
if (intersection.accurate) {
lastAccurateIntersection = intersection;
accurateIntersections++;
maxInaccurateInARow = (maxInaccurateInARow > inaccurateInARow) ? maxInaccurateInARow : inaccurateInARow;
inaccurateInARow = 0;
} else {
inaccurateInARow++;
}
totalIntersections++;
}
return lastAccurateIntersection;
}
function printIntersectionsStats() {
var ratio = accurateIntersections / totalIntersections;
print("Out of " + totalIntersections + " intersections, " + accurateIntersections + " where accurate. (" + ratio * 100 +"%)");
print("Worst case was " + maxInaccurateInARow + " inaccurate intersections in a row.");
}
function controller(wichSide) {
this.side = wichSide;
this.palm = 2 * wichSide;
this.tip = 2 * wichSide + 1;
this.trigger = wichSide;
this.bumper = 6 * wichSide + 5;
this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm);
this.palmPosition = this.oldPalmPosition;
this.oldTipPosition = Controller.getSpatialControlPosition(this.tip);
this.tipPosition = this.oldTipPosition;
this.oldUp = Controller.getSpatialControlNormal(this.palm);
this.up = this.oldUp;
this.oldFront = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition));
this.front = this.oldFront;
this.oldRight = Vec3.cross(this.front, this.up);
this.right = this.oldRight;
this.oldRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
this.rotation = this.oldRotation;
this.triggerValue = Controller.getTriggerValue(this.trigger);
this.bumperValue = Controller.isButtonPressed(this.bumper);
this.pressed = false; // is trigger pressed
this.pressing = false; // is trigger being pressed (is pressed now but wasn't previously)
this.grabbing = false;
this.entityID = { isKnownID: false };
this.modelURL = "";
this.oldModelRotation;
this.oldModelPosition;
this.oldModelHalfDiagonal;
this.positionAtGrab;
this.rotationAtGrab;
this.gravityAtGrab;
this.modelPositionAtGrab;
this.modelRotationAtGrab;
this.jointsIntersectingFromStart = [];
this.laser = Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: LASER_COLOR,
alpha: 1,
visible: false,
lineWidth: LASER_WIDTH,
anchor: "MyAvatar"
});
this.dropLine = Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: DROP_COLOR,
alpha: 1,
visible: false,
lineWidth: DROP_WIDTH });
this.guideScale = 0.02;
this.ball = Overlays.addOverlay("sphere", {
position: { x: 0, y: 0, z: 0 },
size: this.guideScale,
solid: true,
color: { red: 0, green: 255, blue: 0 },
alpha: 1,
visible: false,
anchor: "MyAvatar"
});
this.leftRight = Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: { red: 0, green: 0, blue: 255 },
alpha: 1,
visible: false,
lineWidth: LASER_WIDTH,
anchor: "MyAvatar"
});
this.topDown = Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: { red: 0, green: 0, blue: 255 },
alpha: 1,
visible: false,
lineWidth: LASER_WIDTH,
anchor: "MyAvatar"
});
this.grab = function (entityID, properties) {
print("Grabbing " + entityID.id);
this.grabbing = true;
this.entityID = entityID;
this.modelURL = properties.modelURL;
this.oldModelPosition = properties.position;
this.oldModelRotation = properties.rotation;
this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0;
this.positionAtGrab = this.palmPosition;
this.rotationAtGrab = this.rotation;
this.modelPositionAtGrab = properties.position;
this.modelRotationAtGrab = properties.rotation;
this.gravityAtGrab = properties.gravity;
Entities.editEntity(entityID, { gravity: { x: 0, y: 0, z: 0 }, velocity: { x: 0, y: 0, z: 0 } });
this.jointsIntersectingFromStart = [];
for (var i = 0; i < jointList.length; i++) {
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
if (distance < this.oldModelHalfDiagonal) {
this.jointsIntersectingFromStart.push(i);
}
}
this.showLaser(false);
Overlays.editOverlay(this.dropLine, { visible: true });
}
this.release = function () {
if (this.grabbing) {
Entities.editEntity(this.entityID, { gravity: this.gravityAtGrab });
jointList = MyAvatar.getJointNames();
var closestJointIndex = -1;
var closestJointDistance = 10;
for (var i = 0; i < jointList.length; i++) {
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
if (distance < closestJointDistance) {
closestJointDistance = distance;
closestJointIndex = i;
}
}
if (closestJointIndex != -1) {
print("closestJoint: " + jointList[closestJointIndex]);
print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelHalfDiagonal + ")");
}
if (closestJointDistance < this.oldModelHalfDiagonal) {
if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 ||
(leftController.grabbing && rightController.grabbing &&
leftController.entityID.id == rightController.entityID.id)) {
// Do nothing
} else {
print("Attaching to " + jointList[closestJointIndex]);
var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]);
var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]);
var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition);
attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset);
var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation);
MyAvatar.attach(this.modelURL, jointList[closestJointIndex],
attachmentOffset, attachmentRotation, 2.0 * this.oldModelHalfDiagonal,
true, false);
Entities.deleteEntity(this.entityID);
}
}
Overlays.editOverlay(this.dropLine, { visible: false });
}
this.grabbing = false;
this.entityID.isKnownID = false;
this.jointsIntersectingFromStart = [];
this.showLaser(true);
}
this.checkTrigger = function () {
if (this.triggerValue > 0.9) {
if (this.pressed) {
this.pressing = false;
} else {
this.pressing = true;
}
this.pressed = true;
} else {
this.pressing = false;
this.pressed = false;
}
}
this.checkEntity = function (properties) {
// P P - Model
// /| A - Palm
// / | d B - unit vector toward tip
// / | X - base of the perpendicular line
// A---X----->B d - distance fom axis
// x x - distance from A
//
// |X-A| = (P-A).B
// X == A + ((P-A).B)B
// d = |P-X|
var A = this.palmPosition;
var B = this.front;
var P = properties.position;
var x = Vec3.dot(Vec3.subtract(P, A), B);
var y = Vec3.dot(Vec3.subtract(P, A), this.up);
var z = Vec3.dot(Vec3.subtract(P, A), this.right);
var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X));
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (0 < x && sizeOK) {
return { valid: true, x: x, y: y, z: z };
}
return { valid: false };
}
this.glowedIntersectingModel = { isKnownID: false };
this.moveLaser = function () {
// the overlays here are anchored to the avatar, which means they are specified in the avatar's local frame
var inverseRotation = Quat.inverse(MyAvatar.orientation);
var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position));
startPosition = Vec3.multiply(startPosition, 1 / MyAvatar.scale);
var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition));
direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / (Vec3.length(direction) * MyAvatar.scale));
var endPosition = Vec3.sum(startPosition, direction);
Overlays.editOverlay(this.laser, {
start: startPosition,
end: endPosition
});
Overlays.editOverlay(this.ball, {
position: endPosition
});
Overlays.editOverlay(this.leftRight, {
start: Vec3.sum(endPosition, Vec3.multiply(this.right, 2 * this.guideScale)),
end: Vec3.sum(endPosition, Vec3.multiply(this.right, -2 * this.guideScale))
});
Overlays.editOverlay(this.topDown, {
start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)),
end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale))
});
this.showLaser(!this.grabbing);
if (this.glowedIntersectingModel.isKnownID) {
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 });
this.glowedIntersectingModel.isKnownID = false;
}
if (!this.grabbing) {
var intersection = getRayIntersection({ origin: this.palmPosition,
direction: this.front
});
var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), intersection.properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (intersection.accurate && intersection.entityID.isKnownID && sizeOK) {
this.glowedIntersectingModel = intersection.entityID;
if (wantEntityGlow) {
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.25 });
}
}
}
}
this.showLaser = function (show) {
Overlays.editOverlay(this.laser, { visible: show });
Overlays.editOverlay(this.ball, { visible: show });
Overlays.editOverlay(this.leftRight, { visible: show });
Overlays.editOverlay(this.topDown, { visible: show });
}
this.moveEntity = function (deltaTime) {
if (this.grabbing) {
if (!this.entityID.isKnownID) {
print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
this.entityID = getRayIntersection({ origin: this.palmPosition,
direction: this.front
}).entityID;
print("Identified ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
}
var newPosition;
var newRotation;
var CONSTANT_SCALING_FACTOR = 5.0;
var MINIMUM_SCALING_DISTANCE = 2.0;
var distanceToModel = Vec3.length(Vec3.subtract(this.oldModelPosition, this.palmPosition));
if (distanceToModel < MINIMUM_SCALING_DISTANCE) {
distanceToModel = MINIMUM_SCALING_DISTANCE;
}
var deltaPalm = Vec3.multiply(distanceToModel * CONSTANT_SCALING_FACTOR, Vec3.subtract(this.palmPosition, this.oldPalmPosition));
newPosition = Vec3.sum(this.oldModelPosition, deltaPalm);
newRotation = Quat.multiply(this.rotation,
Quat.inverse(this.rotationAtGrab));
newRotation = Quat.multiply(newRotation, newRotation);
newRotation = Quat.multiply(newRotation,
this.modelRotationAtGrab);
velocity = Vec3.multiply(1.0 / deltaTime, Vec3.subtract(newPosition, this.oldModelPosition));
Entities.editEntity(this.entityID, {
position: newPosition,
rotation: newRotation,
velocity: velocity
});
this.oldModelRotation = newRotation;
this.oldModelPosition = newPosition;
Overlays.editOverlay(this.dropLine, { start: newPosition, end: Vec3.sum(newPosition, { x: 0, y: -DROP_DISTANCE, z: 0 }) });
var indicesToRemove = [];
for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) {
var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition);
if (distance >= this.oldModelHalfDiagonal) {
indicesToRemove.push(this.jointsIntersectingFromStart[i]);
}
}
for (var i = 0; i < indicesToRemove.length; ++i) {
this.jointsIntersectingFromStart.splice(this.jointsIntersectingFromStart.indexOf(indicesToRemove[i], 1));
}
}
}
this.update = function () {
this.oldPalmPosition = this.palmPosition;
this.oldTipPosition = this.tipPosition;
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
this.oldUp = this.up;
this.up = Vec3.normalize(Controller.getSpatialControlNormal(this.palm));
this.oldFront = this.front;
this.front = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition));
this.oldRight = this.right;
this.right = Vec3.normalize(Vec3.cross(this.front, this.up));
this.oldRotation = this.rotation;
this.rotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
this.triggerValue = Controller.getTriggerValue(this.trigger);
var bumperValue = Controller.isButtonPressed(this.bumper);
this.bumperValue = bumperValue;
this.checkTrigger();
this.moveLaser();
if (!this.pressed && this.grabbing) {
// release if trigger not pressed anymore.
this.release();
}
if (this.pressing) {
// Checking for attachments intersecting
var attachments = MyAvatar.getAttachmentData();
var attachmentIndex = -1;
var attachmentX = LASER_LENGTH_FACTOR;
var newModel;
var newProperties;
for (var i = 0; i < attachments.length; ++i) {
var position = Vec3.sum(MyAvatar.getJointPosition(attachments[i].jointName),
Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[i].jointName), attachments[i].translation));
var scale = attachments[i].scale;
var A = this.palmPosition;
var B = this.front;
var P = position;
var x = Vec3.dot(Vec3.subtract(P, A), B);
var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X));
if (d < scale / 2.0 && 0 < x && x < attachmentX) {
attachmentIndex = i;
attachmentX = d;
}
}
if (attachmentIndex != -1) {
print("Detaching: " + attachments[attachmentIndex].modelURL);
MyAvatar.detachOne(attachments[attachmentIndex].modelURL, attachments[attachmentIndex].jointName);
newProperties = {
type: "Model",
position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName),
Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)),
rotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName),
attachments[attachmentIndex].rotation),
// TODO: how do we know the correct dimensions for detachment???
dimensions: { x: attachments[attachmentIndex].scale / 2.0,
y: attachments[attachmentIndex].scale / 2.0,
z: attachments[attachmentIndex].scale / 2.0 },
modelURL: attachments[attachmentIndex].modelURL
};
newModel = Entities.addEntity(newProperties);
} else {
// There is none so ...
// Checking model tree
Vec3.print("Looking at: ", this.palmPosition);
var pickRay = { origin: this.palmPosition,
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) };
var foundIntersection = getRayIntersection(pickRay);
if(!foundIntersection.intersects) {
print("No intersection");
return;
}
newModel = foundIntersection.entityID;
if (!newModel.isKnownID) {
var identify = Entities.identifyEntity(newModel);
if (!identify.isKnownID) {
print("Unknown ID " + identify.id + " (update loop " + newModel.id + ")");
return;
}
newModel = identify;
}
newProperties = Entities.getEntityProperties(newModel);
}
print("foundEntity.modelURL=" + newProperties.modelURL);
var check = this.checkEntity(newProperties);
if (!check.valid) {
return;
}
this.grab(newModel, newProperties);
this.x = check.x;
this.y = check.y;
this.z = check.z;
return;
}
}
this.cleanup = function () {
Overlays.deleteOverlay(this.laser);
Overlays.deleteOverlay(this.ball);
Overlays.deleteOverlay(this.leftRight);
Overlays.deleteOverlay(this.topDown);
}
}
var leftController = new controller(LEFT);
var rightController = new controller(RIGHT);
function moveEntities(deltaTime) {
if (leftController.grabbing && rightController.grabbing && rightController.entityID.id == leftController.entityID.id) {
var newPosition = leftController.oldModelPosition;
var rotation = leftController.oldModelRotation;
var ratio = 1;
var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition));
var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition));
var cos_theta = Vec3.dot(u, v);
if (cos_theta > 1) {
cos_theta = 1;
}
var angle = Math.acos(cos_theta) / Math.PI * 180;
if (angle < 0.1) {
return;
}
var w = Vec3.normalize(Vec3.cross(u, v));
rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation);
leftController.positionAtGrab = leftController.palmPosition;
leftController.rotationAtGrab = leftController.rotation;
leftController.modelPositionAtGrab = leftController.oldModelPosition;
leftController.modelRotationAtGrab = rotation;
rightController.positionAtGrab = rightController.palmPosition;
rightController.rotationAtGrab = rightController.rotation;
rightController.modelPositionAtGrab = rightController.oldModelPosition;
rightController.modelRotationAtGrab = rotation;
Entities.editEntity(leftController.entityID, {
position: newPosition,
rotation: rotation,
// TODO: how do we know the correct dimensions for detachment???
//radius: leftController.oldModelHalfDiagonal * ratio
dimensions: { x: leftController.oldModelHalfDiagonal * ratio,
y: leftController.oldModelHalfDiagonal * ratio,
z: leftController.oldModelHalfDiagonal * ratio }
});
leftController.oldModelPosition = newPosition;
leftController.oldModelRotation = rotation;
leftController.oldModelHalfDiagonal *= ratio;
rightController.oldModelPosition = newPosition;
rightController.oldModelRotation = rotation;
rightController.oldModelHalfDiagonal *= ratio;
return;
}
leftController.moveEntity(deltaTime);
rightController.moveEntity(deltaTime);
}
var hydraConnected = false;
function checkController(deltaTime) {
var numberOfButtons = Controller.getNumberOfButtons();
var numberOfTriggers = Controller.getNumberOfTriggers();
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
// this is expected for hydras
if (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2) {
if (!hydraConnected) {
hydraConnected = true;
}
leftController.update();
rightController.update();
moveEntities(deltaTime);
} else {
if (hydraConnected) {
hydraConnected = false;
leftController.showLaser(false);
rightController.showLaser(false);
}
}
}
var glowedEntityID = { id: -1, isKnownID: false };
// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already
// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that
// added it.
var ROOT_MENU = "Edit";
var ITEM_BEFORE = "Physics";
var MENU_SEPARATOR = "Models";
var EDIT_PROPERTIES = "Edit Properties...";
var INTERSECTION_STATS = "Print Intersection Stats";
var DELETE = "Delete";
var LARGE_MODELS = "Allow Selecting of Large Models";
var SMALL_MODELS = "Allow Selecting of Small Models";
var LIGHTS = "Allow Selecting of Lights";
var modelMenuAddedDelete = false;
var originalLightsArePickable = Entities.getLightsArePickable();
function setupModelMenus() {
print("setupModelMenus()");
// adj our menuitems
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: MENU_SEPARATOR, isSeparator: true, beforeItem: ITEM_BEFORE });
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: EDIT_PROPERTIES,
shortcutKeyEvent: { text: "`" }, afterItem: MENU_SEPARATOR });
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: INTERSECTION_STATS, afterItem: MENU_SEPARATOR });
if (!Menu.menuItemExists(ROOT_MENU, DELETE)) {
print("no delete... adding ours");
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: DELETE,
shortcutKeyEvent: { text: "backspace" }, afterItem: MENU_SEPARATOR });
modelMenuAddedDelete = true;
} else {
print("delete exists... don't add ours");
}
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: LARGE_MODELS, shortcutKey: "CTRL+META+L",
afterItem: DELETE, isCheckable: true });
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: SMALL_MODELS, shortcutKey: "CTRL+META+S",
afterItem: LARGE_MODELS, isCheckable: true });
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: LIGHTS, shortcutKey: "CTRL+SHIFT+META+L",
afterItem: SMALL_MODELS, isCheckable: true });
Entities.setLightsArePickable(false);
}
function cleanupModelMenus() {
Menu.removeSeparator(ROOT_MENU, MENU_SEPARATOR);
Menu.removeMenuItem(ROOT_MENU, EDIT_PROPERTIES);
Menu.removeMenuItem(ROOT_MENU, INTERSECTION_STATS);
if (modelMenuAddedDelete) {
// delete our menuitems
Menu.removeMenuItem(ROOT_MENU, DELETE);
}
Menu.removeMenuItem(ROOT_MENU, LARGE_MODELS);
Menu.removeMenuItem(ROOT_MENU, SMALL_MODELS);
Menu.removeMenuItem(ROOT_MENU, LIGHTS);
}
function scriptEnding() {
leftController.cleanup();
rightController.cleanup();
cleanupModelMenus();
Entities.setLightsArePickable(originalLightsArePickable);
}
Script.scriptEnding.connect(scriptEnding);
// register the call back so it fires before each data send
Script.update.connect(checkController);
setupModelMenus();
var editModelID = -1;
function showPropertiesForm(editModelID) {
entityPropertyDialogBox.openDialog(editModelID);
}
Menu.menuItemEvent.connect(function (menuItem) {
print("menuItemEvent() in JS... menuItem=" + menuItem);
if (menuItem == SMALL_MODELS) {
allowSmallModels = Menu.isOptionChecked(SMALL_MODELS);
} else if (menuItem == LARGE_MODELS) {
allowLargeModels = Menu.isOptionChecked(LARGE_MODELS);
} else if (menuItem == LIGHTS) {
Entities.setLightsArePickable(Menu.isOptionChecked(LIGHTS));
} else if (menuItem == DELETE) {
if (leftController.grabbing) {
print(" Delete Entity.... leftController.entityID="+ leftController.entityID);
Entities.deleteEntity(leftController.entityID);
leftController.grabbing = false;
if (glowedEntityID.id == leftController.entityID.id) {
glowedEntityID = { id: -1, isKnownID: false };
}
} else if (rightController.grabbing) {
print(" Delete Entity.... rightController.entityID="+ rightController.entityID);
Entities.deleteEntity(rightController.entityID);
rightController.grabbing = false;
if (glowedEntityID.id == rightController.entityID.id) {
glowedEntityID = { id: -1, isKnownID: false };
}
} else {
print(" Delete Entity.... not holding...");
}
} else if (menuItem == EDIT_PROPERTIES) {
editModelID = -1;
if (leftController.grabbing) {
print(" Edit Properties.... leftController.entityID="+ leftController.entityID);
editModelID = leftController.entityID;
} else if (rightController.grabbing) {
print(" Edit Properties.... rightController.entityID="+ rightController.entityID);
editModelID = rightController.entityID;
} else {
print(" Edit Properties.... not holding...");
}
if (editModelID != -1) {
print(" Edit Properties.... about to edit properties...");
showPropertiesForm(editModelID);
}
} else if (menuItem == INTERSECTION_STATS) {
printIntersectionsStats();
}
});
Controller.keyReleaseEvent.connect(function (event) {
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
if (event.text == "`") {
handeMenuEvent(EDIT_PROPERTIES);
}
if (event.text == "BACKSPACE") {
handeMenuEvent(DELETE);
}
});