diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d95ac446f..93b784b462 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ set(BUILD_TOOLS_OPTION ON) set(BUILD_INSTALLER_OPTION ON) set(GLES_OPTION OFF) set(DISABLE_QML_OPTION OFF) +set(DOWNLOAD_SERVERLESS_CONTENT_OPTION OFF) if (ANDROID OR UWP) set(BUILD_SERVER_OPTION OFF) @@ -74,6 +75,11 @@ option(BUILD_INSTALLER "Build installer" ${BUILD_INSTALLER_OPTION}) option(USE_GLES "Use OpenGL ES" ${GLES_OPTION}) option(DISABLE_QML "Disable QML" ${DISABLE_QML_OPTION}) option(DISABLE_KTX_CACHE "Disable KTX Cache" OFF) +option( + DOWNLOAD_SERVERLESS_CONTENT + "Download and setup default serverless content beside Interface" + ${DOWNLOAD_SERVERLESS_CONTENT_OPTION} +) set(PLATFORM_QT_GL OpenGL) @@ -88,12 +94,13 @@ foreach(PLATFORM_QT_COMPONENT ${PLATFORM_QT_COMPONENTS}) list(APPEND PLATFORM_QT_LIBRARIES "Qt5::${PLATFORM_QT_COMPONENT}") endforeach() -MESSAGE(STATUS "Build server: " ${BUILD_SERVER}) -MESSAGE(STATUS "Build client: " ${BUILD_CLIENT}) -MESSAGE(STATUS "Build tests: " ${BUILD_TESTS}) -MESSAGE(STATUS "Build tools: " ${BUILD_TOOLS}) -MESSAGE(STATUS "Build installer: " ${BUILD_INSTALLER}) -MESSAGE(STATUS "GL ES: " ${USE_GLES}) +MESSAGE(STATUS "Build server: " ${BUILD_SERVER}) +MESSAGE(STATUS "Build client: " ${BUILD_CLIENT}) +MESSAGE(STATUS "Build tests: " ${BUILD_TESTS}) +MESSAGE(STATUS "Build tools: " ${BUILD_TOOLS}) +MESSAGE(STATUS "Build installer: " ${BUILD_INSTALLER}) +MESSAGE(STATUS "GL ES: " ${USE_GLES}) +MESSAGE(STATUS "DL serverless content: " ${DOWNLOAD_SERVERLESS_CONTENT}) if (DISABLE_QML) MESSAGE(STATUS "QML disabled!") diff --git a/cmake/externals/serverless-content/CMakeLists.txt b/cmake/externals/serverless-content/CMakeLists.txt new file mode 100644 index 0000000000..1c66fb213f --- /dev/null +++ b/cmake/externals/serverless-content/CMakeLists.txt @@ -0,0 +1,16 @@ +include(ExternalProject) + +set(EXTERNAL_NAME serverless-content) + +ExternalProject_Add( + ${EXTERNAL_NAME} + URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC66.zip + URL_MD5 91edfde96e06efc847ca327ab97f4c74 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 +) + +# Hide this external target (for IDE users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 601fbdaa20..3ca5cb0e54 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -73,6 +73,11 @@ macro(SET_PACKAGING_PARAMETERS) add_definitions(-DDEV_BUILD) endif () + if (DEPLOY_PACKAGE) + # for deployed packages always grab the serverless content + set(DOWNLOAD_SERVERLESS_CONTENT ON) + endif () + if (APPLE) set(DMG_SUBFOLDER_NAME "${BUILD_ORGANIZATION}") diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d98ac67dfd..fe00d86c3a 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -43,7 +43,6 @@ endif() list(APPEND GENERATE_QRC_DEPENDS ${RESOURCES_RCC}) add_custom_target(resources ALL DEPENDS ${GENERATE_QRC_DEPENDS}) - # set a default root dir for each of our optional externals if it was not passed set(OPTIONAL_EXTERNALS "LeapMotion") @@ -314,35 +313,41 @@ if (APPLE) ) set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources") - + set(RESOURCES_DEV_DIR "$/../Resources") # copy script files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/scripts" - "$/../Resources/scripts" + "${RESOURCES_DEV_DIR}/scripts" ) # call the fixup_interface macro to add required bundling commands for installation fixup_interface() else() + set(INTERFACE_EXEC_DIR "$") + set(RESOURCES_DEV_DIR "${INTERFACE_EXEC_DIR}/resources") + # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different - "${RESOURCES_RCC}" - "$" + "${RESOURCES_RCC}" + "${INTERFACE_EXEC_DIR}" # FIXME, the edit script code loads HTML from the scripts folder # which in turn relies on CSS that refers to the fonts. In theory # we should be able to modify the CSS to reference the QRC path to # the ttf files, but doing so generates a CORS policy violation, # so we have to retain a copy of the fonts outside of the resources binary COMMAND "${CMAKE_COMMAND}" -E copy_directory - "${PROJECT_SOURCE_DIR}/resources/fonts" - "$/resources/fonts" + "${PROJECT_SOURCE_DIR}/resources/fonts" + "${RESOURCES_DEV_DIR}/fonts" COMMAND "${CMAKE_COMMAND}" -E copy_directory - "${CMAKE_SOURCE_DIR}/scripts" - "$/scripts" + "${CMAKE_SOURCE_DIR}/scripts" + "${INTERFACE_EXEC_DIR}/scripts" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different + "${PROJECT_SOURCE_DIR}/resources/serverless/tutorial.json" + "${RESOURCES_DEV_DIR}/serverless/tutorial.json" ) # link target to external libraries @@ -368,7 +373,6 @@ else() endif() if (SCRIPTS_INSTALL_DIR) - # setup install of scripts beside interface executable install( DIRECTORY "${CMAKE_SOURCE_DIR}/scripts/" @@ -377,6 +381,19 @@ if (SCRIPTS_INSTALL_DIR) ) endif() +if (DOWNLOAD_SERVERLESS_CONTENT) + add_dependency_external_projects(serverless-content) + + ExternalProject_Get_Property(serverless-content SOURCE_DIR) + + # for dev builds, copy the serverless content to the resources folder + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_directory + "${SOURCE_DIR}" + "${RESOURCES_DEV_DIR}/serverless" + ) +endif () + if (WIN32) set(EXTRA_DEPLOY_OPTIONS "--qmldir \"${PROJECT_SOURCE_DIR}/resources/qml\"") diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json index b3f16a115e..174f9af7d7 100644 --- a/interface/resources/controllers/keyboardMouse.json +++ b/interface/resources/controllers/keyboardMouse.json @@ -1,15 +1,10 @@ { "name": "Keyboard/Mouse to Actions", "channels": [ - - { "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" }, - { "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" }, { "from": "Keyboard.A", "when": "Keyboard.RightMouseButton", "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.D", "when": "Keyboard.RightMouseButton", "to": "Actions.LATERAL_RIGHT" }, - { "from": "Keyboard.E", "when": "Keyboard.Shift", "to": "Actions.BOOM_IN", "filters": [ { "type": "scale", "scale": 0.05 } ] }, - { "from": "Keyboard.C", "when": "Keyboard.Shift", "to": "Actions.BOOM_OUT", "filters": [ { "type": "scale", "scale": 0.05 } ] }, - { "from": "Keyboard.S", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" }, - { "from": "Keyboard.W", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" }, + { "from": "Keyboard.E", "to": "Actions.LATERAL_RIGHT" }, + { "from": "Keyboard.Q", "to": "Actions.LATERAL_LEFT" }, { "comment" : "Mouse turn need to be small continuous increments", @@ -44,9 +39,24 @@ ] }, + { "from": { "makeAxis" : [ - ["Keyboard.A", "Keyboard.Left" ], - ["Keyboard.D", "Keyboard.Right"] + ["Keyboard.Left" ], + ["Keyboard.Right"] + ] + }, + "when": ["Application.InHMD", "Application.SnapTurn", "!Keyboard.Shift"], + "to": "Actions.StepYaw", + "filters": + [ + { "type": "pulse", "interval": 0.5, "resetOnZero": true }, + { "type": "scale", "scale": 22.5 } + ] + }, + + { "from": { "makeAxis" : [ + ["Keyboard.A"], + ["Keyboard.D"] ] }, "when": [ "Application.InHMD", "Application.SnapTurn" ], @@ -59,26 +69,39 @@ }, { "from": { "makeAxis" : [ - ["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"], - ["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"] + ["Keyboard.Left"], + ["Keyboard.Right"] + ] + }, + "when": ["Application.CameraFirstPerson", "!Keyboard.Shift"], + "to": "Actions.Yaw" + }, + + { "from": { "makeAxis" : [ + ["Keyboard.Left"], + ["Keyboard.Right"] + ] + }, + "when": ["Application.CameraThirdPerson", "!Keyboard.Shift"], + "to": "Actions.Yaw" + }, + + { "from": { "makeAxis" : [ + ["Keyboard.A", "Keyboard.TouchpadLeft"], + ["Keyboard.D", "Keyboard.TouchpadRight"] ] }, "when": "Application.CameraFirstPerson", "to": "Actions.Yaw" }, { "from": { "makeAxis" : [ - ["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"], - ["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"] + ["Keyboard.A", "Keyboard.TouchpadLeft"], + ["Keyboard.D", "Keyboard.TouchpadRight"] ] }, "when": "Application.CameraThirdPerson", "to": "Actions.Yaw" }, - { "from": { "makeAxis" : [ ["Keyboard.A"], ["Keyboard.D"] ] }, - "when": "Application.CameraFSM", - "to": "Actions.Yaw" - }, - { "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] }, "when": "Keyboard.RightMouseButton", "to": "Actions.Yaw", @@ -90,14 +113,10 @@ { "from": "Keyboard.W", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": "Keyboard.S", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_BACKWARD" }, - { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" }, - { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" }, - { "from": "Keyboard.Left", "when": "Keyboard.RightMouseButton", "to": "Actions.LATERAL_LEFT" }, - { "from": "Keyboard.Right", "when": "Keyboard.RightMouseButton", "to": "Actions.LATERAL_RIGHT" }, + { "from": "Keyboard.Shift", "when": ["!Keyboard.Left", "!Keyboard.Right"], "to": "Actions.SPRINT" }, + { "from": "Keyboard.Control", "to": "Actions.VERTICAL_DOWN" }, { "from": "Keyboard.Left", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.Right", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" }, - { "from": "Keyboard.Down", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" }, - { "from": "Keyboard.Up", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" }, { "from": "Keyboard.Up", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": "Keyboard.Up", "when": "Application.CameraThirdPerson", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": "Keyboard.Down", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_BACKWARD" }, @@ -128,7 +147,7 @@ { "from": "Keyboard.MouseWheelLeft", "to": "Actions.BOOM_OUT", "filters": [ { "type": "scale", "scale": 0.02 } ]}, { "from": "Keyboard.MouseWheelRight", "to": "Actions.BOOM_IN", "filters": [ { "type": "scale", "scale": 0.02 } ]}, - { "from": "Keyboard.Space", "to": "Actions.SHIFT" }, + { "from": "Keyboard.Space", "to": "Actions.VERTICAL_UP" }, { "from": "Keyboard.R", "to": "Actions.ACTION1" }, { "from": "Keyboard.T", "to": "Actions.ACTION2" }, { "from": "Keyboard.Tab", "to": "Actions.ContextMenu" } diff --git a/interface/resources/html/img/tablet-help-keyboard.jpg b/interface/resources/html/img/tablet-help-keyboard.jpg index a62fbe9450..d0f84c17c7 100644 Binary files a/interface/resources/html/img/tablet-help-keyboard.jpg and b/interface/resources/html/img/tablet-help-keyboard.jpg differ diff --git a/interface/resources/qml/+android/AddressBarDialog.qml b/interface/resources/qml/+android/AddressBarDialog.qml index b8d6b5e270..4477d512fc 100644 --- a/interface/resources/qml/+android/AddressBarDialog.qml +++ b/interface/resources/qml/+android/AddressBarDialog.qml @@ -67,6 +67,10 @@ Item { fill: parent } + MouseArea { + anchors.fill: parent + } + QmlHifi.WindowHeader { id: header iconSource: "../../../icons/goto-i.svg" diff --git a/interface/resources/qml/dialogs/CustomQueryDialog.qml b/interface/resources/qml/dialogs/CustomQueryDialog.qml index 4d6fe74bca..6e1bb4b309 100644 --- a/interface/resources/qml/dialogs/CustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/CustomQueryDialog.qml @@ -270,7 +270,9 @@ ModalWindow { onTriggered: { root.result = null; root.canceled(); - root.destroy(); + // FIXME we are leaking memory to avoid a crash + // root.destroy(); + visible = false; } } @@ -292,7 +294,9 @@ ModalWindow { } root.result = JSON.stringify(result); root.selected(root.result); - root.destroy(); + // FIXME we are leaking memory to avoid a crash + // root.destroy(); + visible = false; } } } diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index b5de5362f2..6f05179bd5 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -169,7 +169,9 @@ ModalWindow { shortcut: Qt.Key_Escape onTriggered: { root.canceled(); - root.destroy(); + // FIXME we are leaking memory to avoid a crash + // root.destroy(); + visible = false; } } Action { @@ -179,7 +181,9 @@ ModalWindow { onTriggered: { root.result = items ? comboBox.currentText : textResult.text root.selected(root.result); - root.destroy(); + // FIXME we are leaking memory to avoid a crash + // root.destroy(); + visible = false; } } } diff --git a/interface/resources/qml/hifi/+android/avatarSelection.qml b/interface/resources/qml/hifi/+android/avatarSelection.qml index 3090204308..afa5634575 100644 --- a/interface/resources/qml/hifi/+android/avatarSelection.qml +++ b/interface/resources/qml/hifi/+android/avatarSelection.qml @@ -58,6 +58,10 @@ Item { width: parent ? parent.width : 0 height: parent ? parent.height : 0 + MouseArea { + anchors.fill: parent + } + gradient: Gradient { GradientStop { position: 0.0; color: android.color.gradientTop } GradientStop { position: 1.0; color: android.color.gradientBottom } diff --git a/interface/resources/qml/hifi/+android/button.qml b/interface/resources/qml/hifi/+android/button.qml index 4822b6bf33..3e9ce39351 100644 --- a/interface/resources/qml/hifi/+android/button.qml +++ b/interface/resources/qml/hifi/+android/button.qml @@ -118,7 +118,7 @@ Item { tabletRoot.playButtonClickSound(); }*/ } - onEntered: { + onPressed: { button.isEntered = true; button.entered(); if (button.isActive) { @@ -127,7 +127,7 @@ Item { button.state = "hover state"; } } - onExited: { + onReleased: { button.isEntered = false; button.exited() if (button.isActive) { diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 34be11d4df..1ff954feff 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -24,6 +24,7 @@ Windows.ScrollingWindow { objectName: "AssetServer" title: "Asset Browser" resizable: true + opacity: parent.opacity destroyOnHidden: true implicitWidth: 384; implicitHeight: 640 minSize: Qt.vector2d(200, 300) @@ -57,7 +58,7 @@ Windows.ScrollingWindow { Component.onDestruction: { assetMappingsModel.autoRefreshEnabled = false; } - + function letterbox(headerGlyph, headerText, message) { letterboxMessage.headerGlyph = headerGlyph; letterboxMessage.headerText = headerText; @@ -144,7 +145,7 @@ Windows.ScrollingWindow { function canAddToWorld(path) { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i]; - + if (selectedItemCount > 1) { return false; } @@ -153,8 +154,8 @@ Windows.ScrollingWindow { return total | new RegExp(current).test(path); }, false); } - - function canRename() { + + function canRename() { if (treeView.selection.hasSelection && selectedItemCount == 1) { return true; } else { @@ -198,7 +199,7 @@ Windows.ScrollingWindow { var SHAPE_TYPE_STATIC_MESH = 3; var SHAPE_TYPE_BOX = 4; var SHAPE_TYPE_SPHERE = 5; - + var SHAPE_TYPES = []; SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision"; SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model"; @@ -206,7 +207,7 @@ Windows.ScrollingWindow { SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons"; SHAPE_TYPES[SHAPE_TYPE_BOX] = "Box"; SHAPE_TYPES[SHAPE_TYPE_SPHERE] = "Sphere"; - + var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_SIMPLE_COMPOUND; var DYNAMIC_DEFAULT = false; var prompt = desktop.customInputDialog({ @@ -348,14 +349,14 @@ Windows.ScrollingWindow { } function deleteFile(index) { var paths = []; - + if (!index) { for (var i = 0; i < selectedItemCount; ++i) { index = treeView.selection.selectedIndexes[i]; paths[i] = assetProxyModel.data(index, 0x100); } } - + if (!paths) { return; } @@ -364,13 +365,13 @@ Windows.ScrollingWindow { var items = selectedItemCount.toString(); var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101); var typeString = isFolder ? 'folder' : 'file'; - + if (selectedItemCount > 1) { modalMessage = "You are about to delete " + items + " items \nDo you want to continue?"; } else { modalMessage = "You are about to delete the following " + typeString + ":\n" + paths + "\nDo you want to continue?"; } - + var object = desktop.messageBox({ icon: hifi.icons.question, buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No, @@ -475,11 +476,11 @@ Windows.ScrollingWindow { }); } } - + Item { width: pane.contentWidth height: pane.height - + // The letterbox used for popup messages LetterboxMessage { id: letterboxMessage; @@ -541,7 +542,7 @@ Windows.ScrollingWindow { anchors.margins: hifi.dimensions.contentMargin.x + 2 // Extra for border anchors.left: parent.left anchors.right: parent.right - + treeModel: assetProxyModel selectionMode: SelectionMode.ExtendedSelection headerVisible: true @@ -561,9 +562,13 @@ Windows.ScrollingWindow { id: bakedColumn title: "Use Baked?" role: "baked" - width: 100 + width: 170 } - + + onSortIndicatorOrderChanged: { + Assets.sortProxyModel(sortIndicatorColumn, sortIndicatorOrder); + } + itemDelegate: Loader { id: itemDelegateLoader @@ -599,7 +604,7 @@ Windows.ScrollingWindow { } sourceComponent: getComponent() - + Component { id: labelComponent FiraSansSemiBold { @@ -608,15 +613,15 @@ Windows.ScrollingWindow { color: colorScheme == hifi.colorSchemes.light ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) - + horizontalAlignment: styleData.column === 1 ? TextInput.AlignHCenter : TextInput.AlignLeft - + elide: Text.ElideMiddle MouseArea { id: mouseArea anchors.fill: parent - + acceptedButtons: Qt.NoButton hoverEnabled: true @@ -638,7 +643,7 @@ Windows.ScrollingWindow { color: colorScheme == hifi.colorSchemes.light ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) - + elide: Text.ElideRight horizontalAlignment: TextInput.AlignHCenter @@ -725,7 +730,7 @@ Windows.ScrollingWindow { size: hifi.fontSizes.tableText color: colorScheme == hifi.colorSchemes.light ? hifi.colors.black : hifi.colors.lightGrayText } - + Timer { id: showTimer interval: 1000 @@ -744,7 +749,7 @@ Windows.ScrollingWindow { treeLabelToolTip.visible = false; } }// End_OF( treeLabelToolTip ) - + MouseArea { propagateComposedEvents: true anchors.fill: parent @@ -802,7 +807,7 @@ Windows.ScrollingWindow { anchors.left: treeView.left anchors.right: treeView.right anchors.bottom: uploadSection.top - + RalewayRegular { anchors.verticalCenter: parent.verticalCenter @@ -846,7 +851,7 @@ Windows.ScrollingWindow { checked = Qt.binding(isChecked); } - + function isEnabled() { if (!treeView.selection.hasSelection) { return false; @@ -870,7 +875,7 @@ Windows.ScrollingWindow { } } - return true; + return true; } function isChecked() { if (!treeView.selection.hasSelection) { @@ -878,10 +883,10 @@ Windows.ScrollingWindow { } var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); - return isEnabled() && status !== "Not Baked"; - } + return isEnabled() && status !== "Not Baked"; + } } - + Item { anchors.verticalCenter: parent.verticalCenter width: infoGlyph.size; @@ -905,7 +910,7 @@ Windows.ScrollingWindow { "What is baking?", "Baking compresses and optimizes files for faster network transfer and display. We recommend you bake your content to reduce initial load times for your visitors."); } - } + } }// End_OF( infoRow ) HifiControls.ContentSection { diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 9933953fe8..3152a1eed6 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -1160,14 +1160,14 @@ Rectangle { function authSuccessStep() { if (!root.debugCheckoutSuccess) { root.activeView = "checkoutMain"; - } else { - root.activeView = "checkoutSuccess"; root.ownershipStatusReceived = false; Commerce.alreadyOwned(root.itemId); root.availableUpdatesReceived = false; Commerce.getAvailableUpdates(root.itemId); root.balanceReceived = false; Commerce.balance(); + } else { + root.activeView = "checkoutSuccess"; } } diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index 00273171df..9e3ebcbab0 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -25,6 +25,7 @@ ScrollingWindow { resizable: true destroyOnHidden: false implicitWidth: 424 + opacity: parent.opacity implicitHeight: isHMD ? 695 : 728 minSize: Qt.vector2d(424, 300) diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index a85e5d4498..138eb5c6f8 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -58,7 +58,7 @@ Rectangle { Component.onDestruction: { assetMappingsModel.autoRefreshEnabled = false; } - + function letterbox(headerGlyph, headerText, message) { letterboxMessage.headerGlyph = headerGlyph; letterboxMessage.headerText = headerText; @@ -66,7 +66,7 @@ Rectangle { letterboxMessage.visible = true; letterboxMessage.popupRadius = 0; } - + function errorMessageBox(message) { return tabletRoot.messageBox({ icon: hifi.icons.warning, @@ -145,7 +145,7 @@ Rectangle { function canAddToWorld(path) { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i]; - + if (selectedItemCount > 1) { return false; } @@ -154,8 +154,8 @@ Rectangle { return total | new RegExp(current).test(path); }, false); } - - function canRename() { + + function canRename() { if (treeView.selection.hasSelection && selectedItemCount == 1) { return true; } else { @@ -199,7 +199,7 @@ Rectangle { var SHAPE_TYPE_STATIC_MESH = 3; var SHAPE_TYPE_BOX = 4; var SHAPE_TYPE_SPHERE = 5; - + var SHAPE_TYPES = []; SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision"; SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model"; @@ -207,7 +207,7 @@ Rectangle { SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons"; SHAPE_TYPES[SHAPE_TYPE_BOX] = "Box"; SHAPE_TYPES[SHAPE_TYPE_SPHERE] = "Sphere"; - + var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_SIMPLE_COMPOUND; var DYNAMIC_DEFAULT = false; var prompt = tabletRoot.customInputDialog({ @@ -349,14 +349,14 @@ Rectangle { } function deleteFile(index) { var paths = []; - + if (!index) { for (var i = 0; i < selectedItemCount; ++i) { index = treeView.selection.selectedIndexes[i]; paths[i] = assetProxyModel.data(index, 0x100); } } - + if (!paths) { return; } @@ -365,7 +365,7 @@ Rectangle { var items = selectedItemCount.toString(); var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101); var typeString = isFolder ? 'folder' : 'file'; - + if (selectedItemCount > 1) { modalMessage = "You are about to delete " + items + " items \nDo you want to continue?"; } else { @@ -476,7 +476,7 @@ Rectangle { }); } } - + // The letterbox used for popup messages LetterboxMessage { id: letterboxMessage; @@ -540,7 +540,7 @@ Rectangle { anchors.margins: hifi.dimensions.contentMargin.x + 2 // Extra for border anchors.left: parent.left anchors.right: parent.right - + treeModel: assetProxyModel selectionMode: SelectionMode.ExtendedSelection headerVisible: true @@ -560,9 +560,13 @@ Rectangle { id: bakedColumn title: "Use Baked?" role: "baked" - width: 100 + width: 170 } - + + onSortIndicatorOrderChanged: { + Assets.sortProxyModel(sortIndicatorColumn, sortIndicatorOrder); + } + itemDelegate: Loader { id: itemDelegateLoader @@ -598,7 +602,7 @@ Rectangle { } sourceComponent: getComponent() - + Component { id: labelComponent FiraSansSemiBold { @@ -607,15 +611,15 @@ Rectangle { color: colorScheme == hifi.colorSchemes.light ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) - + horizontalAlignment: styleData.column === 1 ? TextInput.AlignHCenter : TextInput.AlignLeft - + elide: Text.ElideMiddle MouseArea { id: mouseArea anchors.fill: parent - + acceptedButtons: Qt.NoButton hoverEnabled: true @@ -637,7 +641,7 @@ Rectangle { color: colorScheme == hifi.colorSchemes.light ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) - + elide: Text.ElideRight horizontalAlignment: TextInput.AlignHCenter @@ -724,7 +728,7 @@ Rectangle { size: hifi.fontSizes.tableText color: colorScheme == hifi.colorSchemes.light ? hifi.colors.black : hifi.colors.lightGrayText } - + Timer { id: showTimer interval: 1000 @@ -743,7 +747,7 @@ Rectangle { treeLabelToolTip.visible = false; } }// End_OF( treeLabelToolTip ) - + MouseArea { propagateComposedEvents: true anchors.fill: parent @@ -801,7 +805,7 @@ Rectangle { anchors.left: treeView.left anchors.right: treeView.right anchors.bottomMargin: hifi.dimensions.contentSpacing.y - + RalewayRegular { anchors.verticalCenter: parent.verticalCenter @@ -845,7 +849,7 @@ Rectangle { checked = Qt.binding(isChecked); } - + function isEnabled() { if (!treeView.selection.hasSelection) { return false; @@ -869,7 +873,7 @@ Rectangle { } } - return true; + return true; } function isChecked() { if (!treeView.selection.hasSelection) { @@ -877,10 +881,10 @@ Rectangle { } var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); - return isEnabled() && status !== "Not Baked"; - } + return isEnabled() && status !== "Not Baked"; + } } - + Item { anchors.verticalCenter: parent.verticalCenter width: infoGlyph.size; @@ -904,7 +908,7 @@ Rectangle { "What is baking?", "Baking compresses and optimizes files for faster network transfer and display. We recommend you bake your content to reduce initial load times for your visitors."); } - } + } }// End_OF( infoRow ) HifiControls.TabletContentSection { diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index 3debc8b9e7..5216bf45d5 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -71,6 +71,14 @@ Rectangle { onAccepted: { newModelDialog.keyboardEnabled = false; } + + onTextChanged : { + if (modelURL.text.length === 0){ + button1.enabled = false; + } else { + button1.enabled = true; + } + } MouseArea { anchors.fill: parent @@ -200,6 +208,7 @@ Rectangle { id: button1 text: qsTr("Add") z: -1 + enabled: false onClicked: { newModelDialog.sendToScript({ method: "newModelDialogAdd", diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index d4550d3843..4b9e1af4f1 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -113,7 +113,6 @@ StackView { id: addressBarDialog property bool keyboardEnabled: false - property bool keyboardRaised: false property bool punctuationMode: false width: parent.width @@ -401,11 +400,10 @@ StackView { addressLine.text = ""; } } - HifiControls.Keyboard { id: keyboard - raised: parent.keyboardEnabled && parent.keyboardRaised + raised: parent.keyboardEnabled numeric: parent.punctuationMode anchors { bottom: parent.bottom @@ -413,7 +411,7 @@ StackView { right: parent.right } } - + } function updateLocationText(enteringAddress) { diff --git a/interface/resources/serverless/tutorial.json b/interface/resources/serverless/tutorial.json new file mode 100644 index 0000000000..f690de6643 --- /dev/null +++ b/interface/resources/serverless/tutorial.json @@ -0,0 +1,18 @@ +{ + "Entities": [ + { + "type": "Box", + "dimensions": { + "x": 20, + "y": 1, + "z": 20 + }, + "position" : { + "x": 0, + "y": -12, + "z": 0 + } + } + ], + "Version": 84 +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f32c8f09cc..1324ff9aa3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -353,7 +353,7 @@ static const QString WEB_VIEW_TAG = "noDownload=true"; static const QString ZIP_EXTENSION = ".zip"; static const QString CONTENT_ZIP_EXTENSION = ".content.zip"; -static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f; +static const float MIRROR_FULLSCREEN_DISTANCE = 0.789f; static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND; @@ -941,7 +941,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true), _preferredCursor("preferredCursor", DEFAULT_CURSOR_NAME), _scaleMirror(1.0f), - _rotateMirror(0.0f), + _mirrorYawOffset(0.0f), _raiseMirror(0.0f), _enableProcessOctreeThread(true), _lastNackTime(usecTimestampNow()), @@ -959,8 +959,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); setProperty(hifi::properties::CRASHED, _previousSessionCrashed); - _entityClipboard->setIsServerlessMode(true); - { const QString TEST_SCRIPT = "--testScript"; const QString TRACE_FILE = "--traceFile"; @@ -2813,8 +2811,9 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _thirdPersonHMDCameraBoomValid= false; + if (isHMDMode()) { - auto mirrorBodyOrientation = myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)); + auto mirrorBodyOrientation = myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _mirrorYawOffset, 0.0f)); glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); // Mirror HMD yaw and roll @@ -2837,12 +2836,15 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { + mirrorBodyOrientation * hmdOffset); } else { - _myCamera.setOrientation(myAvatar->getWorldOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); + auto userInputMapper = DependencyManager::get(); + const float YAW_SPEED = TWO_PI / 5.0f; + float deltaYaw = userInputMapper->getActionState(controller::Action::YAW) * YAW_SPEED * deltaTime; + _mirrorYawOffset += deltaYaw; + _myCamera.setOrientation(myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _mirrorYawOffset, 0.0f))); _myCamera.setPosition(myAvatar->getDefaultEyePosition() + glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) - + (myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + + (myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, _mirrorYawOffset, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * myAvatar->getBoomLength() * _scaleMirror); } renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; } @@ -3403,8 +3405,6 @@ void Application::keyPressEvent(QKeyEvent* event) { } else { setFullscreen(nullptr); } - } else { - Menu::getInstance()->triggerOption(MenuOption::AddressBar); } break; @@ -3466,13 +3466,6 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; - case Qt::Key_F: { - if (isOption) { - _physicsEngine->dumpNextStats(); - } - break; - } - case Qt::Key_Asterisk: Menu::getInstance()->triggerOption(MenuOption::DefaultSkybox); break; @@ -3492,22 +3485,25 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_S: if (isShifted && isMeta && !isOption) { Menu::getInstance()->triggerOption(MenuOption::SuppressShortTimings); - } else if (!isOption && !isShifted && isMeta) { - AudioInjectorOptions options; - options.localOnly = true; - options.stereo = true; - - if (_snapshotSoundInjector) { - _snapshotSoundInjector->setOptions(options); - _snapshotSoundInjector->restart(); - } else { - QByteArray samples = _snapshotSound->getByteArray(); - _snapshotSoundInjector = AudioInjector::playSound(samples, options); - } - takeSnapshot(true); } break; + case Qt::Key_P: { + AudioInjectorOptions options; + options.localOnly = true; + options.stereo = true; + + if (_snapshotSoundInjector) { + _snapshotSoundInjector->setOptions(options); + _snapshotSoundInjector->restart(); + } else { + QByteArray samples = _snapshotSound->getByteArray(); + _snapshotSoundInjector = AudioInjector::playSound(samples, options); + } + takeSnapshot(true); + break; + } + case Qt::Key_Apostrophe: { if (isMeta) { auto cursor = Cursor::Manager::instance().getCursor(); @@ -3531,38 +3527,6 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->triggerOption(MenuOption::Chat); break; - case Qt::Key_Up: - if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - if (!isShifted) { - _scaleMirror *= 0.95f; - } else { - _raiseMirror += 0.05f; - } - } - break; - - case Qt::Key_Down: - if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - if (!isShifted) { - _scaleMirror *= 1.05f; - } else { - _raiseMirror -= 0.05f; - } - } - break; - - case Qt::Key_Left: - if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - _rotateMirror += PI / 20.0f; - } - break; - - case Qt::Key_Right: - if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - _rotateMirror -= PI / 20.0f; - } - break; - #if 0 case Qt::Key_I: if (isShifted) { @@ -4932,8 +4896,10 @@ void Application::cameraMenuChanged() { auto menu = Menu::getInstance(); if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { if (!isHMDMode() && _myCamera.getMode() != CAMERA_MODE_MIRROR) { + _mirrorYawOffset = 0.0f; _myCamera.setMode(CAMERA_MODE_MIRROR); getMyAvatar()->reset(false, false, false); // to reset any active MyAvatar::FollowHelpers + getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT); } } else if (menu->isOptionChecked(MenuOption::FirstPerson)) { if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { @@ -5213,7 +5179,7 @@ void Application::update(float deltaTime) { // FIXME can we drop drive keys and just have the avatar read the action states directly? myAvatar->clearDriveKeys(); if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) { - if (!_controllerScriptingInterface->areActionsCaptured()) { + if (!_controllerScriptingInterface->areActionsCaptured() && _myCamera.getMode() != CAMERA_MODE_MIRROR) { myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z)); myAvatar->setDriveKey(MyAvatar::TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y)); myAvatar->setDriveKey(MyAvatar::TRANSLATE_X, userInputMapper->getActionState(controller::Action::TRANSLATE_X)); @@ -5226,6 +5192,7 @@ void Application::update(float deltaTime) { myAvatar->setDriveKey(MyAvatar::ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z)); } + myAvatar->setSprintMode((bool)userInputMapper->getActionState(controller::Action::SPRINT)); static const std::vector avatarControllerActions = { controller::Action::LEFT_HAND, controller::Action::RIGHT_HAND, @@ -7491,7 +7458,7 @@ DisplayPluginPointer Application::getActiveDisplayPlugin() const { return _displayPlugin; } - if (!_displayPlugin) { + if (!_aboutToQuit && !_displayPlugin) { const_cast(this)->updateDisplayMode(); Q_ASSERT(_displayPlugin); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 812e51e49c..d7fbb48a58 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -575,7 +575,7 @@ private: Setting::Handle _preferredCursor; float _scaleMirror; - float _rotateMirror; + float _mirrorYawOffset; float _raiseMirror; QSet _keysPressed; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index fa0e8087f0..6c071defff 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -229,21 +229,21 @@ Menu::Menu() { // View > First Person auto firstPersonAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( - viewMenu, MenuOption::FirstPerson, Qt::CTRL | Qt::Key_F, + viewMenu, MenuOption::FirstPerson, Qt::Key_1, true, qApp, SLOT(cameraMenuChanged()))); firstPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); // View > Third Person auto thirdPersonAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( - viewMenu, MenuOption::ThirdPerson, Qt::CTRL | Qt::Key_G, + viewMenu, MenuOption::ThirdPerson, Qt::Key_3, false, qApp, SLOT(cameraMenuChanged()))); thirdPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); // View > Mirror auto viewMirrorAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( - viewMenu, MenuOption::FullscreenMirror, Qt::CTRL | Qt::Key_H, + viewMenu, MenuOption::FullscreenMirror, Qt::Key_2, false, qApp, SLOT(cameraMenuChanged()))); viewMirrorAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9620a2dcec..bd87ec47d8 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2186,7 +2186,6 @@ void MyAvatar::updateActionMotor(float deltaTime) { glm::vec3 direction = forward + right; if (state == CharacterController::State::Hover || _characterController.computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) { - // we can fly --> support vertical motion glm::vec3 up = (getDriveKey(TRANSLATE_Y)) * IDENTITY_UP; direction += up; } @@ -2204,10 +2203,11 @@ void MyAvatar::updateActionMotor(float deltaTime) { if (state == CharacterController::State::Hover) { // we're flying --> complex acceleration curve that builds on top of current motor speed and caps at some max speed + float motorSpeed = glm::length(_actionMotorVelocity); - float finalMaxMotorSpeed = getSensorToWorldScale() * DEFAULT_AVATAR_MAX_FLYING_SPEED; + float finalMaxMotorSpeed = getSensorToWorldScale() * DEFAULT_AVATAR_MAX_FLYING_SPEED * _walkSpeedScalar; float speedGrowthTimescale = 2.0f; - float speedIncreaseFactor = 1.8f; + float speedIncreaseFactor = 1.8f * _walkSpeedScalar; motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale, 0.0f, 1.0f) * speedIncreaseFactor; const float maxBoostSpeed = getSensorToWorldScale() * MAX_BOOST_SPEED; @@ -2223,7 +2223,7 @@ void MyAvatar::updateActionMotor(float deltaTime) { _actionMotorVelocity = motorSpeed * direction; } else { // we're interacting with a floor --> simple horizontal speed and exponential decay - _actionMotorVelocity = getSensorToWorldScale() * _walkSpeed.get() * direction; + _actionMotorVelocity = getSensorToWorldScale() * (_walkSpeed.get() * _walkSpeedScalar) * direction; } float boomChange = getDriveKey(ZOOM); @@ -2816,7 +2816,11 @@ float MyAvatar::getUserEyeHeight() const { } float MyAvatar::getWalkSpeed() const { - return _walkSpeed.get(); + return _walkSpeed.get() * _walkSpeedScalar; +} + +void MyAvatar::setSprintMode(bool sprint) { + _walkSpeedScalar = sprint ? AVATAR_SPRINT_SPEED_SCALAR : AVATAR_WALK_SPEED_SCALAR; } void MyAvatar::setWalkSpeed(float value) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 5ca010d128..4830004375 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -395,6 +395,7 @@ public: // Set what driving keys are being pressed to control thrust levels void clearDriveKeys(); void setDriveKey(DriveKeys key, float val); + void setSprintMode(bool sprint); float getDriveKey(DriveKeys key) const; Q_INVOKABLE float getRawDriveKey(DriveKeys key) const; void relayDriveKeysToCharacterController(); @@ -836,7 +837,8 @@ private: std::map _controllerPoseMap; mutable std::mutex _controllerPoseMapMutex; - bool _hmdLeanRecenterEnabled = true; + bool _hmdLeanRecenterEnabled { true }; + bool _sprint { false }; AnimPose _prePhysicsRoomPose; std::mutex _holdActionsMutex; std::vector _holdActions; @@ -866,6 +868,7 @@ private: // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; + float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; }; QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index d60a9bd126..c9bee659af 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -152,6 +152,10 @@ void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue request->start(); } +void AssetMappingsScriptingInterface::sortProxyModel(int column, Qt::SortOrder order) { + _proxyModel.sort(column, order); +} + void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); @@ -287,7 +291,7 @@ void AssetMappingModel::refresh() { item->setData(parts[i], Qt::UserRole + 2); item->setData("atp:" + fullPath, Qt::UserRole + 3); item->setData(fullPath, Qt::UserRole + 4); - + if (lastItem) { lastItem->appendRow(item); } else { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 1a4c7dae48..b27a72fbd0 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -82,6 +82,7 @@ public: Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback = QJSValue()); Q_INVOKABLE void setBakingEnabled(QStringList paths, bool enabled, QJSValue callback = QJSValue()); + Q_INVOKABLE void sortProxyModel(int column, Qt::SortOrder order = Qt::AscendingOrder); protected: QSet _pendingRequests; diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index a130b46877..34a3630b78 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -182,7 +183,6 @@ void AudioDeviceList::resetDevice(bool contextIsHMD) { } void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD) { - auto oldDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; selectedDevice = device; @@ -200,32 +200,137 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); } -void AudioDeviceList::onDevicesChanged(const QList& devices, bool isHMD) { - QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; +// Function returns 'strings similarity' as a number. The lesser number - the more similar strings are. Absolutely equal strings should return 0. +// Optimized version kindly provided by Ken +int levenshteinDistance(const QString& s1, const QString& s2) { + const int m = s1.size(); + const int n = s2.size(); - const QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName; + if (m == 0) { + return n; + } + if (n == 0) { + return m; + } + + auto cost = (int*)alloca((n + 1) * sizeof(int)); + + for (int j = 0; j <= n; j++) { + cost[j] = j; + } + + for (int i = 0; i < m; i++) { + + int prev = i; + cost[0] = i + 1; + + for (int j = 0; j < n; j++) { + + int temp = cost[j + 1]; + cost[j + 1] = (s1[i] == s2[j]) ? prev : std::min(cost[j], std::min(temp, prev)) + 1; + prev = temp; + } + } + return cost[n]; +} + +std::shared_ptr getSimilarDevice(const QString& deviceName, const QList>& devices) { + + int minDistance = INT_MAX; + int minDistanceIndex = 0; + + for (auto i = 0; i < devices.length(); ++i) { + auto distance = levenshteinDistance(deviceName, devices[i]->info.deviceName()); + if (distance < minDistance) { + minDistance = distance; + minDistanceIndex = i; + } + } + + return devices[minDistanceIndex]; +} + +void AudioDeviceList::onDevicesChanged(const QList& devices) { beginResetModel(); - _devices.clear(); + QList> newDevices; + bool hmdIsSelected = false; + bool desktopIsSelected = false; + + foreach(const QAudioDeviceInfo& deviceInfo, devices) { + for (bool isHMD : {false, true}) { + auto &backupSelectedDeviceName = isHMD ? _backupSelectedHMDDeviceName : _backupSelectedDesktopDeviceName; + if (deviceInfo.deviceName() == backupSelectedDeviceName) { + QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; + selectedDevice = deviceInfo; + backupSelectedDeviceName.clear(); + } + } + } foreach(const QAudioDeviceInfo& deviceInfo, devices) { AudioDevice device; - bool &isSelected = isHMD ? device.selectedHMD : device.selectedDesktop; device.info = deviceInfo; device.display = device.info.deviceName() .replace("High Definition", "HD") .remove("Device") .replace(" )", ")"); - if (!selectedDevice.isNull()) { - isSelected = (device.info == selectedDevice); - } else { - //no selected device for context. fallback to saved - isSelected = (device.info.deviceName() == savedDeviceName); + + for (bool isHMD : {false, true}) { + QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; + bool &isSelected = isHMD ? device.selectedHMD : device.selectedDesktop; + + if (!selectedDevice.isNull()) { + isSelected = (device.info == selectedDevice); + } + else { + //no selected device for context. fallback to saved + const QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName; + isSelected = (device.info.deviceName() == savedDeviceName); + } + + if (isSelected) { + if (isHMD) { + hmdIsSelected = isSelected; + } else { + desktopIsSelected = isSelected; + } + + // check if this device *is not* in old devices list - it means it was just re-plugged so needs to be selected explicitly + bool isNewDevice = true; + for (auto& oldDevice : _devices) { + if (oldDevice->info.deviceName() == device.info.deviceName()) { + isNewDevice = false; + break; + } + } + + if (isNewDevice) { + emit selectedDevicePlugged(device.info, isHMD); + } + } } + qDebug() << "adding audio device:" << device.display << device.selectedDesktop << device.selectedHMD << _mode; - _devices.push_back(newDevice(device)); + newDevices.push_back(newDevice(device)); } + if (!newDevices.isEmpty()) { + if (!hmdIsSelected) { + _backupSelectedHMDDeviceName = !_selectedHMDDevice.isNull() ? _selectedHMDDevice.deviceName() : _hmdSavedDeviceName; + auto device = getSimilarDevice(_backupSelectedHMDDeviceName, newDevices); + device->selectedHMD = true; + emit selectedDevicePlugged(device->info, true); + } + if (!desktopIsSelected) { + _backupSelectedDesktopDeviceName = !_selectedDesktopDevice.isNull() ? _selectedDesktopDevice.deviceName() : _desktopSavedDeviceName; + auto device = getSimilarDevice(_backupSelectedDesktopDeviceName, newDevices); + device->selectedDesktop = true; + emit selectedDevicePlugged(device->info, false); + } + } + + _devices.swap(newDevices); endResetModel(); } @@ -271,12 +376,10 @@ AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) { // connections are made after client is initialized, so we must also fetch the devices const QList& devicesInput = client->getAudioDevices(QAudio::AudioInput); const QList& devicesOutput = client->getAudioDevices(QAudio::AudioOutput); - //setup HMD devices - _inputs.onDevicesChanged(devicesInput, true); - _outputs.onDevicesChanged(devicesOutput, true); - //setup Desktop devices - _inputs.onDevicesChanged(devicesInput, false); - _outputs.onDevicesChanged(devicesOutput, false); + + //setup devices + _inputs.onDevicesChanged(devicesInput); + _outputs.onDevicesChanged(devicesOutput); } AudioDevices::~AudioDevices() {} @@ -375,11 +478,19 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList& devices, bool isHMD); + void onDevicesChanged(const QList& devices); protected: friend class AudioDevices; @@ -64,6 +65,8 @@ protected: const QAudio::Mode _mode; QAudioDeviceInfo _selectedDesktopDevice; QAudioDeviceInfo _selectedHMDDevice; + QString _backupSelectedDesktopDeviceName; + QString _backupSelectedHMDDeviceName; QList> _devices; QString _hmdSavedDeviceName; QString _desktopSavedDeviceName; @@ -117,13 +120,13 @@ public: AudioDevices(bool& contextIsHMD); virtual ~AudioDevices(); - void chooseInputDevice(const QAudioDeviceInfo& device, bool isHMD); - void chooseOutputDevice(const QAudioDeviceInfo& device, bool isHMD); - signals: void nop(); private slots: + void chooseInputDevice(const QAudioDeviceInfo& device, bool isHMD); + void chooseOutputDevice(const QAudioDeviceInfo& device, bool isHMD); + void onContextChanged(const QString& context); void onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& device, const QAudioDeviceInfo& previousDevice, bool isHMD); diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 78f55f0d6e..58ec744f4e 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -78,13 +78,17 @@ void WindowScriptingInterface::setFocus() { }); } -void WindowScriptingInterface::raiseMainWindow() { +void WindowScriptingInterface::raise() { // It's forbidden to call raise() from another thread. qApp->postLambdaEvent([] { qApp->raise(); }); } +void WindowScriptingInterface::raiseMainWindow() { + raise(); +} + /// Display an alert box /// \param const QString& message message to display /// \return QScriptValue::UndefinedValue diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 997e425e53..e3b092d011 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -68,9 +68,16 @@ public slots: */ void setFocus(); + /**jsdoc + * Raise the Interface window if it is minimized. If raised, the window gains focus. + * @function Window.raise + */ + void raise(); + /**jsdoc * Raise the Interface window if it is minimized. If raised, the window gains focus. * @function Window.raiseMainWindow + * @deprecated Use {@link Window.raise|raise} instead. */ void raiseMainWindow(); diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 35274e4fbe..6556cedb21 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -54,6 +54,7 @@ Overlays::Overlays() { } void Overlays::cleanupAllOverlays() { + _shuttingDown = true; QMap overlaysHUD; QMap overlaysWorld; { @@ -147,6 +148,10 @@ void Overlays::enable() { // Note, can't be invoked by scripts, but can be called by the InterfaceParentFinder // class on packet processing threads Overlay::Pointer Overlays::getOverlay(OverlayID id) const { + if (_shuttingDown) { + return nullptr; + } + QMutexLocker locker(&_mutex); if (_overlaysHUD.contains(id)) { return _overlaysHUD[id]; @@ -157,6 +162,10 @@ Overlay::Pointer Overlays::getOverlay(OverlayID id) const { } OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) { + if (_shuttingDown) { + return UNKNOWN_OVERLAY_ID; + } + if (QThread::currentThread() != thread()) { OverlayID result; PROFILE_RANGE(script, __FUNCTION__); @@ -261,6 +270,10 @@ OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) } OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { + if (_shuttingDown) { + return UNKNOWN_OVERLAY_ID; + } + OverlayID thisID = OverlayID(QUuid::createUuid()); overlay->setOverlayID(thisID); overlay->setStackOrder(_stackOrder++); @@ -283,6 +296,10 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { } OverlayID Overlays::cloneOverlay(OverlayID id) { + if (_shuttingDown) { + return UNKNOWN_OVERLAY_ID; + } + if (QThread::currentThread() != thread()) { OverlayID result; PROFILE_RANGE(script, __FUNCTION__); @@ -301,6 +318,10 @@ OverlayID Overlays::cloneOverlay(OverlayID id) { } bool Overlays::editOverlay(OverlayID id, const QVariant& properties) { + if (_shuttingDown) { + return false; + } + auto thisOverlay = getOverlay(id); if (!thisOverlay) { return false; @@ -320,6 +341,10 @@ bool Overlays::editOverlay(OverlayID id, const QVariant& properties) { } bool Overlays::editOverlays(const QVariant& propertiesById) { + if (_shuttingDown) { + return false; + } + bool defer2DOverlays = QThread::currentThread() != thread(); QVariantMap deferrred; @@ -351,6 +376,10 @@ bool Overlays::editOverlays(const QVariant& propertiesById) { } void Overlays::deleteOverlay(OverlayID id) { + if (_shuttingDown) { + return; + } + if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "deleteOverlay", Q_ARG(OverlayID, id)); return; @@ -374,6 +403,9 @@ void Overlays::deleteOverlay(OverlayID id) { } QString Overlays::getOverlayType(OverlayID overlayId) { + if (_shuttingDown) { + return ""; + } if (QThread::currentThread() != thread()) { QString result; PROFILE_RANGE(script, __FUNCTION__); @@ -388,8 +420,23 @@ QString Overlays::getOverlayType(OverlayID overlayId) { return ""; } +QObject* Overlays::getOverlayObject(OverlayID id) { + if (QThread::currentThread() != thread()) { + QObject* result; + PROFILE_RANGE(script, __FUNCTION__); + BLOCKING_INVOKE_METHOD(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(OverlayID, id)); + return result; + } + + Overlay::Pointer thisOverlay = getOverlay(id); + if (thisOverlay) { + return qobject_cast(&(*thisOverlay)); + } + return nullptr; +} + OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { - if (!_enabled) { + if (_shuttingDown || !_enabled) { return UNKNOWN_OVERLAY_ID; } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index c3d87642f1..c2f6e3e693 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -235,6 +235,50 @@ public slots: */ QString getOverlayType(OverlayID overlayId); + /**jsdoc + * Get the overlay script object. In particular, this is useful for accessing the event bridge for a web3d + * overlay. + * @function Overlays.getOverlayObject + * @param {Uuid} overlayID - The ID of the overlay to get the script object of. + * @returns {object} The script object for the overlay if found. + * @example Receive "hello" messages from a web3d overlay. + * // HTML file: name "web3d.html". + * + * + * + * HELLO + * + * + *

HELLO

+ * + * + * + * + * // Script file. + * var web3dOverlay = Overlays.addOverlay("web3d", { + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.5, z: -3 })), + * rotation: MyAvatar.orientation, + * url: Script.resolvePath("web3d.html"), + * alpha: 1.0 + * }); + * + * function onWebEventReceived(event) { + * print("onWebEventReceived() : " + JSON.stringify(event)); + * } + * + * overlayObject = Overlays.getOverlayObject(web3dOverlay); + * overlayObject.webEventReceived.connect(onWebEventReceived); + * + * Script.scriptEnding.connect(function () { + * Overlays.deleteOverlay(web3dOverlay); + * }); + */ + QObject* getOverlayObject(OverlayID id); + /**jsdoc * Get the ID of the 2D overlay at a particular point on the screen or HUD. * @function Overlays.getOverlayAtPoint @@ -680,6 +724,7 @@ private: unsigned int _stackOrder { 1 }; bool _enabled = true; + std::atomic _shuttingDown{ false }; PointerEvent calculateOverlayPointerEvent(OverlayID overlayID, PickRay ray, RayToOverlayIntersectionResult rayPickResult, QMouseEvent* event, PointerEvent::EventType eventType); diff --git a/interface/src/ui/overlays/QmlOverlay.cpp b/interface/src/ui/overlays/QmlOverlay.cpp index f4a9034187..2a583e0450 100644 --- a/interface/src/ui/overlays/QmlOverlay.cpp +++ b/interface/src/ui/overlays/QmlOverlay.cpp @@ -39,18 +39,20 @@ void QmlOverlay::buildQmlElement(const QUrl& url) { auto offscreenUi = DependencyManager::get(); offscreenUi->load(url, [=](QQmlContext* context, QObject* object) { - QQuickItem* rawPtr = dynamic_cast(object); - // Create a shared ptr with a custom deleter lambda, that calls deleteLater - _qmlElement = std::shared_ptr(rawPtr, [](QQuickItem* ptr) { - if (ptr) { - ptr->deleteLater(); - } - }); + _qmlElement = dynamic_cast(object); + connect(_qmlElement, &QObject::destroyed, this, &QmlOverlay::qmlElementDestroyed); }); } +void QmlOverlay::qmlElementDestroyed() { + _qmlElement = nullptr; +} + QmlOverlay::~QmlOverlay() { - _qmlElement.reset(); + if (_qmlElement) { + _qmlElement->deleteLater(); + } + _qmlElement = nullptr; } // QmlOverlay replaces Overlay's properties with those defined in the QML file used but keeps Overlay2D's properties. @@ -62,15 +64,13 @@ void QmlOverlay::setProperties(const QVariantMap& properties) { Overlay2D::setProperties(properties); auto bounds = _bounds; - std::weak_ptr weakQmlElement = _qmlElement; // check to see if qmlElement still exists - auto qmlElement = weakQmlElement.lock(); - if (qmlElement) { - qmlElement->setX(bounds.left()); - qmlElement->setY(bounds.top()); - qmlElement->setWidth(bounds.width()); - qmlElement->setHeight(bounds.height()); - QMetaObject::invokeMethod(qmlElement.get(), "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties)); + if (_qmlElement) { + _qmlElement->setX(bounds.left()); + _qmlElement->setY(bounds.top()); + _qmlElement->setWidth(bounds.width()); + _qmlElement->setHeight(bounds.height()); + QMetaObject::invokeMethod(_qmlElement, "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties)); } } diff --git a/interface/src/ui/overlays/QmlOverlay.h b/interface/src/ui/overlays/QmlOverlay.h index ced2b6fa1f..7f2cf5a918 100644 --- a/interface/src/ui/overlays/QmlOverlay.h +++ b/interface/src/ui/overlays/QmlOverlay.h @@ -32,10 +32,11 @@ public: void render(RenderArgs* args) override; private: + Q_INVOKABLE void qmlElementDestroyed(); Q_INVOKABLE void buildQmlElement(const QUrl& url); protected: - std::shared_ptr _qmlElement; + QQuickItem* _qmlElement{ nullptr }; }; #endif // hifi_QmlOverlay_h diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp index d8dd7f5e35..359ff6b33a 100644 --- a/libraries/controllers/src/controllers/Actions.cpp +++ b/libraries/controllers/src/controllers/Actions.cpp @@ -183,6 +183,7 @@ namespace controller { makeButtonPair(Action::ACTION2, "ACTION2"), makeButtonPair(Action::CONTEXT_MENU, "CONTEXT_MENU"), makeButtonPair(Action::TOGGLE_MUTE, "TOGGLE_MUTE"), + makeButtonPair(Action::SPRINT, "SPRINT") }; return availableInputs; } diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h index a133d62c9f..0c77d63863 100644 --- a/libraries/controllers/src/controllers/Actions.h +++ b/libraries/controllers/src/controllers/Actions.h @@ -174,6 +174,7 @@ enum class Action { TRACKED_OBJECT_13, TRACKED_OBJECT_14, TRACKED_OBJECT_15, + SPRINT, NUM_ACTIONS }; diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index fed2cfa553..f7cb2c4f85 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -30,12 +30,7 @@ #include "UserActivityLogger.h" #include "udt/PacketHeaders.h" -#if USE_STABLE_GLOBAL_SERVICES -const QString DEFAULT_HIFI_ADDRESS = "hifi://welcome/hello"; -#else -const QString DEFAULT_HIFI_ADDRESS = "hifi://dev-welcome/hello"; -#endif - +const QString DEFAULT_HIFI_ADDRESS = "file:///~/serverless/tutorial.json"; const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager"; const QString SETTINGS_CURRENT_ADDRESS_KEY = "address"; diff --git a/libraries/qml/src/qml/OffscreenSurface.cpp b/libraries/qml/src/qml/OffscreenSurface.cpp index 6580c5b1e8..9c1bb79355 100644 --- a/libraries/qml/src/qml/OffscreenSurface.cpp +++ b/libraries/qml/src/qml/OffscreenSurface.cpp @@ -166,18 +166,30 @@ bool OffscreenSurface::eventFilter(QObject* originalDestination, QEvent* event) case QEvent::TouchUpdate: case QEvent::TouchEnd: { QTouchEvent *originalEvent = static_cast(event); - QTouchEvent fakeEvent(*originalEvent); - auto newTouchPoints = fakeEvent.touchPoints(); - for (size_t i = 0; i < newTouchPoints.size(); ++i) { - const auto &originalPoint = originalEvent->touchPoints()[i]; - auto &newPoint = newTouchPoints[i]; - newPoint.setPos(originalPoint.pos()); + QEvent::Type fakeMouseEventType = QEvent::None; + Qt::MouseButton fakeMouseButton = Qt::LeftButton; + Qt::MouseButtons fakeMouseButtons = Qt::NoButton; + switch (event->type()) { + case QEvent::TouchBegin: + fakeMouseEventType = QEvent::MouseButtonPress; + fakeMouseButtons = Qt::LeftButton; + break; + case QEvent::TouchUpdate: + fakeMouseEventType = QEvent::MouseMove; + fakeMouseButtons = Qt::LeftButton; + break; + case QEvent::TouchEnd: + fakeMouseEventType = QEvent::MouseButtonRelease; + fakeMouseButtons = Qt::NoButton; + break; } - fakeEvent.setTouchPoints(newTouchPoints); - if (QCoreApplication::sendEvent(_sharedObject->getWindow(), &fakeEvent)) { - qInfo() << __FUNCTION__ << "sent fake touch event:" << fakeEvent.type() - << "_quickWindow handled it... accepted:" << fakeEvent.isAccepted(); - return false; //event->isAccepted(); + // Same case as OffscreenUi.cpp::eventFilter: touch events are always being accepted so we now use mouse events and consider one touch, touchPoints()[0]. + QMouseEvent fakeMouseEvent(fakeMouseEventType, originalEvent->touchPoints()[0].pos(), fakeMouseButton, fakeMouseButtons, Qt::NoModifier); + fakeMouseEvent.ignore(); + if (QCoreApplication::sendEvent(_sharedObject->getWindow(), &fakeMouseEvent)) { + /*qInfo() << __FUNCTION__ << "sent fake touch event:" << fakeMouseEvent.type() + << "_quickWindow handled it... accepted:" << fakeMouseEvent.isAccepted();*/ + return fakeMouseEvent.isAccepted(); } break; } diff --git a/libraries/qml/src/qml/impl/SharedObject.cpp b/libraries/qml/src/qml/impl/SharedObject.cpp index f2af5bd036..d66f0f1dab 100644 --- a/libraries/qml/src/qml/impl/SharedObject.cpp +++ b/libraries/qml/src/qml/impl/SharedObject.cpp @@ -69,6 +69,7 @@ SharedObject::SharedObject() { _quickWindow->setColor(QColor(255, 255, 255, 0)); _quickWindow->setClearBeforeRendering(true); + QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &SharedObject::onAboutToQuit); } @@ -124,6 +125,7 @@ void SharedObject::setRootItem(QQuickItem* rootItem) { _renderThread->setObjectName(objectName()); _renderThread->start(); + // Create event handler for the render thread _renderObject = new RenderEventHandler(this, _renderThread); QCoreApplication::postEvent(this, new OffscreenEvent(OffscreenEvent::Initialize)); @@ -152,9 +154,16 @@ void SharedObject::destroy() { QObject::disconnect(_renderControl); QObject::disconnect(qApp); - QMutexLocker lock(&_mutex); - _quit = true; - QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::Quit)); + { + QMutexLocker lock(&_mutex); + _quit = true; + QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::Quit), Qt::HighEventPriority); + } + // Block until the rendering thread has stopped + // FIXME this is undesirable because this is blocking the main thread, + // but I haven't found a reliable way to do this only at application + // shutdown + _renderThread->wait(); } diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index ed052adf6e..9c5efb9fa7 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -118,9 +118,15 @@ uint32_t Item::fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) c auto numSubs = fetchMetaSubItems(subItems); for (auto id : subItems) { - auto& item = scene.getItem(id); - if (item.exist()) { - subItemBounds.emplace_back(id, item.getBound()); + // TODO: Adding an extra check here even thought we shouldn't have too. + // We have cases when the id returned by fetchMetaSubItems is not allocated + if (scene.isAllocatedID(id)) { + auto& item = scene.getItem(id); + if (item.exist()) { + subItemBounds.emplace_back(id, item.getBound()); + } else { + numSubs--; + } } else { numSubs--; } diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index 4942c63e27..930da6a494 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -59,5 +59,7 @@ static const float MIN_AVATAR_SCALE = 0.005f; static const float MAX_AVATAR_HEIGHT = 1000.0f * DEFAULT_AVATAR_HEIGHT; // meters static const float MIN_AVATAR_HEIGHT = 0.005f * DEFAULT_AVATAR_HEIGHT; // meters +static const float AVATAR_WALK_SPEED_SCALAR = 1.0f; +static const float AVATAR_SPRINT_SPEED_SCALAR = 3.0f; #endif // hifi_AvatarConstants_h diff --git a/script-archive/inspect.js b/script-archive/inspect.js index 555b4105b7..18b26ab709 100644 --- a/script-archive/inspect.js +++ b/script-archive/inspect.js @@ -26,14 +26,14 @@ var RADIUS_RATE = 1.0 / 100.0; var PAN_RATE = 250.0; var Y_AXIS = { - x: 0, - y: 1, - z: 0 + x: 0, + y: 1, + z: 0 }; var X_AXIS = { - x: 1, - y: 0, - z: 0 + x: 1, + y: 0, + z: 0 }; var LOOK_AT_TIME = 500; @@ -56,21 +56,20 @@ var mode = noMode; var mouseLastX = 0; var mouseLastY = 0; - var center = { - x: 0, - y: 0, - z: 0 + x: 0, + y: 0, + z: 0 }; var position = { - x: 0, - y: 0, - z: 0 + x: 0, + y: 0, + z: 0 }; var vector = { - x: 0, - y: 0, - z: 0 + x: 0, + y: 0, + z: 0 }; var radius = 0.0; var azimuth = 0.0; @@ -83,258 +82,248 @@ var rotatingTowardsTarget = false; var targetCamOrientation; var oldPosition, oldOrientation; - function orientationOf(vector) { - var direction, - yaw, - pitch; + var direction, + yaw, + pitch; - direction = Vec3.normalize(vector); - yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS); - pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS); - return Quat.multiply(yaw, pitch); + direction = Vec3.normalize(vector); + yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS); + pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS); + return Quat.multiply(yaw, pitch); } - function handleRadialMode(dx, dy) { - azimuth += dx / AZIMUTH_RATE; - radius += radius * dy * RADIUS_RATE; - if (radius < 1) { - radius = 1; - } + azimuth += dx / AZIMUTH_RATE; + radius += radius * dy * RADIUS_RATE; + if (radius < 1) { + radius = 1; + } - vector = { - x: (Math.cos(altitude) * Math.cos(azimuth)) * radius, - y: Math.sin(altitude) * radius, - z: (Math.cos(altitude) * Math.sin(azimuth)) * radius - }; - position = Vec3.sum(center, vector); - Camera.setPosition(position); - Camera.setOrientation(orientationOf(vector)); + vector = { + x: (Math.cos(altitude) * Math.cos(azimuth)) * radius, + y: Math.sin(altitude) * radius, + z: (Math.cos(altitude) * Math.sin(azimuth)) * radius + }; + position = Vec3.sum(center, vector); + Camera.setPosition(position); + Camera.setOrientation(orientationOf(vector)); } function handleOrbitMode(dx, dy) { - azimuth += dx / AZIMUTH_RATE; - altitude += dy / ALTITUDE_RATE; - if (altitude > PI / 2.0) { - altitude = PI / 2.0; - } - if (altitude < -PI / 2.0) { - altitude = -PI / 2.0; - } + azimuth += dx / AZIMUTH_RATE; + altitude += dy / ALTITUDE_RATE; + if (altitude > PI / 2.0) { + altitude = PI / 2.0; + } + if (altitude < -PI / 2.0) { + altitude = -PI / 2.0; + } - vector = { - x: (Math.cos(altitude) * Math.cos(azimuth)) * radius, - y: Math.sin(altitude) * radius, - z: (Math.cos(altitude) * Math.sin(azimuth)) * radius - }; - position = Vec3.sum(center, vector); - Camera.setPosition(position); - Camera.setOrientation(orientationOf(vector)); + vector = { + x: (Math.cos(altitude) * Math.cos(azimuth)) * radius, + y: Math.sin(altitude) * radius, + z: (Math.cos(altitude) * Math.sin(azimuth)) * radius + }; + position = Vec3.sum(center, vector); + Camera.setPosition(position); + Camera.setOrientation(orientationOf(vector)); } - function handlePanMode(dx, dy) { - var up = Quat.getUp(Camera.getOrientation()); - var right = Quat.getRight(Camera.getOrientation()); - var distance = Vec3.length(vector); + var up = Quat.getUp(Camera.getOrientation()); + var right = Quat.getRight(Camera.getOrientation()); + var distance = Vec3.length(vector); - var dv = Vec3.sum(Vec3.multiply(up, distance * dy / PAN_RATE), Vec3.multiply(right, -distance * dx / PAN_RATE)); + var dv = Vec3.sum(Vec3.multiply(up, distance * dy / PAN_RATE), Vec3.multiply(right, -distance * dx / PAN_RATE)); - center = Vec3.sum(center, dv); - position = Vec3.sum(position, dv); + center = Vec3.sum(center, dv); + position = Vec3.sum(position, dv); - Camera.setPosition(position); - Camera.setOrientation(orientationOf(vector)); + Camera.setPosition(position); + Camera.setOrientation(orientationOf(vector)); } function saveCameraState() { - oldMode = Camera.mode; - oldPosition = Camera.getPosition(); - oldOrientation = Camera.getOrientation(); + oldMode = Camera.mode; + oldPosition = Camera.getPosition(); + oldOrientation = Camera.getOrientation(); - Camera.mode = "independent"; - Camera.setPosition(oldPosition); + Camera.mode = "independent"; + Camera.setPosition(oldPosition); } function restoreCameraState() { - Camera.mode = oldMode; - Camera.setPosition(oldPosition); - Camera.setOrientation(oldOrientation); + Camera.mode = oldMode; + Camera.setPosition(oldPosition); + Camera.setOrientation(oldOrientation); } function handleModes() { - var newMode = (mode == noMode) ? noMode : detachedMode; - if (alt) { - if (control) { - if (shift) { - newMode = panningMode; - } else { - newMode = orbitMode; - } - } else { - newMode = radialMode; + var newMode = (mode == noMode) ? noMode : detachedMode; + if (alt) { + if (control) { + if (shift) { + newMode = panningMode; + } else { + newMode = orbitMode; + } + } else { + newMode = radialMode; + } } - } - // if entering detachMode - if (newMode == detachedMode && mode != detachedMode) { - avatarPosition = MyAvatar.position; - avatarOrientation = MyAvatar.orientation; - } - // if leaving detachMode - if (mode == detachedMode && newMode == detachedMode && - (avatarPosition.x != MyAvatar.position.x || - avatarPosition.y != MyAvatar.position.y || - avatarPosition.z != MyAvatar.position.z || - avatarOrientation.x != MyAvatar.orientation.x || - avatarOrientation.y != MyAvatar.orientation.y || - avatarOrientation.z != MyAvatar.orientation.z || - avatarOrientation.w != MyAvatar.orientation.w)) { - newMode = noMode; - } + // if entering detachMode + if (newMode == detachedMode && mode != detachedMode) { + avatarPosition = MyAvatar.position; + avatarOrientation = MyAvatar.orientation; + } + // if leaving detachMode + if (mode == detachedMode && newMode == detachedMode && + (avatarPosition.x != MyAvatar.position.x || + avatarPosition.y != MyAvatar.position.y || + avatarPosition.z != MyAvatar.position.z || + avatarOrientation.x != MyAvatar.orientation.x || + avatarOrientation.y != MyAvatar.orientation.y || + avatarOrientation.z != MyAvatar.orientation.z || + avatarOrientation.w != MyAvatar.orientation.w)) { + newMode = noMode; + } - if (mode == noMode && newMode != noMode && Camera.mode == "independent") { - newMode = noMode; - } + if (mode == noMode && newMode != noMode && Camera.mode == "independent") { + newMode = noMode; + } - // if leaving noMode - if (mode == noMode && newMode != noMode) { - saveCameraState(); - } - // if entering noMode - if (newMode == noMode && mode != noMode) { - restoreCameraState(); - } + // if leaving noMode + if (mode == noMode && newMode != noMode) { + saveCameraState(); + } + // if entering noMode + if (newMode == noMode && mode != noMode) { + restoreCameraState(); + } - mode = newMode; + mode = newMode; } function keyPressEvent(event) { - var changed = false; + var changed = false; - if (event.text == "ALT") { - alt = true; - changed = true; - } - if (event.text == "CONTROL") { - control = true; - changed = true; - } - if (event.text == "SHIFT") { - shift = true; - changed = true; - } + if (event.text == "ALT") { + alt = true; + changed = true; + } + if (event.text == "CONTROL") { + control = true; + changed = true; + } + if (event.text == "SHIFT") { + shift = true; + changed = true; + } - if (changed) { - handleModes(); - } + if (changed) { + handleModes(); + } } function keyReleaseEvent(event) { - var changed = false; + var changed = false; - if (event.text == "ALT") { - alt = false; - changed = true; - mode = noMode; - restoreCameraState(); - } - if (event.text == "CONTROL") { - control = false; - changed = true; - } - if (event.text == "SHIFT") { - shift = false; - changed = true; - } - - if (changed) { - handleModes(); - } -} - - - -function mousePressEvent(event) { - if (alt && !isActive) { - mouseLastX = event.x; - mouseLastY = event.y; - - // Compute trajectories related values - var pickRay = Camera.computePickRay(mouseLastX, mouseLastY); - var modelIntersection = Entities.findRayIntersection(pickRay, true); - - position = Camera.getPosition(); - - var avatarTarget = MyAvatar.getTargetAvatarPosition(); - - - var distance = -1; - var string; - - if (modelIntersection.intersects && modelIntersection.accurate) { - distance = modelIntersection.distance; - center = modelIntersection.intersection; - string = "Inspecting model"; - //We've selected our target, now orbit towards it automatically - rotatingTowardsTarget = true; - //calculate our target cam rotation - Script.setTimeout(function() { - rotatingTowardsTarget = false; - }, LOOK_AT_TIME); - - vector = Vec3.subtract(position, center); - targetCamOrientation = orientationOf(vector); - radius = Vec3.length(vector); - azimuth = Math.atan2(vector.z, vector.x); - altitude = Math.asin(vector.y / Vec3.length(vector)); - - isActive = true; + if (event.text == "ALT") { + alt = false; + changed = true; + mode = noMode; + restoreCameraState(); + } + if (event.text == "CONTROL") { + control = false; + changed = true; + } + if (event.text == "SHIFT") { + shift = false; + changed = true; } - } + if (changed) { + handleModes(); + } +} + +function mousePressEvent(event) { + if (alt && !isActive) { + mouseLastX = event.x; + mouseLastY = event.y; + + // Compute trajectories related values + var pickRay = Camera.computePickRay(mouseLastX, mouseLastY); + var modelIntersection = Entities.findRayIntersection(pickRay, true); + var avatarIntersection = AvatarList.findRayIntersection(pickRay); + + position = Camera.getPosition(); + + if (avatarIntersection.intersects || (modelIntersection.intersects && modelIntersection.accurate)) { + if (avatarIntersection.intersects) { + center = avatarIntersection.intersection; + } else { + center = modelIntersection.intersection; + } + // We've selected our target, now orbit towards it automatically + rotatingTowardsTarget = true; + // calculate our target cam rotation + Script.setTimeout(function () { + rotatingTowardsTarget = false; + }, LOOK_AT_TIME); + + vector = Vec3.subtract(position, center); + targetCamOrientation = orientationOf(vector); + radius = Vec3.length(vector); + azimuth = Math.atan2(vector.z, vector.x); + altitude = Math.asin(vector.y / Vec3.length(vector)); + + isActive = true; + } + } } function mouseReleaseEvent(event) { - if (isActive) { - isActive = false; - } + if (isActive) { + isActive = false; + } } function mouseMoveEvent(event) { - if (isActive && mode != noMode && !rotatingTowardsTarget) { - if (mode == radialMode) { - handleRadialMode(event.x - mouseLastX, event.y - mouseLastY); + if (isActive && mode != noMode && !rotatingTowardsTarget) { + if (mode == radialMode) { + handleRadialMode(event.x - mouseLastX, event.y - mouseLastY); + } + if (mode == orbitMode) { + handleOrbitMode(event.x - mouseLastX, event.y - mouseLastY); + } + if (mode == panningMode) { + handlePanMode(event.x - mouseLastX, event.y - mouseLastY); + } } - if (mode == orbitMode) { - handleOrbitMode(event.x - mouseLastX, event.y - mouseLastY); - } - if (mode == panningMode) { - handlePanMode(event.x - mouseLastX, event.y - mouseLastY); - } - - } - mouseLastX = event.x; - mouseLastY = event.y; + mouseLastX = event.x; + mouseLastY = event.y; } function update() { - handleModes(); - if (rotatingTowardsTarget) { - rotateTowardsTarget(); - } + handleModes(); + if (rotatingTowardsTarget) { + rotateTowardsTarget(); + } } function rotateTowardsTarget() { - var newOrientation = Quat.mix(Camera.getOrientation(), targetCamOrientation, .1); - Camera.setOrientation(newOrientation); + var newOrientation = Quat.mix(Camera.getOrientation(), targetCamOrientation, 0.1); + Camera.setOrientation(newOrientation); } function scriptEnding() { - if (mode != noMode) { - restoreCameraState(); - } + if (mode != noMode) { + restoreCameraState(); + } } Controller.keyPressEvent.connect(keyPressEvent); @@ -345,4 +334,4 @@ Controller.mouseReleaseEvent.connect(mouseReleaseEvent); Controller.mouseMoveEvent.connect(mouseMoveEvent); Script.update.connect(update); -Script.scriptEnding.connect(scriptEnding); \ No newline at end of file +Script.scriptEnding.connect(scriptEnding); diff --git a/scripts/system/+android/audio.js b/scripts/system/+android/audio.js index b4f156d4bf..955f74d63a 100644 --- a/scripts/system/+android/audio.js +++ b/scripts/system/+android/audio.js @@ -46,7 +46,6 @@ function onMuteClicked() { printd("On Mute Clicked"); //Menu.setIsOptionChecked("Mute Microphone", !Menu.isOptionChecked("Mute Microphone")); Audio.muted = !Audio.muted; - onMuteToggled(); } function onMuteToggled() { diff --git a/scripts/system/+android/avatarSelection.js b/scripts/system/+android/avatarSelection.js index 2b28fe2c9b..2946e541b5 100644 --- a/scripts/system/+android/avatarSelection.js +++ b/scripts/system/+android/avatarSelection.js @@ -35,6 +35,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See break; case 'hide': Controller.setVPadHidden(false); + module.exports.hide(); module.exports.onHidden(); break; default: diff --git a/scripts/system/+android/modes.js b/scripts/system/+android/modes.js index 097798e393..c41ae1f327 100644 --- a/scripts/system/+android/modes.js +++ b/scripts/system/+android/modes.js @@ -33,7 +33,6 @@ function init() { radar.setUniqueColor(uniqueColor); radar.init(); setupModesBar(); - radar.isTouchValid = isRadarModeValidTouch; } function shutdown() { @@ -183,34 +182,6 @@ function onButtonClicked(clickedButton, whatToDo, hideAllAfter) { } } -function isRadarModeValidTouch(coords) { - var qmlFragments = [modesbar.qmlFragment]; - var windows = []; - for (var i=0; i < qmlFragments.length; i++) { - var aQmlFrag = qmlFragments[i]; - if (aQmlFrag != null && aQmlFrag.isVisible() && - coords.x >= aQmlFrag.position.x * 3 && coords.x <= aQmlFrag.position.x * 3 + aQmlFrag.size.x * 3 && - coords.y >= aQmlFrag.position.y * 3 && coords.y <= aQmlFrag.position.y * 3 + aQmlFrag.size.y * 3 - ) { - printd("godViewModeTouchValid- false because of qmlFragments!? idx " + i); - return false; - } - } - - for (var i=0; i < windows.length; i++) { - var aWin = windows[i]; - if (aWin != null && aWin.position() != null && - coords.x >= aWin.position().x * 3 && coords.x <= aWin.position().x * 3 + aWin.width() * 3 && - coords.y >= aWin.position().y * 3 && coords.y <= aWin.position().y * 3 + aWin.height() * 3 - ) { - printd("godViewModeTouchValid- false because of windows!?"); - return false; - } - } - printd("godViewModeTouchValid- true by default "); - return true; -} - Script.scriptEnding.connect(function () { shutdown(); }); diff --git a/scripts/system/+android/radar.js b/scripts/system/+android/radar.js index 84fb66403f..455299dd5f 100644 --- a/scripts/system/+android/radar.js +++ b/scripts/system/+android/radar.js @@ -13,7 +13,7 @@ var radarModeInterface = {}; -var logEnabled = true; +var logEnabled = false; function printd(str) { if (logEnabled) { print("[radar.js] " + str); @@ -118,19 +118,10 @@ function actionOnObjectFromEvent(event) { } function mousePress(event) { - if (!isTouchValid(coords)) { - currentTouchIsValid = false; - return; - } else { - currentTouchIsValid = true; - } mousePressOrTouchEnd(event); } function mousePressOrTouchEnd(event) { - if (!currentTouchIsValid) { - return; - } if (radar) { if (actionOnObjectFromEvent(event)) { return; @@ -155,9 +146,6 @@ function fakeDoubleTap(event) { teleporter.dragTeleportRelease(event); } -var currentTouchIsValid = false; // Currently used to know if touch hasn't - // started on a UI overlay - var DOUBLE_TAP_TIME = 300; var fakeDoubleTapStart = Date.now(); var touchEndCount = 0; @@ -238,12 +226,6 @@ function touchEnd(event) { return; } - // if touch is invalid, cancel - if (!currentTouchIsValid) { - printd("touchEnd fail because !currentTouchIsValid"); - return; - } - if (analyzeDoubleTap(event)) return; // double tap detected, finish @@ -345,20 +327,6 @@ function computePointAtPlaneY(x, y, py) { p2.z, py); } -/******************************************************************************* - * - ******************************************************************************/ - -function isTouchValid(coords) { - // TODO: Extend to the detection of touches on new menu bars - var radarModeTouchValid = radarModeInterface.isTouchValid(coords); - - // getItemAtPoint does not exist anymore, look for another way to know if we - // are touching buttons - // is it still needed? - return /* !tablet.getItemAtPoint(coords) && */radarModeTouchValid; -} - /******************************************************************************* * ******************************************************************************/ @@ -373,16 +341,8 @@ function touchBegin(event) { x : event.x, y : event.y }; - if (!isTouchValid(coords)) { - printd("analyze touch - RADAR_TOUCH - INVALID"); - currentTouchIsValid = false; - touchStartingCoordinates = null; - } else { - printd("analyze touch - RADAR_TOUCH - ok"); - currentTouchIsValid = true; - touchStartingCoordinates = coords; - touchBeginTime = Date.now(); - } + touchStartingCoordinates = coords; + touchBeginTime = Date.now(); } var startedDraggingCamera = false; // first time @@ -848,9 +808,6 @@ function oneFingerTouchUpdate(event) { } function touchUpdate(event) { - if (!currentTouchIsValid) { - return; // avoid moving and zooming when tap is over UI entities - } if (event.isPinching || event.isPinchOpening) { pinchUpdate(event); } else { diff --git a/scripts/system/assets/images/Overlay-Viz-blank.png b/scripts/system/assets/images/Overlay-Viz-blank.png index 76f535b6e6..bbbf44f7a9 100644 Binary files a/scripts/system/assets/images/Overlay-Viz-blank.png and b/scripts/system/assets/images/Overlay-Viz-blank.png differ diff --git a/scripts/system/away.js b/scripts/system/away.js index 2a45786d0d..dc9b33e952 100644 --- a/scripts/system/away.js +++ b/scripts/system/away.js @@ -24,8 +24,9 @@ var OVERLAY_HEIGHT = 1080; var OVERLAY_DATA = { width: OVERLAY_WIDTH, height: OVERLAY_HEIGHT, - imageURL: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png", - color: {red: 255, green: 255, blue: 255}, + imageURL: Script.resolvePath("assets/images/Overlay-Viz-blank.png"), + emissive: true, + drawInFront: true, alpha: 1 }; var AVATAR_MOVE_FOR_ACTIVE_DISTANCE = 0.8; // meters -- no longer away if avatar moves this far while away @@ -37,7 +38,7 @@ var OVERLAY_DATA_HMD = { localRotation: {x: 0, y: 0, z: 0, w: 1}, width: OVERLAY_WIDTH, height: OVERLAY_HEIGHT, - url: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png", + url: Script.resolvePath("assets/images/Overlay-Viz-blank.png"), color: {red: 255, green: 255, blue: 255}, alpha: 1, scale: 2 * MyAvatar.sensorToWorldScale, diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 511bb6989e..a7186f55bd 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -307,6 +307,10 @@ WebTablet.prototype.setScriptURL = function (scriptURL) { Overlays.editOverlay(this.webOverlayID, { scriptURL: scriptURL }); }; +WebTablet.prototype.getOverlayObject = function () { + return Overlays.getOverlayObject(this.webOverlayID); +}; + WebTablet.prototype.setWidth = function (width) { // imported from libraries/utils.js resizeTablet(width);