diff --git a/scripts/vr-edit/modules/groups.js b/scripts/vr-edit/modules/groups.js index c3e4172ebe..9331071fe2 100644 --- a/scripts/vr-edit/modules/groups.js +++ b/scripts/vr-edit/modules/groups.js @@ -71,6 +71,10 @@ Groups = function () { return rootEntityIDs.indexOf(rootEntityID) !== -1; } + function getRootEntityIDs() { + return rootEntityIDs; + } + function groupsCount() { return selections.length; } @@ -264,6 +268,7 @@ Groups = function () { toggle: toggle, selection: selection, includes: includes, + rootEntityIDs: getRootEntityIDs, groupsCount: groupsCount, entitiesCount: entitiesCount, group: group, diff --git a/scripts/vr-edit/modules/highlights.js b/scripts/vr-edit/modules/highlights.js index 7c8cb0e99f..d893e69f10 100644 --- a/scripts/vr-edit/modules/highlights.js +++ b/scripts/vr-edit/modules/highlights.js @@ -17,11 +17,14 @@ Highlights = function (side) { var handOverlay, entityOverlays = [], + boundingBoxOverlay, + isDisplayingBoundingBox = false, HIGHLIGHT_COLOR = { red: 240, green: 240, blue: 0 }, SCALE_COLOR = { red: 0, green: 240, blue: 240 }, GROUP_COLOR = { red: 220, green: 60, blue: 220 }, HAND_HIGHLIGHT_ALPHA = 0.35, ENTITY_HIGHLIGHT_ALPHA = 0.8, + BOUNDING_BOX_ALPHA = 0.8, HAND_HIGHLIGHT_OFFSET = { x: 0.0, y: 0.11, z: 0.02 }, LEFT_HAND = 0; @@ -43,6 +46,14 @@ Highlights = function (side) { visible: false }); + boundingBoxOverlay = Overlays.addOverlay("cube", { + alpha: BOUNDING_BOX_ALPHA, + solid: false, + drawInFront: true, + ignoreRayIntersection: true, + visible: false + }); + function setHandHighlightRadius(radius) { var dimension = 2 * radius; Overlays.editOverlay(handOverlay, { @@ -75,7 +86,7 @@ Highlights = function (side) { }); } - function display(handIntersected, selection, entityIndex, overlayColor) { + function display(handIntersected, selection, entityIndex, boundingBox, overlayColor) { // Displays highlight for just entityIndex if non-null, otherwise highlights whole selection. var i, length; @@ -86,7 +97,8 @@ Highlights = function (side) { visible: handIntersected }); - if (entityIndex !== null) { + // Display entity overlays. + if (entityIndex !== null) { // Add/edit entity overlay for just entityIndex. maybeAddEntityOverlay(0); editEntityOverlay(0, selection[entityIndex], overlayColor); @@ -103,14 +115,30 @@ Highlights = function (side) { Overlays.deleteOverlay(entityOverlays[i]); entityOverlays.splice(i, 1); } + + // Update bounding box overlay. + if (boundingBox !== null) { + Overlays.editOverlay(boundingBoxOverlay, { + position: boundingBox.center, + rotation: boundingBox.orientation, + dimensions: boundingBox.dimensions, + color: overlayColor, + visible: true + }); + isDisplayingBoundingBox = true; + } else if (isDisplayingBoundingBox) { + Overlays.editOverlay(boundingBoxOverlay, { visible: false }); + isDisplayingBoundingBox = false; + } } function clear() { var i, length; - // Hide hand overlay. + // Hide hand and bounding box overlays. Overlays.editOverlay(handOverlay, { visible: false }); + Overlays.editOverlay(boundingBoxOverlay, { visible: false }); // Delete entity overlays. for (i = 0, length = entityOverlays.length; i < length; i += 1) { @@ -122,6 +150,7 @@ Highlights = function (side) { function destroy() { clear(); Overlays.deleteOverlay(handOverlay); + Overlays.deleteOverlay(boundingBoxOverlay); } return { diff --git a/scripts/vr-edit/modules/selection.js b/scripts/vr-edit/modules/selection.js index a01eef5481..b26d5e46f6 100644 --- a/scripts/vr-edit/modules/selection.js +++ b/scripts/vr-edit/modules/selection.js @@ -99,6 +99,12 @@ SelectionManager = function (side) { traverseEntityTree(rootEntityID, selection, selectionProperties); } + function append(rootEntityID) { + // Add further entities to the selection. + // Assumes that rootEntityID is not already in the selection. + traverseEntityTree(rootEntityID, selection, selectionProperties); + } + function getIntersectedEntityID() { return intersectedEntityID; } @@ -754,6 +760,7 @@ SelectionManager = function (side) { return { select: select, + append: append, selection: getSelection, count: count, intersectedEntityID: getIntersectedEntityID, diff --git a/scripts/vr-edit/vr-edit.js b/scripts/vr-edit/vr-edit.js index 5f7b3bb732..212f85e487 100644 --- a/scripts/vr-edit/vr-edit.js +++ b/scripts/vr-edit/vr-edit.js @@ -690,6 +690,7 @@ if (toolSelected !== TOOL_SCALE || !otherEditor.isEditing(rootEntityID)) { highlights.display(intersection.handIntersected, selection.selection(), toolSelected === TOOL_COLOR || toolSelected === TOOL_PICK_COLOR ? selection.intersectedEntityIndex() : null, + null, toolSelected === TOOL_SCALE || otherEditor.isEditing(rootEntityID) ? highlights.SCALE_COLOR : highlights.HIGHLIGHT_COLOR); } @@ -702,6 +703,7 @@ if (toolSelected !== TOOL_SCALE || !otherEditor.isEditing(rootEntityID)) { highlights.display(intersection.handIntersected, selection.selection(), toolSelected === TOOL_COLOR || toolSelected === TOOL_PICK_COLOR ? selection.intersectedEntityIndex() : null, + null, toolSelected === TOOL_SCALE || otherEditor.isEditing(rootEntityID) ? highlights.SCALE_COLOR : highlights.HIGHLIGHT_COLOR); if (!intersection.laserIntersected && !isUIVisible) { @@ -815,12 +817,13 @@ function enterEditorGrouping() { if (!grouping.includes(rootEntityID)) { - highlights.display(false, selection.selection(), null, highlights.GROUP_COLOR); + highlights.display(false, selection.selection(), null, null, highlights.GROUP_COLOR); } if (toolSelected === TOOL_GROUP_BOX) { if (!grouping.includes(rootEntityID)) { Feedback.play(side, Feedback.SELECT_ENTITY); - grouping.selectInBox(selection.selection()); + grouping.toggle(selection.selection()); + grouping.selectInBox(); } else { Feedback.play(side, Feedback.GENERAL_ERROR); } @@ -1281,13 +1284,14 @@ // Grouping highlights and functions. var groups, - isSelectInBox = false, highlights, exludedLeftRootEntityID = null, exludedrightRootEntityID = null, excludedRootEntityIDs = [], hasHighlights = false, - hasSelectionChanged = false; + hasSelectionChanged = false, + isSelectInBox = false, + selectInBoxSelection = null; // Selection of all groups combined in order to calculate bounding box. if (!this instanceof Grouping) { return new Grouping(); @@ -1298,6 +1302,14 @@ function toggle(selection) { groups.toggle(selection); + if (isSelectInBox) { + // When selecting in a box, toggle() is only called to add entities to the selection. + if (selectInBoxSelection.count() === 0) { + selectInBoxSelection.select(selection[0].id); + } else { + selectInBoxSelection.append(selection[0].id); + } + } if (groups.groupsCount() === 0) { hasHighlights = false; highlights.clear(); @@ -1307,31 +1319,54 @@ } } - function updateSelectInBox() { - // TODO: Calculate bounding box. + function selectInBox() { + // Add any entities or groups of entities wholly within bounding box of current selection. + // Must be wholly within otherwise selection could grow uncontrollably. + var boundingBox; - // TODO: Select further entities per bounding box. + if (selectInBoxSelection.count() > 1) { + boundingBox = selectInBoxSelection.boundingBox(); - // TODO: Update bounding box overlay. + // TODO: Select further entities per bounding box. + + hasSelectionChanged = true; + } } function startSelectInBox() { + // Start automatically selecting entities in bounding box of current selection. + var rootEntityIDs, + i, + length; + isSelectInBox = true; - // TODO: Create bounding box overlay. + // Select entities current groups combined. + selectInBoxSelection = new SelectionManager(); + rootEntityIDs = groups.rootEntityIDs(); + if (rootEntityIDs.length > 0) { + selectInBoxSelection.select(rootEntityIDs[0]); + for (i = 1, length = rootEntityIDs.length; i < length; i += 1) { + selectInBoxSelection.append(rootEntityIDs[i]); + } + } - updateSelectInBox(); - } + // Add any enclosed entities. + selectInBox(); - function selectInBox(selection) { - toggle(selection); - updateSelectInBox(); + // Show bounding box overlay plus any newly selected entities. + hasSelectionChanged = true; } function stopSelectInBox() { - isSelectInBox = false; + // Stop automatically selecting entities within bounding box of current selection. + selectInBoxSelection.destroy(); + selectInBoxSelection = null; - // TODO: Delete bounding box overlay. + // Hide bounding box overlay. + hasSelectionChanged = true; + + isSelectInBox = false; } function includes(rootEntityID) { @@ -1355,7 +1390,9 @@ } function update(leftRootEntityID, rightRootEntityID) { - var hasExludedRootEntitiesChanged; + // Update highlights displayed, excluding entities highlighted by left or right hands. + var hasExludedRootEntitiesChanged, + boundingBox; hasExludedRootEntitiesChanged = leftRootEntityID !== exludedLeftRootEntityID || rightRootEntityID !== exludedrightRootEntityID; @@ -1376,12 +1413,15 @@ exludedrightRootEntityID = rightRootEntityID; } - highlights.display(false, groups.selection(excludedRootEntityIDs), null, highlights.GROUP_COLOR); - + boundingBox = isSelectInBox && selectInBoxSelection.count() > 1 ? selectInBoxSelection.boundingBox() : null; + highlights.display(false, groups.selection(excludedRootEntityIDs), null, boundingBox, highlights.GROUP_COLOR); hasSelectionChanged = false; } function clear() { + if (isSelectInBox) { + stopSelectInBox(); + } groups.clear(); highlights.clear(); } @@ -1395,6 +1435,10 @@ highlights.destroy(); highlights = null; } + if (selectInBoxSelection) { + selectInBoxSelection.destroy(); + selectInBoxSelection = null; + } } return {