diff --git a/cmake/modules/FindNSIGHT.cmake b/cmake/modules/FindNSIGHT.cmake new file mode 100644 index 0000000000..4df0686ebe --- /dev/null +++ b/cmake/modules/FindNSIGHT.cmake @@ -0,0 +1,49 @@ +# +# FindNSIGHT.cmake +# +# Try to find NSIGHT NvToolsExt library and include path. +# Once done this will define +# +# NSIGHT_FOUND +# NSIGHT_INCLUDE_DIRS +# NSIGHT_LIBRARIES +# +# Created on 10/27/2014 by Sam Gateau +# Copyright 2014 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +if (WIN32) + + find_path(NSIGHT_INCLUDE_DIRS + NAMES + nvToolsExt.h + PATH_SUFFIXES + include + PATHS + "C:/Program Files/NVIDIA Corporation/NvToolsExt") + + find_library(NSIGHT_LIBRARY_RELEASE nvToolsExt32_1 + PATH_SUFFIXES + "lib/Win32" "lib" + PATHS + "C:/Program Files/NVIDIA Corporation/NvToolsExt") + find_library(NSIGHT_LIBRARY_DEBUG nvToolsExt32_1 + PATH_SUFFIXES + "lib/Win32" "lib" + PATHS + "C:/Program Files/NVIDIA Corporation/NvToolsExt") + + include(SelectLibraryConfigurations) + select_library_configurations(NSIGHT) +endif () + +set(NSIGHT_LIBRARIES "${NSIGHT_LIBRARY}") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NSIGHT DEFAULT_MSG NSIGHT_INCLUDE_DIRS NSIGHT_LIBRARIES) + +mark_as_advanced(NSIGHT_INCLUDE_DIRS NSIGHT_LIBRARIES NSIGHT_SEARCH_DIRS) + diff --git a/examples/guidedTour.js b/examples/guidedTour.js index 3416e55d1c..1882b527d7 100644 --- a/examples/guidedTour.js +++ b/examples/guidedTour.js @@ -17,9 +17,9 @@ function update(deltaTime) { if (Math.random() < deltaTime) { guide = AvatarList.avatarWithDisplayName(leaderName); if (guide && !isGuide) { - print("found a guide!"); + print("Found a tour guide!"); isGuide = true; - } else if (!isGuide) { + } else if (!guide && isGuide) { print("Lost My Guide"); isguide = false; } diff --git a/examples/headMove.js b/examples/headMove.js index b9330153fc..f377409cb8 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -17,6 +17,8 @@ var willMove = false; var warpActive = false; var warpPosition = { x: 0, y: 0, z: 0 }; +var hipsToEyes; + // Overlays to show target location var WARP_SPHERE_SIZE = 0.15; @@ -43,8 +45,11 @@ var movingWithHead = false; var headStartPosition, headStartDeltaPitch, headStartFinalPitch, headStartRoll, headStartYaw; var deltaYaw = 0.0; var keyDownTime = 0.0; +var timeSinceLastUp = 0.0; var watchAvatar = false; var oldMode; +var lastYawTurned = 0.0; +var startPullbackPosition; function saveCameraState() { oldMode = Camera.getMode(); @@ -65,6 +70,7 @@ function activateWarp() { var TRIGGER_PULLBACK_DISTANCE = 0.04; var WATCH_AVATAR_DISTANCE = 1.5; var MAX_PULLBACK_YAW = 5.0; +var MAX_PULLBACK_PITCH = 5.0; var sound = new Sound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav"); function playSound() { @@ -74,35 +80,44 @@ function playSound() { options.volume = 1.0; Audio.playSound(sound, options); } - var WARP_SMOOTHING = 0.90; var WARP_START_TIME = 0.50; -var WARP_START_DISTANCE = 1.0; +var WARP_START_DISTANCE = 1.5; var WARP_SENSITIVITY = 0.15; +var fixedHeight = true; + function updateWarp() { if (!warpActive) return; - var look = Quat.getFront(Camera.getOrientation()); + var viewEulers = Quat.safeEulerAngles(Camera.getOrientation()); var deltaPosition = Vec3.subtract(MyAvatar.getTrackedHeadPosition(), headStartPosition); var deltaPitch = MyAvatar.getHeadFinalPitch() - headStartFinalPitch; deltaYaw = MyAvatar.getHeadFinalYaw() - headStartYaw; + viewEulers.x -= deltaPitch; + var look = Quat.getFront(Quat.fromVec3Degrees(viewEulers)); - willMove = (!watchAvatar && (keyDownTime > WARP_START_TIME)); + willMove = (keyDownTime > WARP_START_TIME); if (willMove) { - //var distance = Math.pow((deltaPitch - WARP_PITCH_DEAD_ZONE) * WARP_SENSITIVITY, 2.0); var distance = Math.exp(deltaPitch * WARP_SENSITIVITY) * WARP_START_DISTANCE; - var warpDirection = Vec3.normalize({ x: look.x, y: 0, z: look.z }); - warpPosition = Vec3.mix(Vec3.sum(MyAvatar.position, Vec3.multiply(warpDirection, distance)), warpPosition, WARP_SMOOTHING); + var warpDirection = Vec3.normalize({ x: look.x, y: (fixedHeight ? 0 : look.y), z: look.z }); + var startPosition = (watchAvatar ? Camera.getPosition(): MyAvatar.getEyePosition()); + warpPosition = Vec3.mix(Vec3.sum(startPosition, Vec3.multiply(warpDirection, distance)), warpPosition, WARP_SMOOTHING); } var height = MyAvatar.getEyePosition().y - MyAvatar.position.y; + var cameraPosition; - if (!watchAvatar && (Math.abs(deltaYaw) < MAX_PULLBACK_YAW) && (deltaPosition.z > TRIGGER_PULLBACK_DISTANCE)) { + if (!watchAvatar && + (Math.abs(deltaYaw) < MAX_PULLBACK_YAW) && + (Math.abs(deltaPitch) < MAX_PULLBACK_PITCH) && + (Vec3.length(deltaPosition) > TRIGGER_PULLBACK_DISTANCE)) { saveCameraState(); - var cameraPosition = Vec3.subtract(MyAvatar.position, Vec3.multiplyQbyV(Camera.getOrientation(), { x: 0, y: -height, z: -height * WATCH_AVATAR_DISTANCE })); + cameraPosition = Vec3.subtract(MyAvatar.position, Vec3.multiplyQbyV(Camera.getOrientation(), { x: 0, y: -height, z: -height * WATCH_AVATAR_DISTANCE })); Camera.setPosition(cameraPosition); + cameraPosition = Camera.getPosition(); + startPullbackPosition = cameraPosition; watchAvatar = true; } @@ -128,13 +143,14 @@ function finishWarp() { visible: false, }); if (willMove) { + warpPosition.y -= hipsToEyes; MyAvatar.position = warpPosition; playSound(); } } function update(deltaTime) { - + timeSinceLastUp += deltaTime; if (movingWithHead) { keyDownTime += deltaTime; updateWarp(); @@ -145,6 +161,7 @@ Controller.keyPressEvent.connect(function(event) { if (event.text == "SPACE" && !event.isAutoRepeat && !movingWithHead) { keyDownTime = 0.0; movingWithHead = true; + hipsToEyes = MyAvatar.getEyePosition().y - MyAvatar.position.y; headStartPosition = MyAvatar.getTrackedHeadPosition(); headStartDeltaPitch = MyAvatar.getHeadDeltaPitch(); headStartFinalPitch = MyAvatar.getHeadFinalPitch(); @@ -152,26 +169,31 @@ Controller.keyPressEvent.connect(function(event) { headStartYaw = MyAvatar.getHeadFinalYaw(); deltaYaw = 0.0; warpPosition = MyAvatar.position; + warpPosition.y += hipsToEyes; activateWarp(); } }); -var TIME_FOR_TURN_AROUND = 0.50; var TIME_FOR_TURN = 0.25; +var DOUBLE_CLICK_TIME = 0.50; var TURN_AROUND = 180.0; Controller.keyReleaseEvent.connect(function(event) { if (event.text == "SPACE" && !event.isAutoRepeat) { movingWithHead = false; - if (keyDownTime < TIME_FOR_TURN_AROUND) { - if (keyDownTime < TIME_FOR_TURN) { - var currentYaw = MyAvatar.getHeadFinalYaw(); - MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, currentYaw, 0), MyAvatar.orientation); - } else { - MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, TURN_AROUND, 0), MyAvatar.orientation); - } + if (timeSinceLastUp < DOUBLE_CLICK_TIME) { + // Turn all the way around + var turnRemaining = TURN_AROUND - lastYawTurned; + lastYawTurned = 0.0; + MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, TURN_AROUND, 0), MyAvatar.orientation); + playSound(); + } else if (keyDownTime < TIME_FOR_TURN) { + var currentYaw = MyAvatar.getHeadFinalYaw(); + lastYawTurned = currentYaw; + MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, currentYaw, 0), MyAvatar.orientation); playSound(); } + timeSinceLastUp = 0.0; finishWarp(); if (watchAvatar) { restoreCameraState(); diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index 63121d88a9..b6bb6e149e 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -34,7 +34,7 @@ var EASING_MULTIPLIER = 8; var INITIAL_ZOOM_DISTANCE = 2; var INITIAL_ZOOM_DISTANCE_FIRST_PERSON = 3; -EntityCameraTool = function() { +CameraManager = function() { var that = {}; that.enabled = false; @@ -85,24 +85,28 @@ EntityCameraTool = function() { Camera.setMode("independent"); that.updateCamera(); + + cameraTool.setVisible(true); } - that.disable = function() { + that.disable = function(ignoreCamera) { if (!that.enabled) return; that.enabled = false; that.mode = MODE_INACTIVE; - Camera.setMode(that.previousCameraMode); + if (!ignoreCamera) { + Camera.setMode(that.previousCameraMode); + } + cameraTool.setVisible(false); } that.focus = function(entityProperties) { - var dim = entityProperties.dimensions; - dim = SelectionManager.worldDimensions; + var dim = SelectionManager.worldDimensions; var size = Math.max(dim.x, Math.max(dim.y, dim.z)); that.targetZoomDistance = Math.max(size * FOCUS_ZOOM_SCALE, FOCUS_MIN_ZOOM); - that.setFocalPoint(SelectionManager.worldPosition);//entityProperties.position); + that.setFocalPoint(SelectionManager.worldPosition); that.updateCamera(); } @@ -116,6 +120,42 @@ EntityCameraTool = function() { that.updateCamera(); } + that.addYaw = function(yaw) { + that.targetYaw += yaw; + that.updateCamera(); + } + + that.addPitch = function(pitch) { + that.targetPitch += pitch; + that.updateCamera(); + } + + that.addZoom = function(zoom) { + zoom *= that.targetZoomDistance * ZOOM_SCALING; + that.targetZoomDistance = Math.min(Math.max(that.targetZoomDistance + zoom, MIN_ZOOM_DISTANCE), MAX_ZOOM_DISTANCE); + that.updateCamera(); + } + + that.getZoomPercentage = function() { + return (that.zoomDistance - MIN_ZOOM_DISTANCE) / MAX_ZOOM_DISTANCE; + } + + that.setZoomPercentage = function(pct) { + that.targetZoomDistance = pct * (MAX_ZOOM_DISTANCE - MIN_ZOOM_DISTANCE); + } + + that.pan = function(offset) { + var up = Quat.getUp(Camera.getOrientation()); + var right = Quat.getRight(Camera.getOrientation()); + + up = Vec3.multiply(up, offset.y * 0.01 * PAN_ZOOM_SCALE_RATIO * that.zoomDistance); + right = Vec3.multiply(right, offset.x * 0.01 * PAN_ZOOM_SCALE_RATIO * that.zoomDistance); + + var dPosition = Vec3.sum(up, right); + + that.moveFocalPoint(dPosition); + } + that.mouseMoveEvent = function(event) { if (that.enabled && that.mode != MODE_INACTIVE) { if (that.mode == MODE_ORBIT) { @@ -168,7 +208,7 @@ EntityCameraTool = function() { return true; } - return false; + return cameraTool.mousePressEvent(event); } that.mouseReleaseEvent = function(event) { @@ -185,13 +225,13 @@ EntityCameraTool = function() { // Scale based on current zoom level dZoom *= that.targetZoomDistance * ZOOM_SCALING; - that.targetZoomDistance = Math.max(that.targetZoomDistance + dZoom, MIN_ZOOM_DISTANCE); + that.targetZoomDistance = Math.min(Math.max(that.targetZoomDistance + dZoom, MIN_ZOOM_DISTANCE), MAX_ZOOM_DISTANCE); that.updateCamera(); } that.updateCamera = function() { - if (!that.enabled) return; + if (!that.enabled || Camera.getMode() != "independent") 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 }); @@ -215,6 +255,10 @@ EntityCameraTool = function() { // Ease the position and orbit of the camera that.update = function(dt) { + if (Camera.getMode() != "independent") { + return; + } + var scale = Math.min(dt * EASING_MULTIPLIER, 1.0); var dYaw = that.targetYaw - that.yaw; @@ -239,9 +283,336 @@ EntityCameraTool = function() { that.updateCamera(); } + // Last mode that was first or third person + var lastAvatarCameraMode = "first person"; + Camera.modeUpdated.connect(function(newMode) { + print("Camera mode has been updated: " + newMode); + if (newMode == "first person" || newMode == "third person") { + lastAvatarCameraMode = newMode; + that.disable(true); + } else { + that.enable(); + } + }); + + Controller.keyReleaseEvent.connect(function (event) { + if (event.text == "ESC" && that.enabled) { + Camera.setMode(lastAvatarCameraMode); + cameraManager.disable(true); + } + }); + Script.update.connect(that.update); Controller.wheelEvent.connect(that.wheelEvent); + var cameraTool = new CameraTool(that); + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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 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(); }, + }); + 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); } + }); + + Script.scriptEnding.connect(function() { + orbitTool.destroy(); + panTool.destroy(); + zoomTool.destroy(); + }); + + that.mousePressEvent = function(event) { + return orbitTool.mouseReleaseEvent(event) + || panTool.mouseReleaseEvent(event) + || zoomTool.mouseReleaseEvent(event); + }; + + 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; +}; diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index f1a94dbdd7..c503ab82a4 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -19,7 +19,6 @@ SPACE_WORLD = "world"; SelectionManager = (function() { var that = {}; - that.savedProperties = {}; that.eventListener = null; @@ -927,7 +926,6 @@ SelectionDisplay = (function () { }; that.updateHandles = function() { - // print("Updating handles"); if (SelectionManager.selections.length == 0) { that.setOverlaysVisible(false); return; @@ -1134,17 +1132,30 @@ SelectionDisplay = (function () { UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData); } - var lastXZPick = null; + var initialXZPick = null; + var isConstrained = false; + var startPosition = null; var translateXZTool = { mode: 'TRANSLATE_XZ', onBegin: function(event) { SelectionManager.saveProperties(); - var position = SelectionManager.worldPosition; + startPosition = SelectionManager.worldPosition; var dimensions = SelectionManager.worldDimensions; - var bottom = position.y - (dimensions.y / 2) var pickRay = Camera.computePickRay(event.x, event.y); - lastXZPick = rayPlaneIntersection(pickRay, position, { x: 0, y: 1, z: 0 }); + initialXZPick = rayPlaneIntersection(pickRay, startPosition, { x: 0, y: 1, z: 0 }); + + // 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) { + for (var otherEntityID in SelectionManager.savedProperties) { + var properties = SelectionManager.savedProperties[otherEntityID]; + var entityID = Entities.addEntity(properties); + } + } + + isConstrained = false; }, onEnd: function(event, reason) { if (reason == 'cancel') { @@ -1156,6 +1167,8 @@ SelectionDisplay = (function () { } else { pushCommandForSelections(); } + Overlays.editOverlay(xRailOverlay, { visible: false }); + Overlays.editOverlay(zRailOverlay, { visible: false }); }, onMove: function(event) { if (!entitySelected || mode !== "TRANSLATE_XZ") { @@ -1170,26 +1183,47 @@ SelectionDisplay = (function () { Quat.getFront(lastCameraOrientation)); var vector = Vec3.subtract(newIntersection, lastPlaneIntersection); - - var pickRay = Camera.computePickRay(event.x, event.y); var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { x: 0, y: 1, z: 0 }); - vector = Vec3.subtract(pick, lastXZPick); - lastXZPick = pick; + var vector = Vec3.subtract(pick, initialXZPick); + // initialXZPick = pick; + + // If shifted, constrain to one axis + if (event.isShifted) { + if (Math.abs(vector.x) > Math.abs(vector.z)) { + vector.z = 0; + } else { + vector.x = 0; + } + if (!isConstrained) { + Overlays.editOverlay(xRailOverlay, { visible: true }); + var xStart = Vec3.sum(startPosition, { x: -10000, y: 0, z: 0 }); + var xEnd = Vec3.sum(startPosition, { x: 10000, y: 0, z: 0 }); + var zStart = Vec3.sum(startPosition, { x: 0, y: 0, z: -10000 }); + var zEnd = Vec3.sum(startPosition, { x: 0, y: 0, z: 10000 }); + Overlays.editOverlay(xRailOverlay, { start: xStart, end: xEnd, visible: true }); + Overlays.editOverlay(zRailOverlay, { start: zStart, end: zEnd, visible: true }); + isConstrained = true; + } + } else { + if (isConstrained) { + Overlays.editOverlay(xRailOverlay, { visible: false }); + Overlays.editOverlay(zRailOverlay, { visible: false }); + } + } var wantDebug = false; for (var i = 0; i < SelectionManager.selections.length; i++) { - var properties = Entities.getEntityProperties(SelectionManager.selections[i]); - var original = properties.position; - properties.position = Vec3.sum(properties.position, vector); - Entities.editEntity(SelectionManager.selections[i], properties); + var properties = SelectionManager.savedProperties[SelectionManager.selections[i].id]; + Entities.editEntity(SelectionManager.selections[i], { + position: Vec3.sum(properties.position, vector), + }); if (wantDebug) { print("translateXZ... "); Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection); Vec3.print(" newIntersection:", newIntersection); Vec3.print(" vector:", vector); - Vec3.print(" originalPosition:", original); Vec3.print(" newPosition:", properties.position); Vec3.print(" newPosition:", newPosition); } @@ -1288,7 +1322,6 @@ SelectionDisplay = (function () { var rotation = null; var onBegin = function(event) { - print("STARTING: " + stretchMode); var properties = Entities.getEntityProperties(currentSelection); initialProperties = properties; rotation = spaceMode == SPACE_LOCAL ? properties.rotation : Quat.fromPitchYawRollDegrees(0, 0, 0); @@ -1366,7 +1399,6 @@ SelectionDisplay = (function () { }; var onEnd = function(event, reason) { - print("ENDING: " + stretchMode); Overlays.editOverlay(xRailOverlay, { visible: false }); Overlays.editOverlay(yRailOverlay, { visible: false }); Overlays.editOverlay(zRailOverlay, { visible: false }); @@ -1415,7 +1447,6 @@ SelectionDisplay = (function () { var absX = Math.abs(changeInDimensions.x); var absY = Math.abs(changeInDimensions.y); var absZ = Math.abs(changeInDimensions.z); - print('abs: ' + absX + ', ' + absY + ', ' + absZ); var pctChange = 0; if (absX > absY && absX > absZ) { pctChange = changeInDimensions.x / initialProperties.dimensions.x; @@ -1427,7 +1458,6 @@ SelectionDisplay = (function () { pctChange = changeInDimensions.z / initialProperties.dimensions.z; pctChange = changeInDimensions.z / initialDimensions.z; } - print('change: ' + pctChange); pctChange += 1.0; newDimensions = Vec3.multiply(pctChange, initialDimensions); } else { @@ -1881,7 +1911,6 @@ SelectionDisplay = (function () { var tool = grabberTools[result.overlayID]; if (tool) { - print("FOUND TOOL! " + tool.mode); activeTool = tool; mode = tool.mode; somethingClicked = true; @@ -1981,7 +2010,6 @@ SelectionDisplay = (function () { if (result.intersects) { var tool = grabberTools[result.overlayID]; if (tool) { - print("FOUND TOOL! " + tool.mode); activeTool = tool; mode = tool.mode; somethingClicked = true; diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 4d5abaf254..aa38baf9e2 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -33,7 +33,7 @@ Script.include("libraries/entityPropertyDialogBox.js"); var entityPropertyDialogBox = EntityPropertyDialogBox; Script.include("libraries/entityCameraTool.js"); -var entityCameraTool = new EntityCameraTool(); +var cameraManager = new CameraManager(); selectionManager.setEventListener(selectionDisplay.updateHandles); @@ -178,7 +178,7 @@ var toolBar = (function () { 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({ + var entityId = Entities.addEntity({ type: "Model", position: position, dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, @@ -247,9 +247,9 @@ var toolBar = (function () { isActive = !isActive; if (!isActive) { selectionDisplay.unselectAll(); - entityCameraTool.disable(); + cameraManager.disable(); } else { - entityCameraTool.enable(); + cameraManager.enable(); } return true; } @@ -374,7 +374,7 @@ function mousePressEvent(event) { var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event) - || entityCameraTool.mousePressEvent(event) || selectionDisplay.mousePressEvent(event)) { + || cameraManager.mousePressEvent(event) || selectionDisplay.mousePressEvent(event)) { // Event handled; do nothing. return; } else { @@ -482,8 +482,8 @@ function mouseMoveEvent(event) { return; } - // allow the selectionDisplay and entityCameraTool to handle the event first, if it doesn't handle it, then do our own thing - if (selectionDisplay.mouseMoveEvent(event) || entityCameraTool.mouseMoveEvent(event)) { + // 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; } @@ -522,7 +522,7 @@ function mouseReleaseEvent(event) { if (entitySelected) { tooltip.show(false); } - entityCameraTool.mouseReleaseEvent(event); + cameraManager.mouseReleaseEvent(event); } Controller.mousePressEvent.connect(mousePressEvent); @@ -652,7 +652,6 @@ Menu.menuItemEvent.connect(handeMenuEvent); Controller.keyReleaseEvent.connect(function (event) { // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items - print(event.text); if (event.text == "`") { handeMenuEvent("Edit Properties..."); } @@ -666,7 +665,11 @@ Controller.keyReleaseEvent.connect(function (event) { if (entitySelected) { // Get latest properties var properties = Entities.getEntityProperties(selectedEntityID); - entityCameraTool.focus(properties); + cameraManager.focus(properties); + } + } else if (event.text == '[') { + if (isActive) { + cameraManager.enable(); } } }); diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 9c4eeff65b..d9cf40baa3 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -226,11 +226,20 @@ else (APPLE) if (WIN32) find_package(GLEW REQUIRED) include_directories(${GLEW_INCLUDE_DIRS}) - + # we're using static GLEW, so define GLEW_STATIC add_definitions(-DGLEW_STATIC) - - target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib) + + target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" "${NSIGHT_LIBRARIES}" wsock32.lib opengl32.lib) + + # try to find the Nsight package and add it to the build if we find it + find_package(NSIGHT) + if (NSIGHT_FOUND) + include_directories(${NSIGHT_INCLUDE_DIRS}) + add_definitions(-DNSIGHT_FOUND) + target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") + endif () + endif() endif (APPLE) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8c2966562c..011519f6ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -414,6 +414,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : MIDIManager& midiManagerInstance = MIDIManager::getInstance(); midiManagerInstance.openDefaultPort(); #endif + + this->installEventFilter(this); } Application::~Application() { @@ -836,6 +838,19 @@ bool Application::event(QEvent* event) { return QApplication::event(event); } +bool Application::eventFilter(QObject* object, QEvent* event) { + + if (event->type() == QEvent::ShortcutOverride) { + // Filter out captured keys before they're used for shortcut actions. + if (_controllerScriptingInterface.isKeyCaptured(static_cast(event))) { + event->accept(); + return true; + } + } + + return false; +} + void Application::keyPressEvent(QKeyEvent* event) { _keysPressed.insert(event->key()); @@ -1494,9 +1509,12 @@ void Application::setEnableVRMode(bool enableVRMode) { OculusManager::disconnect(); OculusManager::connect(); } + int oculusMaxFPS = Menu::getInstance()->getOculusUIMaxFPS(); + setRenderTargetFramerate(oculusMaxFPS); OculusManager::recalibrate(); } else { OculusManager::abandonCalibration(); + setRenderTargetFramerate(0); } resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); diff --git a/interface/src/Application.h b/interface/src/Application.h index e85c4f4db5..feb9ee8fc3 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -172,6 +172,7 @@ public: void dropEvent(QDropEvent *event); bool event(QEvent* event); + bool eventFilter(QObject* object, QEvent* event); void makeVoxel(glm::vec3 position, float scale, diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index a8138363fa..ceb4cb09a0 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -21,6 +21,32 @@ #include "devices/OculusManager.h" +CameraMode stringToMode(const QString& mode) { + if (mode == "third person") { + return CAMERA_MODE_THIRD_PERSON; + } else if (mode == "first person") { + return CAMERA_MODE_FIRST_PERSON; + } else if (mode == "mirror") { + return CAMERA_MODE_MIRROR; + } else if (mode == "independent") { + return CAMERA_MODE_INDEPENDENT; + } + return CAMERA_MODE_NULL; +} + +QString modeToString(CameraMode mode) { + if (mode == CAMERA_MODE_THIRD_PERSON) { + return "third person"; + } else if (mode == CAMERA_MODE_FIRST_PERSON) { + return "first person"; + } else if (mode == CAMERA_MODE_MIRROR) { + return "mirror"; + } else if (mode == CAMERA_MODE_INDEPENDENT) { + return "independent"; + } + return "unknown"; +} + Camera::Camera() : _mode(CAMERA_MODE_THIRD_PERSON), _position(0.0f, 0.0f, 0.0f), @@ -48,6 +74,7 @@ float Camera::getFarClip() const { void Camera::setMode(CameraMode m) { _mode = m; + emit modeUpdated(m); } @@ -70,6 +97,7 @@ void Camera::setFarClip(float f) { CameraScriptableObject::CameraScriptableObject(Camera* camera, ViewFrustum* viewFrustum) : _camera(camera), _viewFrustum(viewFrustum) { + connect(_camera, &Camera::modeUpdated, this, &CameraScriptableObject::onModeUpdated); } PickRay CameraScriptableObject::computePickRay(float x, float y) { @@ -86,24 +114,7 @@ PickRay CameraScriptableObject::computePickRay(float x, float y) { } QString CameraScriptableObject::getMode() const { - QString mode("unknown"); - switch(_camera->getMode()) { - case CAMERA_MODE_THIRD_PERSON: - mode = "third person"; - break; - case CAMERA_MODE_FIRST_PERSON: - mode = "first person"; - break; - case CAMERA_MODE_MIRROR: - mode = "mirror"; - break; - case CAMERA_MODE_INDEPENDENT: - mode = "independent"; - break; - default: - break; - } - return mode; + return modeToString(_camera->getMode()); } void CameraScriptableObject::setMode(const QString& mode) { @@ -131,5 +142,9 @@ void CameraScriptableObject::setMode(const QString& mode) { } } +void CameraScriptableObject::onModeUpdated(CameraMode m) { + emit modeUpdated(modeToString(m)); +} + diff --git a/interface/src/Camera.h b/interface/src/Camera.h index 80454a969e..e876f70e3a 100644 --- a/interface/src/Camera.h +++ b/interface/src/Camera.h @@ -27,8 +27,11 @@ enum CameraMode NUM_CAMERA_MODES }; -class Camera { +Q_DECLARE_METATYPE(CameraMode); +static int cameraModeId = qRegisterMetaType(); +class Camera : public QObject { + Q_OBJECT public: Camera(); @@ -63,6 +66,9 @@ public: const glm::vec3& getEyeOffsetPosition() const { return _eyeOffsetPosition; } const glm::quat& getEyeOffsetOrientation() const { return _eyeOffsetOrientation; } float getScale() const { return _scale; } + +signals: + void modeUpdated(CameraMode newMode); private: @@ -100,6 +106,12 @@ public slots: PickRay computePickRay(float x, float y); +signals: + void modeUpdated(const QString& newMode); + +private slots: + void onModeUpdated(CameraMode m); + private: Camera* _camera; ViewFrustum* _viewFrustum; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6538aee644..274afd4bca 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -105,6 +105,7 @@ Menu::Menu() : _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE), + _oculusUIMaxFPS(DEFAULT_OCULUS_UI_MAX_FPS), _sixenseReticleMoveSpeed(DEFAULT_SIXENSE_RETICLE_MOVE_SPEED), _invertSixenseButtons(DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS), _automaticAvatarLOD(true), @@ -782,6 +783,8 @@ void Menu::loadSettings(QSettings* settings) { settings->endGroup(); _walletPrivateKey = settings->value("privateKey").toByteArray(); + + _oculusUIMaxFPS = loadSetting(settings, "oculusUIMaxFPS", 0.0f); scanMenuBar(&loadAction, settings); Application::getInstance()->getAvatar()->loadData(settings); @@ -843,6 +846,9 @@ void Menu::saveSettings(QSettings* settings) { settings->setValue("viewFrustumOffsetUp", _viewFrustumOffset.up); settings->endGroup(); settings->setValue("privateKey", _walletPrivateKey); + + // Oculus Rift settings + settings->setValue("oculusUIMaxFPS", _oculusUIMaxFPS); scanMenuBar(&saveAction, settings); Application::getInstance()->getAvatar()->saveData(settings); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3c96fd0dcd..abcbfb51ad 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -100,6 +100,8 @@ public: void setRealWorldFieldOfView(float realWorldFieldOfView) { _realWorldFieldOfView = realWorldFieldOfView; bumpSettings(); } float getOculusUIAngularSize() const { return _oculusUIAngularSize; } void setOculusUIAngularSize(float oculusUIAngularSize) { _oculusUIAngularSize = oculusUIAngularSize; bumpSettings(); } + int getOculusUIMaxFPS() const { return _oculusUIMaxFPS; } + void setOculusUIMaxFPS(int oculusUIMaxFPS) { _oculusUIMaxFPS = oculusUIMaxFPS; bumpSettings(); } float getSixenseReticleMoveSpeed() const { return _sixenseReticleMoveSpeed; } void setSixenseReticleMoveSpeed(float sixenseReticleMoveSpeed) { _sixenseReticleMoveSpeed = sixenseReticleMoveSpeed; bumpSettings(); } bool getInvertSixenseButtons() const { return _invertSixenseButtons; } @@ -292,6 +294,7 @@ private: int _maxVoxels; float _voxelSizeScale; float _oculusUIAngularSize; + int _oculusUIMaxFPS; float _sixenseReticleMoveSpeed; bool _invertSixenseButtons; bool _automaticAvatarLOD; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index a9bdad8148..20e05e779e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -48,6 +48,13 @@ MetavoxelSystem::NetworkSimulation::NetworkSimulation(float dropRate, float repe bandwidthLimit(bandwidthLimit) { } +MetavoxelSystem::~MetavoxelSystem() { + // kill the updater before we delete our network simulation objects + _updater->thread()->quit(); + _updater->thread()->wait(); + _updater = NULL; +} + void MetavoxelSystem::init() { MetavoxelClientManager::init(); DefaultMetavoxelRendererImplementation::init(); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 14a24eea59..08cc1098ca 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -43,6 +43,8 @@ public: int maximumDelay = 0, int bandwidthLimit = 0); }; + virtual ~MetavoxelSystem(); + virtual void init(); virtual MetavoxelLOD getLOD(); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b1c4b44104..3fcc05d7c7 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -52,6 +52,7 @@ const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f; Avatar::Avatar() : AvatarData(), _skeletonModel(this), + _skeletonOffset(0.0f), _bodyYawDelta(0.0f), _velocity(0.0f), _positionDeltaAccumulator(0.0f), @@ -763,6 +764,20 @@ bool Avatar::findCollisions(const QVector& shapes, CollisionList& return collided; } +void Avatar::setSkeletonOffset(const glm::vec3& offset) { + const float MAX_OFFSET_LENGTH = _scale * 0.5f; + float offsetLength = glm::length(offset); + if (offsetLength > MAX_OFFSET_LENGTH) { + _skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset; + } else { + _skeletonOffset = offset; + } +} + +glm::vec3 Avatar::getSkeletonPosition() const { + return _position + _skeletonOffset; +} + QVector Avatar::getJointRotations() const { if (QThread::currentThread() != thread()) { return AvatarData::getJointRotations(); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index cbdebc6a48..29fb4cf241 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -69,6 +69,7 @@ class Texture; class Avatar : public AvatarData { Q_OBJECT Q_PROPERTY(quint32 collisionGroups READ getCollisionGroups WRITE setCollisionGroups) + Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) public: Avatar(); @@ -146,6 +147,10 @@ public: quint32 getCollisionGroups() const { return _collisionGroups; } virtual void setCollisionGroups(quint32 collisionGroups) { _collisionGroups = (collisionGroups & VALID_COLLISION_GROUPS); } + + Q_INVOKABLE void setSkeletonOffset(const glm::vec3& offset); + Q_INVOKABLE glm::vec3 getSkeletonOffset() { return _skeletonOffset; } + virtual glm::vec3 getSkeletonPosition() const; Q_INVOKABLE glm::vec3 getJointPosition(int index) const; Q_INVOKABLE glm::vec3 getJointPosition(const QString& name) const; @@ -184,6 +189,7 @@ signals: protected: Hair _hair; SkeletonModel _skeletonModel; + glm::vec3 _skeletonOffset; QVector _attachmentModels; float _bodyYawDelta; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7576d42325..178113efc1 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -108,6 +108,20 @@ MyAvatar::~MyAvatar() { _lookAtTargetAvatar.clear(); } +QByteArray MyAvatar::toByteArray() { + CameraMode mode = Application::getInstance()->getCamera()->getMode(); + if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { + // fake the avatar position that is sent up to the AvatarMixer + glm::vec3 oldPosition = _position; + _position += _skeletonOffset; + QByteArray array = AvatarData::toByteArray(); + // copy the correct position back + _position = oldPosition; + return array; + } + return AvatarData::toByteArray(); +} + void MyAvatar::reset() { _skeletonModel.reset(); getHead()->reset(); @@ -1054,6 +1068,14 @@ void MyAvatar::setAttachmentData(const QVector& attachmentData) _billboardValid = false; } +glm::vec3 MyAvatar::getSkeletonPosition() const { + CameraMode mode = Application::getInstance()->getCamera()->getMode(); + if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { + return Avatar::getSkeletonPosition(); + } + return Avatar::getPosition(); +} + QString MyAvatar::getScriptedMotorFrame() const { QString frame = "avatar"; if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9cb9246da7..aa3d569e2f 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -41,7 +41,8 @@ class MyAvatar : public Avatar { public: MyAvatar(); ~MyAvatar(); - + + QByteArray toByteArray(); void reset(); void update(float deltaTime); void simulate(float deltaTime); @@ -134,6 +135,8 @@ public: virtual void setFaceModelURL(const QUrl& faceModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setAttachmentData(const QVector& attachmentData); + + virtual glm::vec3 getSkeletonPosition() const; void clearJointAnimationPriorities(); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index a791d01d53..d0f1d75ed6 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -77,7 +77,7 @@ const float PALM_PRIORITY = DEFAULT_PRIORITY; const float LEAN_PRIORITY = DEFAULT_PRIORITY; void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { - setTranslation(_owningAvatar->getPosition()); + setTranslation(_owningAvatar->getSkeletonPosition()); static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); setRotation(_owningAvatar->getOrientation() * refOrientation); setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale() * MODEL_SCALE); diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 20e43d572c..94521dc927 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -21,6 +21,7 @@ #include "ui/overlays/Text3DOverlay.h" const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; +const int DEFAULT_OCULUS_UI_MAX_FPS = 75; class Camera; class PalmData; diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index ad5246f9b6..b0bf30bae5 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -16,6 +16,23 @@ #include +#if defined(NSIGHT_FOUND) + #include "nvToolsExt.h" + class ProfileRange { + public: + ProfileRange(const char *name) { + nvtxRangePush(name); + } + ~ProfileRange() { + nvtxRangePop(); + } + }; + + #define PROFILE_RANGE(name) ProfileRange profileRangeThis(name); +#else +#define PROFILE_RANGE(name) +#endif + namespace gpu { class Batch; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 131c600dc1..e949e9a811 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -395,6 +395,7 @@ void Model::setJointStates(QVector states) { } bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { + PROFILE_RANGE(__FUNCTION__); // render the attachments foreach (Model* attachment, _attachments) { attachment->render(alpha, mode); @@ -560,8 +561,11 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); // Render! - ::gpu::backend::renderBatch(batch); - batch.clear(); + { + PROFILE_RANGE("render Batch"); + ::gpu::backend::renderBatch(batch); + batch.clear(); + } // restore all the default material settings Application::getInstance()->setupWorldLight(); @@ -1551,6 +1555,7 @@ void Model::segregateMeshGroups() { int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { + PROFILE_RANGE(__FUNCTION__); bool dontCullOutOfViewMeshParts = Menu::getInstance()->isOptionChecked(MenuOption::DontCullOutOfViewMeshParts); bool cullTooSmallMeshParts = !Menu::getInstance()->isOptionChecked(MenuOption::DontCullTooSmallMeshParts); bool dontReduceMaterialSwitches = Menu::getInstance()->isOptionChecked(MenuOption::DontReduceMaterialSwitches); diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index f2e65a6e28..1ca99ed2c5 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -213,10 +213,7 @@ bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const { bool ControllerScriptingInterface::isKeyCaptured(const KeyEvent& event) const { // if we've captured some combination of this key it will be in the map - if (_capturedKeys.contains(event.key, event)) { - return true; - } - return false; + return _capturedKeys.contains(event.key, event); } void ControllerScriptingInterface::captureKeyEvents(const KeyEvent& event) { diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 61cc9718b3..42256bc498 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -147,6 +147,8 @@ void PreferencesDialog::loadPreferences() { ui.maxVoxelsPPSSpin->setValue(menuInstance->getMaxVoxelPacketsPerSecond()); ui.oculusUIAngularSizeSpin->setValue(menuInstance->getOculusUIAngularSize()); + + ui.oculusUIMaxFPSSpin->setValue(menuInstance->getOculusUIMaxFPS()); ui.sixenseReticleMoveSpeedSpin->setValue(menuInstance->getSixenseReticleMoveSpeed()); @@ -229,6 +231,8 @@ void PreferencesDialog::savePreferences() { Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value()); Menu::getInstance()->setOculusUIAngularSize(ui.oculusUIAngularSizeSpin->value()); + + Menu::getInstance()->setOculusUIMaxFPS(ui.oculusUIMaxFPSSpin->value()); Menu::getInstance()->setSixenseReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value()); diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index 0108437c1f..2dda1a24b1 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -61,7 +61,7 @@ 0 0 500 - 1386 + 1459 @@ -1772,24 +1772,24 @@ - - - Arial - - - - Qt::LeftToRight - - - - - - localhost - - + + + Arial + + + + Qt::LeftToRight + + + + + + localhost + + - + @@ -2084,6 +2084,85 @@ + + + + 0 + + + 7 + + + 0 + + + 7 + + + + + + Arial + + + + Oculus Rift FPS + + + 0 + + + maxVoxelsSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 100 + 0 + + + + + Arial + + + + 30 + + + 95 + + + 1 + + + 75 + + + + + diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 62cde44909..f965a8fa73 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -67,7 +67,7 @@ AvatarData::~AvatarData() { delete _referential; } -const glm::vec3& AvatarData::getPosition() { +const glm::vec3& AvatarData::getPosition() const { if (_referential) { _referential->update(); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 29682da286..6b882a1389 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -138,15 +138,15 @@ public: AvatarData(); virtual ~AvatarData(); - const QUuid& getSessionUUID() { return _sessionUUID; } + const QUuid& getSessionUUID() const { return _sessionUUID; } - const glm::vec3& getPosition(); + const glm::vec3& getPosition() const; virtual void setPosition(const glm::vec3 position, bool overideReferential = false); glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); - QByteArray toByteArray(); + virtual QByteArray toByteArray(); /// \return true if an error should be logged bool shouldLogError(const quint64& now); diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index cc5d7ef29d..f1c086da67 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -27,8 +27,10 @@ MetavoxelClientManager::MetavoxelClientManager() : } MetavoxelClientManager::~MetavoxelClientManager() { - _updater->thread()->quit(); - _updater->thread()->wait(); + if (_updater) { + _updater->thread()->quit(); + _updater->thread()->wait(); + } } void MetavoxelClientManager::init() { diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 2bd28de784..2f43f8f4ae 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -1040,6 +1040,9 @@ MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { } void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const { + if (!state.shouldSubdivide()) { + return; + } bool leaf = isLeaf(); if (!state.shouldSubdivideReference()) { state.base.stream << leaf;