Distinguish properly between intersected and root entities

This commit is contained in:
David Rowe 2017-08-12 14:56:22 +12:00
parent 2bf0ea1dff
commit 541402b559
2 changed files with 80 additions and 50 deletions

View file

@ -16,7 +16,7 @@ Selection = function (side) {
"use strict"; "use strict";
var selection = [], var selection = [],
selectedEntityID = null, intersectedEntityID = null,
rootEntityID = null, rootEntityID = null,
rootPosition, rootPosition,
rootOrientation, rootOrientation,
@ -65,12 +65,14 @@ Selection = function (side) {
} }
} }
function select(entityID) { function select(intersectionEntityID) {
var entityProperties, var entityProperties,
PARENT_PROPERTIES = ["parentID", "position", "rotation", "dymamic", "collisionless"]; PARENT_PROPERTIES = ["parentID", "position", "rotation", "dymamic", "collisionless"];
intersectedEntityID = intersectionEntityID;
// Find root parent. // Find root parent.
rootEntityID = Entities.rootOf(entityID); rootEntityID = Entities.rootOf(intersectedEntityID);
// Selection position and orientation is that of the root entity. // Selection position and orientation is that of the root entity.
entityProperties = Entities.getEntityProperties(rootEntityID, PARENT_PROPERTIES); entityProperties = Entities.getEntityProperties(rootEntityID, PARENT_PROPERTIES);
@ -80,8 +82,10 @@ Selection = function (side) {
// Find all children. // Find all children.
selection = []; selection = [];
traverseEntityTree(rootEntityID, selection); traverseEntityTree(rootEntityID, selection);
}
selectedEntityID = entityID; function getIntersectedEntityID() {
return intersectedEntityID;
} }
function getRootEntityID() { function getRootEntityID() {
@ -263,7 +267,7 @@ Selection = function (side) {
} }
function finishDirectScaling() { function finishDirectScaling() {
select(selectedEntityID); // Refresh. select(intersectedEntityID); // Refresh.
} }
function startHandleScaling() { function startHandleScaling() {
@ -296,19 +300,23 @@ Selection = function (side) {
} }
function finishHandleScaling() { function finishHandleScaling() {
select(selectedEntityID); // Refresh. select(intersectedEntityID); // Refresh.
} }
function cloneEntities() { function cloneEntities() {
var parentIDIndexes = [], var parentIDIndexes = [],
intersectedEntityIndex = 0,
parentID, parentID,
properties, properties,
i, i,
j, j,
length; length;
// Map parent IDs. // Map parent IDs; find intersectedEntityID's index.
for (i = 1, length = selection.length; i < length; i += 1) { for (i = 1, length = selection.length; i < length; i += 1) {
if (selection[i].id === intersectedEntityID) {
intersectedEntityIndex = i;
}
parentID = selection[i].parentID; parentID = selection[i].parentID;
for (j = 0; j < i; j += 1) { for (j = 0; j < i; j += 1) {
if (parentID === selection[j].id) { if (parentID === selection[j].id) {
@ -327,6 +335,7 @@ Selection = function (side) {
selection[i].id = Entities.addEntity(properties); selection[i].id = Entities.addEntity(properties);
} }
intersectedEntityID = selection[intersectedEntityIndex].id;
rootEntityID = selection[0].id; rootEntityID = selection[0].id;
} }
@ -410,7 +419,7 @@ Selection = function (side) {
function clear() { function clear() {
selection = []; selection = [];
selectedEntityID = null; intersectedEntityID = null;
rootEntityID = null; rootEntityID = null;
} }
@ -429,6 +438,7 @@ Selection = function (side) {
select: select, select: select,
selection: getSelection, selection: getSelection,
count: count, count: count,
intersectedEntityID: getIntersectedEntityID,
rootEntityID: getRootEntityID, rootEntityID: getRootEntityID,
boundingBox: getBoundingBox, boundingBox: getBoundingBox,
getPositionAndOrientation: getPositionAndOrientation, getPositionAndOrientation: getPositionAndOrientation,

View file

@ -337,7 +337,8 @@
// State machine. // State machine.
STATE_MACHINE, STATE_MACHINE,
highlightedEntityID = null, // Root entity of highlighted entity set. intersectedEntityID = null, // Intersected entity of highlighted entity set.
rootEntityID = null, // Root entity of highlighted entity set.
wasScaleTool = false, wasScaleTool = false,
isOtherEditorEditingEntityID = false, isOtherEditorEditingEntityID = false,
isTriggerClicked = false, isTriggerClicked = false,
@ -408,18 +409,22 @@
return handles.isHandle(overlayID); return handles.isHandle(overlayID);
} }
function isEditing(rootEntityID) { function isEditing(aRootEntityID) {
// rootEntityID is an optional parameter. // aRootEntityID is an optional parameter.
return editorState > EDITOR_HIGHLIGHTING return editorState > EDITOR_HIGHLIGHTING
&& (rootEntityID === undefined || rootEntityID === selection.rootEntityID()); && (aRootEntityID === undefined || aRootEntityID === rootEntityID);
} }
function isScaling() { function isScaling() {
return editorState === EDITOR_DIRECT_SCALING || editorState === EDITOR_HANDLE_SCALING; return editorState === EDITOR_DIRECT_SCALING || editorState === EDITOR_HANDLE_SCALING;
} }
function rootEntityID() { function getIntersectedEntityID() {
return selection.rootEntityID(); return intersectedEntityID;
}
function getRootEntityID() {
return rootEntityID;
} }
@ -634,6 +639,8 @@
function enterEditorSearching() { function enterEditorSearching() {
selection.clear(); selection.clear();
intersectedEntityID = null;
rootEntityID = null;
hoveredOverlayID = intersection.overlayID; hoveredOverlayID = intersection.overlayID;
otherEditor.hoverHandle(hoveredOverlayID); otherEditor.hoverHandle(hoveredOverlayID);
} }
@ -650,21 +657,21 @@
} }
function enterEditorHighlighting() { function enterEditorHighlighting() {
selection.select(highlightedEntityID); selection.select(intersectedEntityID);
if (toolSelected !== TOOL_SCALE || !otherEditor.isEditing(highlightedEntityID)) { if (toolSelected !== TOOL_SCALE || !otherEditor.isEditing(rootEntityID)) {
highlights.display(intersection.handIntersected, selection.selection(), highlights.display(intersection.handIntersected, selection.selection(),
toolSelected === TOOL_SCALE || otherEditor.isEditing(highlightedEntityID) toolSelected === TOOL_SCALE || otherEditor.isEditing(rootEntityID)
? highlights.SCALE_COLOR : highlights.HIGHLIGHT_COLOR); ? highlights.SCALE_COLOR : highlights.HIGHLIGHT_COLOR);
} }
isOtherEditorEditingEntityID = otherEditor.isEditing(highlightedEntityID); isOtherEditorEditingEntityID = otherEditor.isEditing(rootEntityID);
wasScaleTool = toolSelected === TOOL_SCALE; wasScaleTool = toolSelected === TOOL_SCALE;
} }
function updateEditorHighlighting() { function updateEditorHighlighting() {
selection.select(highlightedEntityID); selection.select(intersectedEntityID);
if (toolSelected !== TOOL_SCALE || !otherEditor.isEditing(highlightedEntityID)) { if (toolSelected !== TOOL_SCALE || !otherEditor.isEditing(rootEntityID)) {
highlights.display(intersection.handIntersected, selection.selection(), highlights.display(intersection.handIntersected, selection.selection(),
toolSelected === TOOL_SCALE || otherEditor.isEditing(highlightedEntityID) toolSelected === TOOL_SCALE || otherEditor.isEditing(rootEntityID)
? highlights.SCALE_COLOR : highlights.HIGHLIGHT_COLOR); ? highlights.SCALE_COLOR : highlights.HIGHLIGHT_COLOR);
} else { } else {
highlights.clear(); highlights.clear();
@ -678,23 +685,23 @@
} }
function enterEditorGrabbing() { function enterEditorGrabbing() {
selection.select(highlightedEntityID); // For when transitioning from EDITOR_SEARCHING. selection.select(intersectedEntityID); // For when transitioning from EDITOR_SEARCHING.
if (intersection.laserIntersected) { if (intersection.laserIntersected) {
laser.setLength(laser.length()); laser.setLength(laser.length());
} else { } else {
laser.disable(); laser.disable();
} }
if (toolSelected === TOOL_SCALE) { if (toolSelected === TOOL_SCALE) {
handles.display(highlightedEntityID, selection.boundingBox(), selection.count() > 1); handles.display(rootEntityID, selection.boundingBox(), selection.count() > 1);
} }
startEditing(); startEditing();
wasScaleTool = toolSelected === TOOL_SCALE; wasScaleTool = toolSelected === TOOL_SCALE;
} }
function updateEditorGrabbing() { function updateEditorGrabbing() {
selection.select(highlightedEntityID); selection.select(intersectedEntityID);
if (toolSelected === TOOL_SCALE) { if (toolSelected === TOOL_SCALE) {
handles.display(highlightedEntityID, selection.boundingBox(), selection.count() > 1); handles.display(rootEntityID, selection.boundingBox(), selection.count() > 1);
} else { } else {
handles.clear(); handles.clear();
} }
@ -708,7 +715,7 @@
} }
function enterEditorDirectScaling() { function enterEditorDirectScaling() {
selection.select(highlightedEntityID); // In case need to transition to EDITOR_GRABBING. selection.select(intersectedEntityID); // In case need to transition to EDITOR_GRABBING.
isScalingWithHand = intersection.handIntersected; isScalingWithHand = intersection.handIntersected;
if (intersection.laserIntersected) { if (intersection.laserIntersected) {
laser.setLength(laser.length()); laser.setLength(laser.length());
@ -729,7 +736,7 @@
} }
function enterEditorHandleScaling() { function enterEditorHandleScaling() {
selection.select(highlightedEntityID); // In case need to transition to EDITOR_GRABBING. selection.select(intersectedEntityID); // In case need to transition to EDITOR_GRABBING.
isScalingWithHand = intersection.handIntersected; isScalingWithHand = intersection.handIntersected;
if (intersection.laserIntersected) { if (intersection.laserIntersected) {
laser.setLength(laser.length()); laser.setLength(laser.length());
@ -750,9 +757,11 @@
} }
function enterEditorCloning() { function enterEditorCloning() {
selection.select(highlightedEntityID); // For when transitioning from EDITOR_SEARCHING. selection.select(intersectedEntityID); // For when transitioning from EDITOR_SEARCHING.
selection.cloneEntities(); selection.cloneEntities();
highlightedEntityID = selection.rootEntityID(); intersectedEntityID = selection.intersectedEntityID();
rootEntityID = selection.rootEntityID();
intersectedEntityID = rootEntityID;
} }
function exitEditorCloning() { function exitEditorCloning() {
@ -760,7 +769,7 @@
} }
function enterEditorGrouping() { function enterEditorGrouping() {
if (!grouping.includes(highlightedEntityID)) { if (!grouping.includes(rootEntityID)) {
highlights.display(false, selection.selection(), highlights.GROUP_COLOR); highlights.display(false, selection.selection(), highlights.GROUP_COLOR);
} }
grouping.toggle(selection.selection()); grouping.toggle(selection.selection());
@ -869,16 +878,19 @@
setState(EDITOR_IDLE); setState(EDITOR_IDLE);
} else if (intersection.overlayID && !wasTriggerClicked && isTriggerClicked } else if (intersection.overlayID && !wasTriggerClicked && isTriggerClicked
&& otherEditor.isHandle(intersection.overlayID)) { && otherEditor.isHandle(intersection.overlayID)) {
highlightedEntityID = otherEditor.rootEntityID(); intersectedEntityID = otherEditor.intersectedEntityID();
rootEntityID = otherEditor.rootEntityID();
setState(EDITOR_HANDLE_SCALING); setState(EDITOR_HANDLE_SCALING);
} else if (intersection.entityID && intersection.editableEntity } else if (intersection.entityID && intersection.editableEntity
&& (wasTriggerClicked || !isTriggerClicked) && !isAutoGrab) { && (wasTriggerClicked || !isTriggerClicked) && !isAutoGrab) {
highlightedEntityID = Entities.rootOf(intersection.entityID); intersectedEntityID = intersection.entityID;
rootEntityID = Entities.rootOf(intersectedEntityID);
setState(EDITOR_HIGHLIGHTING); setState(EDITOR_HIGHLIGHTING);
} else if (intersection.entityID && intersection.editableEntity } else if (intersection.entityID && intersection.editableEntity
&& (!wasTriggerClicked || isAutoGrab) && isTriggerClicked) { && (!wasTriggerClicked || isAutoGrab) && isTriggerClicked) {
highlightedEntityID = Entities.rootOf(intersection.entityID); intersectedEntityID = intersection.entityID;
if (otherEditor.isEditing(highlightedEntityID)) { rootEntityID = Entities.rootOf(intersectedEntityID);
if (otherEditor.isEditing(rootEntityID)) {
if (toolSelected !== TOOL_SCALE) { if (toolSelected !== TOOL_SCALE) {
setState(EDITOR_DIRECT_SCALING); setState(EDITOR_DIRECT_SCALING);
} }
@ -917,16 +929,17 @@
if (hand.valid() if (hand.valid()
&& intersection.entityID && intersection.editableEntity && intersection.entityID && intersection.editableEntity
&& !(!wasTriggerClicked && isTriggerClicked && !(!wasTriggerClicked && isTriggerClicked
&& (!otherEditor.isEditing(highlightedEntityID) || toolSelected !== TOOL_SCALE)) && (!otherEditor.isEditing(rootEntityID) || toolSelected !== TOOL_SCALE))
&& !(!wasTriggerClicked && isTriggerClicked && intersection.overlayID && !(!wasTriggerClicked && isTriggerClicked && intersection.overlayID
&& otherEditor.isHandle(intersection.overlayID))) { && otherEditor.isHandle(intersection.overlayID))) {
// No transition. // No transition.
doUpdateState = false; doUpdateState = false;
if (otherEditor.isEditing(highlightedEntityID) !== isOtherEditorEditingEntityID) { if (otherEditor.isEditing(rootEntityID) !== isOtherEditorEditingEntityID) {
doUpdateState = true; doUpdateState = true;
} }
if (Entities.rootOf(intersection.entityID) !== highlightedEntityID) { if (Entities.rootOf(intersection.entityID) !== rootEntityID) {
highlightedEntityID = Entities.rootOf(intersection.entityID); intersectedEntityID = intersection.entityID;
rootEntityID = Entities.rootOf(intersectedEntityID);
doUpdateState = true; doUpdateState = true;
} }
if ((toolSelected === TOOL_SCALE) !== wasScaleTool) { if ((toolSelected === TOOL_SCALE) !== wasScaleTool) {
@ -943,11 +956,13 @@
setState(EDITOR_IDLE); setState(EDITOR_IDLE);
} else if (intersection.overlayID && !wasTriggerClicked && isTriggerClicked } else if (intersection.overlayID && !wasTriggerClicked && isTriggerClicked
&& otherEditor.isHandle(intersection.overlayID)) { && otherEditor.isHandle(intersection.overlayID)) {
highlightedEntityID = otherEditor.rootEntityID(); intersectedEntityID = otherEditor.intersectedEntityID();
rootEntityID = otherEditor.rootEntityID();
setState(EDITOR_HANDLE_SCALING); setState(EDITOR_HANDLE_SCALING);
} else if (intersection.entityID && intersection.editableEntity && !wasTriggerClicked && isTriggerClicked) { } else if (intersection.entityID && intersection.editableEntity && !wasTriggerClicked && isTriggerClicked) {
highlightedEntityID = Entities.rootOf(intersection.entityID); // May be a different entityID. intersectedEntityID = intersection.entityID; // May be a different entityID.
if (otherEditor.isEditing(highlightedEntityID)) { rootEntityID = Entities.rootOf(intersectedEntityID);
if (otherEditor.isEditing(rootEntityID)) {
if (toolSelected !== TOOL_SCALE) { if (toolSelected !== TOOL_SCALE) {
setState(EDITOR_DIRECT_SCALING); setState(EDITOR_DIRECT_SCALING);
} else { } else {
@ -998,7 +1013,8 @@
setState(EDITOR_IDLE); setState(EDITOR_IDLE);
} else if (!isTriggerClicked) { } else if (!isTriggerClicked) {
if (intersection.entityID && intersection.editableEntity) { if (intersection.entityID && intersection.editableEntity) {
highlightedEntityID = Entities.rootOf(intersection.entityID); intersectedEntityID = intersection.entityID;
rootEntityID = Entities.rootOf(intersectedEntityID);
setState(EDITOR_HIGHLIGHTING); setState(EDITOR_HIGHLIGHTING);
} else { } else {
setState(EDITOR_SEARCHING); setState(EDITOR_SEARCHING);
@ -1014,7 +1030,7 @@
break; break;
case EDITOR_DIRECT_SCALING: case EDITOR_DIRECT_SCALING:
if (hand.valid() && isTriggerClicked if (hand.valid() && isTriggerClicked
&& (otherEditor.isEditing(highlightedEntityID) || otherEditor.isHandle(intersection.overlayID))) { && (otherEditor.isEditing(rootEntityID) || otherEditor.isHandle(intersection.overlayID))) {
// Don't test for intersection.intersected because when scaling with handles intersection may lag behind. // Don't test for intersection.intersected because when scaling with handles intersection may lag behind.
// Don't test toolSelected === TOOL_SCALE because this is a UI element and so not able to be changed while // Don't test toolSelected === TOOL_SCALE because this is a UI element and so not able to be changed while
// scaling with two hands. // scaling with two hands.
@ -1029,10 +1045,11 @@
if (!intersection.entityID || !intersection.editableEntity) { if (!intersection.entityID || !intersection.editableEntity) {
setState(EDITOR_SEARCHING); setState(EDITOR_SEARCHING);
} else { } else {
highlightedEntityID = Entities.rootOf(intersection.entityID); intersectedEntityID = intersection.entityID;
rootEntityID = Entities.rootOf(intersectedEntityID);
setState(EDITOR_HIGHLIGHTING); setState(EDITOR_HIGHLIGHTING);
} }
} else if (!otherEditor.isEditing(highlightedEntityID)) { } else if (!otherEditor.isEditing(rootEntityID)) {
// Grab highlightEntityID that was scaling and has already been set. // Grab highlightEntityID that was scaling and has already been set.
setState(EDITOR_GRABBING); setState(EDITOR_GRABBING);
} else { } else {
@ -1040,7 +1057,7 @@
} }
break; break;
case EDITOR_HANDLE_SCALING: case EDITOR_HANDLE_SCALING:
if (hand.valid() && isTriggerClicked && otherEditor.isEditing(highlightedEntityID)) { if (hand.valid() && isTriggerClicked && otherEditor.isEditing(rootEntityID)) {
// Don't test for intersection.intersected because when scaling with handles intersection may lag behind. // Don't test for intersection.intersected because when scaling with handles intersection may lag behind.
// Don't test toolSelected === TOOL_SCALE because this is a UI element and so not able to be changed while // Don't test toolSelected === TOOL_SCALE because this is a UI element and so not able to be changed while
// scaling with two hands. // scaling with two hands.
@ -1055,10 +1072,11 @@
if (!intersection.entityID || !intersection.editableEntity) { if (!intersection.entityID || !intersection.editableEntity) {
setState(EDITOR_SEARCHING); setState(EDITOR_SEARCHING);
} else { } else {
highlightedEntityID = Entities.rootOf(intersection.entityID); intersectedEntityID = intersection.entityID;
rootEntityID = Entities.rootOf(intersectedEntityID);
setState(EDITOR_HIGHLIGHTING); setState(EDITOR_HIGHLIGHTING);
} }
} else if (!otherEditor.isEditing(highlightedEntityID)) { } else if (!otherEditor.isEditing(rootEntityID)) {
// Grab highlightEntityID that was scaling and has already been set. // Grab highlightEntityID that was scaling and has already been set.
setState(EDITOR_GRABBING); setState(EDITOR_GRABBING);
} else { } else {
@ -1073,7 +1091,8 @@
setState(EDITOR_IDLE); setState(EDITOR_IDLE);
} else if (!isTriggerClicked) { } else if (!isTriggerClicked) {
if (intersection.entityID && intersection.editableEntity) { if (intersection.entityID && intersection.editableEntity) {
highlightedEntityID = Entities.rootOf(intersection.entityID); intersectedEntityID = intersection.entityID;
rootEntityID = Entities.rootOf(intersectedEntityID);
setState(EDITOR_HIGHLIGHTING); setState(EDITOR_HIGHLIGHTING);
} else { } else {
setState(EDITOR_SEARCHING); setState(EDITOR_SEARCHING);
@ -1150,7 +1169,8 @@
isHandle: isHandle, isHandle: isHandle,
isEditing: isEditing, isEditing: isEditing,
isScaling: isScaling, isScaling: isScaling,
rootEntityID: rootEntityID, intersectedEntityID: getIntersectedEntityID,
rootEntityID: getRootEntityID,
startDirectScaling: startDirectScaling, startDirectScaling: startDirectScaling,
updateDirectScaling: updateDirectScaling, updateDirectScaling: updateDirectScaling,
stopDirectScaling: stopDirectScaling, stopDirectScaling: stopDirectScaling,