mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 19:34:23 +02:00
Merge pull request #3889 from huffman/entity-tools-polish-2
Entity tools polish - round 2
This commit is contained in:
commit
96c3bfceef
3 changed files with 163 additions and 103 deletions
examples
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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" });
|
||||
|
|
Loading…
Reference in a new issue