diff --git a/BUILD.md b/BUILD.md index b30160e7e4..db81ecb30d 100644 --- a/BUILD.md +++ b/BUILD.md @@ -1,13 +1,13 @@ # General Build Information -*Last Updated on May 17, 2020* +*Last Updated on June 27, 2020* ### OS Specific Build Guides * [Build Windows](BUILD_WIN.md) - complete instructions for Windows. * [Build Linux](BUILD_LINUX.md) - additional instructions for Linux. * [Build OSX](BUILD_OSX.md) - additional instructions for OS X. -* [Build Android](BUILD_ANDROID.md) - additional instructions for Android +* [Build Android](BUILD_ANDROID.md) - additional instructions for Android. ### Dependencies - [git](https://git-scm.com/downloads): >= 1.6 @@ -21,8 +21,8 @@ These dependencies need not be installed manually. They are automatically downloaded on the platforms where they are required. - [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases): 2.83 - [glm](https://glm.g-truc.net/0.9.8/index.html): 0.9.8 -- [Oculus SDK](https://developer.oculus.com/downloads/): 1.11 (Win32) / 0.5 (Mac) -- [OpenVR](https://github.com/ValveSoftware/openvr): 1.11.11 (Win32 only) +- [Oculus SDK](https://developer.oculus.com/downloads/): 1.11 (Windows) / 0.5 (Mac) +- [OpenVR](https://github.com/ValveSoftware/openvr): 1.11.11 (Windows, Linux) - [Polyvox](http://www.volumesoffun.com/): 0.2.1 - [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/): 0.7.3 - [SDL2](https://www.libsdl.org/download-2.0.php): 2.0.3 @@ -78,11 +78,11 @@ Where /path/to/directory is the path to a directory where you wish the build fil BUILD_NUMBER // The type of release. - RELEASE_TYPE=PRODUCTION|PR - RELEASE_BUILD=PRODUCTION|PR + RELEASE_TYPE=PRODUCTION|PR|DEV // TODO: What do these do? PRODUCTION_BUILD=0|1 + PR_BUILD=0|1 STABLE_BUILD=0|1 // TODO: What do these do? @@ -150,4 +150,4 @@ The following build options can be used when running CMake #### Devices You can support external input/output devices such as Leap Motion, MIDI, and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device. - \ No newline at end of file + diff --git a/BUILD_OSX.md b/BUILD_OSX.md index b39aadb287..ccf32d71a8 100644 --- a/BUILD_OSX.md +++ b/BUILD_OSX.md @@ -1,6 +1,6 @@ # Build OSX -*Last Updated on April 30, 2019* +*Last Updated on July 3, 2020* Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only macOS specific instructions are found in this document. @@ -8,21 +8,24 @@ Please read the [general build guide](BUILD.md) for information on dependencies [Homebrew](https://brew.sh/) is an excellent package manager for macOS. It makes install of some Vircadia dependencies very simple. - brew install cmake openssl + brew install cmake openssl npm ### Python 3 Download an install Python 3.6.6 or higher from [here](https://www.python.org/downloads/). Execute the `Update Shell Profile.command` script that is provided with the installer. +### OSX SDK + +You will need the OSX SDK for building. The easiest way to get this is to install Xcode from the App Store. + ### OpenSSL Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations. -For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR: +For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR via + `export OPENSSL_ROOT_DIR=/usr/local/opt/openssl` + or by appending `-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl` to `cmake` - export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2l - -Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change. ### Xcode If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles. @@ -34,3 +37,7 @@ If `cmake` complains about Python 3 being missing, you may need to update your C After running cmake, you will have the make files or Xcode project file necessary to build all of the components. Open the hifi.xcodeproj file, choose ALL_BUILD from the Product > Scheme menu (or target drop down), and click Run. If the build completes successfully, you will have built targets for all components located in the `build/${target_name}/Debug` directories. + +### make + +If you build with make rather than Xcode, you can append `-j4`for assigning more threads. The number indicates the number of threads, e.g. 4. diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index a6ab382781..4c4fcbf2dd 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -370,16 +370,18 @@ void EntityServer::entityFilterAdded(EntityItemID id, bool success) { void EntityServer::nodeAdded(SharedNodePointer node) { EntityTreePointer tree = std::static_pointer_cast(_tree); - tree->knowAvatarID(node->getUUID()); + if (tree) { + tree->knowAvatarID(node->getUUID()); + } OctreeServer::nodeAdded(node); } void EntityServer::nodeKilled(SharedNodePointer node) { EntityTreePointer tree = std::static_pointer_cast(_tree); - tree->withWriteLock([&] { + if (tree) { tree->deleteDescendantsOfAvatar(node->getUUID()); - }); - tree->forgetAvatarID(node->getUUID()); + tree->forgetAvatarID(node->getUUID()); + } OctreeServer::nodeKilled(node); } diff --git a/cmake/ports/hifi-client-deps/CONTROL b/cmake/ports/hifi-client-deps/CONTROL index 7070cb6fb9..4a8a2bc44e 100644 --- a/cmake/ports/hifi-client-deps/CONTROL +++ b/cmake/ports/hifi-client-deps/CONTROL @@ -1,4 +1,4 @@ Source: hifi-client-deps Version: 0.1 Description: Collected dependencies for High Fidelity applications -Build-Depends: hifi-deps, aristo (windows), glslang, liblo (windows), nlohmann-json, openvr (windows), quazip (!android), sdl2 (!android), spirv-cross (!android), spirv-tools (!android), sranipal (windows), vulkanmemoryallocator +Build-Depends: hifi-deps, aristo (windows), glslang, liblo (windows), nlohmann-json, openvr (linux|windows), quazip (!android), sdl2 (!android), spirv-cross (!android), spirv-tools (!android), sranipal (windows), vulkanmemoryallocator diff --git a/cmake/ports/openvr/portfile.cmake b/cmake/ports/openvr/portfile.cmake index b91bdd1d54..bcbac8613a 100644 --- a/cmake/ports/openvr/portfile.cmake +++ b/cmake/ports/openvr/portfile.cmake @@ -11,15 +11,23 @@ vcpkg_from_github( set(VCPKG_LIBRARY_LINKAGE dynamic) if(VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") - set(ARCH_PATH "win64") + if(WIN32) + set(ARCH_PATH "win64") + else() + set(ARCH_PATH "linux64") + endif() elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "x86") - set(ARCH_PATH "win32") + if(WIN32) + set(ARCH_PATH "win32") + else() + set(ARCH_PATH "linux32") + endif() else() - message(FATAL_ERROR "Package only supports x64 and x86 windows.") + message(FATAL_ERROR "Package only supports x64 and x86 Windows and Linux.") endif() -if(VCPKG_CMAKE_SYSTEM_NAME) - message(FATAL_ERROR "Package only supports windows desktop.") +if(VCPKG_CMAKE_SYSTEM_NAME AND NOT (VCPKG_CMAKE_SYSTEM_NAME STREQUAL "Linux")) + message(FATAL_ERROR "Package only supports Windows or Linux desktop.") endif() file(MAKE_DIRECTORY @@ -28,18 +36,35 @@ file(MAKE_DIRECTORY ${CURRENT_PACKAGES_DIR}/debug/lib ${CURRENT_PACKAGES_DIR}/debug/bin ) -file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/lib) -file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/debug/lib) -file(COPY - ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll - ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb - DESTINATION ${CURRENT_PACKAGES_DIR}/bin -) -file(COPY - ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll - ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb - DESTINATION ${CURRENT_PACKAGES_DIR}/debug/bin -) + +if(WIN32) + file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/lib) + file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/debug/lib) + file(COPY + ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll + ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb + DESTINATION ${CURRENT_PACKAGES_DIR}/bin + ) + file(COPY + ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll + ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb + DESTINATION ${CURRENT_PACKAGES_DIR}/debug/bin + ) +else() + file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/libopenvr_api.so DESTINATION ${CURRENT_PACKAGES_DIR}/lib) + file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/libopenvr_api.so DESTINATION ${CURRENT_PACKAGES_DIR}/debug/lib) + file(COPY + ${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so + ${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so.dbg + DESTINATION ${CURRENT_PACKAGES_DIR}/bin + ) + file(COPY + ${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so + ${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so.dbg + DESTINATION ${CURRENT_PACKAGES_DIR}/debug/bin + ) +endif() + file(COPY ${SOURCE_PATH}/headers DESTINATION ${CURRENT_PACKAGES_DIR}) file(RENAME ${CURRENT_PACKAGES_DIR}/headers ${CURRENT_PACKAGES_DIR}/include) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 284dd344e7..3ae92651b8 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -247,7 +247,7 @@ "name": "standard_permissions", "type": "table", "label": "Domain-Wide User Permissions", - "help": "Indicate which types of users can have which domain-wide permissions.", + "help": "Indicate which types of users can have which domain-wide permissions.", "caption": "Standard Permissions", "can_add_new_rows": false, "groups": [ @@ -256,7 +256,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -337,7 +337,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -392,7 +392,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -498,7 +498,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -520,7 +520,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -623,7 +623,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -641,7 +641,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -722,7 +722,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -740,7 +740,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -821,7 +821,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -839,7 +839,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -920,7 +920,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -938,7 +938,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -1019,7 +1019,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false diff --git a/hifi_android.py b/hifi_android.py index 0c2ea07cc7..a8fec01035 100644 --- a/hifi_android.py +++ b/hifi_android.py @@ -10,87 +10,74 @@ import zipfile print = functools.partial(print, flush=True) -ANDROID_PACKAGE_URL = 'https://hifi-public.s3.amazonaws.com/dependencies/android/' +ANDROID_PACKAGE_URL = 'https://content.vircadia.com/eu-c-1/vircadia-public/dependencies/android/' ANDROID_PACKAGES = { 'qt' : { 'file': 'qt-5.11.1_linux_armv8-libcpp_openssl_patched.tgz', - 'versionId': '3S97HBM5G5Xw9EfE52sikmgdN3t6C2MN', 'checksum': 'aa449d4bfa963f3bc9a9dfe558ba29df', }, 'bullet': { 'file': 'bullet-2.88_armv8-libcpp.tgz', - 'versionId': 'S8YaoED0Cl8sSb8fSV7Q2G1lQJSNDxqg', 'checksum': '81642779ccb110f8c7338e8739ac38a0', }, 'draco': { 'file': 'draco_armv8-libcpp.tgz', - 'versionId': '3.B.uBj31kWlgND3_R2xwQzT_TP6Dz_8', 'checksum': '617a80d213a5ec69fbfa21a1f2f738cd', }, 'glad': { 'file': 'glad_armv8-libcpp.zip', - 'versionId': 'r5Zran.JSCtvrrB6Q4KaqfIoALPw3lYY', 'checksum': 'a8ee8584cf1ccd34766c7ddd9d5e5449', }, 'gvr': { 'file': 'gvrsdk_v1.101.0.tgz', - 'versionId': 'nqBV_j81Uc31rC7bKIrlya_Hah4v3y5r', 'checksum': '57fd02baa069176ba18597a29b6b4fc7', }, 'nvtt': { 'file': 'nvtt_armv8-libcpp.zip', - 'versionId': 'lmkBVR5t4UF1UUwMwEirnk9H_8Nt90IO', 'checksum': 'eb46d0b683e66987190ed124aabf8910', 'sharedLibFolder': 'lib', 'includeLibs': ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so'] }, 'oculus_1.22': { 'file': 'ovr_sdk_mobile_1.22.zip', - 'versionId': 'InhomR5gwkzyiLAelH3X9k4nvV3iIpA_', 'checksum': '1ac3c5b0521e5406f287f351015daff8', 'sharedLibFolder': 'VrApi/Libs/Android/arm64-v8a/Release', 'includeLibs': ['libvrapi.so'] }, 'oculusPlatform': { 'file': 'OVRPlatformSDK_v1.34.0.zip', - 'versionId': 'vbRUkkyzUAXfTGSEtuiUr_7.Fm5h5BZk', 'checksum': '16e4c5f39520f122bc49cb6d5bb88289', 'sharedLibFolder': 'Android/libs/arm64-v8a', 'includeLibs': ['libovrplatformloader.so'] }, 'openssl': { 'file': 'openssl-1.1.0g_armv8.tgz', - 'versionId': 'AiiPjmgUZTgNj7YV1EEx2lL47aDvvvAW', 'checksum': 'cabb681fbccd79594f65fcc266e02f32' }, 'polyvox': { 'file': 'polyvox_armv8-libcpp.tgz', - 'versionId': 'A2kbKiNhpIenGq23bKRRzg7IMAI5BI92', 'checksum': 'dba88b3a098747af4bb169e9eb9af57e', 'sharedLibFolder': 'lib', 'includeLibs': ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'], }, 'tbb': { 'file': 'tbb-2018_U1_armv8_libcpp.tgz', - 'versionId': 'mrRbWnv4O4evcM1quRH43RJqimlRtaKB', 'checksum': '20768f298f53b195e71b414b0ae240c4', 'sharedLibFolder': 'lib/release', 'includeLibs': ['libtbb.so', 'libtbbmalloc.so'], }, 'hifiAC': { - 'baseUrl': 'http://s3.amazonaws.com/hifi-public/dependencies/', + 'baseUrl': 'https://content.vircadia.com/eu-c-1/vircadia-public/dependencies/', 'file': 'codecSDK-android_armv8-2.0.zip', 'checksum': '1cbef929675818fc64c4101b72f84a6a' }, 'etc2comp': { 'file': 'etc2comp-patched-armv8-libcpp.tgz', - 'versionId': 'bHhGECRAQR1vkpshBcK6ByNc1BQIM8gU', 'checksum': '14b02795d774457a33bbc60e00a786bc' }, 'breakpad': { 'file': 'breakpad.tgz', - 'versionId': '8VrYXz7oyc.QBxNia0BVJOUBvrFO61jI', 'checksum': 'ddcb23df336b08017042ba4786db1d9e', 'sharedLibFolder': 'lib', 'includeLibs': {'libbreakpad_client.a'} @@ -105,14 +92,12 @@ ANDROID_PLATFORM_PACKAGES = { 'Darwin' : { 'qt': { 'file': 'qt-5.11.1_osx_armv8-libcpp_openssl_patched.tgz', - 'versionId': 'OxBD7iKINv1HbyOXmAmDrBb8AF3N.Kup', 'checksum': 'c83cc477c08a892e00c71764dca051a0' }, }, 'Windows' : { 'qt': { 'file': 'qt-5.11.1_win_armv8-libcpp_openssl_patched.tgz', - 'versionId': 'JfWM0P_Mz5Qp0LwpzhrsRwN3fqlLSFeT', 'checksum': '0582191cc55431aa4f660848a542883e' }, } diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 963a3246fc..31f3ee44df 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -6,6 +6,7 @@ // // Created by Vlad Stelmahovsky on 03/22/2017 // Copyright 2017 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -325,178 +326,14 @@ Rectangle { size: 16; text: (bar.currentIndex === 0) ? qsTr("Press and hold the button \"T\" to talk.") : - qsTr("Press and hold grip triggers on both of your controllers to talk."); - } - } - - Separator { - id: secondSeparator; - anchors.top: pttTextContainer.visible ? pttTextContainer.bottom : switchesContainer.bottom; - anchors.topMargin: 10; - } - - Item { - id: inputDeviceHeader - x: margins.paddings; - width: parent.width - margins.paddings*2; - height: 36; - anchors.top: secondSeparator.bottom; - anchors.topMargin: 10; - - HiFiGlyphs { - width: margins.sizeCheckBox; - text: hifi.glyphs.mic; - color: hifi.colors.white; - anchors.left: parent.left; - anchors.leftMargin: -size/4; //the glyph has empty space at left about 25% - anchors.verticalCenter: parent.verticalCenter; - size: 30; - } - RalewayRegular { - anchors.verticalCenter: parent.verticalCenter; - width: margins.sizeText + margins.sizeLevel; - anchors.left: parent.left; - anchors.leftMargin: margins.sizeCheckBox; - size: 22; - color: hifi.colors.white; - text: qsTr("Choose input device"); - } - } - - ListView { - id: inputView; - width: rightMostInputLevelPos; - anchors.top: inputDeviceHeader.bottom; - anchors.topMargin: 10; - x: margins.paddings - interactive: false; - height: contentHeight; - - clip: true; - model: AudioScriptingInterface.devices.input; - delegate: Item { - width: rightMostInputLevelPos - margins.paddings*2 - height: ((type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1)) ? - (margins.sizeCheckBox > checkBoxInput.implicitHeight ? margins.sizeCheckBox + 4 : checkBoxInput.implicitHeight + 4) : 0 - visible: (type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1) - AudioControls.CheckBox { - id: checkBoxInput - anchors.left: parent.left - spacing: margins.sizeCheckBox - boxSize - anchors.verticalCenter: parent.verticalCenter - width: parent.width - inputLevel.width - clip: true - checkable: !checked - checked: bar.currentIndex === 0 ? selectedDesktop : selectedHMD; - boxSize: margins.sizeCheckBox / 2 - isRound: true - text: devicename - fontSize: 16; - onPressed: { - if (!checked) { - stereoInput.checked = false; - AudioScriptingInterface.setStereoInput(false); // the next selected audio device might not support stereo - AudioScriptingInterface.setInputDevice(info, bar.currentIndex === 1); - } - } - } - AudioControls.InputPeak { - id: inputLevel - anchors.right: parent.right - peak: model.peak; - anchors.verticalCenter: parent.verticalCenter - visible: ((bar.currentIndex === 1 && isVR) || - (bar.currentIndex === 0 && !isVR)) && - AudioScriptingInterface.devices.input.peakValuesAvailable; - } - } - } - - AudioControls.LoopbackAudio { - id: loopbackAudio - x: margins.paddings - anchors.top: inputView.bottom; - anchors.topMargin: 10; - - visible: (bar.currentIndex === 1 && isVR) || - (bar.currentIndex === 0 && !isVR); - anchors { left: parent.left; leftMargin: margins.paddings } - } - - Separator { - id: thirdSeparator; - anchors.top: loopbackAudio.visible ? loopbackAudio.bottom : inputView.bottom; - anchors.topMargin: 10; - } - - Item { - id: outputDeviceHeader; - anchors.topMargin: 10; - anchors.top: thirdSeparator.bottom; - x: margins.paddings; - width: parent.width - margins.paddings*2 - height: 36 - - HiFiGlyphs { - anchors.left: parent.left - anchors.leftMargin: -size/4 //the glyph has empty space at left about 25% - anchors.verticalCenter: parent.verticalCenter; - width: margins.sizeCheckBox - text: hifi.glyphs.unmuted; - color: hifi.colors.white; - size: 36; - } - - RalewayRegular { - width: margins.sizeText + margins.sizeLevel - anchors.left: parent.left - anchors.leftMargin: margins.sizeCheckBox - anchors.verticalCenter: parent.verticalCenter; - size: 22; - color: hifi.colors.white; - text: qsTr("Choose output device"); - } - } - - ListView { - id: outputView - width: parent.width - margins.paddings*2 - x: margins.paddings; - interactive: false; - height: contentHeight; - anchors.top: outputDeviceHeader.bottom; - anchors.topMargin: 10; - clip: true; - model: AudioScriptingInterface.devices.output; - delegate: Item { - width: rightMostInputLevelPos - height: ((type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1)) ? - (margins.sizeCheckBox > checkBoxOutput.implicitHeight ? margins.sizeCheckBox + 4 : checkBoxOutput.implicitHeight + 4) : 0 - visible: (type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1) - - AudioControls.CheckBox { - id: checkBoxOutput - width: parent.width - spacing: margins.sizeCheckBox - boxSize - boxSize: margins.sizeCheckBox / 2 - isRound: true - checked: bar.currentIndex === 0 ? selectedDesktop : selectedHMD; - checkable: !checked - text: devicename - fontSize: 16 - onPressed: { - if (!checked) { - AudioScriptingInterface.setOutputDevice(info, bar.currentIndex === 1); - } - } - } + qsTr("Press and hold grip triggers on both controllers to talk."); } } Item { id: avatarGainContainer x: margins.paddings; - anchors.top: outputView.bottom; + anchors.top: pttTextContainer.bottom; anchors.topMargin: 10; width: parent.width - margins.paddings*2 height: avatarGainSliderTextMetrics.height @@ -677,12 +514,174 @@ Rectangle { } } - AudioControls.PlaySampleSound { - id: playSampleSound - x: margins.paddings + Separator { + id: secondSeparator; anchors.top: systemInjectorGainContainer.bottom; anchors.topMargin: 10; } - } -} + Item { + id: inputDeviceHeader + x: margins.paddings; + width: parent.width - margins.paddings*2; + height: 36; + anchors.top: secondSeparator.bottom; + anchors.topMargin: 10; + + HiFiGlyphs { + width: margins.sizeCheckBox; + text: hifi.glyphs.mic; + color: hifi.colors.white; + anchors.left: parent.left; + anchors.leftMargin: -size/4; //the glyph has empty space at left about 25% + anchors.verticalCenter: parent.verticalCenter; + size: 30; + } + + RalewayRegular { + anchors.verticalCenter: parent.verticalCenter; + width: margins.sizeText + margins.sizeLevel; + anchors.left: parent.left; + anchors.leftMargin: margins.sizeCheckBox; + size: 22; + color: hifi.colors.white; + text: qsTr("Choose input device"); + } + } + + AudioControls.LoopbackAudio { + id: loopbackAudio + x: margins.paddings + anchors.top: inputDeviceHeader.bottom; + anchors.topMargin: 10; + visible: (bar.currentIndex === 1 && isVR) || + (bar.currentIndex === 0 && !isVR); + anchors { left: parent.left; leftMargin: margins.paddings } + } + + ListView { + id: inputView; + width: rightMostInputLevelPos; + anchors.top: loopbackAudio.visible ? loopbackAudio.bottom : inputDeviceHeader.bottom; + anchors.topMargin: 10; + x: margins.paddings + interactive: false; + height: contentHeight; + + clip: true; + model: AudioScriptingInterface.devices.input; + delegate: Item { + width: rightMostInputLevelPos - margins.paddings*2 + height: ((type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1)) ? + (margins.sizeCheckBox > checkBoxInput.implicitHeight ? margins.sizeCheckBox + 4 : checkBoxInput.implicitHeight + 4) : 0 + visible: (type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1) + AudioControls.CheckBox { + id: checkBoxInput + anchors.left: parent.left + spacing: margins.sizeCheckBox - boxSize + anchors.verticalCenter: parent.verticalCenter + width: parent.width - inputLevel.width + clip: true + checkable: !checked + checked: bar.currentIndex === 0 ? selectedDesktop : selectedHMD; + boxSize: margins.sizeCheckBox / 2 + isRound: true + text: devicename + fontSize: 16; + onPressed: { + if (!checked) { + stereoInput.checked = false; + AudioScriptingInterface.setStereoInput(false); // the next selected audio device might not support stereo + AudioScriptingInterface.setInputDevice(info, bar.currentIndex === 1); + } + } + } + AudioControls.InputPeak { + id: inputLevel + anchors.right: parent.right + peak: model.peak; + anchors.verticalCenter: parent.verticalCenter + visible: ((bar.currentIndex === 1 && isVR) || + (bar.currentIndex === 0 && !isVR)) && + AudioScriptingInterface.devices.input.peakValuesAvailable; + } + } + } + + Separator { + id: thirdSeparator; + anchors.top: inputView.bottom; + anchors.topMargin: 10; + } + + Item { + id: outputDeviceHeader; + anchors.topMargin: 10; + anchors.top: thirdSeparator.bottom; + x: margins.paddings; + width: parent.width - margins.paddings*2 + height: 36 + + HiFiGlyphs { + anchors.left: parent.left + anchors.leftMargin: -size/4 //the glyph has empty space at left about 25% + anchors.verticalCenter: parent.verticalCenter; + width: margins.sizeCheckBox + text: hifi.glyphs.unmuted; + color: hifi.colors.white; + size: 36; + } + + RalewayRegular { + width: margins.sizeText + margins.sizeLevel + anchors.left: parent.left + anchors.leftMargin: margins.sizeCheckBox + anchors.verticalCenter: parent.verticalCenter; + size: 22; + color: hifi.colors.white; + text: qsTr("Choose output device"); + } + } + + AudioControls.PlaySampleSound { + id: playSampleSound + x: margins.paddings + anchors.top: outputDeviceHeader.bottom; + anchors.topMargin: 10; + } + + ListView { + id: outputView + width: parent.width - margins.paddings*2 + x: margins.paddings; + interactive: false; + height: contentHeight + 10; + anchors.top: playSampleSound.bottom; + anchors.topMargin: 10; + clip: true; + model: AudioScriptingInterface.devices.output; + delegate: Item { + width: rightMostInputLevelPos + height: ((type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1)) ? + (margins.sizeCheckBox > checkBoxOutput.implicitHeight ? margins.sizeCheckBox + 4 : checkBoxOutput.implicitHeight + 4) : 0 + visible: (type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1) + AudioControls.CheckBox { + id: checkBoxOutput + width: parent.width + spacing: margins.sizeCheckBox - boxSize + boxSize: margins.sizeCheckBox / 2 + isRound: true + checked: bar.currentIndex === 0 ? selectedDesktop : selectedHMD; + checkable: !checked + text: devicename + fontSize: 16 + onPressed: { + if (!checked) { + AudioScriptingInterface.setOutputDevice(info, bar.currentIndex === 1); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 05ddcd5bd3..374d53096a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3857,6 +3857,11 @@ void Application::showHelp() { //InfoView::show(INFO_HELP_PATH, false, queryString.toString()); } +void Application::gotoTutorial() { + const QString TUTORIAL_ADDRESS = "file:///~/serverless/tutorial.json"; + DependencyManager::get()->handleLookupString(TUTORIAL_ADDRESS); +} + void Application::resizeEvent(QResizeEvent* event) { resizeGL(); } @@ -4065,7 +4070,7 @@ std::map Application::prepareServerlessDomainContents(QUrl dom bool success = tmpTree->readFromByteArray(domainURL.toString(), data); if (success) { tmpTree->reaverageOctreeElements(); - tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), 0, 0, 0); + tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), "domain", 0, 0, 0); } std::map namedPaths = tmpTree->getNamedPaths(); @@ -5537,7 +5542,7 @@ bool Application::importEntities(const QString& urlOrFilename, const bool isObse // FIXME: readFromURL() can take over the main event loop which may cause problems, especially if downloading the JSON // from the Web. - success = _entityClipboard->readFromURL(urlOrFilename, isObservable, callerId); + success = _entityClipboard->readFromURL(urlOrFilename, isObservable, callerId, true); if (success) { _entityClipboard->reaverageOctreeElements(); } @@ -5545,8 +5550,8 @@ bool Application::importEntities(const QString& urlOrFilename, const bool isObse return success; } -QVector Application::pasteEntities(float x, float y, float z) { - return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), x, y, z); +QVector Application::pasteEntities(const QString& entityHostType, float x, float y, float z) { + return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), entityHostType, x, y, z); } void Application::init() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 684ff6bdaa..3d4e6873a8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -375,7 +375,7 @@ signals: void awayStateWhenFocusLostInVRChanged(bool enabled); public slots: - QVector pasteEntities(float x, float y, float z); + QVector pasteEntities(const QString& entityHostType, float x, float y, float z); bool exportEntities(const QString& filename, const QVector& entityIDs, const glm::vec3* givenOffset = nullptr); bool exportEntities(const QString& filename, float x, float y, float z, float scale); bool importEntities(const QString& url, const bool isObservable = true, const qint64 callerId = -1); @@ -425,6 +425,7 @@ public slots: #endif static void showHelp(); + static void gotoTutorial(); void cycleCamera(); void cameraModeChanged(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index a1bb670837..0ed5f67ea0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -816,6 +816,8 @@ Menu::Menu() { addActionToQMenuAndActionHash(helpMenu, "Controls Reference", 0, qApp, SLOT(showHelp())); + addActionToQMenuAndActionHash(helpMenu, "Tutorial", 0, qApp, SLOT(gotoTutorial())); + helpMenu->addSeparator(); // Help > Release Notes diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index db74b34d91..c145d40549 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -24,7 +24,7 @@ #include "ModelPropertiesDialog.h" #include "InterfaceLogging.h" -static const int MAX_TEXTURE_SIZE = 1024; +static const int MAX_TEXTURE_SIZE = 8192; void copyDirectoryContent(QDir& from, QDir& to) { for (auto entry : from.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index c0a6b64421..af7ac8165b 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -60,10 +60,11 @@ bool ClipboardScriptingInterface::importEntities( return retVal; } -QVector ClipboardScriptingInterface::pasteEntities(glm::vec3 position) { +QVector ClipboardScriptingInterface::pasteEntities(glm::vec3 position, const QString& entityHostType) { QVector retVal; BLOCKING_INVOKE_METHOD(qApp, "pasteEntities", Q_RETURN_ARG(QVector, retVal), + Q_ARG(const QString&, entityHostType), Q_ARG(float, position.x), Q_ARG(float, position.y), Q_ARG(float, position.z)); diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index 9e72d9ea15..9660b2158b 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -117,10 +117,11 @@ public: * Pastes the contents of the clipboard into the domain. * @function Clipboard.pasteEntities * @param {Vec3} position - The position to paste the clipboard contents at. + * @param {Entities.EntityHostType} [entityHostType="domain"] - The type of entities to create. * @returns {Uuid[]} The IDs of the new entities that were created as a result of the paste operation. If entities couldn't * be created then an empty array is returned. */ - Q_INVOKABLE QVector pasteEntities(glm::vec3 position); + Q_INVOKABLE QVector pasteEntities(glm::vec3 position, const QString& entityHostType = "domain"); }; #endif // hifi_ClipboardScriptingInterface_h diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 621323575f..2fd52ee036 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -26,6 +26,9 @@ static const int MAX_TARGET_MARKERS = 30; static const float JOINT_CHAIN_INTERP_TIME = 0.5f; +static QTime debounceJointWarningsClock; +static const int JOINT_WARNING_DEBOUNCE_TIME = 30000; // 30 seconds + static void lookupJointInfo(const AnimInverseKinematics::JointChainInfo& jointChainInfo, int indexA, int indexB, const AnimInverseKinematics::JointInfo** jointInfoA, @@ -91,6 +94,7 @@ AnimInverseKinematics::IKTargetVar::IKTargetVar(const IKTargetVar& orig) : } AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimNode::Type::InverseKinematics, id) { + debounceJointWarningsClock.start(); } AnimInverseKinematics::~AnimInverseKinematics() { @@ -158,6 +162,14 @@ void AnimInverseKinematics::setTargetVars(const QString& jointName, const QStrin } } +bool debounceJointWarnings() { + if (debounceJointWarningsClock.elapsed() >= JOINT_WARNING_DEBOUNCE_TIME) { + debounceJointWarningsClock.restart(); + return true; + } + return false; +} + void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::vector& targets, const AnimPoseVec& underPoses) { _hipsTargetIndex = -1; @@ -172,7 +184,7 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: if (jointIndex >= 0) { // this targetVar has a valid joint --> cache the indices targetVar.jointIndex = jointIndex; - } else { + } else if (debounceJointWarnings()) { qCWarning(animation) << "AnimInverseKinematics could not find jointName" << targetVar.jointName << "in skeleton"; } } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index f34eb85230..bc56781924 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -199,7 +199,7 @@ float importanceSample3DDimension(float startDim) { return dimension; } -ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties, +ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(const Transform& baseTransform, const particle::Properties& particleProperties, const ShapeType& shapeType, const GeometryResource::Pointer& geometryResource, const TriangleInfo& triangleInfo) { CpuParticle particle; @@ -217,7 +217,7 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa const auto& polarFinish = particleProperties.polar.finish; particle.seed = randFloatInRange(-1.0f, 1.0f); - particle.expiration = now + (uint64_t)(particleProperties.lifespan * USECS_PER_SECOND); + particle.expiration = (uint64_t)(particleProperties.lifespan * USECS_PER_SECOND); particle.relativePosition = glm::vec3(0.0f); particle.basePosition = baseTransform.getTranslation(); @@ -403,7 +403,7 @@ void ParticleEffectEntityRenderer::stepSimulation() { computeTriangles(geometryResource->getHFMModel()); } // emit particle - _cpuParticles.push_back(createParticle(now, modelTransform, particleProperties, shapeType, geometryResource, _triangleInfo)); + _cpuParticles.push_back(createParticle(modelTransform, particleProperties, shapeType, geometryResource, _triangleInfo)); _timeUntilNextEmit = emitInterval; if (emitInterval < timeRemaining) { timeRemaining -= emitInterval; @@ -415,7 +415,7 @@ void ParticleEffectEntityRenderer::stepSimulation() { } // Kill any particles that have expired or are over the max size - while (_cpuParticles.size() > particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration <= now)) { + while (_cpuParticles.size() > particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration == 0)) { _cpuParticles.pop_front(); } @@ -428,6 +428,7 @@ void ParticleEffectEntityRenderer::stepSimulation() { } particle.basePosition = modelTransform.getTranslation(); } + particle.expiration = particle.expiration >= interval ? particle.expiration - interval : 0; particle.integrate(deltaTime); } _prevEmitterShouldTrail = particleProperties.emission.shouldTrail; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index cc907f2b1d..8a3d8120f5 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -88,7 +88,7 @@ private: glm::mat4 transform; } _triangleInfo; - static CpuParticle createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties, + static CpuParticle createParticle(const Transform& baseTransform, const particle::Properties& particleProperties, const ShapeType& shapeType, const GeometryResource::Pointer& geometryResource, const TriangleInfo& triangleInfo); void stepSimulation(); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index e0f14b47e7..dae0922f4a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -2399,7 +2399,9 @@ signals: /**jsdoc - * Triggered when an avatar enters an entity, but only if the entity has an entity method exposed for this event. + * Triggered when an avatar enters an entity. + * Note: At the initial loading of the script, if the avatar is already present inside the entity, it might be too late + * to catch this event when the script runs, so it won't trigger. The {@link Entities.preload|preload} signal can be used to handle those cases. *

See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.

* @function Entities.enterEntity * @param {Uuid} entityID - The ID of the entity that the avatar entered. @@ -2408,7 +2410,7 @@ signals: void enterEntity(const EntityItemID& entityItemID); /**jsdoc - * Triggered when an avatar leaves an entity, but only if the entity has an entity method exposed for this event. + * Triggered when an avatar leaves an entity. *

See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.

* @function Entities.leaveEntity * @param {Uuid} entityID - The ID of the entity that the avatar left. diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 1ce19033e5..049a4b6229 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -537,7 +537,7 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti return true; } -EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool isClone) { +EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool isClone, const bool isImport) { EntityItemProperties props = properties; auto nodeList = DependencyManager::get(); @@ -548,7 +548,8 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti if (properties.getEntityHostType() == entity::HostType::DOMAIN && getIsClient() && !nodeList->getThisNodeCanRez() && !nodeList->getThisNodeCanRezTmp() && - !nodeList->getThisNodeCanRezCertified() && !nodeList->getThisNodeCanRezTmpCertified() && !_serverlessDomain && !isClone) { + !nodeList->getThisNodeCanRezCertified() && !nodeList->getThisNodeCanRezTmpCertified() && + !_serverlessDomain && !isClone && !isImport) { return nullptr; } @@ -2233,15 +2234,24 @@ void EntityTree::fixupNeedsParentFixups() { } entity->postParentFixup(); - } else if (getIsServer() || _avatarIDs.contains(entity->getParentID())) { - // this is a child of an avatar, which the entity server will never have - // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. - if (!_childrenOfAvatars.contains(entity->getParentID())) { - _childrenOfAvatars[entity->getParentID()] = QSet(); + } else { + bool needsUpdate = getIsServer(); + if (!needsUpdate) { + std::lock_guard lock(_avatarIDsLock); + needsUpdate = _avatarIDs.contains(entity->getParentID()); + } + + if (needsUpdate) { + std::lock_guard lock(_childrenOfAvatarsLock); + // this is a child of an avatar, which the entity server will never have + // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. + if (!_childrenOfAvatars.contains(entity->getParentID())) { + _childrenOfAvatars[entity->getParentID()] = QSet(); + } + _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); + doMove = true; + iter.remove(); // and pull it out of the list } - _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); - doMove = true; - iter.remove(); // and pull it out of the list } if (queryAACubeSuccess && doMove) { @@ -2261,8 +2271,19 @@ void EntityTree::fixupNeedsParentFixups() { } } -void EntityTree::deleteDescendantsOfAvatar(QUuid avatarID) { - QHash>::const_iterator itr = _childrenOfAvatars.constFind(avatarID); +void EntityTree::knowAvatarID(const QUuid& avatarID) { + std::lock_guard lock(_avatarIDsLock); + _avatarIDs += avatarID; +} + +void EntityTree::forgetAvatarID(const QUuid& avatarID) { + std::lock_guard lock(_avatarIDsLock); + _avatarIDs -= avatarID; +} + +void EntityTree::deleteDescendantsOfAvatar(const QUuid& avatarID) { + std::lock_guard lock(_childrenOfAvatarsLock); + auto itr = _childrenOfAvatars.find(avatarID); if (itr != _childrenOfAvatars.end()) { if (!itr.value().empty()) { std::vector ids; @@ -2280,8 +2301,10 @@ void EntityTree::deleteDescendantsOfAvatar(QUuid avatarID) { void EntityTree::removeFromChildrenOfAvatars(EntityItemPointer entity) { QUuid avatarID = entity->getParentID(); - if (_childrenOfAvatars.contains(avatarID)) { - _childrenOfAvatars[avatarID].remove(entity->getID()); + std::lock_guard lock(_childrenOfAvatarsLock); + auto itr = _childrenOfAvatars.find(avatarID); + if (itr != _childrenOfAvatars.end()) { + itr.value().remove(entity->getID()); } } @@ -2657,11 +2680,12 @@ QByteArray EntityTree::remapActionDataIDs(QByteArray actionData, QHash EntityTree::sendEntities(EntityEditPacketSender* packetSender, EntityTreePointer localTree, - float x, float y, float z) { + const QString& entityHostType, float x, float y, float z) { SendEntitiesOperationArgs args; args.ourTree = this; args.otherTree = localTree; args.root = glm::vec3(x, y, z); + args.entityHostType = entityHostType; // If this is called repeatedly (e.g., multiple pastes with the same data), the new elements will clash unless we // use new identifiers. We need to keep a map so that we can map parent identifiers correctly. QHash map; @@ -2751,6 +2775,11 @@ bool EntityTree::sendEntitiesOperation(const OctreeElementPointer& element, void EntityItemID newID = getMapped(oldID); EntityItemProperties properties = item->getProperties(); + properties.setEntityHostTypeFromString(args->entityHostType); + if (properties.getEntityHostType() == entity::HostType::AVATAR) { + properties.setOwningAvatarID(AVATAR_SELF_ID); + } + EntityItemID oldParentID = properties.getParentID(); if (oldParentID.isInvalidID()) { // no parent properties.setPosition(properties.getPosition() + args->root); @@ -2926,7 +2955,7 @@ void convertGrabUserDataToProperties(EntityItemProperties& properties) { } -bool EntityTree::readFromMap(QVariantMap& map) { +bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { // These are needed to deal with older content (before adding inheritance modes) int contentVersion = map["Version"].toInt(); @@ -3096,7 +3125,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { } } - EntityItemPointer entity = addEntity(entityItemID, properties); + EntityItemPointer entity = addEntity(entityItemID, properties, isImport); if (!entity) { qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); success = false; diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 2d5119d626..66e761f7a0 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -40,6 +40,7 @@ public: class SendEntitiesOperationArgs { public: glm::vec3 root; + QString entityHostType; EntityTree* ourTree; EntityTreePointer otherTree; QHash* map; @@ -117,7 +118,7 @@ public: // The newer API... void postAddEntity(EntityItemPointer entityItem); - EntityItemPointer addEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool isClone = false); + EntityItemPointer addEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool isClone = false, const bool isImport = false); // use this method if you only know the entityID bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode = SharedNodePointer(nullptr)); @@ -177,7 +178,7 @@ public: static QByteArray remapActionDataIDs(QByteArray actionData, QHash& map); QVector sendEntities(EntityEditPacketSender* packetSender, EntityTreePointer localTree, - float x, float y, float z); + const QString& entityHostType, float x, float y, float z); void entityChanged(EntityItemPointer entity); @@ -195,7 +196,7 @@ public: virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, bool skipThoseWithBadParents) override; - virtual bool readFromMap(QVariantMap& entityDescription) override; + virtual bool readFromMap(QVariantMap& entityDescription, const bool isImport = false) override; virtual bool writeToJSON(QString& jsonString, const OctreeElementPointer& element) override; @@ -239,9 +240,9 @@ public: Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name) const; Q_INVOKABLE QStringList getJointNames(const QUuid& entityID) const; - void knowAvatarID(QUuid avatarID) { _avatarIDs += avatarID; } - void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; } - void deleteDescendantsOfAvatar(QUuid avatarID); + void knowAvatarID(const QUuid& avatarID); + void forgetAvatarID(const QUuid& avatarID); + void deleteDescendantsOfAvatar(const QUuid& avatarID); void removeFromChildrenOfAvatars(EntityItemPointer entity); void addToNeedsParentFixupList(EntityItemPointer entity); @@ -364,8 +365,10 @@ protected: QVector _needsParentFixup; // entites with a parentID but no (yet) known parent instance mutable QReadWriteLock _needsParentFixupLock; + std::mutex _avatarIDsLock; // we maintain a list of avatarIDs to notice when an entity is a child of one. QSet _avatarIDs; // IDs of avatars connected to entity server + std::mutex _childrenOfAvatarsLock; QHash> _childrenOfAvatars; // which entities are children of which avatars float _maxTmpEntityLifetime { DEFAULT_MAX_TMP_ENTITY_LIFETIME }; diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index a7af5518a9..8234f2b17d 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -1055,6 +1055,11 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& int indicesAccessorIdx = primitive.indices; + if (indicesAccessorIdx > _file.accessors.size()) { + qWarning(modelformat) << "Indices accessor index is out of bounds for model " << _url; + continue; + } + GLTFAccessor& indicesAccessor = _file.accessors[indicesAccessorIdx]; // Buffers @@ -1093,6 +1098,11 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& foreach(auto &key, keys) { int accessorIdx = primitive.attributes.values[key]; + if (accessorIdx > _file.accessors.size()) { + qWarning(modelformat) << "Accessor index is out of bounds for model " << _url; + continue; + } + GLTFAccessor& accessor = _file.accessors[accessorIdx]; if (key == "POSITION") { @@ -1239,6 +1249,11 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& int v2_index = (indices[n + 1] * 3); int v3_index = (indices[n + 2] * 3); + if (v1_index + 2 >= vertices.size() || v2_index + 2 >= vertices.size() || v3_index + 2 >= vertices.size()) { + qWarning(modelformat) << "Indices out of range for model " << _url; + break; + } + glm::vec3 v1 = glm::vec3(vertices[v1_index], vertices[v1_index + 1], vertices[v1_index + 2]); glm::vec3 v2 = glm::vec3(vertices[v2_index], vertices[v2_index + 1], vertices[v2_index + 2]); glm::vec3 v3 = glm::vec3(vertices[v3_index], vertices[v3_index + 1], vertices[v3_index + 2]); @@ -1333,7 +1348,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } if (validatedIndices.size() == 0) { - qWarning(modelformat) << "Indices out of range for model " << _url; + qWarning(modelformat) << "No valid indices for model " << _url; continue; } diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index 7111ad2e65..d37d509d38 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -51,7 +51,7 @@ using ColorType = glm::vec3; #define HFM_COLOR_ELEMENT gpu::Element::VEC3F_XYZ #endif -const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048; +const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 8192 * 8192; using ShapeVertices = std::vector; diff --git a/libraries/image/src/image/TextureProcessing.cpp b/libraries/image/src/image/TextureProcessing.cpp index c144ed530a..53991ae431 100644 --- a/libraries/image/src/image/TextureProcessing.cpp +++ b/libraries/image/src/image/TextureProcessing.cpp @@ -41,7 +41,7 @@ using namespace gpu; static const glm::uvec2 SPARSE_PAGE_SIZE(128); static const glm::uvec2 MAX_TEXTURE_SIZE_GLES(2048); -static const glm::uvec2 MAX_TEXTURE_SIZE_GL(4096); +static const glm::uvec2 MAX_TEXTURE_SIZE_GL(8192); bool DEV_DECIMATE_TEXTURES = false; std::atomic DECIMATED_TEXTURE_COUNT{ 0 }; std::atomic RECTIFIED_TEXTURE_COUNT{ 0 }; diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 8bdb777f96..148c4f8580 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -249,8 +249,9 @@ public slots: * Takes you to a specified metaverse address. * @function location.handleLookupString * @param {string} address - The address to go to: a "hifi://" address, an IP address (e.g., - * "127.0.0.1" or "localhost"), a domain name, a named path on a domain (starts with - * "/"), a position or position and orientation, or a user (starts with "@"). + * "127.0.0.1" or "localhost"), a file:/// address, a domain name, a named path + * on a domain (starts with "/"), a position or position and orientation, or a user (starts with + * "@"). * @param {boolean} [fromSuggestions=false] - Set to true if the address is obtained from the "Goto" dialog. * Helps ensure that user's location history is correctly maintained. */ diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index aac0de27a1..897ac142bf 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -734,7 +734,8 @@ QString getMarketplaceID(const QString& urlString) { bool Octree::readFromURL( const QString& urlString, const bool isObservable, - const qint64 callerId + const qint64 callerId, + const bool isImport ) { QString trimmedUrl = urlString.trimmed(); QString marketplaceID = getMarketplaceID(trimmedUrl); @@ -766,7 +767,7 @@ bool Octree::readFromURL( } QDataStream inputStream(data); - return readFromStream(data.size(), inputStream, marketplaceID); + return readFromStream(data.size(), inputStream, marketplaceID, isImport); } bool Octree::readFromByteArray( @@ -791,7 +792,8 @@ bool Octree::readFromByteArray( bool Octree::readFromStream( uint64_t streamLength, QDataStream& inputStream, - const QString& marketplaceID + const QString& marketplaceID, + const bool isImport ) { // decide if this is binary SVO or JSON-formatted SVO QIODevice *device = inputStream.device(); @@ -804,7 +806,7 @@ bool Octree::readFromStream( return false; } else { qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength; - return readJSONFromStream(streamLength, inputStream, marketplaceID); + return readJSONFromStream(streamLength, inputStream, marketplaceID, isImport); } } @@ -834,7 +836,8 @@ const int READ_JSON_BUFFER_SIZE = 2048; bool Octree::readJSONFromStream( uint64_t streamLength, QDataStream& inputStream, - const QString& marketplaceID /*=""*/ + const QString& marketplaceID, /*=""*/ + const bool isImport ) { // if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until // we get an eof. Leave streamLength parameter for consistency. @@ -866,7 +869,7 @@ bool Octree::readJSONFromStream( addMarketplaceIDToDocumentEntities(asMap, marketplaceID); } - bool success = readFromMap(asMap); + bool success = readFromMap(asMap, isImport); delete[] rawData; return success; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 45dae3049d..a7885801de 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -216,13 +216,12 @@ public: // Octree importers bool readFromFile(const char* filename); - bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1); // will support file urls as well... + bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1, const bool isImport = false); // will support file urls as well... bool readFromByteArray(const QString& url, const QByteArray& byteArray); - bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID=""); - bool readSVOFromStream(uint64_t streamLength, QDataStream& inputStream); - bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID=""); + bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false); + bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false); bool readJSONFromGzippedFile(QString qFileName); - virtual bool readFromMap(QVariantMap& entityDescription) = 0; + virtual bool readFromMap(QVariantMap& entityDescription, const bool isImport = false) = 0; uint64_t getOctreeElementsCount(); diff --git a/libraries/shared/src/NumericalConstants.h b/libraries/shared/src/NumericalConstants.h index 8377c48960..b7fecfa1e4 100644 --- a/libraries/shared/src/NumericalConstants.h +++ b/libraries/shared/src/NumericalConstants.h @@ -28,8 +28,8 @@ const float ARCSECONDS_PER_ARCMINUTE = 60.0f; const float ARCSECONDS_PER_DEGREE = ARCMINUTES_PER_DEGREE * ARCSECONDS_PER_ARCMINUTE; const float EPSILON = 0.000001f; //smallish positive number - used as margin of error for some computations -const float SQUARE_ROOT_OF_2 = (float)sqrt(2.0f); -const float SQUARE_ROOT_OF_3 = (float)sqrt(3.0f); +const float SQUARE_ROOT_OF_2 = 1.414214f; +const float SQUARE_ROOT_OF_3 = 1.732051f; const float METERS_PER_DECIMETER = 0.1f; const float METERS_PER_CENTIMETER = 0.01f; const float METERS_PER_MILLIMETER = 0.001f; diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index e80b2215bf..9690ee3fb5 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -1,12 +1,13 @@ # # Created by Bradley Austin Davis on 2015/11/18 # Copyright 2015 High Fidelity, Inc. +# Copyright 2020 Vircadia contributors. # # 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 AND (NOT USE_GLES)) +if ((WIN32 OR UNIX AND NOT APPLE) AND NOT USE_GLES) set(TARGET_NAME openvr) setup_hifi_plugin(Gui Qml Multimedia) link_hifi_libraries(shared task gl qml networking controllers ui @@ -15,7 +16,9 @@ if (WIN32 AND (NOT USE_GLES)) include_hifi_library_headers(octree) target_openvr() - target_sranipal() - target_aristo() - target_link_libraries(${TARGET_NAME} Winmm.lib) + if (WIN32) + target_sranipal() + target_aristo() + target_link_libraries(${TARGET_NAME} Winmm.lib) + endif() endif() diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 7691d2ab70..c5eb740325 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -1,6 +1,7 @@ // // Created by Bradley Austin Davis on 2015/05/12 // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -739,6 +740,8 @@ int OpenVrDisplayPlugin::getRequiredThreadCount() const { QString OpenVrDisplayPlugin::getPreferredAudioInDevice() const { QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_RecordingDeviceOverride_String); + // FIXME: Address Linux. +#ifdef Q_OS_WIN if (!device.isEmpty()) { static const WCHAR INIT = 0; size_t size = device.size() + 1; @@ -748,11 +751,14 @@ QString OpenVrDisplayPlugin::getPreferredAudioInDevice() const { // FIXME: This may not be necessary if vr::k_pch_audio_RecordingDeviceOverride_StringName is used above. device = AudioClient::getWinDeviceName(deviceW.data()); } +#endif return device; } QString OpenVrDisplayPlugin::getPreferredAudioOutDevice() const { QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_PlaybackDeviceOverride_String); + // FIXME: Address Linux. +#ifdef Q_OS_WIN if (!device.isEmpty()) { static const WCHAR INIT = 0; size_t size = device.size() + 1; @@ -762,6 +768,7 @@ QString OpenVrDisplayPlugin::getPreferredAudioOutDevice() const { // FIXME: This may not be necessary if vr::k_pch_audio_PlaybackDeviceOverride_StringName is used above. device = AudioClient::getWinDeviceName(deviceW.data()); } +#endif return device; } diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index e55e7feaf4..ce7625eedb 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -1,6 +1,7 @@ // // Created by Bradley Austin Davis on 2015/11/01 // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -18,8 +19,6 @@ #include #include -#include -#include #include #include #include @@ -51,7 +50,7 @@ static const uint32_t RELEASE_OPENVR_HMD_DELAY_MS = 5000; bool isOculusPresent() { bool result = false; -#if defined(Q_OS_WIN32) +#ifdef Q_OS_WIN HANDLE oculusServiceEvent = ::OpenEventW(SYNCHRONIZE, FALSE, L"OculusHMDConnected"); // The existence of the service indicates a running Oculus runtime if (oculusServiceEvent) { @@ -208,8 +207,10 @@ void finishOpenVrKeyboardInput() { updateFromOpenVrKeyboardInput(); // Simulate an enter press on the top level window to trigger the action if (0 == (_currentHints & Qt::ImhMultiLine)) { - qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n"))); - qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyRelease, Qt::Key_Return, Qt::KeyboardModifiers())); + auto keyPress = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n")); + auto keyRelease = QKeyEvent(QEvent::KeyRelease, Qt::Key_Return, Qt::KeyboardModifiers()); + qApp->sendEvent(offscreenUi->getWindow(), &keyPress); + qApp->sendEvent(offscreenUi->getWindow(), &keyRelease); } } @@ -293,11 +294,20 @@ void handleOpenVrEvents() { ulong promitySensorFlag = (1UL << ((int)vr::k_EButton_ProximitySensor)); _headInHeadset = (controllerState.ulButtonPressed & promitySensorFlag) == promitySensorFlag; } - } #if DEV_BUILD - qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")"; + //qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")"; + // FIXME: Reinstate the line above and remove the following lines once the problem with excessive occurrences of + // VREvent_ActionBindingReloaded events is fixed in SteamVR for Linux. + // https://github.com/ValveSoftware/SteamVR-for-Linux/issues/307 + #ifdef Q_OS_LINUX + if (event.eventType != vr::VREvent_ActionBindingReloaded) { + qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")"; + }; + #else + qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")"; + #endif #endif } @@ -407,9 +417,32 @@ void showMinSpecWarning() { qFatal("Unable to create overlay"); } - // Needed here for PathUtils +#ifdef Q_OS_LINUX + QFile cmdlineFile("/proc/self/cmdline"); + if (!cmdlineFile.open(QIODevice::ReadOnly)) { + qFatal("Unable to open /proc/self/cmdline"); + } + + auto contents = cmdlineFile.readAll(); + auto arguments = contents.split('\0'); + arguments.pop_back(); // Last element is empty. + cmdlineFile.close(); + + int __argc = arguments.count(); + char** __argv = new char* [__argc]; + for (int i = 0; i < __argc; i++) { + __argv[i] = arguments[i].data(); + } +#endif + QCoreApplication miniApp(__argc, __argv); +#ifdef Q_OS_LINUX + QObject::connect(&miniApp, &QCoreApplication::destroyed, [=] { + delete[] __argv; + }); +#endif + vrSystem->ResetSeatedZeroPose(); QString imagePath = PathUtils::resourcesPath() + "/images/steam-min-spec-failed.png"; vrOverlay->SetOverlayFromFile(minSpecFailedOverlay, imagePath.toLocal8Bit().toStdString().c_str()); @@ -487,7 +520,12 @@ bool checkMinSpecImpl() { } extern "C" { +#if defined(Q_OS_WIN32) __declspec(dllexport) int __stdcall CheckMinSpec() { +#else + __attribute__((visibility("default"))) int CheckMinSpec() { +#endif return checkMinSpecImpl() ? 1 : 0; } + } diff --git a/plugins/openvr/src/OpenVrHelpers.h b/plugins/openvr/src/OpenVrHelpers.h index b0960a03eb..23bd9f39de 100644 --- a/plugins/openvr/src/OpenVrHelpers.h +++ b/plugins/openvr/src/OpenVrHelpers.h @@ -1,6 +1,7 @@ // // Created by Bradley Austin Davis on 2015/06/12 // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -76,7 +77,7 @@ struct PoseData { } void update(const glm::mat4& resetMat) { - for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { + for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { if (!vrPoses[i].bPoseIsValid) { continue; } @@ -87,7 +88,7 @@ struct PoseData { } void resetToInvalid() { - for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { + for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { vrPoses[i].bPoseIsValid = false; } } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 2afdd10403..3629698e11 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -1,6 +1,5 @@ // // ViveControllerManager.cpp -// input-plugins/src/input-plugins // // Created by Sam Gondelman on 6/29/15. // Copyright 2013 High Fidelity, Inc. @@ -20,10 +19,12 @@ #pragma warning( disable : 4334 ) #endif +#ifdef VIVE_PRO_EYE #include #include #include #include +#endif #ifdef _WIN32 #pragma warning( pop ) @@ -50,7 +51,7 @@ #include #include -#include +#include #include #include "OpenVrDisplayPlugin.h" @@ -61,13 +62,8 @@ vr::IVRSystem* acquireOpenVrSystem(); void releaseOpenVrSystem(); static const QString OPENVR_LAYOUT = QString("OpenVrConfiguration.qml"); -static const char* CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; const quint64 CALIBRATION_TIMELAPSE = 1 * USECS_PER_SECOND; -static const char* MENU_PARENT = "Avatar"; -static const char* MENU_NAME = "Vive Controllers"; -static const char* MENU_PATH = "Avatar" ">" "Vive Controllers"; - static const int MIN_HEAD = 1; static const int MIN_PUCK_COUNT = 2; static const int MIN_FEET_AND_HIPS = 3; @@ -80,6 +76,7 @@ static const int SECOND_FOOT = 1; static const int HIP = 2; static const int CHEST = 3; +#ifdef VIVE_PRO_EYE enum ViveHandJointIndex { HAND = 0, THUMB_1, @@ -105,6 +102,7 @@ enum ViveHandJointIndex { Size }; +#endif const char* ViveControllerManager::NAME { "OpenVR" }; @@ -158,22 +156,7 @@ static QString deviceTrackingResultToString(vr::ETrackingResult trackingResult) return result; } -static glm::mat4 calculateResetMat() { - auto chaperone = vr::VRChaperone(); - if (chaperone) { - float const UI_RADIUS = 1.0f; - float const UI_HEIGHT = 1.6f; - float const UI_Z_OFFSET = 0.5; - - float xSize, zSize; - chaperone->GetPlayAreaSize(&xSize, &zSize); - glm::vec3 uiPos(0.0f, UI_HEIGHT, UI_RADIUS - (0.5f * zSize) - UI_Z_OFFSET); - - return glm::inverse(createMatFromQuatAndPos(glm::quat(), uiPos)); - } - return glm::mat4(); -} - +#ifdef VIVE_PRO_EYE class ViveProEyeReadThread : public QThread { public: ViveProEyeReadThread() { @@ -217,6 +200,7 @@ public: QMutex eyeDataMutex; EyeDataBuffer eyeDataBuffer; }; +#endif static QString outOfRangeDataStrategyToString(ViveControllerManager::OutOfRangeDataStrategy strategy) { @@ -334,7 +318,7 @@ bool areBothHandControllersActive(vr::IVRSystem*& system) { isHandControllerActive(system, vr::TrackedControllerRole_RightHand); } - +#ifdef VIVE_PRO_EYE void ViveControllerManager::enableGestureDetection() { if (_viveCameraHandTracker) { return; @@ -379,6 +363,7 @@ void ViveControllerManager::disableGestureDetection() { StopGestureDetection(); _viveCameraHandTracker = false; } +#endif bool ViveControllerManager::activate() { InputPlugin::activate(); @@ -400,6 +385,7 @@ bool ViveControllerManager::activate() { userInputMapper->registerDevice(_inputDevice); _registeredWithInputMapper = true; +#ifdef VIVE_PRO_EYE if (ViveSR::anipal::Eye::IsViveProEye()) { qDebug() << "Vive Pro eye-tracking detected"; @@ -420,6 +406,7 @@ bool ViveControllerManager::activate() { _viveProEyeReadThread->start(QThread::HighPriority); } } +#endif return true; } @@ -442,12 +429,14 @@ void ViveControllerManager::deactivate() { userInputMapper->removeDevice(_inputDevice->_deviceID); _registeredWithInputMapper = false; +#ifdef VIVE_PRO_EYE if (_viveProEyeReadThread) { _viveProEyeReadThread->quit = true; _viveProEyeReadThread->wait(); _viveProEyeReadThread = nullptr; ViveSR::anipal::Release(ViveSR::anipal::Eye::ANIPAL_TYPE_EYE); } +#endif saveSettings(); } @@ -460,6 +449,7 @@ bool ViveControllerManager::isHeadControllerMounted() const { return activityLevel == vr::k_EDeviceActivityLevel_UserInteraction; } +#ifdef VIVE_PRO_EYE void ViveControllerManager::invalidateEyeInputs() { _inputDevice->_poseStateMap[controller::LEFT_EYE].valid = false; _inputDevice->_poseStateMap[controller::RIGHT_EYE].valid = false; @@ -467,7 +457,6 @@ void ViveControllerManager::invalidateEyeInputs() { _inputDevice->_axisStateMap[controller::EYEBLINK_R].valid = false; } - void ViveControllerManager::updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { if (!isHeadControllerMounted()) { invalidateEyeInputs(); @@ -769,6 +758,7 @@ void ViveControllerManager::updateCameraHandTracker(float deltaTime, } _lastHandTrackerFrameIndex = handTrackerFrameIndex; } +#endif void ViveControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { @@ -807,11 +797,14 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu _registeredWithInputMapper = true; } +#ifdef VIVE_PRO_EYE if (_viveProEye && _eyeTrackingEnabled) { updateEyeTracker(deltaTime, inputCalibrationData); } updateCameraHandTracker(deltaTime, inputCalibrationData); +#endif + } void ViveControllerManager::loadSettings() { @@ -893,7 +886,7 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false); // collect poses for all generic trackers - for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { + for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { handleTrackedObject(i, inputCalibrationData); handleHmd(i, inputCalibrationData); } @@ -968,8 +961,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso bool overrideHead = headObject["override"].toBool(); if (overrideHead) { _headConfig = HeadConfig::Puck; - _headPuckYOffset = headObject["Y"].toDouble() * CM_TO_M; - _headPuckZOffset = headObject["Z"].toDouble() * CM_TO_M; + _headPuckYOffset = (float)headObject["Y"].toDouble() * CM_TO_M; + _headPuckZOffset = (float)headObject["Z"].toDouble() * CM_TO_M; } else { _headConfig = HeadConfig::HMD; } @@ -978,8 +971,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso bool overrideHands = handsObject["override"].toBool(); if (overrideHands) { _handConfig = HandConfig::Pucks; - _handPuckYOffset = handsObject["Y"].toDouble() * CM_TO_M; - _handPuckZOffset = handsObject["Z"].toDouble() * CM_TO_M; + _handPuckYOffset = (float)handsObject["Y"].toDouble() * CM_TO_M; + _handPuckZOffset = (float)handsObject["Z"].toDouble() * CM_TO_M; } else { _handConfig = HandConfig::HandController; } @@ -1013,8 +1006,8 @@ QJsonObject ViveControllerManager::InputDevice::configurationSettings() { configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD); configurationSettings["handController"] = (_handConfig == HandConfig::HandController); configurationSettings["puckCount"] = (int)_validTrackedObjects.size(); - configurationSettings["armCircumference"] = (double)_armCircumference * M_TO_CM; - configurationSettings["shoulderWidth"] = (double)_shoulderWidth * M_TO_CM; + configurationSettings["armCircumference"] = (double)(_armCircumference * M_TO_CM); + configurationSettings["shoulderWidth"] = (double)(_shoulderWidth * M_TO_CM); configurationSettings["outOfRangeDataStrategy"] = outOfRangeDataStrategyToString(_outOfRangeDataStrategy); return configurationSettings; } @@ -1231,8 +1224,6 @@ bool ViveControllerManager::InputDevice::configureHead(const glm::mat4& defaultT bool ViveControllerManager::InputDevice::configureBody(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition); int puckCount = (int)_validTrackedObjects.size(); - glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); - glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); if (_config == Config::None) { return true; } else if (_config == Config::Feet && puckCount >= MIN_PUCK_COUNT) { @@ -1330,8 +1321,6 @@ controller::Pose ViveControllerManager::InputDevice::addOffsetToPuckPose(const c } void ViveControllerManager::InputDevice::handleHmd(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) { - uint32_t poseIndex = controller::TRACKED_OBJECT_00 + deviceIndex; - if (_system->IsTrackedDeviceConnected(deviceIndex) && _system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_HMD && _nextSimPoseData.vrPoses[deviceIndex].bPoseIsValid) { @@ -1505,11 +1494,11 @@ void ViveControllerManager::InputDevice::printDeviceTrackingResultChange(uint32_ } bool ViveControllerManager::InputDevice::checkForCalibrationEvent() { - auto& endOfMap = _buttonPressedMap.end(); - auto& leftTrigger = _buttonPressedMap.find(controller::LT); - auto& rightTrigger = _buttonPressedMap.find(controller::RT); - auto& leftAppButton = _buttonPressedMap.find(LEFT_APP_MENU); - auto& rightAppButton = _buttonPressedMap.find(RIGHT_APP_MENU); + auto endOfMap = _buttonPressedMap.end(); + auto leftTrigger = _buttonPressedMap.find(controller::LT); + auto rightTrigger = _buttonPressedMap.find(controller::RT); + auto leftAppButton = _buttonPressedMap.find(LEFT_APP_MENU); + auto rightAppButton = _buttonPressedMap.find(RIGHT_APP_MENU); return ((leftTrigger != endOfMap && leftAppButton != endOfMap) && (rightTrigger != endOfMap && rightAppButton != endOfMap)); } @@ -1860,10 +1849,74 @@ void ViveControllerManager::InputDevice::setConfigFromString(const QString& valu * Hipsnumber{@link Pose}Hips pose. * Spine2number{@link Pose}Spine2 pose. * Headnumber{@link Pose}Head pose. + * LeftEyenumber{@link Pose}Left eye pose. + * RightEyenumber{@link Pose}Right eye pose. + * EyeBlink_LnumbernumberLeft eyelid blink. + * EyeBlink_RnumbernumberRight eyelid blink. * LeftArmnumber{@link Pose}Left arm pose. * RightArmnumber{@link Pose}Right arm pose * LeftHandnumber{@link Pose}Left hand pose. + * LeftHandThumb1number{@link Pose}Left thumb 1 finger joint pose. + * LeftHandThumb2number{@link Pose}Left thumb 2 finger joint pose. + * LeftHandThumb3number{@link Pose}Left thumb 3 finger joint pose. + * LeftHandThumb4number{@link Pose}Left thumb 4 finger joint pose. + * LeftHandIndex1number{@link Pose}Left index 1 finger joint pose. + * LeftHandIndex2number{@link Pose}Left index 2 finger joint pose. + * LeftHandIndex3number{@link Pose}Left index 3 finger joint pose. + * LeftHandIndex4number{@link Pose}Left index 4 finger joint pose. + * LeftHandMiddle1number{@link Pose}Left middle 1 finger joint pose. + * + * LeftHandMiddle2number{@link Pose}Left middle 2 finger joint pose. + * + * LeftHandMiddle3number{@link Pose}Left middle 3 finger joint pose. + * + * LeftHandMiddle4number{@link Pose}Left middle 4 finger joint pose. + * + * LeftHandRing1number{@link Pose}Left ring 1 finger joint pose. + * LeftHandRing2number{@link Pose}Left ring 2 finger joint pose. + * LeftHandRing3number{@link Pose}Left ring 3 finger joint pose. + * LeftHandRing4number{@link Pose}Left ring 4 finger joint pose. + * LeftHandPinky1number{@link Pose}Left pinky 1 finger joint pose. + * LeftHandPinky2number{@link Pose}Left pinky 2 finger joint pose. + * LeftHandPinky3number{@link Pose}Left pinky 3 finger joint pose. + * LeftHandPinky4number{@link Pose}Left pinky 4 finger joint pose. * RightHandnumber{@link Pose}Right hand pose. + * RightHandThumb1number{@link Pose}Right thumb 1 finger joint pose. + * + * RightHandThumb2number{@link Pose}Right thumb 2 finger joint pose. + * + * RightHandThumb3number{@link Pose}Right thumb 3 finger joint pose. + * + * RightHandThumb4number{@link Pose}Right thumb 4 finger joint pose. + * + * RightHandIndex1number{@link Pose}Right index 1 finger joint pose. + * + * RightHandIndex2number{@link Pose}Right index 2 finger joint pose. + * + * RightHandIndex3number{@link Pose}Right index 3 finger joint pose. + * + * RightHandIndex4number{@link Pose}Right index 4 finger joint pose. + * + * RightHandMiddle1number{@link Pose}Right middle 1 finger joint pose. + * + * RightHandMiddle2number{@link Pose}Right middle 2 finger joint pose. + * + * RightHandMiddle3number{@link Pose}Right middle 3 finger joint pose. + * + * RightHandMiddle4number{@link Pose}Right middle 4 finger joint pose. + * + * RightHandRing1number{@link Pose}Right ring 1 finger joint pose. + * RightHandRing2number{@link Pose}Right ring 2 finger joint pose. + * RightHandRing3number{@link Pose}Right ring 3 finger joint pose. + * RightHandRing4number{@link Pose}Right ring 4 finger joint pose. + * RightHandPinky1number{@link Pose}Right pinky 1 finger joint pose. + * + * RightHandPinky2number{@link Pose}Right pinky 2 finger joint pose. + * + * RightHandPinky3number{@link Pose}Right pinky 3 finger joint pose. + * + * RightHandPinky4number{@link Pose}Right pinky 4 finger joint pose. + * * Trackers * TrackedObject00number{@link Pose}Tracker 0 pose. * TrackedObject01number{@link Pose}Tracker 1 pose. diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 687d1f25d9..83de8176cc 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -1,6 +1,5 @@ // // ViveControllerManager.h -// input-plugins/src/input-plugins // // Created by Sam Gondelman on 6/29/15. // Copyright 2013 High Fidelity, Inc. @@ -26,12 +25,18 @@ #include #include "OpenVrHelpers.h" +#ifdef Q_OS_WIN +#define VIVE_PRO_EYE +#endif + using PuckPosePair = std::pair; namespace vr { class IVRSystem; } + +#ifdef VIVE_PRO_EYE class ViveProEyeReadThread; class EyeDataBuffer { @@ -46,7 +51,7 @@ public: float leftEyeOpenness { 0.0f }; float rightEyeOpenness { 0.0f }; }; - +#endif class ViveControllerManager : public InputPlugin { @@ -67,18 +72,22 @@ public: bool isHeadController() const override { return true; } bool isHeadControllerMounted() const; +#ifdef VIVE_PRO_EYE void enableGestureDetection(); void disableGestureDetection(); +#endif bool activate() override; void deactivate() override; - QString getDeviceName() { return QString::fromStdString(_inputDevice->_headsetName); } + QString getDeviceName() override { return QString::fromStdString(_inputDevice->_headsetName); } void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } +#ifdef VIVE_PRO_EYE void invalidateEyeInputs(); void updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData); void updateCameraHandTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData); +#endif void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; virtual void saveSettings() const override; @@ -253,6 +262,7 @@ private: vr::IVRSystem* _system { nullptr }; std::shared_ptr _inputDevice { std::make_shared(_system) }; +#ifdef VIVE_PRO_EYE bool _viveProEye { false }; bool _eyeTrackingEnabled { false }; std::shared_ptr _viveProEyeReadThread; @@ -270,6 +280,7 @@ private: void trackFinger(int hand, int jointIndex1, int jointIndex2, int jointIndex3, int jointIndex4, controller::StandardPoseChannel joint1, controller::StandardPoseChannel joint2, controller::StandardPoseChannel joint3, controller::StandardPoseChannel joint4); +#endif static const char* NAME; }; diff --git a/scripts/communityModules/chat/FloofChat.html b/scripts/communityScripts/chat/FloofChat.html similarity index 80% rename from scripts/communityModules/chat/FloofChat.html rename to scripts/communityScripts/chat/FloofChat.html index a1e84e132f..7baac63455 100644 --- a/scripts/communityModules/chat/FloofChat.html +++ b/scripts/communityScripts/chat/FloofChat.html @@ -12,6 +12,7 @@ + @@ -28,11 +29,19 @@
+ +
+ +
@@ -46,6 +55,7 @@