overte-JulianGro/scripts/system/libraries/entitySelectionTool.js
2017-09-27 12:58:11 -07:00

4686 lines
150 KiB
JavaScript

//
// entitySelectionToolClass.js
// examples
//
// Created by Brad hefta-Gaub on 10/1/14.
// Modified by Daniela Fontes @DanielaFifo and Tiago Andrade @TagoWill on 4/7/2017
// Copyright 2014 High Fidelity, Inc.
//
// This script implements a class useful for building tools for editing entities.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global HIFI_PUBLIC_BUCKET, SPACE_LOCAL, Script, SelectionManager */
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
SPACE_LOCAL = "local";
SPACE_WORLD = "world";
Script.include("./controllers.js");
function objectTranslationPlanePoint(position, dimensions) {
var newPosition = { x: position.x, y: position.y, z: position.z };
newPosition.y -= dimensions.y / 2.0;
return newPosition;
}
SelectionManager = (function() {
var that = {};
// FUNCTION: SUBSCRIBE TO UPDATE MESSAGES
function subscribeToUpdateMessages() {
Messages.subscribe("entityToolUpdates");
Messages.messageReceived.connect(handleEntitySelectionToolUpdates);
}
// FUNCTION: HANDLE ENTITY SELECTION TOOL UDPATES
function handleEntitySelectionToolUpdates(channel, message, sender) {
if (channel !== 'entityToolUpdates') {
return;
}
if (sender !== MyAvatar.sessionUUID) {
return;
}
var messageParsed;
try {
messageParsed = JSON.parse(message);
} catch (err) {
print("error -- entitySelectionTool got malformed message: " + message);
}
// if (message === 'callUpdate') {
// that._update();
// }
if (messageParsed.method === "selectEntity") {
print("setting selection to " + messageParsed.entityID);
that.setSelections([messageParsed.entityID]);
}
}
subscribeToUpdateMessages();
that.savedProperties = {};
that.selections = [];
var listeners = [];
that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
that.localPosition = {
x: 0,
y: 0,
z: 0
};
that.localDimensions = {
x: 0,
y: 0,
z: 0
};
that.localRegistrationPoint = {
x: 0.5,
y: 0.5,
z: 0.5
};
that.worldRotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
that.worldPosition = {
x: 0,
y: 0,
z: 0
};
that.worldDimensions = {
x: 0,
y: 0,
z: 0
};
that.worldRegistrationPoint = {
x: 0.5,
y: 0.5,
z: 0.5
};
that.centerPosition = {
x: 0,
y: 0,
z: 0
};
that.saveProperties = function() {
that.savedProperties = {};
for (var i = 0; i < that.selections.length; i++) {
var entityID = that.selections[i];
that.savedProperties[entityID] = Entities.getEntityProperties(entityID);
}
};
that.addEventListener = function(func) {
listeners.push(func);
};
that.hasSelection = function() {
return that.selections.length > 0;
};
that.setSelections = function(entityIDs) {
that.selections = [];
for (var i = 0; i < entityIDs.length; i++) {
var entityID = entityIDs[i];
that.selections.push(entityID);
}
that._update(true);
};
that.addEntity = function(entityID, toggleSelection) {
if (entityID) {
var idx = -1;
for (var i = 0; i < that.selections.length; i++) {
if (entityID == that.selections[i]) {
idx = i;
break;
}
}
if (idx == -1) {
that.selections.push(entityID);
} else if (toggleSelection) {
that.selections.splice(idx, 1);
}
}
that._update(true);
};
that.removeEntity = function(entityID) {
var idx = that.selections.indexOf(entityID);
if (idx >= 0) {
that.selections.splice(idx, 1);
}
that._update(true);
};
that.clearSelections = function() {
that.selections = [];
that._update(true);
};
that._update = function(selectionUpdated) {
var properties = null;
if (that.selections.length === 0) {
that.localDimensions = null;
that.localPosition = null;
that.worldDimensions = null;
that.worldPosition = null;
} else if (that.selections.length == 1) {
properties = Entities.getEntityProperties(that.selections[0]);
that.localDimensions = properties.dimensions;
that.localPosition = properties.position;
that.localRotation = properties.rotation;
that.localRegistrationPoint = properties.registrationPoint;
that.worldDimensions = properties.boundingBox.dimensions;
that.worldPosition = properties.boundingBox.center;
SelectionDisplay.setSpaceMode(SPACE_LOCAL);
} else {
that.localRotation = null;
that.localDimensions = null;
that.localPosition = null;
properties = Entities.getEntityProperties(that.selections[0]);
var brn = properties.boundingBox.brn;
var tfl = properties.boundingBox.tfl;
for (var i = 1; i < that.selections.length; i++) {
properties = Entities.getEntityProperties(that.selections[i]);
var bb = properties.boundingBox;
brn.x = Math.min(bb.brn.x, brn.x);
brn.y = Math.min(bb.brn.y, brn.y);
brn.z = Math.min(bb.brn.z, brn.z);
tfl.x = Math.max(bb.tfl.x, tfl.x);
tfl.y = Math.max(bb.tfl.y, tfl.y);
tfl.z = Math.max(bb.tfl.z, tfl.z);
}
that.localDimensions = null;
that.localPosition = null;
that.worldDimensions = {
x: tfl.x - brn.x,
y: tfl.y - brn.y,
z: tfl.z - brn.z
};
that.worldPosition = {
x: brn.x + (that.worldDimensions.x / 2),
y: brn.y + (that.worldDimensions.y / 2),
z: brn.z + (that.worldDimensions.z / 2),
};
// For 1+ selections we can only modify selections in world space
SelectionDisplay.setSpaceMode(SPACE_WORLD);
}
for (var j = 0; j < listeners.length; j++) {
try {
listeners[j](selectionUpdated === true);
} catch (e) {
print("EntitySelectionTool got exception: " + JSON.stringify(e));
}
}
};
return that;
})();
// Normalize degrees to be in the range (-180, 180]
function normalizeDegrees(degrees) {
while (degrees > 180) degrees -= 360;
while (degrees <= -180) degrees += 360;
return degrees;
}
// FUNCTION: getRelativeCenterPosition
// Return the enter position of an entity relative to it's registrationPoint
// A registration point of (0.5, 0.5, 0.5) will have an offset of (0, 0, 0)
// A registration point of (1.0, 1.0, 1.0) will have an offset of (-dimensions.x / 2, -dimensions.y / 2, -dimensions.z / 2)
function getRelativeCenterPosition(dimensions, registrationPoint) {
return {
x: -dimensions.x * (registrationPoint.x - 0.5),
y: -dimensions.y * (registrationPoint.y - 0.5),
z: -dimensions.z * (registrationPoint.z - 0.5)
};
}
// SELECTION DISPLAY DEFINITION
SelectionDisplay = (function() {
var that = {};
var MINIMUM_DIMENSION = 0.001;
var GRABBER_DISTANCE_TO_SIZE_RATIO = 0.0075;
// These are multipliers for sizing the rotation degrees display while rotating an entity
var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.2;
var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.6;
var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.18;
var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.14;
var ROTATE_ARROW_WEST_NORTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-north.svg";
var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.svg";
var showExtendedStretchHandles = false;
var spaceMode = SPACE_LOCAL;
var mode = "UNKNOWN";
var overlayNames = [];
var lastCameraPosition = Camera.getPosition();
var lastCameraOrientation = Camera.getOrientation();
var lastControllerPoses = [
getControllerWorldLocation(Controller.Standard.LeftHand, true),
getControllerWorldLocation(Controller.Standard.RightHand, true)
];
var handleHoverColor = {
red: 224,
green: 67,
blue: 36
};
var handleHoverAlpha = 1.0;
var rotateOverlayTargetSize = 10000; // really big target
var innerSnapAngle = 22.5; // the angle which we snap to on the inner rotation tool
var innerRadius;
var outerRadius;
var yawHandleRotation;
var pitchHandleRotation;
var rollHandleRotation;
var yawCenter;
var pitchCenter;
var rollCenter;
var yawZero;
var pitchZero;
var rollZero;
var yawNormal;
var pitchNormal;
var rollNormal;
var rotationNormal;
var originalRotation;
var originalPitch;
var originalYaw;
var originalRoll;
var handleColor = {
red: 255,
green: 255,
blue: 255
};
var handleAlpha = 0.7;
var highlightedHandleColor = {
red: 183,
green: 64,
blue: 44
};
var highlightedHandleAlpha = 0.9;
var previousHandle = false;
var previousHandleColor;
var previousHandleAlpha;
var grabberSizeCorner = 0.025; // These get resized by updateHandleSizes().
var grabberSizeEdge = 0.015;
var grabberSizeFace = 0.025;
var grabberAlpha = 1;
var grabberColorCorner = {
red: 120,
green: 120,
blue: 120
};
var grabberColorEdge = {
red: 0,
green: 0,
blue: 0
};
var grabberColorFace = {
red: 120,
green: 120,
blue: 120
};
var grabberColorCloner = {
red: 0,
green: 155,
blue: 0
};
var grabberLineWidth = 0.5;
var grabberSolid = true;
var grabberMoveUpPosition = {
x: 0,
y: 0,
z: 0
};
var lightOverlayColor = {
red: 255,
green: 153,
blue: 0
};
var grabberPropertiesCorner = {
position: {
x: 0,
y: 0,
z: 0
},
size: grabberSizeCorner,
color: grabberColorCorner,
alpha: 1,
solid: grabberSolid,
visible: false,
dashed: false,
lineWidth: grabberLineWidth,
drawInFront: true,
borderSize: 1.4,
};
var grabberPropertiesEdge = {
position: {
x: 0,
y: 0,
z: 0
},
size: grabberSizeEdge,
color: grabberColorEdge,
alpha: 1,
solid: grabberSolid,
visible: false,
dashed: false,
lineWidth: grabberLineWidth,
drawInFront: true,
borderSize: 1.4,
};
var grabberPropertiesFace = {
position: {
x: 0,
y: 0,
z: 0
},
size: grabberSizeFace,
color: grabberColorFace,
alpha: 1,
solid: grabberSolid,
visible: false,
dashed: false,
lineWidth: grabberLineWidth,
drawInFront: true,
borderSize: 1.4,
};
var grabberPropertiesCloner = {
position: {
x: 0,
y: 0,
z: 0
},
size: grabberSizeCorner,
color: grabberColorCloner,
alpha: 1,
solid: grabberSolid,
visible: false,
dashed: false,
lineWidth: grabberLineWidth,
drawInFront: true,
borderSize: 1.4,
};
var spotLightLineProperties = {
color: lightOverlayColor,
lineWidth: 1.5,
};
var highlightBox = Overlays.addOverlay("cube", {
position: {
x: 0,
y: 0,
z: 0
},
size: 1,
color: {
red: 90,
green: 90,
blue: 90
},
alpha: 1,
solid: false,
visible: false,
dashed: true,
lineWidth: 2.0,
ignoreRayIntersection: true, // this never ray intersects
drawInFront: true
});
var selectionBox = Overlays.addOverlay("cube", {
position: {
x: 0,
y: 0,
z: 0
},
size: 1,
color: {
red: 255,
green: 0,
blue: 0
},
alpha: 1,
solid: false,
visible: false,
dashed: false,
lineWidth: 1.0,
});
var selectionBoxes = [];
var rotationDegreesDisplay = Overlays.addOverlay("text3d", {
position: {
x: 0,
y: 0,
z: 0
},
text: "",
color: {
red: 0,
green: 0,
blue: 0
},
backgroundColor: {
red: 255,
green: 255,
blue: 255
},
alpha: 0.7,
backgroundAlpha: 0.7,
visible: false,
isFacingAvatar: true,
drawInFront: true,
ignoreRayIntersection: true,
dimensions: {
x: 0,
y: 0
},
lineHeight: 0.0,
topMargin: 0,
rightMargin: 0,
bottomMargin: 0,
leftMargin: 0,
});
var grabberMoveUp = Overlays.addOverlay("image3d", {
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.svg",
position: {
x: 0,
y: 0,
z: 0
},
color: handleColor,
alpha: handleAlpha,
visible: false,
size: 0.1,
scale: 0.1,
isFacingAvatar: true,
drawInFront: true,
});
// var normalLine = Overlays.addOverlay("line3d", {
// visible: true,
// lineWidth: 2.0,
// start: { x: 0, y: 0, z: 0 },
// end: { x: 0, y: 0, z: 0 },
// color: { red: 255, green: 255, blue: 0 },
// ignoreRayIntersection: true,
// });
var grabberLBN = Overlays.addOverlay("cube", grabberPropertiesCorner);
var grabberRBN = Overlays.addOverlay("cube", grabberPropertiesCorner);
var grabberLBF = Overlays.addOverlay("cube", grabberPropertiesCorner);
var grabberRBF = Overlays.addOverlay("cube", grabberPropertiesCorner);
var grabberLTN = Overlays.addOverlay("cube", grabberPropertiesCorner);
var grabberRTN = Overlays.addOverlay("cube", grabberPropertiesCorner);
var grabberLTF = Overlays.addOverlay("cube", grabberPropertiesCorner);
var grabberRTF = Overlays.addOverlay("cube", grabberPropertiesCorner);
var grabberTOP = Overlays.addOverlay("cube", grabberPropertiesFace);
var grabberBOTTOM = Overlays.addOverlay("cube", grabberPropertiesFace);
var grabberLEFT = Overlays.addOverlay("cube", grabberPropertiesFace);
var grabberRIGHT = Overlays.addOverlay("cube", grabberPropertiesFace);
var grabberNEAR = Overlays.addOverlay("cube", grabberPropertiesFace);
var grabberFAR = Overlays.addOverlay("cube", grabberPropertiesFace);
var grabberEdgeTR = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeTL = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeTF = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeTN = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeBR = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeBL = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeBF = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeBN = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeNR = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeNL = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeFR = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberEdgeFL = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberSpotLightCircle = Overlays.addOverlay("circle3d", {
color: lightOverlayColor,
isSolid: false,
visible: false
});
var grabberSpotLightLineT = Overlays.addOverlay("line3d", spotLightLineProperties);
var grabberSpotLightLineB = Overlays.addOverlay("line3d", spotLightLineProperties);
var grabberSpotLightLineL = Overlays.addOverlay("line3d", spotLightLineProperties);
var grabberSpotLightLineR = Overlays.addOverlay("line3d", spotLightLineProperties);
var grabberSpotLightCenter = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberSpotLightRadius = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberSpotLightL = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberSpotLightR = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberSpotLightT = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberSpotLightB = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberPointLightCircleX = Overlays.addOverlay("circle3d", {
rotation: Quat.fromPitchYawRollDegrees(0, 90, 0),
color: lightOverlayColor,
isSolid: false,
visible: false
});
var grabberPointLightCircleY = Overlays.addOverlay("circle3d", {
rotation: Quat.fromPitchYawRollDegrees(90, 0, 0),
color: lightOverlayColor,
isSolid: false,
visible: false
});
var grabberPointLightCircleZ = Overlays.addOverlay("circle3d", {
rotation: Quat.fromPitchYawRollDegrees(0, 0, 0),
color: lightOverlayColor,
isSolid: false,
visible: false
});
var grabberPointLightT = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberPointLightB = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberPointLightL = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberPointLightR = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberPointLightF = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberPointLightN = Overlays.addOverlay("cube", grabberPropertiesEdge);
var grabberCloner = Overlays.addOverlay("cube", grabberPropertiesCloner);
var stretchHandles = [
grabberLBN,
grabberRBN,
grabberLBF,
grabberRBF,
grabberLTN,
grabberRTN,
grabberLTF,
grabberRTF,
grabberTOP,
grabberBOTTOM,
grabberLEFT,
grabberRIGHT,
grabberNEAR,
grabberFAR,
grabberEdgeTR,
grabberEdgeTL,
grabberEdgeTF,
grabberEdgeTN,
grabberEdgeBR,
grabberEdgeBL,
grabberEdgeBF,
grabberEdgeBN,
grabberEdgeNR,
grabberEdgeNL,
grabberEdgeFR,
grabberEdgeFL,
grabberSpotLightLineT,
grabberSpotLightLineB,
grabberSpotLightLineL,
grabberSpotLightLineR,
grabberSpotLightCenter,
grabberSpotLightRadius,
grabberSpotLightL,
grabberSpotLightR,
grabberSpotLightT,
grabberSpotLightB,
grabberPointLightT,
grabberPointLightB,
grabberPointLightL,
grabberPointLightR,
grabberPointLightF,
grabberPointLightN,
grabberCloner
];
var baseOverlayAngles = {
x: 0,
y: 0,
z: 0
};
var baseOverlayRotation = Quat.fromVec3Degrees(baseOverlayAngles);
var baseOfEntityProjectionOverlay = Overlays.addOverlay("rectangle3d", {
position: {
x: 1,
y: 0,
z: 0
},
color: {
red: 51,
green: 152,
blue: 203
},
alpha: 0.5,
solid: true,
visible: false,
width: 300,
height: 200,
rotation: baseOverlayRotation,
ignoreRayIntersection: true, // always ignore this
});
var yawOverlayAngles = {
x: 90,
y: 0,
z: 0
};
var yawOverlayRotation = Quat.fromVec3Degrees(yawOverlayAngles);
var pitchOverlayAngles = {
x: 0,
y: 90,
z: 0
};
var pitchOverlayRotation = Quat.fromVec3Degrees(pitchOverlayAngles);
var rollOverlayAngles = {
x: 0,
y: 180,
z: 0
};
var rollOverlayRotation = Quat.fromVec3Degrees(rollOverlayAngles);
var xRailOverlay = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: 1.0,
start: {
x: 0,
y: 0,
z: 0
},
end: {
x: 0,
y: 0,
z: 0
},
color: {
red: 255,
green: 0,
blue: 0
},
ignoreRayIntersection: true // always ignore this
});
var yRailOverlay = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: 1.0,
start: {
x: 0,
y: 0,
z: 0
},
end: {
x: 0,
y: 0,
z: 0
},
color: {
red: 0,
green: 255,
blue: 0
},
ignoreRayIntersection: true // always ignore this
});
var zRailOverlay = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: 1.0,
start: {
x: 0,
y: 0,
z: 0
},
end: {
x: 0,
y: 0,
z: 0
},
color: {
red: 0,
green: 0,
blue: 255
},
ignoreRayIntersection: true // always ignore this
});
var rotateZeroOverlay = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: 2.0,
start: {
x: 0,
y: 0,
z: 0
},
end: {
x: 0,
y: 0,
z: 0
},
color: {
red: 255,
green: 0,
blue: 0
},
ignoreRayIntersection: true, // always ignore this
});
var rotateCurrentOverlay = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: 2.0,
start: {
x: 0,
y: 0,
z: 0
},
end: {
x: 0,
y: 0,
z: 0
},
color: {
red: 0,
green: 0,
blue: 255
},
ignoreRayIntersection: true, // always ignore this
});
var rotateOverlayTarget = Overlays.addOverlay("circle3d", {
position: {
x: 0,
y: 0,
z: 0
},
size: rotateOverlayTargetSize,
color: {
red: 0,
green: 0,
blue: 0
},
alpha: 0.0,
solid: true,
visible: false,
rotation: yawOverlayRotation,
});
var rotateOverlayInner = Overlays.addOverlay("circle3d", {
position: {
x: 0,
y: 0,
z: 0
},
size: 1,
color: {
red: 51,
green: 152,
blue: 203
},
alpha: 0.2,
solid: true,
visible: false,
rotation: yawOverlayRotation,
hasTickMarks: true,
majorTickMarksAngle: innerSnapAngle,
minorTickMarksAngle: 0,
majorTickMarksLength: -0.25,
minorTickMarksLength: 0,
majorTickMarksColor: {
red: 0,
green: 0,
blue: 0
},
minorTickMarksColor: {
red: 0,
green: 0,
blue: 0
},
ignoreRayIntersection: true, // always ignore this
});
var rotateOverlayOuter = Overlays.addOverlay("circle3d", {
position: {
x: 0,
y: 0,
z: 0
},
size: 1,
color: {
red: 51,
green: 152,
blue: 203
},
alpha: 0.2,
solid: true,
visible: false,
rotation: yawOverlayRotation,
hasTickMarks: true,
majorTickMarksAngle: 45.0,
minorTickMarksAngle: 5,
majorTickMarksLength: 0.25,
minorTickMarksLength: 0.1,
majorTickMarksColor: {
red: 0,
green: 0,
blue: 0
},
minorTickMarksColor: {
red: 0,
green: 0,
blue: 0
},
ignoreRayIntersection: true, // always ignore this
});
var rotateOverlayCurrent = Overlays.addOverlay("circle3d", {
position: {
x: 0,
y: 0,
z: 0
},
size: 1,
color: {
red: 224,
green: 67,
blue: 36
},
alpha: 0.8,
solid: true,
visible: false,
rotation: yawOverlayRotation,
ignoreRayIntersection: true, // always ignore this
hasTickMarks: true,
majorTickMarksColor: {
red: 0,
green: 0,
blue: 0
},
minorTickMarksColor: {
red: 0,
green: 0,
blue: 0
},
});
var yawHandle = Overlays.addOverlay("image3d", {
url: ROTATE_ARROW_WEST_NORTH_URL,
position: {
x: 0,
y: 0,
z: 0
},
color: handleColor,
alpha: handleAlpha,
visible: false,
size: 0.1,
scale: 0.1,
isFacingAvatar: false,
drawInFront: true,
});
var pitchHandle = Overlays.addOverlay("image3d", {
url: ROTATE_ARROW_WEST_NORTH_URL,
position: {
x: 0,
y: 0,
z: 0
},
color: handleColor,
alpha: handleAlpha,
visible: false,
size: 0.1,
scale: 0.1,
isFacingAvatar: false,
drawInFront: true,
});
var rollHandle = Overlays.addOverlay("image3d", {
url: ROTATE_ARROW_WEST_NORTH_URL,
position: {
x: 0,
y: 0,
z: 0
},
color: handleColor,
alpha: handleAlpha,
visible: false,
size: 0.1,
scale: 0.1,
isFacingAvatar: false,
drawInFront: true,
});
var allOverlays = [
highlightBox,
selectionBox,
grabberMoveUp,
yawHandle,
pitchHandle,
rollHandle,
rotateOverlayTarget,
rotateOverlayInner,
rotateOverlayOuter,
rotateOverlayCurrent,
rotateZeroOverlay,
rotateCurrentOverlay,
rotationDegreesDisplay,
xRailOverlay,
yRailOverlay,
zRailOverlay,
baseOfEntityProjectionOverlay,
grabberSpotLightCircle,
grabberPointLightCircleX,
grabberPointLightCircleY,
grabberPointLightCircleZ,
].concat(stretchHandles);
overlayNames[highlightBox] = "highlightBox";
overlayNames[selectionBox] = "selectionBox";
overlayNames[baseOfEntityProjectionOverlay] = "baseOfEntityProjectionOverlay";
overlayNames[grabberMoveUp] = "grabberMoveUp";
overlayNames[grabberLBN] = "grabberLBN";
overlayNames[grabberLBF] = "grabberLBF";
overlayNames[grabberRBN] = "grabberRBN";
overlayNames[grabberRBF] = "grabberRBF";
overlayNames[grabberLTN] = "grabberLTN";
overlayNames[grabberLTF] = "grabberLTF";
overlayNames[grabberRTN] = "grabberRTN";
overlayNames[grabberRTF] = "grabberRTF";
overlayNames[grabberTOP] = "grabberTOP";
overlayNames[grabberBOTTOM] = "grabberBOTTOM";
overlayNames[grabberLEFT] = "grabberLEFT";
overlayNames[grabberRIGHT] = "grabberRIGHT";
overlayNames[grabberNEAR] = "grabberNEAR";
overlayNames[grabberFAR] = "grabberFAR";
overlayNames[grabberEdgeTR] = "grabberEdgeTR";
overlayNames[grabberEdgeTL] = "grabberEdgeTL";
overlayNames[grabberEdgeTF] = "grabberEdgeTF";
overlayNames[grabberEdgeTN] = "grabberEdgeTN";
overlayNames[grabberEdgeBR] = "grabberEdgeBR";
overlayNames[grabberEdgeBL] = "grabberEdgeBL";
overlayNames[grabberEdgeBF] = "grabberEdgeBF";
overlayNames[grabberEdgeBN] = "grabberEdgeBN";
overlayNames[grabberEdgeNR] = "grabberEdgeNR";
overlayNames[grabberEdgeNL] = "grabberEdgeNL";
overlayNames[grabberEdgeFR] = "grabberEdgeFR";
overlayNames[grabberEdgeFL] = "grabberEdgeFL";
overlayNames[yawHandle] = "yawHandle";
overlayNames[pitchHandle] = "pitchHandle";
overlayNames[rollHandle] = "rollHandle";
overlayNames[rotateOverlayTarget] = "rotateOverlayTarget";
overlayNames[rotateOverlayInner] = "rotateOverlayInner";
overlayNames[rotateOverlayOuter] = "rotateOverlayOuter";
overlayNames[rotateOverlayCurrent] = "rotateOverlayCurrent";
overlayNames[rotateZeroOverlay] = "rotateZeroOverlay";
overlayNames[rotateCurrentOverlay] = "rotateCurrentOverlay";
overlayNames[grabberCloner] = "grabberCloner";
var activeTool = null;
var grabberTools = {};
// We get mouseMoveEvents from the handControllers, via handControllerPointer.
// But we dont' get mousePressEvents.
that.triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click');
Script.scriptEnding.connect(that.triggerMapping.disable);
that.TRIGGER_GRAB_VALUE = 0.85; // From handControllerGrab/Pointer.js. Should refactor.
that.TRIGGER_ON_VALUE = 0.4;
that.TRIGGER_OFF_VALUE = 0.15;
that.triggered = false;
var activeHand = Controller.Standard.RightHand;
function makeTriggerHandler(hand) {
return function (value) {
if (!that.triggered && (value > that.TRIGGER_GRAB_VALUE)) { // should we smooth?
that.triggered = true;
if (activeHand !== hand) {
// No switching while the other is already triggered, so no need to release.
activeHand = (activeHand === Controller.Standard.RightHand) ?
Controller.Standard.LeftHand : Controller.Standard.RightHand;
}
if (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(Reticle.position)) {
return;
}
that.mousePressEvent({});
} else if (that.triggered && (value < that.TRIGGER_OFF_VALUE)) {
that.triggered = false;
that.mouseReleaseEvent({});
}
};
}
that.triggerMapping.from(Controller.Standard.RT).peek().to(makeTriggerHandler(Controller.Standard.RightHand));
that.triggerMapping.from(Controller.Standard.LT).peek().to(makeTriggerHandler(Controller.Standard.LeftHand));
function controllerComputePickRay() {
var controllerPose = getControllerWorldLocation(activeHand, true);
if (controllerPose.valid && that.triggered) {
var controllerPosition = controllerPose.translation;
// This gets point direction right, but if you want general quaternion it would be more complicated:
var controllerDirection = Quat.getUp(controllerPose.rotation);
return {origin: controllerPosition, direction: controllerDirection};
}
}
function generalComputePickRay(x, y) {
return controllerComputePickRay() || Camera.computePickRay(x, y);
}
function addGrabberTool(overlay, tool) {
grabberTools[overlay] = {
mode: tool.mode,
onBegin: tool.onBegin,
onMove: tool.onMove,
onEnd: tool.onEnd,
};
}
that.cleanup = function() {
for (var i = 0; i < allOverlays.length; i++) {
Overlays.deleteOverlay(allOverlays[i]);
}
for (var j = 0; j < selectionBoxes.length; j++) {
Overlays.deleteOverlay(selectionBoxes[j]);
}
};
that.highlightSelectable = function(entityID) {
var properties = Entities.getEntityProperties(entityID);
Overlays.editOverlay(highlightBox, {
visible: true,
position: properties.boundingBox.center,
dimensions: properties.dimensions,
rotation: properties.rotation
});
};
that.unhighlightSelectable = function(entityID) {
Overlays.editOverlay(highlightBox, {
visible: false
});
};
that.select = function(entityID, event) {
var properties = Entities.getEntityProperties(SelectionManager.selections[0]);
lastCameraPosition = Camera.getPosition();
lastCameraOrientation = Camera.getOrientation();
if (event !== false) {
pickRay = generalComputePickRay(event.x, event.y);
var wantDebug = false;
if (wantDebug) {
print("select() with EVENT...... ");
print(" event.y:" + event.y);
Vec3.print(" current position:", properties.position);
}
}
Overlays.editOverlay(highlightBox, {
visible: false
});
that.updateHandles();
};
// FUNCTION: UPDATE ROTATION HANDLES
that.updateRotationHandles = function() {
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5);
var innerActive = false;
var innerAlpha = 0.2;
var outerAlpha = 0.2;
if (innerActive) {
innerAlpha = 0.5;
} else {
outerAlpha = 0.5;
}
var rotateHandleOffset = 0.05;
var top, far, left, bottom, near, right, boundsCenter, objectCenter, BLN, BRN, BLF, TLN, TRN, TLF, TRF;
var dimensions, rotation;
if (spaceMode == SPACE_LOCAL) {
rotation = SelectionManager.localRotation;
} else {
rotation = SelectionManager.worldRotation;
}
objectCenter = SelectionManager.worldPosition;
dimensions = SelectionManager.worldDimensions;
var position = objectCenter;
top = objectCenter.y + (dimensions.y / 2);
far = objectCenter.z + (dimensions.z / 2);
left = objectCenter.x + (dimensions.x / 2);
bottom = objectCenter.y - (dimensions.y / 2);
near = objectCenter.z - (dimensions.z / 2);
right = objectCenter.x - (dimensions.x / 2);
boundsCenter = objectCenter;
var yawCorner;
var pitchCorner;
var rollCorner;
// determine which bottom corner we are closest to
/*------------------------------
example:
BRF +--------+ BLF
| |
| |
BRN +--------+ BLN
*
------------------------------*/
var cameraPosition = Camera.getPosition();
if (cameraPosition.x > objectCenter.x) {
// must be BRF or BRN
if (cameraPosition.z < objectCenter.z) {
yawHandleRotation = Quat.fromVec3Degrees({
x: 270,
y: 90,
z: 0
});
pitchHandleRotation = Quat.fromVec3Degrees({
x: 0,
y: 90,
z: 0
});
rollHandleRotation = Quat.fromVec3Degrees({
x: 0,
y: 0,
z: 0
});
yawNormal = {
x: 0,
y: 1,
z: 0
};
pitchNormal = {
x: 1,
y: 0,
z: 0
};
rollNormal = {
x: 0,
y: 0,
z: 1
};
yawCorner = {
x: left + rotateHandleOffset,
y: bottom - rotateHandleOffset,
z: near - rotateHandleOffset
};
pitchCorner = {
x: right - rotateHandleOffset,
y: top + rotateHandleOffset,
z: near - rotateHandleOffset
};
rollCorner = {
x: left + rotateHandleOffset,
y: top + rotateHandleOffset,
z: far + rotateHandleOffset
};
yawCenter = {
x: boundsCenter.x,
y: bottom,
z: boundsCenter.z
};
pitchCenter = {
x: right,
y: boundsCenter.y,
z: boundsCenter.z
};
rollCenter = {
x: boundsCenter.x,
y: boundsCenter.y,
z: far
};
Overlays.editOverlay(pitchHandle, {
url: ROTATE_ARROW_WEST_SOUTH_URL
});
Overlays.editOverlay(rollHandle, {
url: ROTATE_ARROW_WEST_SOUTH_URL
});
} else {
yawHandleRotation = Quat.fromVec3Degrees({
x: 270,
y: 0,
z: 0
});
pitchHandleRotation = Quat.fromVec3Degrees({
x: 180,
y: 270,
z: 0
});
rollHandleRotation = Quat.fromVec3Degrees({
x: 0,
y: 0,
z: 90
});
yawNormal = {
x: 0,
y: 1,
z: 0
};
pitchNormal = {
x: 1,
y: 0,
z: 0
};
rollNormal = {
x: 0,
y: 0,
z: 1
};
yawCorner = {
x: left + rotateHandleOffset,
y: bottom - rotateHandleOffset,
z: far + rotateHandleOffset
};
pitchCorner = {
x: right - rotateHandleOffset,
y: top + rotateHandleOffset,
z: far + rotateHandleOffset
};
rollCorner = {
x: left + rotateHandleOffset,
y: top + rotateHandleOffset,
z: near - rotateHandleOffset
};
yawCenter = {
x: boundsCenter.x,
y: bottom,
z: boundsCenter.z
};
pitchCenter = {
x: right,
y: boundsCenter.y,
z: boundsCenter.z
};
rollCenter = {
x: boundsCenter.x,
y: boundsCenter.y,
z: near
};
Overlays.editOverlay(pitchHandle, {
url: ROTATE_ARROW_WEST_NORTH_URL
});
Overlays.editOverlay(rollHandle, {
url: ROTATE_ARROW_WEST_NORTH_URL
});
}
} else {
// must be BLF or BLN
if (cameraPosition.z < objectCenter.z) {
yawHandleRotation = Quat.fromVec3Degrees({
x: 270,
y: 180,
z: 0
});
pitchHandleRotation = Quat.fromVec3Degrees({
x: 90,
y: 0,
z: 90
});
rollHandleRotation = Quat.fromVec3Degrees({
x: 0,
y: 0,
z: 180
});
yawNormal = {
x: 0,
y: 1,
z: 0
};
pitchNormal = {
x: 1,
y: 0,
z: 0
};
rollNormal = {
x: 0,
y: 0,
z: 1
};
yawCorner = {
x: right - rotateHandleOffset,
y: bottom - rotateHandleOffset,
z: near - rotateHandleOffset
};
pitchCorner = {
x: left + rotateHandleOffset,
y: top + rotateHandleOffset,
z: near - rotateHandleOffset
};
rollCorner = {
x: right - rotateHandleOffset,
y: top + rotateHandleOffset,
z: far + rotateHandleOffset
};
yawCenter = {
x: boundsCenter.x,
y: bottom,
z: boundsCenter.z
};
pitchCenter = {
x: left,
y: boundsCenter.y,
z: boundsCenter.z
};
rollCenter = {
x: boundsCenter.x,
y: boundsCenter.y,
z: far
};
Overlays.editOverlay(pitchHandle, {
url: ROTATE_ARROW_WEST_NORTH_URL
});
Overlays.editOverlay(rollHandle, {
url: ROTATE_ARROW_WEST_NORTH_URL
});
} else {
yawHandleRotation = Quat.fromVec3Degrees({
x: 270,
y: 270,
z: 0
});
pitchHandleRotation = Quat.fromVec3Degrees({
x: 180,
y: 270,
z: 0
});
rollHandleRotation = Quat.fromVec3Degrees({
x: 0,
y: 0,
z: 180
});
yawNormal = {
x: 0,
y: 1,
z: 0
};
rollNormal = {
x: 0,
y: 0,
z: 1
};
pitchNormal = {
x: 1,
y: 0,
z: 0
};
yawCorner = {
x: right - rotateHandleOffset,
y: bottom - rotateHandleOffset,
z: far + rotateHandleOffset
};
rollCorner = {
x: right - rotateHandleOffset,
y: top + rotateHandleOffset,
z: near - rotateHandleOffset
};
pitchCorner = {
x: left + rotateHandleOffset,
y: top + rotateHandleOffset,
z: far + rotateHandleOffset
};
yawCenter = {
x: boundsCenter.x,
y: bottom,
z: boundsCenter.z
};
rollCenter = {
x: boundsCenter.x,
y: boundsCenter.y,
z: near
};
pitchCenter = {
x: left,
y: boundsCenter.y,
z: boundsCenter.z
};
Overlays.editOverlay(pitchHandle, {
url: ROTATE_ARROW_WEST_NORTH_URL
});
Overlays.editOverlay(rollHandle, {
url: ROTATE_ARROW_WEST_NORTH_URL
});
}
}
var rotateHandlesVisible = true;
var rotationOverlaysVisible = false;
var translateHandlesVisible = true;
var stretchHandlesVisible = true;
var selectionBoxVisible = true;
var isPointLight = false;
if (selectionManager.selections.length == 1) {
var properties = Entities.getEntityProperties(selectionManager.selections[0]);
isPointLight = properties.type == "Light" && !properties.isSpotlight;
}
if (mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL" || mode == "TRANSLATE_X in case they Z") {
rotationOverlaysVisible = true;
rotateHandlesVisible = false;
translateHandlesVisible = false;
stretchHandlesVisible = false;
selectionBoxVisible = false;
} else if (mode == "TRANSLATE_UP_DOWN" || isPointLight) {
rotateHandlesVisible = false;
stretchHandlesVisible = false;
} else if (mode != "UNKNOWN") {
// every other mode is a stretch mode...
rotateHandlesVisible = false;
translateHandlesVisible = false;
}
Overlays.editOverlay(rotateOverlayTarget, {
visible: rotationOverlaysVisible
});
Overlays.editOverlay(rotateZeroOverlay, {
visible: rotationOverlaysVisible
});
Overlays.editOverlay(rotateCurrentOverlay, {
visible: rotationOverlaysVisible
});
Overlays.editOverlay(yawHandle, {
visible: rotateHandlesVisible,
position: yawCorner,
rotation: yawHandleRotation
});
Overlays.editOverlay(pitchHandle, {
visible: rotateHandlesVisible,
position: pitchCorner,
rotation: pitchHandleRotation
});
Overlays.editOverlay(rollHandle, {
visible: rotateHandlesVisible,
position: rollCorner,
rotation: rollHandleRotation
});
};
// FUNCTION: SET SPACE MODE
that.setSpaceMode = function(newSpaceMode) {
if (spaceMode != newSpaceMode) {
spaceMode = newSpaceMode;
that.updateHandles();
}
};
// FUNCTION: TOGGLE SPACE MODE
that.toggleSpaceMode = function() {
if (spaceMode == SPACE_WORLD && SelectionManager.selections.length > 1) {
print("Local space editing is not available with multiple selections");
return;
}
spaceMode = spaceMode == SPACE_LOCAL ? SPACE_WORLD : SPACE_LOCAL;
that.updateHandles();
};
// FUNCTION: UNSELECT ALL
// TODO?: Needs implementation
that.unselectAll = function() {};
// FUNCTION: UPDATE HANDLES
that.updateHandles = function() {
if (SelectionManager.selections.length === 0) {
that.setOverlaysVisible(false);
return;
}
that.updateRotationHandles();
var rotation, dimensions, position, registrationPoint;
if (spaceMode == SPACE_LOCAL) {
rotation = SelectionManager.localRotation;
dimensions = SelectionManager.localDimensions;
position = SelectionManager.localPosition;
registrationPoint = SelectionManager.localRegistrationPoint;
} else {
rotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
dimensions = SelectionManager.worldDimensions;
position = SelectionManager.worldPosition;
registrationPoint = SelectionManager.worldRegistrationPoint;
}
var registrationPointDimensions = {
x: dimensions.x * registrationPoint.x,
y: dimensions.y * registrationPoint.y,
z: dimensions.z * registrationPoint.z,
};
// Center of entity, relative to registration point
center = getRelativeCenterPosition(dimensions, registrationPoint);
// Distances in world coordinates relative to the registration point
var left = -registrationPointDimensions.x;
var right = dimensions.x - registrationPointDimensions.x;
var bottom = -registrationPointDimensions.y;
var top = dimensions.y - registrationPointDimensions.y;
var near = -registrationPointDimensions.z;
var far = dimensions.z - registrationPointDimensions.z;
var front = far;
var worldTop = SelectionManager.worldDimensions.y / 2;
var LBN = {
x: left,
y: bottom,
z: near
};
var RBN = {
x: right,
y: bottom,
z: near
};
var LBF = {
x: left,
y: bottom,
z: far
};
var RBF = {
x: right,
y: bottom,
z: far
};
var LTN = {
x: left,
y: top,
z: near
};
var RTN = {
x: right,
y: top,
z: near
};
var LTF = {
x: left,
y: top,
z: far
};
var RTF = {
x: right,
y: top,
z: far
};
var TOP = {
x: center.x,
y: top,
z: center.z
};
var BOTTOM = {
x: center.x,
y: bottom,
z: center.z
};
var LEFT = {
x: left,
y: center.y,
z: center.z
};
var RIGHT = {
x: right,
y: center.y,
z: center.z
};
var NEAR = {
x: center.x,
y: center.y,
z: near
};
var FAR = {
x: center.x,
y: center.y,
z: far
};
var EdgeTR = {
x: right,
y: top,
z: center.z
};
var EdgeTL = {
x: left,
y: top,
z: center.z
};
var EdgeTF = {
x: center.x,
y: top,
z: front
};
var EdgeTN = {
x: center.x,
y: top,
z: near
};
var EdgeBR = {
x: right,
y: bottom,
z: center.z
};
var EdgeBL = {
x: left,
y: bottom,
z: center.z
};
var EdgeBF = {
x: center.x,
y: bottom,
z: front
};
var EdgeBN = {
x: center.x,
y: bottom,
z: near
};
var EdgeNR = {
x: right,
y: center.y,
z: near
};
var EdgeNL = {
x: left,
y: center.y,
z: near
};
var EdgeFR = {
x: right,
y: center.y,
z: front
};
var EdgeFL = {
x: left,
y: center.y,
z: front
};
LBN = Vec3.multiplyQbyV(rotation, LBN);
RBN = Vec3.multiplyQbyV(rotation, RBN);
LBF = Vec3.multiplyQbyV(rotation, LBF);
RBF = Vec3.multiplyQbyV(rotation, RBF);
LTN = Vec3.multiplyQbyV(rotation, LTN);
RTN = Vec3.multiplyQbyV(rotation, RTN);
LTF = Vec3.multiplyQbyV(rotation, LTF);
RTF = Vec3.multiplyQbyV(rotation, RTF);
TOP = Vec3.multiplyQbyV(rotation, TOP);
BOTTOM = Vec3.multiplyQbyV(rotation, BOTTOM);
LEFT = Vec3.multiplyQbyV(rotation, LEFT);
RIGHT = Vec3.multiplyQbyV(rotation, RIGHT);
NEAR = Vec3.multiplyQbyV(rotation, NEAR);
FAR = Vec3.multiplyQbyV(rotation, FAR);
EdgeTR = Vec3.multiplyQbyV(rotation, EdgeTR);
EdgeTL = Vec3.multiplyQbyV(rotation, EdgeTL);
EdgeTF = Vec3.multiplyQbyV(rotation, EdgeTF);
EdgeTN = Vec3.multiplyQbyV(rotation, EdgeTN);
EdgeBR = Vec3.multiplyQbyV(rotation, EdgeBR);
EdgeBL = Vec3.multiplyQbyV(rotation, EdgeBL);
EdgeBF = Vec3.multiplyQbyV(rotation, EdgeBF);
EdgeBN = Vec3.multiplyQbyV(rotation, EdgeBN);
EdgeNR = Vec3.multiplyQbyV(rotation, EdgeNR);
EdgeNL = Vec3.multiplyQbyV(rotation, EdgeNL);
EdgeFR = Vec3.multiplyQbyV(rotation, EdgeFR);
EdgeFL = Vec3.multiplyQbyV(rotation, EdgeFL);
LBN = Vec3.sum(position, LBN);
RBN = Vec3.sum(position, RBN);
LBF = Vec3.sum(position, LBF);
RBF = Vec3.sum(position, RBF);
LTN = Vec3.sum(position, LTN);
RTN = Vec3.sum(position, RTN);
LTF = Vec3.sum(position, LTF);
RTF = Vec3.sum(position, RTF);
TOP = Vec3.sum(position, TOP);
BOTTOM = Vec3.sum(position, BOTTOM);
LEFT = Vec3.sum(position, LEFT);
RIGHT = Vec3.sum(position, RIGHT);
NEAR = Vec3.sum(position, NEAR);
FAR = Vec3.sum(position, FAR);
EdgeTR = Vec3.sum(position, EdgeTR);
EdgeTL = Vec3.sum(position, EdgeTL);
EdgeTF = Vec3.sum(position, EdgeTF);
EdgeTN = Vec3.sum(position, EdgeTN);
EdgeBR = Vec3.sum(position, EdgeBR);
EdgeBL = Vec3.sum(position, EdgeBL);
EdgeBF = Vec3.sum(position, EdgeBF);
EdgeBN = Vec3.sum(position, EdgeBN);
EdgeNR = Vec3.sum(position, EdgeNR);
EdgeNL = Vec3.sum(position, EdgeNL);
EdgeFR = Vec3.sum(position, EdgeFR);
EdgeFL = Vec3.sum(position, EdgeFL);
var stretchHandlesVisible = spaceMode == SPACE_LOCAL;
var extendedStretchHandlesVisible = stretchHandlesVisible && showExtendedStretchHandles;
if (selectionManager.selections.length == 1) {
var properties = Entities.getEntityProperties(selectionManager.selections[0]);
if (properties.type == "Light" && properties.isSpotlight) {
stretchHandlesVisible = false;
extendedStretchHandlesVisible = false;
Overlays.editOverlay(grabberSpotLightCenter, {
position: position,
visible: false,
});
Overlays.editOverlay(grabberSpotLightRadius, {
position: NEAR,
rotation: rotation,
visible: true,
});
var distance = (properties.dimensions.z / 2) * Math.sin(properties.cutoff * (Math.PI / 180));
Overlays.editOverlay(grabberSpotLightL, {
position: EdgeNL,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberSpotLightR, {
position: EdgeNR,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberSpotLightT, {
position: EdgeTN,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberSpotLightB, {
position: EdgeBN,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberSpotLightCircle, {
position: NEAR,
dimensions: {
x: distance,
y: distance,
z: 1
},
lineWidth: 1.5,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberSpotLightLineT, {
start: position,
end: EdgeTN,
visible: true,
});
Overlays.editOverlay(grabberSpotLightLineB, {
start: position,
end: EdgeBN,
visible: true,
});
Overlays.editOverlay(grabberSpotLightLineR, {
start: position,
end: EdgeNR,
visible: true,
});
Overlays.editOverlay(grabberSpotLightLineL, {
start: position,
end: EdgeNL,
visible: true,
});
Overlays.editOverlay(grabberPointLightCircleX, {
visible: false
});
Overlays.editOverlay(grabberPointLightCircleY, {
visible: false
});
Overlays.editOverlay(grabberPointLightCircleZ, {
visible: false
});
Overlays.editOverlay(grabberPointLightT, {
visible: false
});
Overlays.editOverlay(grabberPointLightB, {
visible: false
});
Overlays.editOverlay(grabberPointLightL, {
visible: false
});
Overlays.editOverlay(grabberPointLightR, {
visible: false
});
Overlays.editOverlay(grabberPointLightF, {
visible: false
});
Overlays.editOverlay(grabberPointLightN, {
visible: false
});
} else if (properties.type == "Light" && !properties.isSpotlight) {
stretchHandlesVisible = false;
extendedStretchHandlesVisible = false;
Overlays.editOverlay(grabberPointLightT, {
position: TOP,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberPointLightB, {
position: BOTTOM,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberPointLightL, {
position: LEFT,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberPointLightR, {
position: RIGHT,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberPointLightF, {
position: FAR,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberPointLightN, {
position: NEAR,
rotation: rotation,
visible: true,
});
Overlays.editOverlay(grabberPointLightCircleX, {
position: position,
rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(0, 90, 0)),
dimensions: {
x: properties.dimensions.z / 2.0,
y: properties.dimensions.z / 2.0,
z: 1
},
visible: true,
});
Overlays.editOverlay(grabberPointLightCircleY, {
position: position,
rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(90, 0, 0)),
dimensions: {
x: properties.dimensions.z / 2.0,
y: properties.dimensions.z / 2.0,
z: 1
},
visible: true,
});
Overlays.editOverlay(grabberPointLightCircleZ, {
position: position,
rotation: rotation,
dimensions: {
x: properties.dimensions.z / 2.0,
y: properties.dimensions.z / 2.0,
z: 1
},
visible: true,
});
Overlays.editOverlay(grabberSpotLightRadius, {
visible: false
});
Overlays.editOverlay(grabberSpotLightL, {
visible: false
});
Overlays.editOverlay(grabberSpotLightR, {
visible: false
});
Overlays.editOverlay(grabberSpotLightT, {
visible: false
});
Overlays.editOverlay(grabberSpotLightB, {
visible: false
});
Overlays.editOverlay(grabberSpotLightCircle, {
visible: false
});
Overlays.editOverlay(grabberSpotLightLineL, {
visible: false
});
Overlays.editOverlay(grabberSpotLightLineR, {
visible: false
});
Overlays.editOverlay(grabberSpotLightLineT, {
visible: false
});
Overlays.editOverlay(grabberSpotLightLineB, {
visible: false
});
} else {
Overlays.editOverlay(grabberSpotLightCenter, {
visible: false
});
Overlays.editOverlay(grabberSpotLightRadius, {
visible: false
});
Overlays.editOverlay(grabberSpotLightL, {
visible: false
});
Overlays.editOverlay(grabberSpotLightR, {
visible: false
});
Overlays.editOverlay(grabberSpotLightT, {
visible: false
});
Overlays.editOverlay(grabberSpotLightB, {
visible: false
});
Overlays.editOverlay(grabberSpotLightCircle, {
visible: false
});
Overlays.editOverlay(grabberSpotLightLineL, {
visible: false
});
Overlays.editOverlay(grabberSpotLightLineR, {
visible: false
});
Overlays.editOverlay(grabberSpotLightLineT, {
visible: false
});
Overlays.editOverlay(grabberSpotLightLineB, {
visible: false
});
Overlays.editOverlay(grabberPointLightCircleX, {
visible: false
});
Overlays.editOverlay(grabberPointLightCircleY, {
visible: false
});
Overlays.editOverlay(grabberPointLightCircleZ, {
visible: false
});
Overlays.editOverlay(grabberPointLightT, {
visible: false
});
Overlays.editOverlay(grabberPointLightB, {
visible: false
});
Overlays.editOverlay(grabberPointLightL, {
visible: false
});
Overlays.editOverlay(grabberPointLightR, {
visible: false
});
Overlays.editOverlay(grabberPointLightF, {
visible: false
});
Overlays.editOverlay(grabberPointLightN, {
visible: false
});
}
}
Overlays.editOverlay(grabberLBN, {
visible: stretchHandlesVisible,
rotation: rotation,
position: LBN
});
Overlays.editOverlay(grabberRBN, {
visible: stretchHandlesVisible,
rotation: rotation,
position: RBN
});
Overlays.editOverlay(grabberLBF, {
visible: stretchHandlesVisible,
rotation: rotation,
position: LBF
});
Overlays.editOverlay(grabberRBF, {
visible: stretchHandlesVisible,
rotation: rotation,
position: RBF
});
Overlays.editOverlay(grabberLTN, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: LTN
});
Overlays.editOverlay(grabberRTN, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: RTN
});
Overlays.editOverlay(grabberLTF, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: LTF
});
Overlays.editOverlay(grabberRTF, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: RTF
});
Overlays.editOverlay(grabberTOP, {
visible: stretchHandlesVisible,
rotation: rotation,
position: TOP
});
Overlays.editOverlay(grabberBOTTOM, {
visible: stretchHandlesVisible,
rotation: rotation,
position: BOTTOM
});
Overlays.editOverlay(grabberLEFT, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: LEFT
});
Overlays.editOverlay(grabberRIGHT, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: RIGHT
});
Overlays.editOverlay(grabberNEAR, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: NEAR
});
Overlays.editOverlay(grabberFAR, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: FAR
});
Overlays.editOverlay(grabberCloner, {
visible: true,
rotation: rotation,
position: EdgeTR
});
var selectionBoxPosition = Vec3.multiplyQbyV(rotation, center);
selectionBoxPosition = Vec3.sum(position, selectionBoxPosition);
Overlays.editOverlay(selectionBox, {
position: selectionBoxPosition,
dimensions: dimensions,
rotation: rotation,
visible: !(mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL"),
});
// Create more selection box overlays if we don't have enough
var overlaysNeeded = selectionManager.selections.length - selectionBoxes.length;
for (var i = 0; i < overlaysNeeded; i++) {
selectionBoxes.push(
Overlays.addOverlay("cube", {
position: {
x: 0,
y: 0,
z: 0
},
size: 1,
color: {
red: 255,
green: 153,
blue: 0
},
alpha: 1,
solid: false,
visible: false,
dashed: false,
lineWidth: 1.0,
ignoreRayIntersection: true,
}));
}
i = 0;
// Only show individual selections boxes if there is more than 1 selection
if (selectionManager.selections.length > 1) {
for (; i < selectionManager.selections.length; i++) {
var props = Entities.getEntityProperties(selectionManager.selections[i]);
// Adjust overlay position to take registrationPoint into account
// centeredRP = registrationPoint with range [-0.5, 0.5]
var centeredRP = Vec3.subtract(props.registrationPoint, {
x: 0.5,
y: 0.5,
z: 0.5
});
var offset = vec3Mult(props.dimensions, centeredRP);
offset = Vec3.multiply(-1, offset);
offset = Vec3.multiplyQbyV(props.rotation, offset);
var curBoxPosition = Vec3.sum(props.position, offset);
var color = {red: 255, green: 128, blue: 0};
if (i >= selectionManager.selections.length - 1) color = {red: 255, green: 255, blue: 64};
Overlays.editOverlay(selectionBoxes[i], {
position: curBoxPosition,
color: color,
rotation: props.rotation,
dimensions: props.dimensions,
visible: true,
});
}
}
// Hide any remaining selection boxes
for (; i < selectionBoxes.length; i++) {
Overlays.editOverlay(selectionBoxes[i], {
visible: false
});
}
Overlays.editOverlay(grabberEdgeTR, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: EdgeTR
});
Overlays.editOverlay(grabberEdgeTL, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: EdgeTL
});
Overlays.editOverlay(grabberEdgeTF, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: EdgeTF
});
Overlays.editOverlay(grabberEdgeTN, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: EdgeTN
});
Overlays.editOverlay(grabberEdgeBR, {
visible: stretchHandlesVisible,
rotation: rotation,
position: EdgeBR
});
Overlays.editOverlay(grabberEdgeBL, {
visible: stretchHandlesVisible,
rotation: rotation,
position: EdgeBL
});
Overlays.editOverlay(grabberEdgeBF, {
visible: stretchHandlesVisible,
rotation: rotation,
position: EdgeBF
});
Overlays.editOverlay(grabberEdgeBN, {
visible: stretchHandlesVisible,
rotation: rotation,
position: EdgeBN
});
Overlays.editOverlay(grabberEdgeNR, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: EdgeNR
});
Overlays.editOverlay(grabberEdgeNL, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: EdgeNL
});
Overlays.editOverlay(grabberEdgeFR, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: EdgeFR
});
Overlays.editOverlay(grabberEdgeFL, {
visible: extendedStretchHandlesVisible,
rotation: rotation,
position: EdgeFL
});
var grabberMoveUpOffset = 0.1;
grabberMoveUpPosition = {
x: position.x,
y: position.y + worldTop + grabberMoveUpOffset,
z: position.z
};
Overlays.editOverlay(grabberMoveUp, {
visible: (activeTool === null) || (mode == "TRANSLATE_UP_DOWN")
});
Overlays.editOverlay(baseOfEntityProjectionOverlay, {
visible: mode != "ROTATE_YAW" && mode != "ROTATE_PITCH" && mode != "ROTATE_ROLL",
solid: true,
position: {
x: selectionManager.worldPosition.x,
y: grid.getOrigin().y,
z: selectionManager.worldPosition.z
},
dimensions: {
x: selectionManager.worldDimensions.x,
y: selectionManager.worldDimensions.z
},
rotation: Quat.fromPitchYawRollDegrees(90, 0, 0),
});
};
// FUNCTION: SET OVERLAYS VISIBLE
that.setOverlaysVisible = function(isVisible) {
var length = allOverlays.length;
for (var overlayIndex = 0; overlayIndex < length; overlayIndex++) {
Overlays.editOverlay(allOverlays[overlayIndex], {
visible: isVisible
});
}
length = selectionBoxes.length;
for (var boxIndex = 0; boxIndex < length; boxIndex++) {
Overlays.editOverlay(selectionBoxes[boxIndex], {
visible: isVisible
});
}
};
// FUNCTION: UNSELECT
// TODO?: Needs implementation
that.unselect = function(entityID) {};
var initialXZPick = null;
var isConstrained = false;
var constrainMajorOnly = false;
var startPosition = null;
var duplicatedEntityIDs = null;
// TOOL DEFINITION: TRANSLATE XZ TOOL
var translateXZTool = {
mode: 'TRANSLATE_XZ',
pickPlanePosition: { x: 0, y: 0, z: 0 },
greatestDimension: 0.0,
startingDistance: 0.0,
startingElevation: 0.0,
onBegin: function(event,isAltFromGrab) {
SelectionManager.saveProperties();
startPosition = SelectionManager.worldPosition;
var dimensions = SelectionManager.worldDimensions;
var pickRay = generalComputePickRay(event.x, event.y);
initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, {
x: 0,
y: 1,
z: 0
});
// Duplicate entities if alt is pressed. This will make a
// copy of the selected entities and move the _original_ entities, not
// the new ones.
if (event.isAlt || isAltFromGrab) {
duplicatedEntityIDs = [];
for (var otherEntityID in SelectionManager.savedProperties) {
var properties = SelectionManager.savedProperties[otherEntityID];
if (!properties.locked) {
var entityID = Entities.addEntity(properties);
duplicatedEntityIDs.push({
entityID: entityID,
properties: properties,
});
}
}
} else {
duplicatedEntityIDs = null;
}
isConstrained = false;
},
onEnd: function(event, reason) {
pushCommandForSelections(duplicatedEntityIDs);
Overlays.editOverlay(xRailOverlay, {
visible: false
});
Overlays.editOverlay(zRailOverlay, {
visible: false
});
},
elevation: function(origin, intersection) {
return (origin.y - intersection.y) / Vec3.distance(origin, intersection);
},
onMove: function(event) {
var wantDebug = false;
pickRay = generalComputePickRay(event.x, event.y);
var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, {
x: 0,
y: 1,
z: 0
});
// If the pick ray doesn't hit the pick plane in this direction, do nothing.
// this will happen when someone drags across the horizon from the side they started on.
if (!pick) {
if (wantDebug) {
print("Pick ray does not intersect XZ plane.");
}
return;
}
var vector = Vec3.subtract(pick, initialXZPick);
// If the mouse is too close to the horizon of the pick plane, stop moving
var MIN_ELEVATION = 0.02; // largest dimension of object divided by distance to it
var elevation = translateXZTool.elevation(pickRay.origin, pick);
if (wantDebug) {
print("Start Elevation: " + translateXZTool.startingElevation + ", elevation: " + elevation);
}
if ((translateXZTool.startingElevation > 0.0 && elevation < MIN_ELEVATION) ||
(translateXZTool.startingElevation < 0.0 && elevation > -MIN_ELEVATION)) {
if (wantDebug) {
print("too close to horizon!");
}
return;
}
// If the angular size of the object is too small, stop moving
var MIN_ANGULAR_SIZE = 0.01; // Radians
if (translateXZTool.greatestDimension > 0) {
var angularSize = Math.atan(translateXZTool.greatestDimension / Vec3.distance(pickRay.origin, pick));
if (wantDebug) {
print("Angular size = " + angularSize);
}
if (angularSize < MIN_ANGULAR_SIZE) {
return;
}
}
// If shifted, constrain to one axis
if (event.isShifted) {
if (Math.abs(vector.x) > Math.abs(vector.z)) {
vector.z = 0;
} else {
vector.x = 0;
}
if (!isConstrained) {
Overlays.editOverlay(xRailOverlay, {
visible: true
});
var xStart = Vec3.sum(startPosition, {
x: -10000,
y: 0,
z: 0
});
var xEnd = Vec3.sum(startPosition, {
x: 10000,
y: 0,
z: 0
});
var zStart = Vec3.sum(startPosition, {
x: 0,
y: 0,
z: -10000
});
var zEnd = Vec3.sum(startPosition, {
x: 0,
y: 0,
z: 10000
});
Overlays.editOverlay(xRailOverlay, {
start: xStart,
end: xEnd,
visible: true
});
Overlays.editOverlay(zRailOverlay, {
start: zStart,
end: zEnd,
visible: true
});
isConstrained = true;
}
} else {
if (isConstrained) {
Overlays.editOverlay(xRailOverlay, {
visible: false
});
Overlays.editOverlay(zRailOverlay, {
visible: false
});
isConstrained = false;
}
}
constrainMajorOnly = event.isControl;
var cornerPosition = Vec3.sum(startPosition, Vec3.multiply(-0.5, selectionManager.worldDimensions));
vector = Vec3.subtract(
grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly),
cornerPosition);
for (var i = 0; i < SelectionManager.selections.length; i++) {
var properties = SelectionManager.savedProperties[SelectionManager.selections[i]];
if (!properties) {
continue;
}
var newPosition = Vec3.sum(properties.position, {
x: vector.x,
y: 0,
z: vector.z
});
Entities.editEntity(SelectionManager.selections[i], {
position: newPosition,
});
if (wantDebug) {
print("translateXZ... ");
Vec3.print(" vector:", vector);
Vec3.print(" newPosition:", properties.position);
Vec3.print(" newPosition:", newPosition);
}
}
SelectionManager._update();
}
};
// GRABBER TOOL: GRABBER MOVE UP
var lastXYPick = null;
var upDownPickNormal = null;
addGrabberTool(grabberMoveUp, {
mode: "TRANSLATE_UP_DOWN",
onBegin: function(event) {
pickRay = generalComputePickRay(event.x, event.y);
upDownPickNormal = Quat.getForward(lastCameraOrientation);
// Remove y component so the y-axis lies along the plane we picking on - this will
// give movements that follow the mouse.
upDownPickNormal.y = 0;
lastXYPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal);
SelectionManager.saveProperties();
// Duplicate entities if alt is pressed. This will make a
// copy of the selected entities and move the _original_ entities, not
// the new ones.
if (event.isAlt) {
duplicatedEntityIDs = [];
for (var otherEntityID in SelectionManager.savedProperties) {
var properties = SelectionManager.savedProperties[otherEntityID];
if (!properties.locked) {
var entityID = Entities.addEntity(properties);
duplicatedEntityIDs.push({
entityID: entityID,
properties: properties,
});
}
}
} else {
duplicatedEntityIDs = null;
}
},
onEnd: function(event, reason) {
pushCommandForSelections(duplicatedEntityIDs);
},
onMove: function(event) {
pickRay = generalComputePickRay(event.x, event.y);
// translate mode left/right based on view toward entity
var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal);
var vector = Vec3.subtract(newIntersection, lastXYPick);
vector = grid.snapToGrid(vector);
// we only care about the Y axis
vector.x = 0;
vector.z = 0;
var wantDebug = false;
if (wantDebug) {
print("translateUpDown... ");
print(" event.y:" + event.y);
Vec3.print(" newIntersection:", newIntersection);
Vec3.print(" vector:", vector);
//Vec3.print(" newPosition:", newPosition);
}
for (var i = 0; i < SelectionManager.selections.length; i++) {
var id = SelectionManager.selections[i];
var properties = selectionManager.savedProperties[id];
var original = properties.position;
var newPosition = Vec3.sum(properties.position, vector);
Entities.editEntity(id, {
position: newPosition,
});
}
SelectionManager._update();
},
});
// GRABBER TOOL: GRABBER CLONER
addGrabberTool(grabberCloner, {
mode: "CLONE",
onBegin: function(event) {
var pickRay = generalComputePickRay(event.x, event.y);
var result = Overlays.findRayIntersection(pickRay);
translateXZTool.pickPlanePosition = result.intersection;
translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y),
SelectionManager.worldDimensions.z);
translateXZTool.onBegin(event,true);
},
elevation: function (event) {
translateXZTool.elevation(event);
},
onEnd: function (event) {
translateXZTool.onEnd(event);
},
onMove: function (event) {
translateXZTool.onMove(event);
}
});
// FUNCTION: VEC 3 MULT
var vec3Mult = function(v1, v2) {
return {
x: v1.x * v2.x,
y: v1.y * v2.y,
z: v1.z * v2.z
};
};
// FUNCTION: MAKE STRETCH TOOL
// stretchMode - name of mode
// direction - direction to stretch in
// pivot - point to use as a pivot
// offset - the position of the overlay tool relative to the selections center position
var makeStretchTool = function(stretchMode, direction, pivot, offset, customOnMove) {
// directionFor3DStretch - direction and pivot for 3D stretch
// distanceFor3DStretch - distance from the intersection point and the handController
// used to increase the scale taking into account the distance to the object
// DISTANCE_INFLUENCE_THRESHOLD - constant that holds the minimum distance where the
// distance to the object will influence the stretch/resize/scale
var directionFor3DStretch = getDirectionsFor3DStretch(stretchMode);
var distanceFor3DStretch = 0;
var DISTANCE_INFLUENCE_THRESHOLD = 1.2;
var signs = {
x: direction.x < 0 ? -1 : (direction.x > 0 ? 1 : 0),
y: direction.y < 0 ? -1 : (direction.y > 0 ? 1 : 0),
z: direction.z < 0 ? -1 : (direction.z > 0 ? 1 : 0),
};
var mask = {
x: Math.abs(direction.x) > 0 ? 1 : 0,
y: Math.abs(direction.y) > 0 ? 1 : 0,
z: Math.abs(direction.z) > 0 ? 1 : 0,
};
var numDimensions = mask.x + mask.y + mask.z;
var planeNormal = null;
var lastPick = null;
var lastPick3D = null;
var initialPosition = null;
var initialDimensions = null;
var initialIntersection = null;
var initialProperties = null;
var registrationPoint = null;
var deltaPivot = null;
var deltaPivot3D = null;
var pickRayPosition = null;
var pickRayPosition3D = null;
var rotation = null;
var onBegin = function(event) {
var properties = Entities.getEntityProperties(SelectionManager.selections[0]);
initialProperties = properties;
rotation = spaceMode == SPACE_LOCAL ? properties.rotation : Quat.fromPitchYawRollDegrees(0, 0, 0);
if (spaceMode == SPACE_LOCAL) {
rotation = SelectionManager.localRotation;
initialPosition = SelectionManager.localPosition;
initialDimensions = SelectionManager.localDimensions;
registrationPoint = SelectionManager.localRegistrationPoint;
} else {
rotation = SelectionManager.worldRotation;
initialPosition = SelectionManager.worldPosition;
initialDimensions = SelectionManager.worldDimensions;
registrationPoint = SelectionManager.worldRegistrationPoint;
}
// Modify range of registrationPoint to be [-0.5, 0.5]
var centeredRP = Vec3.subtract(registrationPoint, {
x: 0.5,
y: 0.5,
z: 0.5
});
// Scale pivot to be in the same range as registrationPoint
var scaledPivot = Vec3.multiply(0.5, pivot);
deltaPivot = Vec3.subtract(centeredRP, scaledPivot);
var scaledOffset = Vec3.multiply(0.5, offset);
// Offset from the registration point
offsetRP = Vec3.subtract(scaledOffset, centeredRP);
// Scaled offset in world coordinates
var scaledOffsetWorld = vec3Mult(initialDimensions, offsetRP);
pickRayPosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld));
if (directionFor3DStretch) {
// pivot, offset and pickPlanePosition for 3D manipulation
var scaledPivot3D = Vec3.multiply(0.5, Vec3.multiply(1.0, directionFor3DStretch));
deltaPivot3D = Vec3.subtract(centeredRP, scaledPivot3D);
var scaledOffsetWorld3D = vec3Mult(initialDimensions,
Vec3.subtract(Vec3.multiply(0.5, Vec3.multiply(-1.0, directionFor3DStretch)),
centeredRP));
pickRayPosition3D = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld));
}
var start = null;
var end = null;
if (numDimensions == 1 && mask.x) {
start = Vec3.multiplyQbyV(rotation, {
x: -10000,
y: 0,
z: 0
});
start = Vec3.sum(start, properties.position);
end = Vec3.multiplyQbyV(rotation, {
x: 10000,
y: 0,
z: 0
});
end = Vec3.sum(end, properties.position);
Overlays.editOverlay(xRailOverlay, {
start: start,
end: end,
visible: true,
});
}
if (numDimensions == 1 && mask.y) {
start = Vec3.multiplyQbyV(rotation, {
x: 0,
y: -10000,
z: 0
});
start = Vec3.sum(start, properties.position);
end = Vec3.multiplyQbyV(rotation, {
x: 0,
y: 10000,
z: 0
});
end = Vec3.sum(end, properties.position);
Overlays.editOverlay(yRailOverlay, {
start: start,
end: end,
visible: true,
});
}
if (numDimensions == 1 && mask.z) {
start = Vec3.multiplyQbyV(rotation, {
x: 0,
y: 0,
z: -10000
});
start = Vec3.sum(start, properties.position);
end = Vec3.multiplyQbyV(rotation, {
x: 0,
y: 0,
z: 10000
});
end = Vec3.sum(end, properties.position);
Overlays.editOverlay(zRailOverlay, {
start: start,
end: end,
visible: true,
});
}
if (numDimensions == 1) {
if (mask.x == 1) {
planeNormal = {
x: 0,
y: 1,
z: 0
};
} else if (mask.y == 1) {
planeNormal = {
x: 1,
y: 0,
z: 0
};
} else {
planeNormal = {
x: 0,
y: 1,
z: 0
};
}
} else if (numDimensions == 2) {
if (mask.x === 0) {
planeNormal = {
x: 1,
y: 0,
z: 0
};
} else if (mask.y === 0) {
planeNormal = {
x: 0,
y: 1,
z: 0
};
} else {
planeNormal = {
x: 0,
y: 0,
z: z
};
}
}
planeNormal = Vec3.multiplyQbyV(rotation, planeNormal);
var pickRay = generalComputePickRay(event.x, event.y);
lastPick = rayPlaneIntersection(pickRay,
pickRayPosition,
planeNormal);
var planeNormal3D = {
x: 0,
y: 0,
z: 0
};
if (directionFor3DStretch) {
lastPick3D = rayPlaneIntersection(pickRay,
pickRayPosition3D,
planeNormal3D);
distanceFor3DStretch = Vec3.length(Vec3.subtract(pickRayPosition3D, pickRay.origin));
}
SelectionManager.saveProperties();
};
var onEnd = function(event, reason) {
Overlays.editOverlay(xRailOverlay, {
visible: false
});
Overlays.editOverlay(yRailOverlay, {
visible: false
});
Overlays.editOverlay(zRailOverlay, {
visible: false
});
pushCommandForSelections();
};
var onMove = function(event) {
var proportional = spaceMode == SPACE_WORLD || event.isShifted || activeTool.mode == "STRETCH_RADIUS";
var position, dimensions, rotation;
if (spaceMode == SPACE_LOCAL) {
position = SelectionManager.localPosition;
dimensions = SelectionManager.localDimensions;
rotation = SelectionManager.localRotation;
} else {
position = SelectionManager.worldPosition;
dimensions = SelectionManager.worldDimensions;
rotation = SelectionManager.worldRotation;
}
var localDeltaPivot = deltaPivot;
var localSigns = signs;
var pickRay = generalComputePickRay(event.x, event.y);
// Are we using handControllers or Mouse - only relevant for 3D tools
var controllerPose = getControllerWorldLocation(activeHand, true);
var vector = null;
if (HMD.isHMDAvailable() && HMD.isHandControllerAvailable() &&
controllerPose.valid && that.triggered && directionFor3DStretch) {
localDeltaPivot = deltaPivot3D;
newPick = pickRay.origin;
vector = Vec3.subtract(newPick, lastPick3D);
vector = Vec3.multiplyQbyV(Quat.inverse(rotation), vector);
if (distanceFor3DStretch > DISTANCE_INFLUENCE_THRESHOLD) {
// Range of Motion
vector = Vec3.multiply(distanceFor3DStretch , vector);
}
localSigns = directionFor3DStretch;
} else {
newPick = rayPlaneIntersection(pickRay,
pickRayPosition,
planeNormal);
vector = Vec3.subtract(newPick, lastPick);
vector = Vec3.multiplyQbyV(Quat.inverse(rotation), vector);
vector = vec3Mult(mask, vector);
}
if (customOnMove) {
var change = Vec3.multiply(-1, vec3Mult(localSigns, vector));
customOnMove(vector, change);
} else {
vector = grid.snapToSpacing(vector);
var changeInDimensions = Vec3.multiply(-1, vec3Mult(localSigns, vector));
var newDimensions;
if (proportional) {
var absX = Math.abs(changeInDimensions.x);
var absY = Math.abs(changeInDimensions.y);
var absZ = Math.abs(changeInDimensions.z);
var pctChange = 0;
if (absX > absY && absX > absZ) {
pctChange = changeInDimensions.x / initialProperties.dimensions.x;
pctChange = changeInDimensions.x / initialDimensions.x;
} else if (absY > absZ) {
pctChange = changeInDimensions.y / initialProperties.dimensions.y;
pctChange = changeInDimensions.y / initialDimensions.y;
} else {
pctChange = changeInDimensions.z / initialProperties.dimensions.z;
pctChange = changeInDimensions.z / initialDimensions.z;
}
pctChange += 1.0;
newDimensions = Vec3.multiply(pctChange, initialDimensions);
} else {
newDimensions = Vec3.sum(initialDimensions, changeInDimensions);
}
newDimensions.x = Math.max(newDimensions.x, MINIMUM_DIMENSION);
newDimensions.y = Math.max(newDimensions.y, MINIMUM_DIMENSION);
newDimensions.z = Math.max(newDimensions.z, MINIMUM_DIMENSION);
var changeInPosition = Vec3.multiplyQbyV(rotation, vec3Mult(localDeltaPivot, changeInDimensions));
var newPosition = Vec3.sum(initialPosition, changeInPosition);
for (var i = 0; i < SelectionManager.selections.length; i++) {
Entities.editEntity(SelectionManager.selections[i], {
position: newPosition,
dimensions: newDimensions,
});
}
var wantDebug = false;
if (wantDebug) {
print(stretchMode);
//Vec3.print(" newIntersection:", newIntersection);
Vec3.print(" vector:", vector);
//Vec3.print(" oldPOS:", oldPOS);
//Vec3.print(" newPOS:", newPOS);
Vec3.print(" changeInDimensions:", changeInDimensions);
Vec3.print(" newDimensions:", newDimensions);
Vec3.print(" changeInPosition:", changeInPosition);
Vec3.print(" newPosition:", newPosition);
}
}
SelectionManager._update();
};//--End of onMove def
return {
mode: stretchMode,
onBegin: onBegin,
onMove: onMove,
onEnd: onEnd
};
};
// Direction for the stretch tool when using hand controller
var directionsFor3DGrab = {
LBN: {
x: 1,
y: 1,
z: 1
},
RBN: {
x: -1,
y: 1,
z: 1
},
LBF: {
x: 1,
y: 1,
z: -1
},
RBF: {
x: -1,
y: 1,
z: -1
},
LTN: {
x: 1,
y: -1,
z: 1
},
RTN: {
x: -1,
y: -1,
z: 1
},
LTF: {
x: 1,
y: -1,
z: -1
},
RTF: {
x: -1,
y: -1,
z: -1
}
};
// FUNCTION: GET DIRECTION FOR 3D STRETCH
// Returns a vector with directions for the stretch tool in 3D using hand controllers
function getDirectionsFor3DStretch(mode) {
if (mode === "STRETCH_LBN") {
return directionsFor3DGrab.LBN;
} else if (mode === "STRETCH_RBN") {
return directionsFor3DGrab.RBN;
} else if (mode === "STRETCH_LBF") {
return directionsFor3DGrab.LBF;
} else if (mode === "STRETCH_RBF") {
return directionsFor3DGrab.RBF;
} else if (mode === "STRETCH_LTN") {
return directionsFor3DGrab.LTN;
} else if (mode === "STRETCH_RTN") {
return directionsFor3DGrab.RTN;
} else if (mode === "STRETCH_LTF") {
return directionsFor3DGrab.LTF;
} else if (mode === "STRETCH_RTF") {
return directionsFor3DGrab.RTF;
} else {
return null;
}
}
// FUNCTION: ADD STRETCH TOOL
function addStretchTool(overlay, mode, pivot, direction, offset, handleMove) {
if (!pivot) {
pivot = direction;
}
var tool = makeStretchTool(mode, direction, pivot, offset, handleMove);
addGrabberTool(overlay, tool);
}
// FUNCTION: CUTOFF STRETCH FUNC
function cutoffStretchFunc(vector, change) {
vector = change;
Vec3.print("Radius stretch: ", vector);
var length = vector.x + vector.y + vector.z;
var props = selectionManager.savedProperties[selectionManager.selections[0]];
var radius = props.dimensions.z / 2;
var originalCutoff = props.cutoff;
var originalSize = radius * Math.tan(originalCutoff * (Math.PI / 180));
var newSize = originalSize + length;
var cutoff = Math.atan2(newSize, radius) * 180 / Math.PI;
Entities.editEntity(selectionManager.selections[0], {
cutoff: cutoff,
});
SelectionManager._update();
}
// FUNCTION: RADIUS STRETCH FUNC
function radiusStretchFunc(vector, change) {
var props = selectionManager.savedProperties[selectionManager.selections[0]];
// Find the axis being adjusted
var size;
if (Math.abs(change.x) > 0) {
size = props.dimensions.x + change.x;
} else if (Math.abs(change.y) > 0) {
size = props.dimensions.y + change.y;
} else if (Math.abs(change.z) > 0) {
size = props.dimensions.z + change.z;
}
var newDimensions = {
x: size,
y: size,
z: size
};
Entities.editEntity(selectionManager.selections[0], {
dimensions: newDimensions,
});
SelectionManager._update();
}
// STRETCH TOOL DEF SECTION
addStretchTool(grabberNEAR, "STRETCH_NEAR", {
x: 0,
y: 0,
z: 1
}, {
x: 0,
y: 0,
z: 1
}, {
x: 0,
y: 0,
z: -1
});
addStretchTool(grabberFAR, "STRETCH_FAR", {
x: 0,
y: 0,
z: -1
}, {
x: 0,
y: 0,
z: -1
}, {
x: 0,
y: 0,
z: 1
});
addStretchTool(grabberTOP, "STRETCH_TOP", {
x: 0,
y: -1,
z: 0
}, {
x: 0,
y: -1,
z: 0
}, {
x: 0,
y: 1,
z: 0
});
addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", {
x: 0,
y: 1,
z: 0
}, {
x: 0,
y: 1,
z: 0
}, {
x: 0,
y: -1,
z: 0
});
addStretchTool(grabberRIGHT, "STRETCH_RIGHT", {
x: -1,
y: 0,
z: 0
}, {
x: -1,
y: 0,
z: 0
}, {
x: 1,
y: 0,
z: 0
});
addStretchTool(grabberLEFT, "STRETCH_LEFT", {
x: 1,
y: 0,
z: 0
}, {
x: 1,
y: 0,
z: 0
}, {
x: -1,
y: 0,
z: 0
});
addStretchTool(grabberSpotLightRadius, "STRETCH_RADIUS", {
x: 0,
y: 0,
z: 0
}, {
x: 0,
y: 0,
z: 1
}, {
x: 0,
y: 0,
z: -1
});
addStretchTool(grabberSpotLightT, "STRETCH_CUTOFF_T", {
x: 0,
y: 0,
z: 0
}, {
x: 0,
y: -1,
z: 0
}, {
x: 0,
y: 1,
z: 0
}, cutoffStretchFunc);
addStretchTool(grabberSpotLightB, "STRETCH_CUTOFF_B", {
x: 0,
y: 0,
z: 0
}, {
x: 0,
y: 1,
z: 0
}, {
x: 0,
y: -1,
z: 0
}, cutoffStretchFunc);
addStretchTool(grabberSpotLightL, "STRETCH_CUTOFF_L", {
x: 0,
y: 0,
z: 0
}, {
x: 1,
y: 0,
z: 0
}, {
x: -1,
y: 0,
z: 0
}, cutoffStretchFunc);
addStretchTool(grabberSpotLightR, "STRETCH_CUTOFF_R", {
x: 0,
y: 0,
z: 0
}, {
x: -1,
y: 0,
z: 0
}, {
x: 1,
y: 0,
z: 0
}, cutoffStretchFunc);
addStretchTool(grabberPointLightT, "STRETCH_RADIUS_T", {
x: 0,
y: 0,
z: 0
}, {
x: 0,
y: -1,
z: 0
}, {
x: 0,
y: 0,
z: 1
}, radiusStretchFunc);
addStretchTool(grabberPointLightB, "STRETCH_RADIUS_B", {
x: 0,
y: 0,
z: 0
}, {
x: 0,
y: 1,
z: 0
}, {
x: 0,
y: 0,
z: 1
}, radiusStretchFunc);
addStretchTool(grabberPointLightL, "STRETCH_RADIUS_L", {
x: 0,
y: 0,
z: 0
}, {
x: 1,
y: 0,
z: 0
}, {
x: 0,
y: 0,
z: 1
}, radiusStretchFunc);
addStretchTool(grabberPointLightR, "STRETCH_RADIUS_R", {
x: 0,
y: 0,
z: 0
}, {
x: -1,
y: 0,
z: 0
}, {
x: 0,
y: 0,
z: 1
}, radiusStretchFunc);
addStretchTool(grabberPointLightF, "STRETCH_RADIUS_F", {
x: 0,
y: 0,
z: 0
}, {
x: 0,
y: 0,
z: -1
}, {
x: 0,
y: 0,
z: 1
}, radiusStretchFunc);
addStretchTool(grabberPointLightN, "STRETCH_RADIUS_N", {
x: 0,
y: 0,
z: 0
}, {
x: 0,
y: 0,
z: 1
}, {
x: 0,
y: 0,
z: -1
}, radiusStretchFunc);
addStretchTool(grabberLBN, "STRETCH_LBN", null, {
x: 1,
y: 0,
z: 1
}, {
x: -1,
y: -1,
z: -1
});
addStretchTool(grabberRBN, "STRETCH_RBN", null, {
x: -1,
y: 0,
z: 1
}, {
x: 1,
y: -1,
z: -1
});
addStretchTool(grabberLBF, "STRETCH_LBF", null, {
x: 1,
y: 0,
z: -1
}, {
x: -1,
y: -1,
z: 1
});
addStretchTool(grabberRBF, "STRETCH_RBF", null, {
x: -1,
y: 0,
z: -1
}, {
x: 1,
y: -1,
z: 1
});
addStretchTool(grabberLTN, "STRETCH_LTN", null, {
x: 1,
y: 0,
z: 1
}, {
x: -1,
y: 1,
z: -1
});
addStretchTool(grabberRTN, "STRETCH_RTN", null, {
x: -1,
y: 0,
z: 1
}, {
x: 1,
y: 1,
z: -1
});
addStretchTool(grabberLTF, "STRETCH_LTF", null, {
x: 1,
y: 0,
z: -1
}, {
x: -1,
y: 1,
z: 1
});
addStretchTool(grabberRTF, "STRETCH_RTF", null, {
x: -1,
y: 0,
z: -1
}, {
x: 1,
y: 1,
z: 1
});
addStretchTool(grabberEdgeTR, "STRETCH_EdgeTR", null, {
x: 1,
y: 1,
z: 0
}, {
x: 1,
y: 1,
z: 0
});
addStretchTool(grabberEdgeTL, "STRETCH_EdgeTL", null, {
x: -1,
y: 1,
z: 0
}, {
x: -1,
y: 1,
z: 0
});
addStretchTool(grabberEdgeTF, "STRETCH_EdgeTF", null, {
x: 0,
y: 1,
z: -1
}, {
x: 0,
y: 1,
z: -1
});
addStretchTool(grabberEdgeTN, "STRETCH_EdgeTN", null, {
x: 0,
y: 1,
z: 1
}, {
x: 0,
y: 1,
z: 1
});
addStretchTool(grabberEdgeBR, "STRETCH_EdgeBR", null, {
x: -1,
y: 0,
z: 0
}, {
x: 1,
y: -1,
z: 0
});
addStretchTool(grabberEdgeBL, "STRETCH_EdgeBL", null, {
x: 1,
y: 0,
z: 0
}, {
x: -1,
y: -1,
z: 0
});
addStretchTool(grabberEdgeBF, "STRETCH_EdgeBF", null, {
x: 0,
y: 0,
z: -1
}, {
x: 0,
y: -1,
z: -1
});
addStretchTool(grabberEdgeBN, "STRETCH_EdgeBN", null, {
x: 0,
y: 0,
z: 1
}, {
x: 0,
y: -1,
z: 1
});
addStretchTool(grabberEdgeNR, "STRETCH_EdgeNR", null, {
x: -1,
y: 0,
z: 1
}, {
x: 1,
y: 0,
z: -1
});
addStretchTool(grabberEdgeNL, "STRETCH_EdgeNL", null, {
x: 1,
y: 0,
z: 1
}, {
x: -1,
y: 0,
z: -1
});
addStretchTool(grabberEdgeFR, "STRETCH_EdgeFR", null, {
x: -1,
y: 0,
z: -1
}, {
x: 1,
y: 0,
z: 1
});
addStretchTool(grabberEdgeFL, "STRETCH_EdgeFL", null, {
x: 1,
y: 0,
z: -1
}, {
x: -1,
y: 0,
z: 1
});
// FUNCTION: UPDATE ROTATION DEGREES OVERLAY
function updateRotationDegreesOverlay(angleFromZero, handleRotation, centerPosition) {
var angle = angleFromZero * (Math.PI / 180);
var position = {
x: Math.cos(angle) * outerRadius * ROTATION_DISPLAY_DISTANCE_MULTIPLIER,
y: Math.sin(angle) * outerRadius * ROTATION_DISPLAY_DISTANCE_MULTIPLIER,
z: 0,
};
position = Vec3.multiplyQbyV(handleRotation, position);
position = Vec3.sum(centerPosition, position);
Overlays.editOverlay(rotationDegreesDisplay, {
position: position,
dimensions: {
x: innerRadius * ROTATION_DISPLAY_SIZE_X_MULTIPLIER,
y: innerRadius * ROTATION_DISPLAY_SIZE_Y_MULTIPLIER
},
lineHeight: innerRadius * ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER,
text: normalizeDegrees(angleFromZero) + "°",
});
}
// YAW GRABBER TOOL DEFINITION
var initialPosition = SelectionManager.worldPosition;
addGrabberTool(yawHandle, {
mode: "ROTATE_YAW",
onBegin: function(event) {
SelectionManager.saveProperties();
initialPosition = SelectionManager.worldPosition;
// Size the overlays to the current selection size
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5);
innerRadius = diagonal;
outerRadius = diagonal * 1.15;
var innerAlpha = 0.2;
var outerAlpha = 0.2;
Overlays.editOverlay(rotateOverlayInner, {
visible: true,
size: innerRadius,
innerRadius: 0.9,
startAt: 0,
endAt: 360,
alpha: innerAlpha
});
Overlays.editOverlay(rotateOverlayOuter, {
visible: true,
size: outerRadius,
innerRadius: 0.9,
startAt: 0,
endAt: 360,
alpha: outerAlpha,
});
Overlays.editOverlay(rotateOverlayCurrent, {
visible: true,
size: outerRadius,
startAt: 0,
endAt: 0,
innerRadius: 0.9,
});
Overlays.editOverlay(rotationDegreesDisplay, {
visible: true,
});
updateRotationDegreesOverlay(0, yawHandleRotation, yawCenter);
},
onEnd: function(event, reason) {
Overlays.editOverlay(rotateOverlayInner, {
visible: false
});
Overlays.editOverlay(rotateOverlayOuter, {
visible: false
});
Overlays.editOverlay(rotateOverlayCurrent, {
visible: false
});
Overlays.editOverlay(rotationDegreesDisplay, {
visible: false
});
pushCommandForSelections();
},
onMove: function(event) {
var pickRay = generalComputePickRay(event.x, event.y);
Overlays.editOverlay(selectionBox, {
visible: false
});
Overlays.editOverlay(baseOfEntityProjectionOverlay, {
visible: false
});
var result = Overlays.findRayIntersection(pickRay, true, [rotateOverlayTarget]);
if (result.intersects) {
var center = yawCenter;
var zero = yawZero;
var centerToZero = Vec3.subtract(zero, center);
var centerToIntersect = Vec3.subtract(result.intersection, center);
// Note: orientedAngle which wants normalized centerToZero and centerToIntersect
// handles that internally, so it's to pass unnormalized vectors here.
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
var distanceFromCenter = Vec3.distance(center, result.intersection);
var snapToInner = distanceFromCenter < innerRadius;
var snapAngle = snapToInner ? innerSnapAngle : 1.0;
angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle;
var yawChange = Quat.fromVec3Degrees({
x: 0,
y: angleFromZero,
z: 0
});
// Entities should only reposition if we are rotating multiple selections around
// the selections center point. Otherwise, the rotation will be around the entities
// registration point which does not need repositioning.
var reposition = SelectionManager.selections.length > 1;
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var properties = Entities.getEntityProperties(entityID);
var initialProperties = SelectionManager.savedProperties[entityID];
var newProperties = {
rotation: Quat.multiply(yawChange, initialProperties.rotation),
};
if (reposition) {
var dPos = Vec3.subtract(initialProperties.position, initialPosition);
dPos = Vec3.multiplyQbyV(yawChange, dPos);
newProperties.position = Vec3.sum(initialPosition, dPos);
}
Entities.editEntity(entityID, newProperties);
}
updateRotationDegreesOverlay(angleFromZero, yawHandleRotation, yawCenter);
// update the rotation display accordingly...
var startAtCurrent = 0;
var endAtCurrent = angleFromZero;
var startAtRemainder = angleFromZero;
var endAtRemainder = 360;
if (angleFromZero < 0) {
startAtCurrent = 360 + angleFromZero;
endAtCurrent = 360;
startAtRemainder = 0;
endAtRemainder = startAtCurrent;
}
if (snapToInner) {
Overlays.editOverlay(rotateOverlayOuter, {
startAt: 0,
endAt: 360
});
Overlays.editOverlay(rotateOverlayInner, {
startAt: startAtRemainder,
endAt: endAtRemainder
});
Overlays.editOverlay(rotateOverlayCurrent, {
startAt: startAtCurrent,
endAt: endAtCurrent,
size: innerRadius,
majorTickMarksAngle: innerSnapAngle,
minorTickMarksAngle: 0,
majorTickMarksLength: -0.25,
minorTickMarksLength: 0,
});
} else {
Overlays.editOverlay(rotateOverlayInner, {
startAt: 0,
endAt: 360
});
Overlays.editOverlay(rotateOverlayOuter, {
startAt: startAtRemainder,
endAt: endAtRemainder
});
Overlays.editOverlay(rotateOverlayCurrent, {
startAt: startAtCurrent,
endAt: endAtCurrent,
size: outerRadius,
majorTickMarksAngle: 45.0,
minorTickMarksAngle: 5,
majorTickMarksLength: 0.25,
minorTickMarksLength: 0.1,
});
}
}
}
});
// PITCH GRABBER TOOL DEFINITION
addGrabberTool(pitchHandle, {
mode: "ROTATE_PITCH",
onBegin: function(event) {
SelectionManager.saveProperties();
initialPosition = SelectionManager.worldPosition;
// Size the overlays to the current selection size
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5);
innerRadius = diagonal;
outerRadius = diagonal * 1.15;
var innerAlpha = 0.2;
var outerAlpha = 0.2;
Overlays.editOverlay(rotateOverlayInner, {
visible: true,
size: innerRadius,
innerRadius: 0.9,
startAt: 0,
endAt: 360,
alpha: innerAlpha
});
Overlays.editOverlay(rotateOverlayOuter, {
visible: true,
size: outerRadius,
innerRadius: 0.9,
startAt: 0,
endAt: 360,
alpha: outerAlpha,
});
Overlays.editOverlay(rotateOverlayCurrent, {
visible: true,
size: outerRadius,
startAt: 0,
endAt: 0,
innerRadius: 0.9,
});
Overlays.editOverlay(rotationDegreesDisplay, {
visible: true,
});
updateRotationDegreesOverlay(0, pitchHandleRotation, pitchCenter);
},
onEnd: function(event, reason) {
Overlays.editOverlay(rotateOverlayInner, {
visible: false
});
Overlays.editOverlay(rotateOverlayOuter, {
visible: false
});
Overlays.editOverlay(rotateOverlayCurrent, {
visible: false
});
Overlays.editOverlay(rotationDegreesDisplay, {
visible: false
});
pushCommandForSelections();
},
onMove: function(event) {
var pickRay = generalComputePickRay(event.x, event.y);
Overlays.editOverlay(selectionBox, {
visible: false
});
Overlays.editOverlay(baseOfEntityProjectionOverlay, {
visible: false
});
var result = Overlays.findRayIntersection(pickRay, true, [rotateOverlayTarget]);
if (result.intersects) {
var center = pitchCenter;
var zero = pitchZero;
var centerToZero = Vec3.subtract(zero, center);
var centerToIntersect = Vec3.subtract(result.intersection, center);
// Note: orientedAngle which wants normalized centerToZero & centerToIntersect, handles
// this internally, so it's fine to pass non-normalized versions here.
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
var distanceFromCenter = Vec3.distance(center, result.intersection);
var snapToInner = distanceFromCenter < innerRadius;
var snapAngle = snapToInner ? innerSnapAngle : 1.0;
angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle;
var pitchChange = Quat.fromVec3Degrees({
x: angleFromZero,
y: 0,
z: 0
});
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID];
var dPos = Vec3.subtract(initialProperties.position, initialPosition);
dPos = Vec3.multiplyQbyV(pitchChange, dPos);
Entities.editEntity(entityID, {
position: Vec3.sum(initialPosition, dPos),
rotation: Quat.multiply(pitchChange, initialProperties.rotation),
});
}
updateRotationDegreesOverlay(angleFromZero, pitchHandleRotation, pitchCenter);
// update the rotation display accordingly...
var startAtCurrent = 0;
var endAtCurrent = angleFromZero;
var startAtRemainder = angleFromZero;
var endAtRemainder = 360;
if (angleFromZero < 0) {
startAtCurrent = 360 + angleFromZero;
endAtCurrent = 360;
startAtRemainder = 0;
endAtRemainder = startAtCurrent;
}
if (snapToInner) {
Overlays.editOverlay(rotateOverlayOuter, {
startAt: 0,
endAt: 360
});
Overlays.editOverlay(rotateOverlayInner, {
startAt: startAtRemainder,
endAt: endAtRemainder
});
Overlays.editOverlay(rotateOverlayCurrent, {
startAt: startAtCurrent,
endAt: endAtCurrent,
size: innerRadius,
majorTickMarksAngle: innerSnapAngle,
minorTickMarksAngle: 0,
majorTickMarksLength: -0.25,
minorTickMarksLength: 0,
});
} else {
Overlays.editOverlay(rotateOverlayInner, {
startAt: 0,
endAt: 360
});
Overlays.editOverlay(rotateOverlayOuter, {
startAt: startAtRemainder,
endAt: endAtRemainder
});
Overlays.editOverlay(rotateOverlayCurrent, {
startAt: startAtCurrent,
endAt: endAtCurrent,
size: outerRadius,
majorTickMarksAngle: 45.0,
minorTickMarksAngle: 5,
majorTickMarksLength: 0.25,
minorTickMarksLength: 0.1,
});
}
}
}
});
// ROLL GRABBER TOOL DEFINITION
addGrabberTool(rollHandle, {
mode: "ROTATE_ROLL",
onBegin: function(event) {
SelectionManager.saveProperties();
initialPosition = SelectionManager.worldPosition;
// Size the overlays to the current selection size
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5);
innerRadius = diagonal;
outerRadius = diagonal * 1.15;
var innerAlpha = 0.2;
var outerAlpha = 0.2;
Overlays.editOverlay(rotateOverlayInner, {
visible: true,
size: innerRadius,
innerRadius: 0.9,
startAt: 0,
endAt: 360,
alpha: innerAlpha
});
Overlays.editOverlay(rotateOverlayOuter, {
visible: true,
size: outerRadius,
innerRadius: 0.9,
startAt: 0,
endAt: 360,
alpha: outerAlpha,
});
Overlays.editOverlay(rotateOverlayCurrent, {
visible: true,
size: outerRadius,
startAt: 0,
endAt: 0,
innerRadius: 0.9,
});
Overlays.editOverlay(rotationDegreesDisplay, {
visible: true,
});
updateRotationDegreesOverlay(0, rollHandleRotation, rollCenter);
},
onEnd: function(event, reason) {
Overlays.editOverlay(rotateOverlayInner, {
visible: false
});
Overlays.editOverlay(rotateOverlayOuter, {
visible: false
});
Overlays.editOverlay(rotateOverlayCurrent, {
visible: false
});
Overlays.editOverlay(rotationDegreesDisplay, {
visible: false
});
pushCommandForSelections();
},
onMove: function(event) {
var pickRay = generalComputePickRay(event.x, event.y);
Overlays.editOverlay(selectionBox, {
visible: false
});
Overlays.editOverlay(baseOfEntityProjectionOverlay, {
visible: false
});
var result = Overlays.findRayIntersection(pickRay, true, [rotateOverlayTarget]);
if (result.intersects) {
var center = rollCenter;
var zero = rollZero;
var centerToZero = Vec3.subtract(zero, center);
var centerToIntersect = Vec3.subtract(result.intersection, center);
// Note: orientedAngle which wants normalized centerToZero & centerToIntersect, handles
// this internally, so it's fine to pass non-normalized versions here.
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
var distanceFromCenter = Vec3.distance(center, result.intersection);
var snapToInner = distanceFromCenter < innerRadius;
var snapAngle = snapToInner ? innerSnapAngle : 1.0;
angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle;
var rollChange = Quat.fromVec3Degrees({
x: 0,
y: 0,
z: angleFromZero
});
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID];
var dPos = Vec3.subtract(initialProperties.position, initialPosition);
dPos = Vec3.multiplyQbyV(rollChange, dPos);
Entities.editEntity(entityID, {
position: Vec3.sum(initialPosition, dPos),
rotation: Quat.multiply(rollChange, initialProperties.rotation),
});
}
updateRotationDegreesOverlay(angleFromZero, rollHandleRotation, rollCenter);
// update the rotation display accordingly...
var startAtCurrent = 0;
var endAtCurrent = angleFromZero;
var startAtRemainder = angleFromZero;
var endAtRemainder = 360;
if (angleFromZero < 0) {
startAtCurrent = 360 + angleFromZero;
endAtCurrent = 360;
startAtRemainder = 0;
endAtRemainder = startAtCurrent;
}
if (snapToInner) {
Overlays.editOverlay(rotateOverlayOuter, {
startAt: 0,
endAt: 360
});
Overlays.editOverlay(rotateOverlayInner, {
startAt: startAtRemainder,
endAt: endAtRemainder
});
Overlays.editOverlay(rotateOverlayCurrent, {
startAt: startAtCurrent,
endAt: endAtCurrent,
size: innerRadius,
majorTickMarksAngle: innerSnapAngle,
minorTickMarksAngle: 0,
majorTickMarksLength: -0.25,
minorTickMarksLength: 0,
});
} else {
Overlays.editOverlay(rotateOverlayInner, {
startAt: 0,
endAt: 360
});
Overlays.editOverlay(rotateOverlayOuter, {
startAt: startAtRemainder,
endAt: endAtRemainder
});
Overlays.editOverlay(rotateOverlayCurrent, {
startAt: startAtCurrent,
endAt: endAtCurrent,
size: outerRadius,
majorTickMarksAngle: 45.0,
minorTickMarksAngle: 5,
majorTickMarksLength: 0.25,
minorTickMarksLength: 0.1,
});
}
}
}
});
// FUNCTION: CHECK MOVE
that.checkMove = function() {
if (SelectionManager.hasSelection()) {
// FIXME - this cause problems with editing in the entity properties window
//SelectionManager._update();
if (!Vec3.equal(Camera.getPosition(), lastCameraPosition) ||
!Quat.equal(Camera.getOrientation(), lastCameraOrientation)) {
that.updateRotationHandles();
}
}
};
that.checkControllerMove = function() {
if (SelectionManager.hasSelection()) {
var controllerPose = getControllerWorldLocation(activeHand, true);
var hand = (activeHand === Controller.Standard.LeftHand) ? 0 : 1;
if (controllerPose.valid && lastControllerPoses[hand].valid) {
if (!Vec3.equal(controllerPose.position, lastControllerPoses[hand].position) ||
!Vec3.equal(controllerPose.rotation, lastControllerPoses[hand].rotation)) {
print("setting controller pose");
that.mouseMoveEvent({});
}
}
lastControllerPoses[hand] = controllerPose;
}
};
// FUNCTION: MOUSE PRESS EVENT
that.mousePressEvent = function(event) {
var wantDebug = false;
if (!event.isLeftButton && !that.triggered) {
// if another mouse button than left is pressed ignore it
return false;
}
var somethingClicked = false;
var pickRay = generalComputePickRay(event.x, event.y);
var result = Overlays.findRayIntersection(pickRay, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]);
if (result.intersects) {
// mouse clicks on the tablet should override the edit affordances
return false;
}
entityIconOverlayManager.setIconsSelectable(selectionManager.selections,true);
// ignore ray intersection for our selection box and yaw/pitch/roll
result = Overlays.findRayIntersection(pickRay, true, null, [ yawHandle, pitchHandle, rollHandle, selectionBox ] );
if (result.intersects) {
if (wantDebug) {
print("something intersects... ");
print(" result.overlayID:" + result.overlayID + "[" + overlayNames[result.overlayID] + "]");
print(" result.intersects:" + result.intersects);
print(" result.overlayID:" + result.overlayID);
print(" result.distance:" + result.distance);
print(" result.face:" + result.face);
Vec3.print(" result.intersection:", result.intersection);
}
var tool = grabberTools[result.overlayID];
if (tool) {
activeTool = tool;
mode = tool.mode;
somethingClicked = 'tool';
if (activeTool && activeTool.onBegin) {
activeTool.onBegin(event);
}
} else {
switch (result.overlayID) {
case grabberMoveUp:
mode = "TRANSLATE_UP_DOWN";
somethingClicked = mode;
// in translate mode, we hide our stretch handles...
for (var i = 0; i < stretchHandles.length; i++) {
Overlays.editOverlay(stretchHandles[i], {
visible: false
});
}
break;
case grabberNEAR:
case grabberEdgeTN: // TODO: maybe this should be TOP+NEAR stretching?
case grabberEdgeBN: // TODO: maybe this should be BOTTOM+FAR stretching?
mode = "STRETCH_NEAR";
somethingClicked = mode;
break;
case grabberFAR:
case grabberEdgeTF: // TODO: maybe this should be TOP+FAR stretching?
case grabberEdgeBF: // TODO: maybe this should be BOTTOM+FAR stretching?
mode = "STRETCH_FAR";
somethingClicked = mode;
break;
case grabberTOP:
mode = "STRETCH_TOP";
somethingClicked = mode;
break;
case grabberBOTTOM:
mode = "STRETCH_BOTTOM";
somethingClicked = mode;
break;
case grabberRIGHT:
case grabberEdgeTR: // TODO: maybe this should be TOP+RIGHT stretching?
case grabberEdgeBR: // TODO: maybe this should be BOTTOM+RIGHT stretching?
mode = "STRETCH_RIGHT";
somethingClicked = mode;
break;
case grabberLEFT:
case grabberEdgeTL: // TODO: maybe this should be TOP+LEFT stretching?
case grabberEdgeBL: // TODO: maybe this should be BOTTOM+LEFT stretching?
mode = "STRETCH_LEFT";
somethingClicked = mode;
break;
default:
mode = "UNKNOWN";
break;
}
}
}
// if one of the items above was clicked, then we know we are in translate or stretch mode, and we
// should hide our rotate handles...
if (somethingClicked) {
Overlays.editOverlay(yawHandle, {
visible: false
});
Overlays.editOverlay(pitchHandle, {
visible: false
});
Overlays.editOverlay(rollHandle, {
visible: false
});
if (mode != "TRANSLATE_UP_DOWN") {
Overlays.editOverlay(grabberMoveUp, {
visible: false
});
}
}
if (!somethingClicked) {
if (wantDebug) {
print("rotate handle case...");
}
// Only intersect versus yaw/pitch/roll.
result = Overlays.findRayIntersection(pickRay, true, [ yawHandle, pitchHandle, rollHandle ] );
var overlayOrientation;
var overlayCenter;
var properties = Entities.getEntityProperties(selectionManager.selections[0]);
var angles = Quat.safeEulerAngles(properties.rotation);
var pitch = angles.x;
var yaw = angles.y;
var roll = angles.z;
originalRotation = properties.rotation;
originalPitch = pitch;
originalYaw = yaw;
originalRoll = roll;
if (result.intersects) {
var resultTool = grabberTools[result.overlayID];
if (resultTool) {
activeTool = resultTool;
mode = resultTool.mode;
somethingClicked = 'tool';
if (activeTool && activeTool.onBegin) {
activeTool.onBegin(event);
}
}
switch (result.overlayID) {
case yawHandle:
mode = "ROTATE_YAW";
somethingClicked = mode;
overlayOrientation = yawHandleRotation;
overlayCenter = yawCenter;
yawZero = result.intersection;
rotationNormal = yawNormal;
break;
case pitchHandle:
mode = "ROTATE_PITCH";
initialPosition = SelectionManager.worldPosition;
somethingClicked = mode;
overlayOrientation = pitchHandleRotation;
overlayCenter = pitchCenter;
pitchZero = result.intersection;
rotationNormal = pitchNormal;
break;
case rollHandle:
mode = "ROTATE_ROLL";
somethingClicked = mode;
overlayOrientation = rollHandleRotation;
overlayCenter = rollCenter;
rollZero = result.intersection;
rotationNormal = rollNormal;
break;
default:
if (wantDebug) {
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
}
mode = "UNKNOWN";
break;
}
}
if (wantDebug) {
print(" somethingClicked:" + somethingClicked);
print(" mode:" + mode);
}
if (somethingClicked) {
Overlays.editOverlay(rotateOverlayTarget, {
visible: true,
rotation: overlayOrientation,
position: overlayCenter
});
Overlays.editOverlay(rotateOverlayInner, {
visible: true,
rotation: overlayOrientation,
position: overlayCenter
});
Overlays.editOverlay(rotateOverlayOuter, {
visible: true,
rotation: overlayOrientation,
position: overlayCenter,
startAt: 0,
endAt: 360
});
Overlays.editOverlay(rotateOverlayCurrent, {
visible: true,
rotation: overlayOrientation,
position: overlayCenter,
startAt: 0,
endAt: 0
});
Overlays.editOverlay(yawHandle, {
visible: false
});
Overlays.editOverlay(pitchHandle, {
visible: false
});
Overlays.editOverlay(rollHandle, {
visible: false
});
// TODO: these three duplicate prior three, remove them.
Overlays.editOverlay(yawHandle, {
visible: false
});
Overlays.editOverlay(pitchHandle, {
visible: false
});
Overlays.editOverlay(rollHandle, {
visible: false
});
Overlays.editOverlay(grabberMoveUp, {
visible: false
});
Overlays.editOverlay(grabberLBN, {
visible: false
});
Overlays.editOverlay(grabberLBF, {
visible: false
});
Overlays.editOverlay(grabberRBN, {
visible: false
});
Overlays.editOverlay(grabberRBF, {
visible: false
});
Overlays.editOverlay(grabberLTN, {
visible: false
});
Overlays.editOverlay(grabberLTF, {
visible: false
});
Overlays.editOverlay(grabberRTN, {
visible: false
});
Overlays.editOverlay(grabberRTF, {
visible: false
});
Overlays.editOverlay(grabberTOP, {
visible: false
});
Overlays.editOverlay(grabberBOTTOM, {
visible: false
});
Overlays.editOverlay(grabberLEFT, {
visible: false
});
Overlays.editOverlay(grabberRIGHT, {
visible: false
});
Overlays.editOverlay(grabberNEAR, {
visible: false
});
Overlays.editOverlay(grabberFAR, {
visible: false
});
Overlays.editOverlay(grabberEdgeTR, {
visible: false
});
Overlays.editOverlay(grabberEdgeTL, {
visible: false
});
Overlays.editOverlay(grabberEdgeTF, {
visible: false
});
Overlays.editOverlay(grabberEdgeTN, {
visible: false
});
Overlays.editOverlay(grabberEdgeBR, {
visible: false
});
Overlays.editOverlay(grabberEdgeBL, {
visible: false
});
Overlays.editOverlay(grabberEdgeBF, {
visible: false
});
Overlays.editOverlay(grabberEdgeBN, {
visible: false
});
Overlays.editOverlay(grabberEdgeNR, {
visible: false
});
Overlays.editOverlay(grabberEdgeNL, {
visible: false
});
Overlays.editOverlay(grabberEdgeFR, {
visible: false
});
Overlays.editOverlay(grabberEdgeFL, {
visible: false
});
}
}
if (!somethingClicked) {
// Only intersect versus selectionBox.
result = Overlays.findRayIntersection(pickRay, true, [selectionBox]);
if (result.intersects) {
switch (result.overlayID) {
case selectionBox:
activeTool = translateXZTool;
translateXZTool.pickPlanePosition = result.intersection;
translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y),
SelectionManager.worldDimensions.z);
if (wantDebug) {
print("longest dimension: " + translateXZTool.greatestDimension);
translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position);
print("starting distance: " + translateXZTool.startingDistance);
translateXZTool.startingElevation = translateXZTool.elevation(pickRay.origin, translateXZTool.pickPlanePosition);
print(" starting elevation: " + translateXZTool.startingElevation);
}
mode = translateXZTool.mode;
activeTool.onBegin(event);
somethingClicked = 'selectionBox';
break;
default:
if (wantDebug) {
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
}
mode = "UNKNOWN";
break;
}
}
}
if (somethingClicked) {
pickRay = generalComputePickRay(event.x, event.y);
if (wantDebug) {
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
}
}
// reset everything as intersectable...
// TODO: we could optimize this since some of these were already flipped back
Overlays.editOverlay(selectionBox, {
ignoreRayIntersection: false
});
Overlays.editOverlay(yawHandle, {
ignoreRayIntersection: false
});
Overlays.editOverlay(pitchHandle, {
ignoreRayIntersection: false
});
Overlays.editOverlay(rollHandle, {
ignoreRayIntersection: false
});
return somethingClicked;
};
// FUNCTION: MOUSE MOVE EVENT
that.mouseMoveEvent = function(event) {
if (activeTool) {
activeTool.onMove(event);
SelectionManager._update();
return true;
}
// if no tool is active, then just look for handles to highlight...
var pickRay = generalComputePickRay(event.x, event.y);
var result = Overlays.findRayIntersection(pickRay);
var pickedColor;
var pickedAlpha;
var highlightNeeded = false;
if (result.intersects) {
switch (result.overlayID) {
case yawHandle:
case pitchHandle:
case rollHandle:
pickedColor = handleColor;
pickedAlpha = handleAlpha;
highlightNeeded = true;
break;
case grabberMoveUp:
pickedColor = handleColor;
pickedAlpha = handleAlpha;
highlightNeeded = true;
break;
case grabberLBN:
case grabberLBF:
case grabberRBN:
case grabberRBF:
case grabberLTN:
case grabberLTF:
case grabberRTN:
case grabberRTF:
pickedColor = grabberColorCorner;
pickedAlpha = grabberAlpha;
highlightNeeded = true;
break;
case grabberTOP:
case grabberBOTTOM:
case grabberLEFT:
case grabberRIGHT:
case grabberNEAR:
case grabberFAR:
pickedColor = grabberColorFace;
pickedAlpha = grabberAlpha;
highlightNeeded = true;
break;
case grabberEdgeTR:
case grabberEdgeTL:
case grabberEdgeTF:
case grabberEdgeTN:
case grabberEdgeBR:
case grabberEdgeBL:
case grabberEdgeBF:
case grabberEdgeBN:
case grabberEdgeNR:
case grabberEdgeNL:
case grabberEdgeFR:
case grabberEdgeFL:
case grabberSpotLightRadius:
case grabberSpotLightT:
case grabberSpotLightB:
case grabberSpotLightL:
case grabberSpotLightR:
case grabberPointLightT:
case grabberPointLightB:
case grabberPointLightR:
case grabberPointLightL:
case grabberPointLightN:
case grabberPointLightF:
pickedColor = grabberColorEdge;
pickedAlpha = grabberAlpha;
highlightNeeded = true;
break;
case grabberCloner:
pickedColor = grabberColorCloner;
pickedAlpha = grabberAlpha;
highlightNeeded = true;
break;
default:
if (previousHandle) {
Overlays.editOverlay(previousHandle, {
color: previousHandleColor,
alpha: previousHandleAlpha
});
previousHandle = false;
}
break;
}
if (highlightNeeded) {
if (previousHandle) {
Overlays.editOverlay(previousHandle, {
color: previousHandleColor,
alpha: previousHandleAlpha
});
previousHandle = false;
}
Overlays.editOverlay(result.overlayID, {
color: highlightedHandleColor,
alpha: highlightedHandleAlpha
});
previousHandle = result.overlayID;
previousHandleColor = pickedColor;
previousHandleAlpha = pickedAlpha;
}
} else {
if (previousHandle) {
Overlays.editOverlay(previousHandle, {
color: previousHandleColor,
alpha: previousHandleAlpha
});
previousHandle = false;
}
}
return false;
};
// FUNCTION: UPDATE HANDLE SIZES
that.updateHandleSizes = function() {
if (selectionManager.hasSelection()) {
var diff = Vec3.subtract(selectionManager.worldPosition, Camera.getPosition());
var grabberSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 5;
var dimensions = SelectionManager.worldDimensions;
var avgDimension = (dimensions.x + dimensions.y + dimensions.z) / 3;
grabberSize = Math.min(grabberSize, avgDimension / 10);
for (var i = 0; i < stretchHandles.length; i++) {
Overlays.editOverlay(stretchHandles[i], {
size: grabberSize,
});
}
var handleSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 7;
handleSize = Math.min(handleSize, avgDimension / 3);
Overlays.editOverlay(yawHandle, {
scale: handleSize,
});
Overlays.editOverlay(pitchHandle, {
scale: handleSize,
});
Overlays.editOverlay(rollHandle, {
scale: handleSize,
});
var pos = Vec3.sum(grabberMoveUpPosition, {
x: 0,
y: Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 3,
z: 0
});
Overlays.editOverlay(grabberMoveUp, {
position: pos,
scale: handleSize / 1.25,
});
}
};
Script.update.connect(that.updateHandleSizes);
// FUNCTION: MOUSE RELEASE EVENT
that.mouseReleaseEvent = function(event) {
var showHandles = false;
if (activeTool && activeTool.onEnd) {
activeTool.onEnd(event);
}
activeTool = null;
// hide our rotation overlays..., and show our handles
if (mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL") {
Overlays.editOverlay(rotateOverlayTarget, {
visible: false
});
Overlays.editOverlay(rotateOverlayInner, {
visible: false
});
Overlays.editOverlay(rotateOverlayOuter, {
visible: false
});
Overlays.editOverlay(rotateOverlayCurrent, {
visible: false
});
showHandles = true;
}
if (mode != "UNKNOWN") {
showHandles = true;
}
mode = "UNKNOWN";
// if something is selected, then reset the "original" properties for any potential next click+move operation
if (SelectionManager.hasSelection()) {
if (showHandles) {
that.select(SelectionManager.selections[0], event);
}
}
};
// NOTE: mousePressEvent and mouseMoveEvent from the main script should call us., so we don't hook these:
// Controller.mousePressEvent.connect(that.mousePressEvent);
// Controller.mouseMoveEvent.connect(that.mouseMoveEvent);
Controller.mouseReleaseEvent.connect(that.mouseReleaseEvent);
return that;
}());