Add camera orientation overlay

This commit is contained in:
Ryan Huffman 2014-12-19 09:03:04 -08:00
parent 5b89208068
commit 93aaa38c4c
3 changed files with 209 additions and 302 deletions

View file

@ -495,11 +495,11 @@ var mouseHasMovedSincePress = false;
function mousePressEvent(event) {
mouseHasMovedSincePress = false;
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
if (toolBar.mousePressEvent(event) || cameraManager.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
return;
}
if (isActive) {
if (cameraManager.mousePressEvent(event) || selectionDisplay.mousePressEvent(event)) {
if (selectionDisplay.mousePressEvent(event)) {
// Event handled; do nothing.
return;
}

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/overlayUtils.js");
var MOUSE_SENSITIVITY = 0.9;
var SCROLL_SENSITIVITY = 0.05;
var PAN_ZOOM_SCALE_RATIO = 0.4;
@ -41,6 +43,27 @@ var easeOutCubic = function(t) {
EASE_TIME = 0.5;
var ORIENTATION_OVERLAY_SIZE = 30;
var ORIENTATION_OVERLAY_HALF_SIZE = ORIENTATION_OVERLAY_SIZE / 2;
var orientationOverlayPosition = {
x: Window.innerWidth - 46,
y: 46,
};
var orientationOverlay = OverlayGroup({
position: orientationOverlayPosition,
});
function mergeObjects(obj1, obj2) {
var newObj = {};
for (key in obj1) {
newObj[key] = obj1[key];
}
for (key in obj2) {
newObj[key] = obj2[key];
}
return newObj;
}
CameraManager = function() {
var that = {};
@ -92,8 +115,6 @@ CameraManager = function() {
Camera.mode = "independent";
that.updateCamera();
cameraTool.setVisible(false);
}
that.disable = function(ignoreCamera) {
@ -104,7 +125,6 @@ CameraManager = function() {
if (!ignoreCamera) {
Camera.mode = that.previousCameraMode;
}
cameraTool.setVisible(false);
}
that.focus = function(position, dimensions, easeOrientation) {
@ -140,6 +160,11 @@ CameraManager = function() {
that.updateCamera();
}
that.setTargetPitchYaw = function(pitch, yaw) {
that.targetPitch = pitch;
that.targetYaw = yaw;
}
that.moveFocalPoint = function(dPos) {
that.setFocalPoint(Vec3.sum(that.focalPoint, dPos));
}
@ -230,6 +255,10 @@ CameraManager = function() {
that.mousePressEvent = function(event) {
if (!that.enabled) return;
if (cameraTool.mousePressEvent(event)) {
return true;
}
if (event.isRightButton || (event.isLeftButton && event.isControl && !event.isShifted)) {
that.mode = MODE_ORBIT;
} else if (event.isMiddleButton || (event.isLeftButton && event.isControl && event.isShifted)) {
@ -247,7 +276,7 @@ CameraManager = function() {
return true;
}
return cameraTool.mousePressEvent(event);
return false;
}
that.mouseReleaseEvent = function(event) {
@ -270,8 +299,18 @@ CameraManager = function() {
that.updateCamera();
}
that.updateOrientationOverlay = function() {
var flip = Quat.fromPitchYawRollDegrees(0, 180, 0);
orientationOverlay.setProperties({
rotation: Quat.multiply(flip, Quat.inverse(Camera.orientation)),
});
}
that.updateCamera = function() {
if (!that.enabled || Camera.mode != "independent") return;
if (!that.enabled || Camera.mode != "independent") {
that.updateOrientationOverlay();
return;
}
var yRot = Quat.angleAxis(that.yaw, { x: 0, y: 1, z: 0 });
var xRot = Quat.angleAxis(that.pitch, { x: 1, y: 0, z: 0 });
@ -290,6 +329,8 @@ CameraManager = function() {
}
Camera.setOrientation(q);
that.updateOrientationOverlay();
}
function normalizeDegrees(degrees) {
@ -301,6 +342,7 @@ CameraManager = function() {
// Ease the position and orbit of the camera
that.update = function(dt) {
if (Camera.mode != "independent") {
that.updateCamera();
return;
}
@ -363,316 +405,117 @@ CameraManager = function() {
return that;
}
var ZoomTool = function(opts) {
var that = {};
var position = opts.position || { x: 0, y: 0 };
var height = opts.height || 200;
var color = opts.color || { red: 255, green: 0, blue: 0 };
var arrowButtonSize = opts.buttonSize || 20;
var arrowButtonBackground = opts.arrowBackground || { red: 255, green: 255, blue: 255 };
var zoomBackground = { red: 128, green: 0, blue: 0 };
var zoomHeight = height - (arrowButtonSize * 2);
var zoomBarY = position.y + arrowButtonSize,
var onIncreasePressed = opts.onIncreasePressed;
var onDecreasePressed = opts.onDecreasePressed;
var onPercentageSet = opts.onPercentageSet;
var increaseButton = Overlays.addOverlay("text", {
x: position.x,
y: position.y,
width: arrowButtonSize,
height: arrowButtonSize,
color: color,
backgroundColor: arrowButtonBackground,
topMargin: 4,
leftMargin: 4,
text: "+",
alpha: 1.0,
backgroundAlpha: 1.0,
visible: true,
});
var decreaseButton = Overlays.addOverlay("text", {
x: position.x,
y: position.y + arrowButtonSize + zoomHeight,
width: arrowButtonSize,
height: arrowButtonSize,
color: color,
backgroundColor: arrowButtonBackground,
topMargin: 4,
leftMargin: 4,
text: "-",
alpha: 1.0,
backgroundAlpha: 1.0,
visible: true,
});
var zoomBar = Overlays.addOverlay("text", {
x: position.x + 5,
y: zoomBarY,
width: 10,
height: zoomHeight,
color: { red: 0, green: 255, blue: 0 },
backgroundColor: zoomBackground,
topMargin: 4,
leftMargin: 4,
text: "",
alpha: 1.0,
backgroundAlpha: 1.0,
visible: true,
});
var zoomHandle = Overlays.addOverlay("text", {
x: position.x,
y: position.y + arrowButtonSize,
width: arrowButtonSize,
height: 10,
backgroundColor: { red: 0, green: 255, blue: 0 },
topMargin: 4,
leftMargin: 4,
text: "",
alpha: 1.0,
backgroundAlpha: 1.0,
visible: true,
});
var allOverlays = [
increaseButton,
decreaseButton,
zoomBar,
zoomHandle,
];
that.destroy = function() {
for (var i = 0; i < allOverlays.length; i++) {
Overlays.deleteOverlay(allOverlays[i]);
}
};
that.setVisible = function(visible) {
for (var i = 0; i < allOverlays.length; i++) {
Overlays.editOverlay(allOverlays[i], { visible: visible });
}
}
that.setZoomPercentage = function(pct) {
var yOffset = (zoomHeight - 10) * pct;
Overlays.editOverlay(zoomHandle, {
y: position.y + arrowButtonSize + yOffset,
});
}
that.mouseReleaseEvent = function(event) {
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
var clicked = false;
if (clickedOverlay == increaseButton) {
if (onIncreasePressed) onIncreasePressed();
clicked = true;
} else if (clickedOverlay == decreaseButton) {
if (onDecreasePressed) onDecreasePressed();
clicked = true;
} else if (clickedOverlay == zoomBar) {
if (onPercentageSet) onPercentageSet((event.y - zoomBarY) / zoomHeight);
clicked = true;
}
return clicked;
}
return that;
};
var ArrowTool = function(opts) {
var that = {};
var position = opts.position || { x: 0, y: 0 };
var arrowButtonSize = opts.buttonSize || 20;
var color = opts.color || { red: 255, green: 0, blue: 0 };
var arrowButtonBackground = opts.arrowBackground || { red: 255, green: 255, blue: 255 };
var centerButtonBackground = opts.centerBackground || { red: 255, green: 255, blue: 255 };
var onUpPressed = opts.onUpPressed;
var onDownPressed = opts.onDownPressed;
var onLeftPressed = opts.onLeftPressed;
var onRightPressed = opts.onRightPressed;
var onCenterPressed = opts.onCenterPressed;
var upButton = Overlays.addOverlay("text", {
x: position.x + arrowButtonSize,
y: position.y,
width: arrowButtonSize,
height: arrowButtonSize,
color: color,
backgroundColor: arrowButtonBackground,
topMargin: 4,
leftMargin: 4,
text: "^",
alpha: 1.0,
backgroundAlpha: 1.0,
visible: true,
});
var leftButton = Overlays.addOverlay("text", {
x: position.x,
y: position.y + arrowButtonSize,
width: arrowButtonSize,
height: arrowButtonSize,
color: color,
backgroundColor: arrowButtonBackground,
topMargin: 4,
leftMargin: 4,
text: "<",
alpha: 1.0,
backgroundAlpha: 1.0,
visible: true,
});
var rightButton = Overlays.addOverlay("text", {
x: position.x + (arrowButtonSize * 2),
y: position.y + arrowButtonSize,
width: arrowButtonSize,
height: arrowButtonSize,
color: color,
backgroundColor: arrowButtonBackground,
topMargin: 4,
leftMargin: 4,
text: ">",
alpha: 1.0,
visible: true,
});
var downButton = Overlays.addOverlay("text", {
x: position.x + arrowButtonSize,
y: position.y + (arrowButtonSize * 2),
width: arrowButtonSize,
height: arrowButtonSize,
color: color,
backgroundColor: arrowButtonBackground,
topMargin: 4,
leftMargin: 4,
text: "v",
alpha: 1.0,
backgroundAlpha: 1.0,
visible: true,
});
var centerButton = Overlays.addOverlay("text", {
x: position.x + arrowButtonSize,
y: position.y + arrowButtonSize,
width: arrowButtonSize,
height: arrowButtonSize,
color: color,
backgroundColor: centerButtonBackground,
topMargin: 4,
leftMargin: 4,
text: "",
alpha: 1.0,
backgroundAlpha: 1.0,
visible: true,
});
var allOverlays = [
upButton,
downButton,
leftButton,
rightButton,
centerButton,
];
that.destroy = function() {
for (var i = 0; i < allOverlays.length; i++) {
Overlays.deleteOverlay(allOverlays[i]);
}
};
that.setVisible = function(visible) {
for (var i = 0; i < allOverlays.length; i++) {
Overlays.editOverlay(allOverlays[i], { visible: visible });
}
}
that.mouseReleaseEvent = function(event) {
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
var clicked = false;
if (clickedOverlay == leftButton) {
if (onLeftPressed) onLeftPressed();
clicked = true;
} else if (clickedOverlay == rightButton) {
if (onRightPressed) onRightPressed();
clicked = true;
} else if (clickedOverlay == upButton) {
if (onUpPressed) onUpPressed();
clicked = true;
} else if (clickedOverlay == downButton) {
if (onDownPressed) onDownPressed();
clicked = true;
} else if (clickedOverlay == centerButton) {
if (onCenterPressed) onCenterPressed();
clicked = true;
}
return clicked;
}
return that;
}
CameraTool = function(cameraManager) {
var that = {};
var toolsPosition = { x: 20, y: 280 };
var orbitToolPosition = toolsPosition;
var panToolPosition = { x: toolsPosition.x + 80, y: toolsPosition.y };
var zoomToolPosition = { x: toolsPosition.x + 20, y: toolsPosition.y + 80 };
var RED = { red: 191, green: 78, blue: 38 };
var GREEN = { red: 26, green: 193, blue: 105 };
var BLUE = { red: 0, green: 131, blue: 204 };
var orbitIncrement = 15;
orbitTool = ArrowTool({
position: orbitToolPosition,
arrowBackground: { red: 192, green: 192, blue: 192 },
centerBackground: { red: 128, green: 128, blue: 255 },
color: { red: 0, green: 0, blue: 0 },
onUpPressed: function() { cameraManager.addPitch(orbitIncrement); },
onDownPressed: function() { cameraManager.addPitch(-orbitIncrement); },
onLeftPressed: function() { cameraManager.addYaw(-orbitIncrement); },
onRightPressed: function() { cameraManager.addYaw(orbitIncrement); },
onCenterPressed: function() { cameraManager.focus(); },
var defaultCubeProps = {
size: 8,
alpha: 1,
color: { red: 255, green: 0, blue: 0 },
solid: true,
visible: true,
drawOnApplicationOverlay: true,
};
var defaultLineProps = {
lineWidth: 1.5,
alpha: 1,
position: { x: 0, y: 0, z: 0 },
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: { red: 255, green: 0, blue: 0 },
visible: true,
drawOnApplicationOverlay: true,
};
var padding = 40;
var borderWidth = 4;
var backgroundBorder = Overlays.addOverlay("text", {
x: orientationOverlayPosition.x - (ORIENTATION_OVERLAY_HALF_SIZE + padding / 2 + borderWidth / 2),
y: orientationOverlayPosition.y - (ORIENTATION_OVERLAY_HALF_SIZE + padding / 2 + borderWidth / 2),
width: ORIENTATION_OVERLAY_SIZE + padding + borderWidth,
height: ORIENTATION_OVERLAY_SIZE + padding + borderWidth,
backgroundColor: { red: 192, green: 192, blue: 192 },
text: "",
alpha: 1.0,
backgroundAlpha: 0.8,
visible: true
});
panTool = ArrowTool({
position: panToolPosition,
arrowBackground: { red: 192, green: 192, blue: 192 },
centerBackground: { red: 128, green: 128, blue: 255 },
color: { red: 0, green: 0, blue: 0 },
onUpPressed: function() { cameraManager.pan({ x: 0, y: 15 }); },
onDownPressed: function() { cameraManager.pan({ x: 0, y: -15 }); },
onLeftPressed: function() { cameraManager.pan({ x: -15, y: 0 }); },
onRightPressed: function() { cameraManager.pan({ x: 15, y: 0 }); },
});
zoomTool = ZoomTool({
position: zoomToolPosition,
arrowBackground: { red: 192, green: 192, blue: 192 },
color: { red: 0, green: 0, blue: 0 },
onIncreasePressed: function() { cameraManager.addZoom(-10); },
onDecreasePressed: function() { cameraManager.addZoom(10); },
onPercentageSet: function(pct) { cameraManager.setZoomPercentage(pct); }
var background = Overlays.addOverlay("text", {
x: orientationOverlayPosition.x - (ORIENTATION_OVERLAY_HALF_SIZE + padding / 2),
y: orientationOverlayPosition.y - (ORIENTATION_OVERLAY_HALF_SIZE + padding / 2),
width: ORIENTATION_OVERLAY_SIZE + padding,
height: ORIENTATION_OVERLAY_SIZE + padding,
backgroundColor: { x: 0, y: 0, z: 0 },
text: "",
alpha: 1.0,
backgroundAlpha: 0.9,
visible: true
});
var OOHS = ORIENTATION_OVERLAY_HALF_SIZE;
var cubeX = orientationOverlay.createOverlay("cube", mergeObjects(defaultCubeProps, {
position: { x: -OOHS, y: OOHS, z: OOHS },
color: RED,
}));
var cubeY = orientationOverlay.createOverlay("cube", mergeObjects(defaultCubeProps, {
position: { x: OOHS, y: -OOHS, z: OOHS },
color: GREEN,
}));
var cubeZ = orientationOverlay.createOverlay("cube", mergeObjects(defaultCubeProps, {
position: { x: OOHS, y: OOHS, z: -OOHS },
color: BLUE,
}));
orientationOverlay.createOverlay("line3d", mergeObjects(defaultLineProps, {
start: { x: -OOHS, y: OOHS, z: OOHS },
end: { x: OOHS, y: OOHS, z: OOHS },
color: RED,
}));
orientationOverlay.createOverlay("line3d", mergeObjects(defaultLineProps, {
start: { x: OOHS, y: -OOHS, z: OOHS },
end: { x: OOHS, y: OOHS, z: OOHS },
color: GREEN,
}));
orientationOverlay.createOverlay("line3d", mergeObjects(defaultLineProps, {
start: { x: OOHS, y: OOHS, z: -OOHS },
end: { x: OOHS, y: OOHS, z: OOHS },
color: BLUE,
}));
Script.scriptEnding.connect(function() {
orbitTool.destroy();
panTool.destroy();
zoomTool.destroy();
orientationOverlay.destroy();
Overlays.deleteOverlay(background);
Overlays.deleteOverlay(backgroundBorder);
});
that.mousePressEvent = function(event) {
return orbitTool.mouseReleaseEvent(event)
|| panTool.mouseReleaseEvent(event)
|| zoomTool.mouseReleaseEvent(event);
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
print("Overlays: " + cubeX + ", " + cubeY);
print("Clicked: " + clickedOverlay);
if (clickedOverlay == cubeX) {
targetPitch = 0;
targetYaw = event.isLeftButton ? 90 : -90;
cameraManager.setTargetPitchYaw(targetPitch, targetYaw);
return true;
} else if (clickedOverlay == cubeY) {
targetPitch = event.isLeftButton ? 90 : -90;
targetYaw = 0;
cameraManager.setTargetPitchYaw(targetPitch, targetYaw);
return true;
} else if (clickedOverlay == cubeZ) {
targetPitch = 0;
targetYaw = event.isLeftButton ? 0 : 180;
cameraManager.setTargetPitchYaw(targetPitch, targetYaw);
return true;
}
};
that.setVisible = function(visible) {
orbitTool.setVisible(visible);
panTool.setVisible(visible);
zoomTool.setVisible(visible);
};
Script.update.connect(function() {
cameraManager.getZoomPercentage();
zoomTool.setZoomPercentage(cameraManager.getZoomPercentage());
});
that.setVisible(false);
return that;
};

View file

@ -0,0 +1,64 @@
/**
* OverlayGroup provides a way to create composite overlays and control their
* position relative to a settable rootPosition and rootRotation.
*/
OverlayGroup = function(opts) {
var that = {};
var overlays = {};
var rootPosition = opts.position || { x: 0, y: 0, z: 0 };
var rootRotation = opts.rotation || Quat.fromPitchYawRollRadians(0, 0, 0);
var visible = true;
function updateOverlays() {
for (overlayID in overlays) {
var overlay = overlays[overlayID];
var newPosition = Vec3.multiplyQbyV(rootRotation, overlay.position);
newPosition = Vec3.sum(rootPosition, newPosition);
Overlays.editOverlay(overlayID, {
visible: visible,
position: newPosition,
rotation: Quat.multiply(rootRotation, overlay.rotation),
});
};
}
that.createOverlay = function(type, properties) {
properties.position = properties.position || { x: 0, y: 0, z: 0 };
properties.rotation = properties.rotation || Quat.fromPitchYawRollRadians(0, 0, 0);
var overlay = Overlays.addOverlay(type, properties);
overlays[overlay] = {
position: properties.position,
rotation: properties.rotation,
};
updateOverlays();
return overlay;
}
that.setProperties = function(properties) {
if (properties.position !== undefined) {
rootPosition = properties.position;
}
if (properties.rotation !== undefined) {
rootRotation = properties.rotation;
}
if (properties.visible !== undefined) {
visible = properties.visible;
}
updateOverlays();
};
that.destroy = function() {
for (var overlay in overlays) {
Overlays.deleteOverlay(overlay);
}
overlays = {};
}
return that;
};