Merge pull request #3678 from huffman/entity-tool-fixes

Entity tool updates and fixes
This commit is contained in:
Brad Hefta-Gaub 2014-10-28 15:24:21 -07:00
commit caecf473ff
4 changed files with 416 additions and 239 deletions

View file

@ -19,10 +19,15 @@ SPACE_WORLD = "world";
SelectionManager = (function() {
var that = {};
var PENDING_SELECTION_CHECK_INTERVAL = 50;
that.savedProperties = {};
that.eventListener = null;
that.selections = [];
// These are selections that don't have a known ID yet
that.pendingSelections = [];
var pendingSelectionTimer = null;
that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
that.localPosition = { x: 0, y: 0, z: 0 };
@ -45,11 +50,58 @@ SelectionManager = (function() {
that.eventListener = 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];
if (entityID.isKnownID) {
that.selections.push(entityID);
} else {
that.pendingSelections.push(entityID);
if (pendingSelectionTimer == null) {
pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL);
}
}
}
that._update();
};
that._checkPendingSelections = function() {
for (var i = 0; i < that.pendingSelections.length; i++) {
var entityID = that.pendingSelections[i];
var newEntityID = Entities.identifyEntity(entityID);
if (newEntityID.isKnownID) {
that.pendingSelections.splice(i, 1);
that.addEntity(newEntityID);
i--;
}
}
if (that.pendingSelections.length == 0) {
Script.clearInterval(pendingSelectionTimer);
pendingSelectionTimer = null;
}
}
that.addEntity = function(entityID) {
print("Adding: " + entityID.id);
var idx = that.selections.indexOf(entityID);
if (idx == -1) {
that.selections.push(entityID);
if (entityID.isKnownID) {
var idx = that.selections.indexOf(entityID);
if (idx == -1) {
that.selections.push(entityID);
}
} else {
var idx = that.pendingSelections.indexOf(entityID);
if (idx == -1) {
that.pendingSelections.push(entityID);
if (pendingSelectionTimer == null) {
pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL);
}
}
}
that._update();
@ -61,11 +113,22 @@ SelectionManager = (function() {
that.selections.splice(idx, 1);
}
var idx = that.pendingSelections.indexOf(entityID);
if (idx >= 0) {
that.pendingSelections.splice(idx, 1);
}
that._update();
};
that.clearSelections = function() {
that.selections = [];
that.pendingSelections = [];
if (pendingSelectionTimer !== null) {
Script.clearInterval(pendingSelectionTimer);
pendingSelectionTimer = null;
}
that._update();
};
@ -77,8 +140,6 @@ SelectionManager = (function() {
that.worldDimensions = null;
that.worldPosition = null;
} else if (that.selections.length == 1) {
SelectionDisplay.setSpaceMode(SPACE_LOCAL);
var properties = Entities.getEntityProperties(that.selections[0]);
that.localDimensions = properties.dimensions;
that.localPosition = properties.position;
@ -86,10 +147,9 @@ SelectionManager = (function() {
that.worldDimensions = properties.boundingBox.dimensions;
that.worldPosition = properties.boundingBox.center;
} else {
// For 1+ selections we can only modify selections in world space
SelectionDisplay.setSpaceMode(SPACE_WORLD);
SelectionDisplay.setSpaceMode(SPACE_LOCAL);
} else {
that.localRotation = null;
that.localDimensions = null;
that.localPosition = null;
@ -122,6 +182,9 @@ SelectionManager = (function() {
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);
}
if (that.eventListener) {
@ -600,7 +663,7 @@ SelectionDisplay = (function () {
currentSelection = entityID;
entitySelected = true;
lastCameraPosition = Camera.getPosition();
// lastCameraPosition = Camera.getPosition();
lastCameraOrientation = Camera.getOrientation();
if (event !== false) {
@ -623,10 +686,15 @@ SelectionDisplay = (function () {
}
Entities.editEntity(entityID, { localRenderAlpha: 0.1 });
Overlays.editOverlay(highlightBox, { visible: false });
that.updateHandles();
}
that.updateRotationHandles = function() {
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5);
innerRadius = diagonal;
outerRadius = diagonal * 1.15;
var innerActive = false;
var innerAlpha = 0.2;
var outerAlpha = 0.2;
@ -637,22 +705,18 @@ SelectionDisplay = (function () {
}
var rotateHandleOffset = 0.05;
var grabberMoveUpOffset = 0.1;
var top, far, left, bottom, near, right, boundsCenter, objectCenter, BLN, BRN, BLF, TLN, TRN, TLF, TRF;
// objectCenter = { x: properties.position.x, y: properties.position.y, z: properties.position.z };
var dimensions;
var dimensions, rotation;
if (spaceMode == SPACE_LOCAL) {
objectCenter = SelectionManager.localPosition;
dimensions = SelectionManager.localDimensions;
rotation = SelectionManager.localRotation;
} else {
objectCenter = SelectionManager.worldPosition;
dimensions = SelectionManager.worldDimensions;
rotation = SelectionManager.worldRotation;
}
objectCenter = SelectionManager.worldPosition;
dimensions = SelectionManager.worldDimensions;
var position = objectCenter;
top = objectCenter.y + (dimensions.y / 2);
far = objectCenter.z + (dimensions.z / 2);
@ -662,7 +726,6 @@ SelectionDisplay = (function () {
near = objectCenter.z - (dimensions.z / 2);
right = objectCenter.x - (dimensions.x / 2);
// boundsCenter = { x: properties.boundingBox.center.x, y: properties.boundingBox.center.y, z: properties.boundingBox.center.z };
boundsCenter = objectCenter;
var yawCorner;
@ -812,10 +875,12 @@ SelectionDisplay = (function () {
}
var rotateHandlesVisible = true;
var rotationOverlaysVisible = false;
var translateHandlesVisible = true;
var stretchHandlesVisible = true;
var selectionBoxVisible = true;
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;
@ -828,77 +893,33 @@ SelectionDisplay = (function () {
rotateHandlesVisible = false;
translateHandlesVisible = false;
}
Overlays.editOverlay(highlightBox, { visible: false });
var dimensions, rotation, position;
if (spaceMode == SPACE_LOCAL) {
rotation = SelectionManager.localRotation;
dimensions = SelectionManager.localDimensions;
position = SelectionManager.localPosition;
} else {
rotation = SelectionManager.worldRotation;
dimensions = SelectionManager.worldDimensions;
position = SelectionManager.worldPosition;
}
Overlays.editOverlay(grabberMoveUp, { visible: translateHandlesVisible, position: { x: boundsCenter.x, y: top + grabberMoveUpOffset, z: boundsCenter.z } });
that.updateHandles();
var rotation = SelectionManager.worldRotation;
var dimensions = SelectionManager.worldDimensions;
var position = SelectionManager.worldPosition;
Overlays.editOverlay(baseOfEntityProjectionOverlay,
{
visible: true,
solid:true,
lineWidth: 2.0,
position: { x: properties.position.x,
position: { x: position.x,
y: 0,
z: properties.position.z },
z: position.z },
dimensions: { x: properties.dimensions.x, y: properties.dimensions.z },
rotation: properties.rotation,
dimensions: { x: dimensions.x, y: 0, z: dimensions.z },
rotation: rotation,
});
Overlays.editOverlay(rotateOverlayTarget, { visible: false });
Overlays.editOverlay(rotateOverlayInner,
{
visible: false,
size: innerRadius,
innerRadius: 0.9,
alpha: innerAlpha
});
Overlays.editOverlay(rotateOverlayOuter,
{
visible: false,
size: outerRadius,
innerRadius: 0.9,
startAt: 0,
endAt: 360,
alpha: outerAlpha,
});
Overlays.editOverlay(rotateOverlayCurrent,
{
visible: false,
size: outerRadius,
startAt: 0,
endAt: 0,
innerRadius: 0.9,
});
Overlays.editOverlay(rotateZeroOverlay, { visible: false });
Overlays.editOverlay(rotateCurrentOverlay, { visible: false });
Overlays.editOverlay(rotateOverlayTarget, { visible: rotationOverlaysVisible });
Overlays.editOverlay(rotateZeroOverlay, { visible: rotationOverlaysVisible });
Overlays.editOverlay(rotateCurrentOverlay, { visible: rotationOverlaysVisible });
// TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden
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});
Entities.editEntity(entityID, { localRenderAlpha: 0.1 });
};
that.setSpaceMode = function(newSpaceMode) {
@ -931,6 +952,8 @@ SelectionDisplay = (function () {
return;
}
that.updateRotationHandles();
var rotation, dimensions, position;
if (spaceMode == SPACE_LOCAL) {
@ -945,12 +968,14 @@ SelectionDisplay = (function () {
var halfDimensions = Vec3.multiply(0.5, dimensions);
left = -halfDimensions.x;
right = halfDimensions.x;
top = halfDimensions.y;
bottom = -halfDimensions.y;
var left = -halfDimensions.x;
var right = halfDimensions.x;
var top = halfDimensions.y;
var bottom = -halfDimensions.y;
var front = far = halfDimensions.z;
near = -halfDimensions.z;
var near = -halfDimensions.z;
var worldTop = SelectionManager.worldDimensions.y / 2;
var LBN = { x: left, y: bottom, z: near };
var RBN = { x: right, y: bottom, z: near };
@ -1060,7 +1085,7 @@ SelectionDisplay = (function () {
position: position,
dimensions: dimensions,
rotation: rotation,
visible: true,
visible: !(mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL"),
});
Overlays.editOverlay(grabberEdgeTR, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeTR });
@ -1076,6 +1101,8 @@ SelectionDisplay = (function () {
Overlays.editOverlay(grabberEdgeFR, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeFR });
Overlays.editOverlay(grabberEdgeFL, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeFL });
var grabberMoveUpOffset = 0.1;
Overlays.editOverlay(grabberMoveUp, { visible: activeTool == null || mode == "TRANSLATE_UP_DOWN", position: { x: position.x, y: position.y + worldTop + grabberMoveUpOffset, z: position.z } });
};
that.setOverlaysVisible = function(isVisible) {
@ -1094,47 +1121,10 @@ SelectionDisplay = (function () {
entitySelected = false;
};
function applyEntityProperties(data) {
for (var i = 0; i < data.length; i++) {
var entityID = data[i].entityID;
var properties = data[i].properties;
Entities.editEntity(entityID, properties);
}
selectionManager._update();
};
// For currently selected entities, push a command to the UndoStack that uses the current entity properties for the
// redo command, and the saved properties for the undo command.
function pushCommandForSelections() {
var undoData = [];
var redoData = [];
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
var currentProperties = Entities.getEntityProperties(entityID);
undoData.push({
entityID: entityID,
properties: {
position: initialProperties.position,
rotation: initialProperties.rotation,
dimensions: initialProperties.dimensions,
},
});
redoData.push({
entityID: entityID,
properties: {
position: currentProperties.position,
rotation: currentProperties.rotation,
dimensions: currentProperties.dimensions,
},
});
}
UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
}
var initialXZPick = null;
var isConstrained = false;
var startPosition = null;
var duplicatedEntityIDs = null;
var translateXZTool = {
mode: 'TRANSLATE_XZ',
onBegin: function(event) {
@ -1149,43 +1139,32 @@ SelectionDisplay = (function () {
// 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];
var entityID = Entities.addEntity(properties);
duplicatedEntityIDs.push({
entityID: entityID,
properties: properties,
});
}
} else {
duplicatedEntityIDs = null;
}
isConstrained = false;
},
onEnd: function(event, reason) {
if (reason == 'cancel') {
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
Entities.editEntity(entityID, initialProperties);
}
} else {
pushCommandForSelections();
}
pushCommandForSelections(duplicatedEntityIDs);
Overlays.editOverlay(xRailOverlay, { visible: false });
Overlays.editOverlay(zRailOverlay, { visible: false });
},
onMove: function(event) {
if (!entitySelected || mode !== "TRANSLATE_XZ") {
return; // not allowed
}
pickRay = Camera.computePickRay(event.x, event.y);
// translate mode left/right based on view toward entity
var newIntersection = rayPlaneIntersection(pickRay,
selectedEntityPropertiesOriginalPosition,
Quat.getFront(lastCameraOrientation));
var vector = Vec3.subtract(newIntersection, lastPlaneIntersection);
var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { x: 0, y: 1, z: 0 });
var vector = Vec3.subtract(pick, initialXZPick);
// initialXZPick = pick;
// If shifted, constrain to one axis
if (event.isShifted) {
@ -1222,7 +1201,6 @@ SelectionDisplay = (function () {
if (wantDebug) {
print("translateXZ... ");
Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection);
Vec3.print(" newIntersection:", newIntersection);
Vec3.print(" vector:", vector);
Vec3.print(" newPosition:", properties.position);
Vec3.print(" newPosition:", newPosition);
@ -1239,22 +1217,28 @@ SelectionDisplay = (function () {
mode: "TRANSLATE_UP_DOWN",
onBegin: function(event) {
SelectionManager.saveProperties();
},
onEnd: function(event, reason) {
if (reason == 'cancel') {
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
Entities.editEntity(entityID, initialProperties);
// 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];
var entityID = Entities.addEntity(properties);
duplicatedEntityIDs.push({
entityID: entityID,
properties: properties,
});
}
} else {
pushCommandForSelections();
duplicatedEntityIDs = null;
}
},
onEnd: function(event, reason) {
pushCommandForSelections(duplicatedEntityIDs);
},
onMove: function(event) {
if (!entitySelected || mode !== "TRANSLATE_UP_DOWN") {
return; // not allowed
}
pickRay = Camera.computePickRay(event.x, event.y);
// translate mode left/right based on view toward entity
@ -1403,21 +1387,10 @@ SelectionDisplay = (function () {
Overlays.editOverlay(yRailOverlay, { visible: false });
Overlays.editOverlay(zRailOverlay, { visible: false });
if (reason == 'cancel') {
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
Entities.editEntity(entityID, initialProperties);
}
} else {
pushCommandForSelections();
}
pushCommandForSelections();
};
var onMove = function(event) {
if (!entitySelected || mode !== stretchMode) {
return; // not allowed
}
var proportional = spaceMode == SPACE_WORLD || event.isShifted;
var position, dimensions, rotation;
@ -1510,14 +1483,6 @@ SelectionDisplay = (function () {
};
};
that.cancelTool = function() {
if (activeTool) {
activeTool.onEnd(null, 'cancel');
activeTool = null;
SelectionManager._update();
}
};
function addStretchTool(overlay, mode, pivot, direction) {
if (!pivot) {
pivot = Vec3.multiply(-1, direction);
@ -1563,23 +1528,49 @@ SelectionDisplay = (function () {
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,
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,
});
},
onEnd: function(event, reason) {
if (reason == 'cancel') {
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
Entities.editEntity(entityID, initialProperties);
}
} else {
pushCommandForSelections();
}
Overlays.editOverlay(rotateOverlayInner, { visible: false });
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
pushCommandForSelections();
},
onMove: function(event) {
if (!entitySelected || mode !== "ROTATE_YAW") {
return; // not allowed
}
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
if (debug) {
@ -1591,9 +1582,6 @@ SelectionDisplay = (function () {
Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false});
Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false });
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true });
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
var result = Overlays.findRayIntersection(pickRay);
@ -1611,6 +1599,7 @@ SelectionDisplay = (function () {
var distanceFromCenter = Vec3.distance(center, result.intersection);
var snapToInner = false;
// var innerRadius = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
if (distanceFromCenter < innerRadius) {
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
snapToInner = true;
@ -1671,22 +1660,49 @@ SelectionDisplay = (function () {
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);
var innerRadius = diagonal;
var outerRadius = diagonal * 1.15;
var innerAlpha = 0.2;
var outerAlpha = 0.2;
Overlays.editOverlay(rotateOverlayInner,
{
visible: true,
size: innerRadius,
innerRadius: 0.9,
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,
});
},
onEnd: function(event, reason) {
if (reason == 'cancel') {
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
Entities.editEntity(entityID, initialProperties);
}
} else {
pushCommandForSelections();
}
Overlays.editOverlay(rotateOverlayInner, { visible: false });
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
pushCommandForSelections();
},
onMove: function(event) {
if (!entitySelected || mode !== "ROTATE_PITCH") {
return; // not allowed
}
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
if (debug) {
@ -1698,9 +1714,6 @@ SelectionDisplay = (function () {
Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false});
Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false });
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true });
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
var result = Overlays.findRayIntersection(pickRay);
if (debug) {
@ -1777,22 +1790,49 @@ SelectionDisplay = (function () {
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);
var innerRadius = diagonal;
var outerRadius = diagonal * 1.15;
var innerAlpha = 0.2;
var outerAlpha = 0.2;
Overlays.editOverlay(rotateOverlayInner,
{
visible: true,
size: innerRadius,
innerRadius: 0.9,
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,
});
},
onEnd: function(event, reason) {
if (reason == 'cancel') {
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
Entities.editEntity(entityID, initialProperties);
}
} else {
pushCommandForSelections();
}
Overlays.editOverlay(rotateOverlayInner, { visible: false });
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
pushCommandForSelections();
},
onMove: function(event) {
if (!entitySelected || mode !== "ROTATE_ROLL") {
return; // not allowed
}
var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems");
if (debug) {
@ -1804,9 +1844,6 @@ SelectionDisplay = (function () {
Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false});
Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false });
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true });
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
var result = Overlays.findRayIntersection(pickRay);
if (debug) {

View file

@ -1,4 +1,4 @@
//
// newEditEntities.js
// examples
//
@ -282,7 +282,7 @@ var toolBar = (function () {
toggleNewModelButton(false);
file = Window.browse("Select your model file ...",
Settings.getValue("LastModelUploadLocation").path(),
Settings.getValue("LastModelUploadLocation").path(),
"Model files (*.fst *.fbx)");
//"Model files (*.fst *.fbx *.svo)");
if (file !== null) {
@ -305,7 +305,7 @@ var toolBar = (function () {
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE));
if (position.x > 0 && position.y > 0 && position.z > 0) {
Entities.addEntity({
Entities.addEntity({
type: "Box",
position: position,
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
@ -322,7 +322,7 @@ var toolBar = (function () {
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE));
if (position.x > 0 && position.y > 0 && position.z > 0) {
Entities.addEntity({
Entities.addEntity({
type: "Sphere",
position: position,
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
@ -468,7 +468,7 @@ function mousePressEvent(event) {
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (0 < x && sizeOK) {
@ -502,7 +502,7 @@ function mousePressEvent(event) {
w: selectedEntityProperties.rotation.w,
};
selectedEntityProperties.glowLevel = 0.0;
print("Clicked on " + selectedEntityID.id + " " + entitySelected);
tooltip.updateText(selectedEntityProperties);
tooltip.show(true);
@ -516,7 +516,7 @@ function mouseMoveEvent(event) {
if (!isActive) {
return;
}
// 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)) {
return;
@ -531,11 +531,11 @@ function mouseMoveEvent(event) {
}
var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(),
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(),
entityIntersection.properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (entityIntersection.entityID.isKnownID && sizeOK) {
@ -545,7 +545,7 @@ function mouseMoveEvent(event) {
highlightedEntityID = entityIntersection.entityID;
selectionDisplay.highlightSelectable(entityIntersection.entityID);
}
}
}
@ -585,9 +585,9 @@ function setupModelMenus() {
}
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",
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L",
afterItem: "Paste Models", isCheckable: true });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S",
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S",
afterItem: "Allow Select Large Models", isCheckable: true });
Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" });
@ -641,14 +641,24 @@ function handeMenuEvent(menuItem) {
} else if (menuItem == "Allow Select Large Models") {
allowLargeModels = Menu.isOptionChecked("Allow Select Large Models");
} else if (menuItem == "Delete") {
if (entitySelected) {
if (SelectionManager.hasSelection()) {
print(" Delete Entity.... selectedEntityID="+ selectedEntityID);
SelectionManager.saveProperties();
var savedProperties = [];
for (var i = 0; i < selectionManager.selections.length; i++) {
Entities.deleteEntity(selectionManager.selections[i]);
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
SelectionManager.savedProperties[entityID.id];
savedProperties.push({
entityID: entityID,
properties: initialProperties
});
Entities.deleteEntity(entityID);
}
SelectionManager.clearSelections();
pushCommandForSelections([], savedProperties);
selectionDisplay.unselect(selectedEntityID);
entitySelected = false;
selectionManager.clearSelections();
} else {
print(" Delete Entity.... not holding...");
}
@ -658,15 +668,16 @@ function handeMenuEvent(menuItem) {
editModelID = -1;
if (selectionManager.selections.length == 1) {
print(" Edit Properties.... selectedEntityID="+ selectedEntityID);
editModelID = selectedEntityID;
editModelID = selectionManager.selections[0];
} else {
print(" Edit Properties.... not holding...");
}
if (editModelID != -1) {
print(" Edit Properties.... about to edit properties...");
entityPropertyDialogBox.openDialog(editModelID);
selectionManager._update();
}
} else if (menuItem == "Paste Models") {
modelImporter.paste();
} else if (menuItem == "Export Models") {
@ -694,8 +705,6 @@ Controller.keyReleaseEvent.connect(function (event) {
handeMenuEvent("Delete");
} else if (event.text == "TAB") {
selectionDisplay.toggleSpaceMode();
} else if (event.text == "ESC") {
selectionDisplay.cancelTool();
} else if (event.text == "f") {
if (entitySelected) {
// Get latest properties
@ -706,8 +715,130 @@ Controller.keyReleaseEvent.connect(function (event) {
if (isActive) {
cameraManager.enable();
}
} else {
var delta = null;
if (event.text == 'UP') {
if (event.isControl || event.isAlt) {
delta = { x: 0, y: 1, z: 0 };
} else {
delta = { x: 0, y: 0, z: -1 };
}
} else if (event.text == 'DOWN') {
if (event.isControl || event.isAlt) {
delta = { x: 0, y: -1, z: 0 };
} else {
delta = { x: 0, y: 0, z: 1 };
}
} else if (event.text == 'LEFT') {
delta = { x: -1, y: 0, z: 0 };
} else if (event.text == 'RIGHT') {
delta = { x: 1, y: 0, z: 0 };
}
if (delta != null) {
// Adjust delta so that movements are relative to the current camera orientation
var lookDirection = Quat.getFront(Camera.getOrientation());
lookDirection.z *= -1;
var angle = Math.atan2(lookDirection.z, lookDirection.x);
angle -= (Math.PI / 4);
var rotation = Math.floor(angle / (Math.PI / 2)) * (Math.PI / 2);
var rotator = Quat.fromPitchYawRollRadians(0, rotation, 0);
delta = Vec3.multiplyQbyV(rotator, delta);
SelectionManager.saveProperties();
for (var i = 0; i < selectionManager.selections.length; i++) {
var entityID = selectionManager.selections[i];
var properties = Entities.getEntityProperties(entityID);
Entities.editEntity(entityID, {
position: Vec3.sum(properties.position, delta)
});
}
pushCommandForSelections();
selectionManager._update();
}
}
});
// When an entity has been deleted we need a way to "undo" this deletion. Because it's not currently
// possible to create an entity with a specific id, earlier undo commands to the deleted entity
// will fail if there isn't a way to find the new entity id.
DELETED_ENTITY_MAP = {
}
function applyEntityProperties(data) {
var properties = data.setProperties;
var selectedEntityIDs = [];
for (var i = 0; i < properties.length; i++) {
var entityID = properties[i].entityID;
if (DELETED_ENTITY_MAP[entityID.id] !== undefined) {
entityID = DELETED_ENTITY_MAP[entityID.id];
}
Entities.editEntity(entityID, properties[i].properties);
selectedEntityIDs.push(entityID);
}
for (var i = 0; i < data.createEntities.length; i++) {
var entityID = data.createEntities[i].entityID;
var properties = data.createEntities[i].properties;
var newEntityID = Entities.addEntity(properties);
DELETED_ENTITY_MAP[entityID.id] = newEntityID;
print(newEntityID.isKnownID);
if (data.selectCreated) {
selectedEntityIDs.push(newEntityID);
}
}
for (var i = 0; i < data.deleteEntities.length; i++) {
var entityID = data.deleteEntities[i].entityID;
if (DELETED_ENTITY_MAP[entityID.id] !== undefined) {
entityID = DELETED_ENTITY_MAP[entityID.id];
}
Entities.deleteEntity(entityID);
}
selectionManager.setSelections(selectedEntityIDs);
};
// For currently selected entities, push a command to the UndoStack that uses the current entity properties for the
// redo command, and the saved properties for the undo command. Also, include create and delete entity data.
function pushCommandForSelections(createdEntityData, deletedEntityData) {
var undoData = {
setProperties: [],
createEntities: deletedEntityData || [],
deleteEntities: createdEntityData || [],
selectCreated: true,
};
var redoData = {
setProperties: [],
createEntities: createdEntityData || [],
deleteEntities: deletedEntityData || [],
selectCreated: false,
};
for (var i = 0; i < SelectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
var initialProperties = SelectionManager.savedProperties[entityID.id];
var currentProperties = Entities.getEntityProperties(entityID);
undoData.setProperties.push({
entityID: entityID,
properties: {
position: initialProperties.position,
rotation: initialProperties.rotation,
dimensions: initialProperties.dimensions,
},
});
redoData.setProperties.push({
entityID: entityID,
properties: {
position: currentProperties.position,
rotation: currentProperties.rotation,
dimensions: currentProperties.dimensions,
},
});
}
UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
}

View file

@ -30,6 +30,7 @@ void UndoStackScriptingInterface::pushCommand(QScriptValue undoFunction, QScript
ScriptUndoCommand::ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData,
QScriptValue redoFunction, QScriptValue redoData) :
_hasRedone(false),
_undoFunction(undoFunction),
_undoData(undoData),
_redoFunction(redoFunction),
@ -41,7 +42,15 @@ void ScriptUndoCommand::undo() {
}
void ScriptUndoCommand::redo() {
QMetaObject::invokeMethod(this, "doRedo");
// QUndoStack will call `redo()` when adding a command to the stack. This
// makes it difficult to work with commands that span a period of time - for instance,
// the entity duplicate + move command that duplicates an entity and then moves it.
// A better implementation might be to properly implement `mergeWith()` and `id()`
// so that the two actions in the example would be merged.
if (_hasRedone) {
QMetaObject::invokeMethod(this, "doRedo");
}
_hasRedone = true;
}
void ScriptUndoCommand::doUndo() {
@ -50,7 +59,6 @@ void ScriptUndoCommand::doUndo() {
_undoFunction.call(QScriptValue(), args);
}
void ScriptUndoCommand::doRedo() {
QScriptValueList args;
args << _redoData;

View file

@ -43,6 +43,7 @@ public slots:
void doRedo();
private:
bool _hasRedone;
QScriptValue _undoFunction;
QScriptValue _undoData;
QScriptValue _redoFunction;