Merge pull request from huffman/entity-tools-polish-2

Entity tools polish - round 2
This commit is contained in:
Brad Hefta-Gaub 2014-12-03 14:31:27 -08:00
commit 96c3bfceef
3 changed files with 163 additions and 103 deletions

View file

@ -89,11 +89,19 @@ SelectionManager = (function() {
}
}
that.addEntity = function(entityID) {
that.addEntity = function(entityID, toggleSelection) {
if (entityID.isKnownID) {
var idx = that.selections.indexOf(entityID);
var idx = -1;
for (var i = 0; i < that.selections.length; i++) {
if (entityID.id == that.selections[i].id) {
idx = i;
break;
}
}
if (idx == -1) {
that.selections.push(entityID);
} else if (toggleSelection) {
that.selections.splice(idx, 1);
}
} else {
var idx = that.pendingSelections.indexOf(entityID);
@ -227,7 +235,6 @@ SelectionDisplay = (function () {
var overlayNames = new Array();
var lastCameraPosition = Camera.getPosition();
var lastCameraOrientation = Camera.getOrientation();
var lastPlaneIntersection;
var handleHoverColor = { red: 224, green: 67, blue: 36 };
var handleHoverAlpha = 1.0;
@ -324,21 +331,23 @@ SelectionDisplay = (function () {
solid: false,
visible: false,
dashed: true,
lineWidth: 1.0,
lineWidth: 2.0,
ignoreRayIntersection: true // this never ray intersects
});
var selectionBox = Overlays.addOverlay("cube", {
position: { x:0, y: 0, z: 0},
size: 1,
color: { red: 60, green: 60, blue: 60},
color: { red: 255, green: 0, blue: 0},
alpha: 1,
solid: false,
visible: false,
dashed: true,
dashed: false,
lineWidth: 1.0,
});
var selectionBoxes = [];
var rotationDegreesDisplay = Overlays.addOverlay("text3d", {
position: { x:0, y: 0, z: 0},
text: "",
@ -684,6 +693,9 @@ SelectionDisplay = (function () {
for (var i = 0; i < allOverlays.length; i++) {
Overlays.deleteOverlay(allOverlays[i]);
}
for (var i = 0; i < selectionBoxes.length; i++) {
Overlays.deleteOverlay(selectionBoxes[i]);
}
};
that.highlightSelectable = function(entityID) {
@ -708,13 +720,11 @@ SelectionDisplay = (function () {
if (event !== false) {
pickRay = Camera.computePickRay(event.x, event.y);
lastPlaneIntersection = rayPlaneIntersection(pickRay, properties.position, Quat.getFront(lastCameraOrientation));
var wantDebug = false;
if (wantDebug) {
print("select() with EVENT...... ");
print(" event.y:" + event.y);
Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection);
Vec3.print(" current position:", properties.position);
}
@ -933,23 +943,6 @@ SelectionDisplay = (function () {
var dimensions = selectionManager.worldDimensions;
var position = selectionManager.worldPosition;
Overlays.editOverlay(baseOfEntityProjectionOverlay,
{
visible: mode != "ROTATE_YAW" && mode != "ROTATE_PITCH" && mode != "ROTATE_ROLL",
solid: true,
// lineWidth: 2.0,
position: {
x: position.x,
y: grid.getOrigin().y,
z: position.z
},
dimensions: {
x: dimensions.x,
y: dimensions.z
},
rotation: rotation,
});
Overlays.editOverlay(rotateOverlayTarget, { visible: rotationOverlaysVisible });
Overlays.editOverlay(rotateZeroOverlay, { visible: rotationOverlaysVisible });
@ -986,7 +979,6 @@ SelectionDisplay = (function () {
return;
}
that.updateRotationHandles();
that.highlightSelectable();
@ -1126,6 +1118,41 @@ SelectionDisplay = (function () {
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,
}));
}
var 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 properties = Entities.getEntityProperties(selectionManager.selections[i]);
Overlays.editOverlay(selectionBoxes[i], {
position: properties.position,
rotation: properties.rotation,
dimensions: properties.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 });
@ -1142,6 +1169,23 @@ SelectionDisplay = (function () {
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(0, 0, 0),
});
};
that.setOverlaysVisible = function(isVisible) {
@ -1149,6 +1193,10 @@ SelectionDisplay = (function () {
for (var i = 0; i < length; i++) {
Overlays.editOverlay(allOverlays[i], { visible: isVisible });
}
length = selectionBoxes.length;
for (var i = 0; i < length; i++) {
Overlays.editOverlay(selectionBoxes[i], { visible: isVisible });
}
};
that.unselect = function (entityID) {
@ -1242,7 +1290,6 @@ SelectionDisplay = (function () {
if (wantDebug) {
print("translateXZ... ");
Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection);
Vec3.print(" vector:", vector);
Vec3.print(" newPosition:", properties.position);
Vec3.print(" newPosition:", newPosition);
@ -1254,10 +1301,17 @@ SelectionDisplay = (function () {
};
var lastXYPick = null
var upDownPickNormal = null;
addGrabberTool(grabberMoveUp, {
mode: "TRANSLATE_UP_DOWN",
onBegin: function(event) {
lastXYPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, Quat.getFront(lastCameraOrientation));
pickRay = Camera.computePickRay(event.x, event.y);
upDownPickNormal = Quat.getFront(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();
@ -1285,11 +1339,9 @@ SelectionDisplay = (function () {
pickRay = Camera.computePickRay(event.x, event.y);
// translate mode left/right based on view toward entity
var newIntersection = rayPlaneIntersection(pickRay,
SelectionManager.worldPosition,
Quat.getFront(lastCameraOrientation));
var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal);
var vector = Vec3.subtract(newIntersection, lastPlaneIntersection);
var vector = Vec3.subtract(newIntersection, lastXYPick);
vector = grid.snapToGrid(vector);
// we only care about the Y axis
@ -1300,7 +1352,6 @@ SelectionDisplay = (function () {
if (wantDebug) {
print("translateUpDown... ");
print(" event.y:" + event.y);
Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection);
Vec3.print(" newIntersection:", newIntersection);
Vec3.print(" vector:", vector);
Vec3.print(" newPosition:", newPosition);
@ -1513,7 +1564,6 @@ SelectionDisplay = (function () {
var wantDebug = false;
if (wantDebug) {
print(stretchMode);
Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection);
Vec3.print(" newIntersection:", newIntersection);
Vec3.print(" vector:", vector);
Vec3.print(" oldPOS:", oldPOS);
@ -2010,7 +2060,7 @@ SelectionDisplay = (function () {
that.checkMove = function() {
if (SelectionManager.hasSelection() &&
(!Vec3.equal(Camera.getPosition(), lastCameraPosition) || !Quat.equal(Camera.getOrientation(), lastCameraOrientation))){
that.select(selectionManager.selections[0], false, false);
that.updateRotationHandles();
}
};
@ -2262,11 +2312,8 @@ SelectionDisplay = (function () {
if (somethingClicked) {
pickRay = Camera.computePickRay(event.x, event.y);
lastPlaneIntersection = rayPlaneIntersection(pickRay, selectionManager.worldPosition,
Quat.getFront(lastCameraOrientation));
if (wantDebug) {
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection);
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
}
}

View file

@ -177,6 +177,8 @@ Grid = function(opts) {
color: gridColor,
alpha: gridAlpha,
});
that.emitUpdate();
}
function cleanup() {
@ -207,6 +209,7 @@ GridTool = function(opts) {
horizontalGrid.addListener(function(data) {
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
selectionDisplay.updateHandles();
});
webView.eventBridge.webEventReceived.connect(function(data) {

View file

@ -51,8 +51,8 @@ var toolWidth = 50;
var MIN_ANGULAR_SIZE = 2;
var MAX_ANGULAR_SIZE = 45;
var allowLargeModels = false;
var allowSmallModels = false;
var allowLargeModels = true;
var allowSmallModels = true;
var wantEntityGlow = false;
var SPAWN_DISTANCE = 1;
@ -476,7 +476,6 @@ function findClickedEntity(event) {
var identify = Entities.identifyEntity(foundEntity);
if (!identify.isKnownID) {
print("Unknown ID " + identify.id + " (update loop " + foundEntity.id + ")");
selectionManager.clearSelections();
return null;
}
foundEntity = identify;
@ -485,74 +484,18 @@ function findClickedEntity(event) {
return { pickRay: pickRay, entityID: foundEntity };
}
var mouseHasMovedSincePress = false;
function mousePressEvent(event) {
mouseHasMovedSincePress = false;
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
return;
}
if (isActive) {
var entitySelected = false;
if (cameraManager.mousePressEvent(event) || selectionDisplay.mousePressEvent(event)) {
// Event handled; do nothing.
return;
} else {
var result = findClickedEntity(event);
if (result === null) {
selectionManager.clearSelections();
return;
}
var pickRay = result.pickRay;
var foundEntity = result.entityID;
var properties = Entities.getEntityProperties(foundEntity);
if (isLocked(properties)) {
print("Model locked " + properties.id);
} else {
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal);
// P P - Model
// /| A - Palm
// / | d B - unit vector toward tip
// / | X - base of the perpendicular line
// A---X----->B d - distance fom axis
// x x - distance from A
//
// |X-A| = (P-A).B
// X == A + ((P-A).B)B
// d = |P-X|
var A = pickRay.origin;
var B = Vec3.normalize(pickRay.direction);
var P = properties.position;
var x = Vec3.dot(Vec3.subtract(P, A), B);
var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X));
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (0 < x && sizeOK) {
entitySelected = true;
selectedEntityID = foundEntity;
orientation = MyAvatar.orientation;
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
if (!event.isShifted) {
selectionManager.clearSelections();
}
selectionManager.addEntity(foundEntity);
print("Model selected: " + foundEntity.id);
}
}
}
if (entitySelected) {
selectionDisplay.select(selectedEntityID, event);
}
} else if (Menu.isOptionChecked(MENU_INSPECT_TOOL_ENABLED)) {
var result = findClickedEntity(event);
@ -572,6 +515,7 @@ function mousePressEvent(event) {
var highlightedEntityID = { isKnownID: false };
function mouseMoveEvent(event) {
mouseHasMovedSincePress = true;
if (isActive) {
// allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
@ -615,6 +559,72 @@ function mouseReleaseEvent(event) {
}
cameraManager.mouseReleaseEvent(event);
if (!mouseHasMovedSincePress) {
mouseClickEvent(event);
}
}
function mouseClickEvent(event) {
var result = findClickedEntity(event);
if (result === null) {
if (!event.isShifted) {
selectionManager.clearSelections();
}
return;
}
var pickRay = result.pickRay;
var foundEntity = result.entityID;
var properties = Entities.getEntityProperties(foundEntity);
if (isLocked(properties)) {
print("Model locked " + properties.id);
} else {
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal);
// P P - Model
// /| A - Palm
// / | d B - unit vector toward tip
// / | X - base of the perpendicular line
// A---X----->B d - distance fom axis
// x x - distance from A
//
// |X-A| = (P-A).B
// X == A + ((P-A).B)B
// d = |P-X|
var A = pickRay.origin;
var B = Vec3.normalize(pickRay.direction);
var P = properties.position;
var x = Vec3.dot(Vec3.subtract(P, A), B);
var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X));
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (0 < x && sizeOK) {
entitySelected = true;
selectedEntityID = foundEntity;
orientation = MyAvatar.orientation;
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
if (!event.isShifted) {
selectionManager.clearSelections();
}
var toggle = event.isShifted;
selectionManager.addEntity(foundEntity, toggle);
print("Model selected: " + foundEntity.id);
selectionDisplay.select(selectedEntityID, event);
}
}
}
Controller.mousePressEvent.connect(mousePressEvent);
@ -644,9 +654,9 @@ function setupModelMenus() {
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L",
afterItem: "Paste Models", isCheckable: true });
afterItem: "Paste Models", isCheckable: true, isChecked: true });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S",
afterItem: "Allow Select Large Models", isCheckable: true });
afterItem: "Allow Select Large Models", isCheckable: true, isChecked: true });
Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" });
Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" });