mirror of
https://github.com/lubosz/overte.git
synced 2025-04-07 09:22:42 +02:00
Merge branch 'master' into feature/eye-tracking-option
# Conflicts: # plugins/openvr/src/ViveControllerManager.cpp
This commit is contained in:
commit
8dd8ebcbaf
45 changed files with 753 additions and 404 deletions
14
BUILD.md
14
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.
|
||||
|
||||
|
||||
|
|
19
BUILD_OSX.md
19
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.
|
||||
|
|
|
@ -370,16 +370,18 @@ void EntityServer::entityFilterAdded(EntityItemID id, bool success) {
|
|||
|
||||
void EntityServer::nodeAdded(SharedNodePointer node) {
|
||||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_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<EntityTree>(_tree);
|
||||
tree->withWriteLock([&] {
|
||||
if (tree) {
|
||||
tree->deleteDescendantsOfAvatar(node->getUUID());
|
||||
});
|
||||
tree->forgetAvatarID(node->getUUID());
|
||||
tree->forgetAvatarID(node->getUUID());
|
||||
}
|
||||
OctreeServer::nodeKilled(node);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -247,7 +247,7 @@
|
|||
"name": "standard_permissions",
|
||||
"type": "table",
|
||||
"label": "Domain-Wide User Permissions",
|
||||
"help": "Indicate which types of users can have which <a data-toggle='tooltip' data-html=true title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>domain-wide permissions</a>.",
|
||||
"help": "Indicate which types of users can have which <a data-toggle='tooltip' data-html=true title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>domain-wide permissions</a>.",
|
||||
"caption": "Standard Permissions",
|
||||
"can_add_new_rows": false,
|
||||
"groups": [
|
||||
|
@ -256,7 +256,7 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>?</a>",
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>?</a>",
|
||||
"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 <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in, as well as permissions from the previous section. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in, as well as permissions from the previous section. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"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 <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users in specific groups can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users in specific groups can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"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 <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level or group permissions that might otherwise apply to that user.</p>'>?</a>",
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level or group permissions that might otherwise apply to that user.</p>'>?</a>",
|
||||
"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 <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide IP Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users from specific IPs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific IPs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users from specific IPs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users from specific IPs can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users from specific IPs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users from specific IPs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users from specific IPs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users from specific IPs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users from specific IPs can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific IP will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). IP address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide IP Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users from specific IPs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific IPs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users from specific IPs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users from specific IPs can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users from specific IPs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users from specific IPs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users from specific IPs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users from specific IPs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users from specific IPs can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific IP will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). IP address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"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 <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide MAC Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific MACs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific MACs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific MACs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific MACs can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific MACs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific MACs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific MACs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific MACs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific MACs can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific MAC will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). MAC address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide MAC Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific MACs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific MACs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific MACs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific MACs can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific MACs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific MACs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific MACs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific MACs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific MACs can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific MAC will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). MAC address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"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 <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide Machine Fingerprint Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific Machine Fingerprints can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific Machine Fingerprints can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific Machine Fingerprints can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific Machine Fingerprints can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific Machine Fingerprints can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific Machine Fingerprints can replace entire content sets by wiping existing domain content.</li><li><strong>Can Get and Set Private User Data</strong><br>Sets whether a user can get and set the Private User Data entity property</li></ul><p>Note that permissions assigned to a specific Machine Fingerprint will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). Machine Fingerprint address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide Machine Fingerprint Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific Machine Fingerprints can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific Machine Fingerprints can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific Machine Fingerprints can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific Machine Fingerprints can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific Machine Fingerprints can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific Machine Fingerprints can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific Machine Fingerprint will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). Machine Fingerprint address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"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
|
||||
|
|
|
@ -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'
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<AddressManager>()->handleLookupString(TUTORIAL_ADDRESS);
|
||||
}
|
||||
|
||||
void Application::resizeEvent(QResizeEvent* event) {
|
||||
resizeGL();
|
||||
}
|
||||
|
@ -4065,7 +4070,7 @@ std::map<QString, QString> 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<QString, QString> 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<EntityItemID> Application::pasteEntities(float x, float y, float z) {
|
||||
return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), x, y, z);
|
||||
QVector<EntityItemID> Application::pasteEntities(const QString& entityHostType, float x, float y, float z) {
|
||||
return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), entityHostType, x, y, z);
|
||||
}
|
||||
|
||||
void Application::init() {
|
||||
|
|
|
@ -375,7 +375,7 @@ signals:
|
|||
void awayStateWhenFocusLostInVRChanged(bool enabled);
|
||||
|
||||
public slots:
|
||||
QVector<EntityItemID> pasteEntities(float x, float y, float z);
|
||||
QVector<EntityItemID> pasteEntities(const QString& entityHostType, float x, float y, float z);
|
||||
bool exportEntities(const QString& filename, const QVector<QUuid>& 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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -60,10 +60,11 @@ bool ClipboardScriptingInterface::importEntities(
|
|||
return retVal;
|
||||
}
|
||||
|
||||
QVector<EntityItemID> ClipboardScriptingInterface::pasteEntities(glm::vec3 position) {
|
||||
QVector<EntityItemID> ClipboardScriptingInterface::pasteEntities(glm::vec3 position, const QString& entityHostType) {
|
||||
QVector<EntityItemID> retVal;
|
||||
BLOCKING_INVOKE_METHOD(qApp, "pasteEntities",
|
||||
Q_RETURN_ARG(QVector<EntityItemID>, retVal),
|
||||
Q_ARG(const QString&, entityHostType),
|
||||
Q_ARG(float, position.x),
|
||||
Q_ARG(float, position.y),
|
||||
Q_ARG(float, position.z));
|
||||
|
|
|
@ -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<EntityItemID> pasteEntities(glm::vec3 position);
|
||||
Q_INVOKABLE QVector<EntityItemID> pasteEntities(glm::vec3 position, const QString& entityHostType = "domain");
|
||||
};
|
||||
|
||||
#endif // hifi_ClipboardScriptingInterface_h
|
||||
|
|
|
@ -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<IKTarget>& 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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
|
||||
* @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.
|
||||
* <p>See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.</p>
|
||||
* @function Entities.leaveEntity
|
||||
* @param {Uuid} entityID - The ID of the entity that the avatar left.
|
||||
|
|
|
@ -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<NodeList>();
|
||||
|
@ -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<EntityItemID>();
|
||||
} else {
|
||||
bool needsUpdate = getIsServer();
|
||||
if (!needsUpdate) {
|
||||
std::lock_guard<std::mutex> lock(_avatarIDsLock);
|
||||
needsUpdate = _avatarIDs.contains(entity->getParentID());
|
||||
}
|
||||
|
||||
if (needsUpdate) {
|
||||
std::lock_guard<std::mutex> 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<EntityItemID>();
|
||||
}
|
||||
_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<QUuid, QSet<EntityItemID>>::const_iterator itr = _childrenOfAvatars.constFind(avatarID);
|
||||
void EntityTree::knowAvatarID(const QUuid& avatarID) {
|
||||
std::lock_guard<std::mutex> lock(_avatarIDsLock);
|
||||
_avatarIDs += avatarID;
|
||||
}
|
||||
|
||||
void EntityTree::forgetAvatarID(const QUuid& avatarID) {
|
||||
std::lock_guard<std::mutex> lock(_avatarIDsLock);
|
||||
_avatarIDs -= avatarID;
|
||||
}
|
||||
|
||||
void EntityTree::deleteDescendantsOfAvatar(const QUuid& avatarID) {
|
||||
std::lock_guard<std::mutex> lock(_childrenOfAvatarsLock);
|
||||
auto itr = _childrenOfAvatars.find(avatarID);
|
||||
if (itr != _childrenOfAvatars.end()) {
|
||||
if (!itr.value().empty()) {
|
||||
std::vector<EntityItemID> 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<std::mutex> 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<EntityIte
|
|||
}
|
||||
|
||||
QVector<EntityItemID> 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<EntityItemID, EntityItemID> 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;
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
class SendEntitiesOperationArgs {
|
||||
public:
|
||||
glm::vec3 root;
|
||||
QString entityHostType;
|
||||
EntityTree* ourTree;
|
||||
EntityTreePointer otherTree;
|
||||
QHash<EntityItemID, EntityItemID>* 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<EntityItemID, EntityItemID>& map);
|
||||
|
||||
QVector<EntityItemID> 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<EntityItemWeakPointer> _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<QUuid> _avatarIDs; // IDs of avatars connected to entity server
|
||||
std::mutex _childrenOfAvatarsLock;
|
||||
QHash<QUuid, QSet<EntityItemID>> _childrenOfAvatars; // which entities are children of which avatars
|
||||
|
||||
float _maxTmpEntityLifetime { DEFAULT_MAX_TMP_ENTITY_LIFETIME };
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<glm::vec3>;
|
||||
|
|
|
@ -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<size_t> DECIMATED_TEXTURE_COUNT{ 0 };
|
||||
std::atomic<size_t> RECTIFIED_TEXTURE_COUNT{ 0 };
|
||||
|
|
|
@ -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 <code>"hifi://"</code> address, an IP address (e.g.,
|
||||
* <code>"127.0.0.1"</code> or <code>"localhost"</code>), a domain name, a named path on a domain (starts with
|
||||
* <code>"/"</code>), a position or position and orientation, or a user (starts with <code>"@"</code>).
|
||||
* <code>"127.0.0.1"</code> or <code>"localhost"</code>), a <code>file:///</code> address, a domain name, a named path
|
||||
* on a domain (starts with <code>"/"</code>), a position or position and orientation, or a user (starts with
|
||||
* <code>"@"</code>).
|
||||
* @param {boolean} [fromSuggestions=false] - Set to <code>true</code> if the address is obtained from the "Goto" dialog.
|
||||
* Helps ensure that user's location history is correctly maintained.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <QtGui/QInputMethodEvent>
|
||||
#include <QtQuick/QQuickWindow>
|
||||
|
||||
#include <PathUtils.h>
|
||||
#include <Windows.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <controllers/Pose.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <SRanipal.h>
|
||||
#include <SRanipal_Eye.h>
|
||||
#include <SRanipal_Enums.h>
|
||||
#include <interface_gesture.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning( pop )
|
||||
|
@ -50,7 +51,7 @@
|
|||
#include <plugins/DisplayPlugin.h>
|
||||
|
||||
#include <controllers/UserInputMapper.h>
|
||||
#include <Plugins/InputConfiguration.h>
|
||||
#include <plugins/InputConfiguration.h>
|
||||
#include <controllers/StandardControls.h>
|
||||
|
||||
#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
|
|||
* <tr><td><code>Hips</code></td><td>number</td><td>{@link Pose}</td><td>Hips pose.</td></tr>
|
||||
* <tr><td><code>Spine2</code></td><td>number</td><td>{@link Pose}</td><td>Spine2 pose.</td></tr>
|
||||
* <tr><td><code>Head</code></td><td>number</td><td>{@link Pose}</td><td>Head pose.</td></tr>
|
||||
* <tr><td><code>LeftEye</code></td><td>number</td><td>{@link Pose}</td><td>Left eye pose.</td></tr>
|
||||
* <tr><td><code>RightEye</code></td><td>number</td><td>{@link Pose}</td><td>Right eye pose.</td></tr>
|
||||
* <tr><td><code>EyeBlink_L</code></td><td>number</td><td>number</td><td>Left eyelid blink.</td></tr>
|
||||
* <tr><td><code>EyeBlink_R</code></td><td>number</td><td>number</td><td>Right eyelid blink.</td></tr>
|
||||
* <tr><td><code>LeftArm</code></td><td>number</td><td>{@link Pose}</td><td>Left arm pose.</td></tr>
|
||||
* <tr><td><code>RightArm</code></td><td>number</td><td>{@link Pose}</td><td>Right arm pose</td></tr>
|
||||
* <tr><td><code>LeftHand</code></td><td>number</td><td>{@link Pose}</td><td>Left hand pose.</td></tr>
|
||||
* <tr><td><code>LeftHandThumb1</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 1 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandThumb2</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 2 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandThumb3</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 3 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandThumb4</code></td><td>number</td><td>{@link Pose}</td><td>Left thumb 4 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandIndex1</code></td><td>number</td><td>{@link Pose}</td><td>Left index 1 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandIndex2</code></td><td>number</td><td>{@link Pose}</td><td>Left index 2 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandIndex3</code></td><td>number</td><td>{@link Pose}</td><td>Left index 3 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandIndex4</code></td><td>number</td><td>{@link Pose}</td><td>Left index 4 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandMiddle1</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 1 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>LeftHandMiddle2</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 2 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>LeftHandMiddle3</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 3 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>LeftHandMiddle4</code></td><td>number</td><td>{@link Pose}</td><td>Left middle 4 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>LeftHandRing1</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 1 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandRing2</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 2 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandRing3</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 3 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandRing4</code></td><td>number</td><td>{@link Pose}</td><td>Left ring 4 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandPinky1</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 1 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandPinky2</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 2 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandPinky3</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 3 finger joint pose.</td></tr>
|
||||
* <tr><td><code>LeftHandPinky4</code></td><td>number</td><td>{@link Pose}</td><td>Left pinky 4 finger joint pose.</td></tr>
|
||||
* <tr><td><code>RightHand</code></td><td>number</td><td>{@link Pose}</td><td>Right hand pose.</td></tr>
|
||||
* <tr><td><code>RightHandThumb1</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 1 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandThumb2</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 2 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandThumb3</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 3 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandThumb4</code></td><td>number</td><td>{@link Pose}</td><td>Right thumb 4 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandIndex1</code></td><td>number</td><td>{@link Pose}</td><td>Right index 1 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandIndex2</code></td><td>number</td><td>{@link Pose}</td><td>Right index 2 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandIndex3</code></td><td>number</td><td>{@link Pose}</td><td>Right index 3 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandIndex4</code></td><td>number</td><td>{@link Pose}</td><td>Right index 4 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandMiddle1</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 1 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandMiddle2</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 2 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandMiddle3</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 3 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandMiddle4</code></td><td>number</td><td>{@link Pose}</td><td>Right middle 4 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandRing1</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 1 finger joint pose.</td></tr>
|
||||
* <tr><td><code>RightHandRing2</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 2 finger joint pose.</td></tr>
|
||||
* <tr><td><code>RightHandRing3</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 3 finger joint pose.</td></tr>
|
||||
* <tr><td><code>RightHandRing4</code></td><td>number</td><td>{@link Pose}</td><td>Right ring 4 finger joint pose.</td></tr>
|
||||
* <tr><td><code>RightHandPinky1</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 1 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandPinky2</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 2 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandPinky3</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 3 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td><code>RightHandPinky4</code></td><td>number</td><td>{@link Pose}</td><td>Right pinky 4 finger joint pose.
|
||||
* </td></tr>
|
||||
* <tr><td colspan="4"><strong>Trackers</strong></td></tr>
|
||||
* <tr><td><code>TrackedObject00</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 0 pose.</td></tr>
|
||||
* <tr><td><code>TrackedObject01</code></td><td>number</td><td>{@link Pose}</td><td>Tracker 1 pose.</td></tr>
|
||||
|
|
|
@ -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 <plugins/InputPlugin.h>
|
||||
#include "OpenVrHelpers.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#define VIVE_PRO_EYE
|
||||
#endif
|
||||
|
||||
using PuckPosePair = std::pair<uint32_t, controller::Pose>;
|
||||
|
||||
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> _inputDevice { std::make_shared<InputDevice>(_system) };
|
||||
|
||||
#ifdef VIVE_PRO_EYE
|
||||
bool _viveProEye { false };
|
||||
bool _eyeTrackingEnabled { false };
|
||||
std::shared_ptr<ViveProEyeReadThread> _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;
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<link type="text/css" rel="stylesheet" href="css/FloofChat.css" media="screen,projection"/>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Raleway:300,400,600,700" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400&display=swap" rel="stylesheet">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
|
||||
</head>
|
||||
|
@ -28,11 +29,19 @@
|
|||
</span>
|
||||
<div class="switch muteSwitch col s2">
|
||||
<label>
|
||||
<span style="font-size: 20px" id="muteText">Mute</span>
|
||||
<span id="muteText">Hide Popups</span>
|
||||
<input type="checkbox" id="muteInput" onclick="muteSwitchToggle()">
|
||||
<span class="lever waves-light"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="switch muteSwitch col s2">
|
||||
<label>
|
||||
<span id="muteAudioText">Mute Sound</span>
|
||||
<input type="checkbox" id="muteAudioInput" onclick="muteAudioSwitchToggle()">
|
||||
<span class="lever waves-light"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<span class="col s1">
|
||||
</span>
|
||||
|
@ -46,6 +55,7 @@
|
|||
|
||||
<script>
|
||||
var muted = {"Local": false, "Domain": false, "Grid": false};
|
||||
var mutedAudio = {"Local": false, "Domain": false, "Grid": false};
|
||||
var instance;
|
||||
var appUUID;
|
||||
var messageData = {}; // The data that is sent along with the message.
|
||||
|
@ -171,13 +181,23 @@
|
|||
case ext == "JPG":
|
||||
case ext == "GIF":
|
||||
case ext == "JPEG":
|
||||
elContent = elContent.replace(this, "<br/><img src='" + this + "'class=\"responsive z-depth-2\"><br/><a href=\"javascript:gotoClipboard('" + this + "');\" target='_blank'>" + this + "</a>");
|
||||
elContent = elContent.replace(this, "<br/><img src='" + this
|
||||
+ "'class=\"responsive z-depth-2\"><br/><a href=\"javascript:gotoClipboard('" + this + "');\" target='_blank'>" + this
|
||||
+ "</a><a onclick=\"gotoExternalURL('" + this
|
||||
+ "');return false;\"href=\"" + this
|
||||
+ "\">📲</a>");
|
||||
break;
|
||||
case ext == "iframe":
|
||||
elContent = elContent.replace(this, "<br/><iframe class=\"z-depth-2\" src='" + this + "'width=\"440\" height=\"248\" frameborder=\"0\"></iframe>");
|
||||
elContent = elContent.replace(this, "<br/><iframe class=\"z-depth-2\" src='" + this
|
||||
+ "'width=\"440\" height=\"248\" frameborder=\"0\"></iframe>");
|
||||
break;
|
||||
case ext == "webm":
|
||||
elContent = elContent.replace(this, "<br/><video controls class=\"z-depth-2 responsive\"><source src='" + this + "' type='video/" + ext + "'></video><br/><a href=\"javascript:gotoClipboard('" + this + "');\">" + this + "</a>");
|
||||
elContent = elContent.replace(this, "<br/><video controls class=\"z-depth-2 responsive\"><source src='" + this
|
||||
+ "' type='video/" + ext + "'></video><br/><a href=\"javascript:gotoClipboard('" + this
|
||||
+ "');\">" + this
|
||||
+ "</a><a onclick=\"gotoExternalURL('" + this
|
||||
+ "');return false;\"href=\"" + this
|
||||
+ "\">📲</a>");
|
||||
break;
|
||||
case protocol === "HIFI":
|
||||
case protocol === "hifi":
|
||||
|
@ -186,13 +206,24 @@
|
|||
case !!this.match(/(https?:\/\/)?(www\.)?(youtube\.com\/watch\?v=|youtu\.be\/)([^& \n<]+)(?:[^ \n<]+)?/g):
|
||||
var youtubeMatch = this.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/);
|
||||
if (youtubeMatch && youtubeMatch[2].length == 11) {
|
||||
elContent = "<br/><iframe class=\"z-depth-2\" width='420' height='236' src='https://www.youtube.com/embed/" + youtubeMatch[2] + "' frameborder='0'></iframe><br/><a href=\"javascript:gotoURL('" + this + "');\">" + this + "</a>";
|
||||
elContent = "<br/><iframe class=\"z-depth-2\" width='420' height='236' src='https://www.youtube.com/embed/" + youtubeMatch[2]
|
||||
+ "' frameborder='0'></iframe><br/><a href=\"javascript:gotoURL('" + this
|
||||
+ "');\">" + this
|
||||
+ "</a><a onclick=\"gotoExternalURL('" + this
|
||||
+ "');return false;\"href=\"" + this
|
||||
+ "\">📲</a>";
|
||||
break;
|
||||
}
|
||||
// else fall through to default
|
||||
default:
|
||||
elContent = elContent.replace(this, "<br/><a href=\"javascript:gotoURL('" + this + "');\">" + this + "</a>");
|
||||
elContent = elContent.replace(this, "<br/><a onclick=\"gotoURL('" + this
|
||||
+ "');return false;\" href=\"" + this
|
||||
+ "\">" + this
|
||||
+ "</a><a onclick=\"gotoExternalURL('" + this
|
||||
+ "');return false;\"href=\"" + this
|
||||
+ "\">📲</a>");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -284,6 +315,10 @@
|
|||
function gotoURL(url) {
|
||||
emitWebEvent({type: "CMD", cmd: "URL", url: url});
|
||||
}
|
||||
|
||||
function gotoExternalURL(url) {
|
||||
emitWebEvent({ type: "CMD", cmd: "EXTERNALURL", url: url });
|
||||
}
|
||||
|
||||
function gotoClipboard(url) {
|
||||
M.toast({html: 'Copied URL to Clipboard', classes: 'rounded pink white-text'});
|
||||
|
@ -322,7 +357,7 @@
|
|||
location.reload();
|
||||
}
|
||||
|
||||
function logMessage(userName, message, logScreen, colour) {
|
||||
function logMessage(timestamp, userName, message, logScreen, colour) {
|
||||
var LogScreen = $("#" + logScreen);
|
||||
var $logLine =
|
||||
$('<div/>')
|
||||
|
@ -333,6 +368,10 @@
|
|||
.addClass('z-depth-2')
|
||||
.data('chat-message', message).css("color", rgbToHex(colour))
|
||||
.appendTo(LogScreen);
|
||||
$('<span/>')
|
||||
.addClass('LogLogLineTimestamp')
|
||||
.text(timestamp).css("color", rgbToHex(colour))
|
||||
.appendTo($logLine);
|
||||
$('<b/>')
|
||||
.addClass('LogLogLineMessage')
|
||||
.text(userName + ": ").css("color", rgbToHex(colour))
|
||||
|
@ -350,18 +389,23 @@
|
|||
|
||||
function time() {
|
||||
var d = new Date();
|
||||
var month = (d.getMonth()).toString();
|
||||
var day = (d.getDate()).toString();
|
||||
var h = (d.getHours()).toString();
|
||||
var m = (d.getMinutes()).toString();
|
||||
var s = (d.getSeconds()).toString();
|
||||
var h2 = ("0" + h).slice(-2);
|
||||
var m2 = ("0" + m).slice(-2);
|
||||
var s2 = ("0" + s).slice(-2);
|
||||
s2 += (d.getMilliseconds() / 1000).toFixed(2).slice(1);
|
||||
return h2 + ":" + m2 + ":" + s2;
|
||||
// s2 += (d.getMilliseconds() / 1000).toFixed(2).slice(1);
|
||||
return month + "/" + day + " - " + h2 + ":" + m2 + ":" + s2;
|
||||
}
|
||||
|
||||
var muteInput;
|
||||
var muteText;
|
||||
|
||||
var muteAudioInput;
|
||||
var muteAudioText;
|
||||
|
||||
function muteSwitchToggle() {
|
||||
muted[getCurrTab()] = muteInput.checked;
|
||||
|
@ -369,18 +413,33 @@
|
|||
muteText.classList.remove(!muteInput.checked ? "red-text" : "white-text");
|
||||
emitWebEvent({type: "CMD", cmd: "MUTED", muted: muted});
|
||||
}
|
||||
|
||||
function muteAudioSwitchToggle() {
|
||||
mutedAudio[getCurrTab()] = muteAudioInput.checked;
|
||||
muteAudioText.classList.add(muteAudioInput.checked ? "red-text" : "white-text");
|
||||
muteAudioText.classList.remove(!muteAudioInput.checked ? "red-text" : "white-text");
|
||||
emitWebEvent({ type: "CMD", cmd: "MUTEDAUDIO", muted: mutedAudio });
|
||||
}
|
||||
|
||||
function main() {
|
||||
|
||||
muteInput = document.getElementById("muteInput");
|
||||
muteText = document.getElementById("muteText");
|
||||
|
||||
muteAudioInput = document.getElementById("muteAudioInput");
|
||||
muteAudioText = document.getElementById("muteAudioText");
|
||||
|
||||
instance = M.Tabs.init(document.getElementById("tabs"), {
|
||||
"onShow": function (e) {
|
||||
scrollChatLog(getCurrTab());
|
||||
|
||||
muteInput.checked = muted[getCurrTab()];
|
||||
muteText.classList.add(muteInput.checked ? "red-text" : "white-text");
|
||||
muteText.classList.remove(!muteInput.checked ? "red-text" : "white-text");
|
||||
|
||||
muteAudioInput.checked = mutedAudio[getCurrTab()];
|
||||
muteAudioText.classList.add(muteAudioInput.checked ? "red-text" : "white-text");
|
||||
muteAudioText.classList.remove(!muteAudioInput.checked ? "red-text" : "white-text");
|
||||
}
|
||||
});
|
||||
instance.select("Local");
|
||||
|
@ -430,11 +489,11 @@
|
|||
var temp = cmd.data;
|
||||
if (temp.length === 1) {
|
||||
var temp2 = temp[0];
|
||||
logMessage("[" + temp2[0] + "] " + temp2[2], temp2[1], temp2[4], temp2[3]);
|
||||
logMessage("[" + temp2[0] + "] ", temp2[2], temp2[1], temp2[4], temp2[3]);
|
||||
scrollChatLog(temp2[4]);
|
||||
} else if (temp.length > 1) {
|
||||
temp.forEach(function (msg) {
|
||||
logMessage("[" + msg[0] + "] " + msg[2], msg[1], msg[4], msg[3]);
|
||||
logMessage("[" + msg[0] + "] ", msg[2], msg[1], msg[4], msg[3]);
|
||||
scrollChatLog(msg[4]);
|
||||
});
|
||||
}
|
||||
|
@ -445,6 +504,12 @@
|
|||
muteText.classList.add(muteInput.checked ? "red-text" : "white-text");
|
||||
muteText.classList.remove(!muteInput.checked ? "red-text" : "white-text");
|
||||
}
|
||||
if (cmd.cmd === "MUTEDAUDIO") {
|
||||
mutedAudio = cmd.muted;
|
||||
muteAudioInput.checked = mutedAudio[getCurrTab()];
|
||||
muteAudioText.classList.add(muteAudioInput.checked ? "red-text" : "white-text");
|
||||
muteAudioText.classList.remove(!muteAudioInput.checked ? "red-text" : "white-text");
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 100); // Delay to allow everything to settle
|
|
@ -23,6 +23,12 @@ var SHIFT_KEY = 33554432;
|
|||
var FLOOF_CHAT_CHANNEL = "Chat";
|
||||
var FLOOF_NOTIFICATION_CHANNEL = "Floof-Notif";
|
||||
|
||||
var MAIN_CHAT_WINDOW_HEIGHT = 450;
|
||||
var MAIN_CHAT_WINDOW_WIDTH = 750;
|
||||
|
||||
var CHAT_BAR_HISTORY_LIMIT = 256;
|
||||
var CHAT_HISTORY_LIMIT = 500;
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
shutdown();
|
||||
});
|
||||
|
@ -41,8 +47,8 @@ var appUUID = Uuid.generate();
|
|||
|
||||
var chatBar;
|
||||
var chatHistory;
|
||||
var chatBarHistoryLimit = Settings.getValue(settingsRoot + "/chatBarHistoryLimit", 256);
|
||||
var chatHistoryLimit = Settings.getValue(settingsRoot + "/chatHistoryLimit", 500);
|
||||
var chatBarHistoryLimit = Settings.getValue(settingsRoot + "/chatBarHistoryLimit", CHAT_BAR_HISTORY_LIMIT);
|
||||
var chatHistoryLimit = Settings.getValue(settingsRoot + "/chatHistoryLimit", CHAT_HISTORY_LIMIT);
|
||||
var chatBarHistory = Settings.getValue(settingsRoot + "/chatBarHistory", ["Meow :3"]);
|
||||
var historyLog = [];
|
||||
|
||||
|
@ -50,14 +56,16 @@ var visible = false;
|
|||
var historyVisible = false;
|
||||
var settingsRoot = "FloofChat";
|
||||
|
||||
var athenaGotoUrl = "https://metaverse.projectathena.io/interim/d-goto/app/goto.json";
|
||||
var gotoJSONUrl = Settings.getValue(settingsRoot + "/gotoJSONUrl", athenaGotoUrl);
|
||||
var vircadiaGotoUrl = "https://metaverse.vircadia.com/interim/d-goto/app/goto.json";
|
||||
var gotoJSONUrl = Settings.getValue(settingsRoot + "/gotoJSONUrl", vircadiaGotoUrl);
|
||||
|
||||
var muted = Settings.getValue(settingsRoot + "/muted", {"Local": false, "Domain": false, "Grid": true});
|
||||
var mutedAudio = Settings.getValue(settingsRoot + "/mutedAudio", {"Local": false, "Domain": false, "Grid": true});
|
||||
var notificationSound = SoundCache.getSound(Script.resolvePath("resources/bubblepop.wav"));
|
||||
|
||||
var ws;
|
||||
var wsReady = false;
|
||||
var WEB_SOCKET_URL = "ws://chat.projectathena.io:8880"; // WebSocket for Grid chat.
|
||||
var WEB_SOCKET_URL = "ws://chat.vircadia.com:8880"; // WebSocket for Grid chat.
|
||||
var shutdownBool = false;
|
||||
|
||||
var defaultColour = {red: 255, green: 255, blue: 255};
|
||||
|
@ -80,12 +88,12 @@ function init() {
|
|||
setupHistoryWindow(false);
|
||||
|
||||
chatBar = new OverlayWindow({
|
||||
source: Paths.defaultScripts + '/communityModules/chat/FloofChat.qml?' + Date.now(),
|
||||
source: ROOT + "FloofChat.qml?" + Date.now(),
|
||||
width: 360,
|
||||
height: 180
|
||||
});
|
||||
|
||||
button.clicked.connect(toggleChatHistory);
|
||||
button.clicked.connect(toggleMainChatWindow);
|
||||
chatBar.fromQml.connect(fromQml);
|
||||
chatBar.sendToQml(JSON.stringify({visible: false, history: chatBarHistory}));
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
|
@ -106,6 +114,11 @@ function connectWebSocket(timeout) {
|
|||
}
|
||||
if (!cmd.FAILED) {
|
||||
addToLog(cmd.message, cmd.displayName, cmd.colour, cmd.channel);
|
||||
|
||||
if (!mutedAudio["Grid"] && MyAvatar.sessionDisplayName !== cmd.displayName) {
|
||||
playNotificationSound();
|
||||
}
|
||||
|
||||
if (!muted["Grid"]) {
|
||||
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||
sender: "(G) " + cmd.displayName,
|
||||
|
@ -166,13 +179,13 @@ function setupHistoryWindow() {
|
|||
chatHistory = new OverlayWebWindow({
|
||||
title: 'Chat',
|
||||
source: ROOT + "FloofChat.html?appUUID=" + appUUID + "&" + Date.now(),
|
||||
width: 900,
|
||||
height: 700,
|
||||
width: MAIN_CHAT_WINDOW_WIDTH,
|
||||
height: MAIN_CHAT_WINDOW_HEIGHT,
|
||||
visible: false
|
||||
});
|
||||
chatHistory.setPosition({x: 0, y: Window.innerHeight - 700});
|
||||
chatHistory.setPosition({x: 0, y: Window.innerHeight - MAIN_CHAT_WINDOW_HEIGHT});
|
||||
chatHistory.webEventReceived.connect(onWebEventReceived);
|
||||
chatHistory.closed.connect(toggleChatHistory);
|
||||
chatHistory.closed.connect(toggleMainChatWindow);
|
||||
}
|
||||
|
||||
function emitScriptEvent(obj) {
|
||||
|
@ -180,7 +193,7 @@ function emitScriptEvent(obj) {
|
|||
tablet.emitScriptEvent(JSON.stringify(obj));
|
||||
}
|
||||
|
||||
function toggleChatHistory() {
|
||||
function toggleMainChatWindow() {
|
||||
historyVisible = !historyVisible;
|
||||
button.editProperties({isActive: historyVisible});
|
||||
chatHistory.visible = historyVisible;
|
||||
|
@ -282,18 +295,23 @@ function onWebEventReceived(event) {
|
|||
if (event.type === "ready") {
|
||||
chatHistory.emitScriptEvent(JSON.stringify({type: "MSG", data: historyLog}));
|
||||
chatHistory.emitScriptEvent(JSON.stringify({type: "CMD", cmd: "MUTED", muted: muted}));
|
||||
chatHistory.emitScriptEvent(JSON.stringify({type: "CMD", cmd: "MUTEDAUDIO", muted: mutedAudio}));
|
||||
}
|
||||
if (event.type === "CMD") {
|
||||
if (event.cmd === "MUTED") {
|
||||
muted = event.muted;
|
||||
Settings.setValue(settingsRoot + "/muted", muted);
|
||||
}
|
||||
if (event.cmd === "MUTEDAUDIO") {
|
||||
mutedAudio = event.muted;
|
||||
Settings.setValue(settingsRoot + "/mutedAudio", mutedAudio);
|
||||
}
|
||||
if (event.cmd === "COLOUR") {
|
||||
Settings.setValue(settingsRoot + "/" + event.colourType + "Colour", event.colour);
|
||||
colours[event.colourType] = event.colour;
|
||||
}
|
||||
if (event.cmd === "REDOCK") {
|
||||
chatHistory.setPosition({x: 0, y: Window.innerHeight - 700});
|
||||
chatHistory.setPosition({x: 0, y: Window.innerHeight - MAIN_CHAT_WINDOW_HEIGHT});
|
||||
}
|
||||
if (event.cmd === "GOTO") {
|
||||
gotoConfirm(event.url);
|
||||
|
@ -307,12 +325,15 @@ function onWebEventReceived(event) {
|
|||
visible: true
|
||||
});
|
||||
}
|
||||
if (event.cmd === "EXTERNALURL") {
|
||||
Window.openUrl(event.url);
|
||||
}
|
||||
if (event.cmd === "COPY") {
|
||||
Window.copyToClipboard(event.url);
|
||||
}
|
||||
}
|
||||
if (event.type === "WEBMSG") {
|
||||
event.avatarName = MyAvatar.displayName;
|
||||
event.avatarName = MyAvatar.sessionDisplayName;
|
||||
event = processChat(event);
|
||||
if (event.message === "") return;
|
||||
sendWS({
|
||||
|
@ -325,7 +346,7 @@ function onWebEventReceived(event) {
|
|||
});
|
||||
}
|
||||
if (event.type === "MSG") {
|
||||
event.avatarName = MyAvatar.displayName;
|
||||
event.avatarName = MyAvatar.sessionDisplayName;
|
||||
event = processChat(event);
|
||||
if (event.message === "") return;
|
||||
Messages.sendMessage("Chat", JSON.stringify({
|
||||
|
@ -340,6 +361,17 @@ function onWebEventReceived(event) {
|
|||
}
|
||||
}
|
||||
|
||||
function playNotificationSound() {
|
||||
if (notificationSound.downloaded) {
|
||||
var injectorOptions = {
|
||||
localOnly: true,
|
||||
position: MyAvatar.position,
|
||||
volume: 0.02
|
||||
};
|
||||
Audio.playSound(notificationSound, injectorOptions);
|
||||
}
|
||||
}
|
||||
|
||||
function replaceFormatting(text) {
|
||||
var found = false;
|
||||
if (text.indexOf("**") !== -1) {
|
||||
|
@ -423,6 +455,11 @@ function messageReceived(channel, message) {
|
|||
if (cmd.channel === "Local") {
|
||||
if (Vec3.withinEpsilon(MyAvatar.position, cmd.position, 20)) {
|
||||
addToLog(cmd.message, cmd.displayName, cmd.colour, cmd.channel);
|
||||
|
||||
if (!mutedAudio["Local"] && MyAvatar.sessionDisplayName !== cmd.displayName) {
|
||||
playNotificationSound();
|
||||
}
|
||||
|
||||
if (!muted["Local"]) {
|
||||
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||
sender: "(L) " + cmd.displayName,
|
||||
|
@ -433,6 +470,11 @@ function messageReceived(channel, message) {
|
|||
}
|
||||
} else if (cmd.channel === "Domain") {
|
||||
addToLog(cmd.message, cmd.displayName, cmd.colour, cmd.channel);
|
||||
|
||||
if (!mutedAudio["Domain"] && MyAvatar.sessionDisplayName !== cmd.displayName) {
|
||||
playNotificationSound();
|
||||
}
|
||||
|
||||
if (!muted["Domain"]) {
|
||||
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||
sender: "(D) " + cmd.displayName,
|
||||
|
@ -442,6 +484,11 @@ function messageReceived(channel, message) {
|
|||
}
|
||||
} else if (cmd.channel === "Grid") {
|
||||
addToLog(cmd.message, cmd.displayName, cmd.colour, cmd.channel);
|
||||
|
||||
if (!mutedAudio["Grid"] && MyAvatar.sessionDisplayName !== cmd.displayName) {
|
||||
playNotificationSound();
|
||||
}
|
||||
|
||||
if (!muted["Grid"]) {
|
||||
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||
sender: "(G) " + cmd.displayName,
|
||||
|
@ -451,6 +498,11 @@ function messageReceived(channel, message) {
|
|||
}
|
||||
} else {
|
||||
addToLog(cmd.message, cmd.displayName, cmd.colour, cmd.channel);
|
||||
|
||||
if (MyAvatar.sessionDisplayName !== cmd.displayName) {
|
||||
playNotificationSound();
|
||||
}
|
||||
|
||||
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||
sender: cmd.displayName,
|
||||
text: replaceFormatting(cmd.message),
|
||||
|
@ -464,19 +516,22 @@ function messageReceived(channel, message) {
|
|||
|
||||
function time() {
|
||||
var d = new Date();
|
||||
var month = (d.getMonth()).toString();
|
||||
var day = (d.getDate()).toString();
|
||||
var h = (d.getHours()).toString();
|
||||
var m = (d.getMinutes()).toString();
|
||||
var s = (d.getSeconds()).toString();
|
||||
var h2 = ("0" + h).slice(-2);
|
||||
var m2 = ("0" + m).slice(-2);
|
||||
var s2 = ("0" + s).slice(-2);
|
||||
s2 += (d.getMilliseconds() / 1000).toFixed(2).slice(1);
|
||||
return h2 + ":" + m2 + ":" + s2;
|
||||
// s2 += (d.getMilliseconds() / 1000).toFixed(2).slice(1);
|
||||
return month + "/" + day + " - " + h2 + ":" + m2 + ":" + s2;
|
||||
}
|
||||
|
||||
function addToLog(msg, dp, colour, tab) {
|
||||
historyLog.push([time(), msg, dp, colour, tab]);
|
||||
chatHistory.emitScriptEvent(JSON.stringify({type: "MSG", data: [[time(), msg, dp, colour, tab]]}));
|
||||
var currentTimestamp = time();
|
||||
historyLog.push([currentTimestamp, msg, dp, colour, tab]);
|
||||
chatHistory.emitScriptEvent(JSON.stringify({ type: "MSG", data: [[currentTimestamp, msg, dp, colour, tab]]}));
|
||||
while (historyLog.length > chatHistoryLimit) {
|
||||
historyLog.shift();
|
||||
}
|
||||
|
@ -503,7 +558,7 @@ function fromQml(message) {
|
|||
if (cmd.message !== "") {
|
||||
addToChatBarHistory(cmd.message);
|
||||
if (cmd.event.modifiers === CONTROL_KEY) {
|
||||
cmd.avatarName = MyAvatar.displayName;
|
||||
cmd.avatarName = MyAvatar.sessionDisplayName;
|
||||
cmd = processChat(cmd);
|
||||
if (cmd.message === "") return;
|
||||
Messages.sendMessage(FLOOF_CHAT_CHANNEL, JSON.stringify({
|
||||
|
@ -512,7 +567,7 @@ function fromQml(message) {
|
|||
displayName: cmd.avatarName
|
||||
}));
|
||||
} else if (cmd.event.modifiers === CONTROL_KEY + SHIFT_KEY) {
|
||||
cmd.avatarName = MyAvatar.displayName;
|
||||
cmd.avatarName = MyAvatar.sessionDisplayName;
|
||||
cmd = processChat(cmd);
|
||||
if (cmd.message === "") return;
|
||||
sendWS({
|
||||
|
@ -524,7 +579,7 @@ function fromQml(message) {
|
|||
displayName: cmd.avatarName
|
||||
});
|
||||
} else {
|
||||
cmd.avatarName = MyAvatar.displayName;
|
||||
cmd.avatarName = MyAvatar.sessionDisplayName;
|
||||
cmd = processChat(cmd);
|
||||
if (cmd.message === "") return;
|
||||
Messages.sendMessage(FLOOF_CHAT_CHANNEL, JSON.stringify({
|
||||
|
@ -540,7 +595,7 @@ function fromQml(message) {
|
|||
setVisible(false);
|
||||
} else if (cmd.type === "CMD") {
|
||||
if (cmd.cmd === "Clicked") {
|
||||
toggleChatHistory()
|
||||
toggleMainChatWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -565,7 +620,7 @@ function setVisible(_visible) {
|
|||
|
||||
function keyPressEvent(event) {
|
||||
if (event.key === H_KEY && !event.isAutoRepeat && event.isControl) {
|
||||
toggleChatHistory()
|
||||
toggleMainChatWindow()
|
||||
}
|
||||
if (event.key === ENTER_KEY && !event.isAutoRepeat && !visible) {
|
||||
setVisible(true);
|
||||
|
@ -588,4 +643,4 @@ function shutdown() {
|
|||
}
|
||||
chatBar.close();
|
||||
chatHistory.close();
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
@ -50,6 +50,12 @@ div.dockButton button.active {
|
|||
border-top: none;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
width: 250px !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -69,9 +75,10 @@ body {
|
|||
}
|
||||
|
||||
.ChatLog {
|
||||
height: calc(100vh - 137px);
|
||||
padding: 20px !important;
|
||||
font-size: 20px;
|
||||
height: calc(100vh - 127px);
|
||||
padding: 10px !important;
|
||||
font-size: 18px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
color: white;
|
||||
background-color: black;
|
||||
overflow-x: hidden;
|
||||
|
@ -80,7 +87,7 @@ body {
|
|||
}
|
||||
|
||||
.ChatLogLine {
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.ChatLogLineDisplayName {
|
||||
|
@ -91,25 +98,30 @@ body {
|
|||
}
|
||||
|
||||
.LogLogLine {
|
||||
margin-bottom: 15px;
|
||||
padding: 10px !important;
|
||||
margin-bottom: 7px;
|
||||
padding: 6px !important;
|
||||
}
|
||||
|
||||
.LogLogLineMessage {
|
||||
/*font-style: italic;*/
|
||||
}
|
||||
|
||||
.LogLogLineTimestamp {
|
||||
font-weight: 300;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.ChatInput {
|
||||
color: #252525;
|
||||
background: #252525;
|
||||
height: 60px !important;
|
||||
height: 45px !important;
|
||||
}
|
||||
|
||||
.ChatInputText {
|
||||
padding: 5px !important;
|
||||
height: 50px !important;
|
||||
padding: 5px 5px 5px 10px !important;
|
||||
height: 35px !important;
|
||||
width: calc(100vw - 20px) !important;
|
||||
font-size: 20px !important;
|
||||
font-size: 18px !important;
|
||||
background-color: white !important;
|
||||
border-style: solid !important;
|
||||
border-color: #232323 !important;
|
||||
|
@ -146,6 +158,14 @@ body {
|
|||
background-color: #a62113 !important;
|
||||
}
|
||||
|
||||
#muteText {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#muteAudioText {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
img, a{
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
BIN
scripts/communityScripts/chat/resources/bubblepop.wav
Normal file
BIN
scripts/communityScripts/chat/resources/bubblepop.wav
Normal file
Binary file not shown.
|
@ -34,16 +34,15 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
|||
"system/miniTablet.js",
|
||||
"system/audioMuteOverlay.js",
|
||||
"system/inspect.js",
|
||||
"system/keyboardShortcuts/keyboardShortcuts.js",
|
||||
"system/hand-track-walk.js"
|
||||
"system/keyboardShortcuts/keyboardShortcuts.js"
|
||||
];
|
||||
var DEFAULT_SCRIPTS_SEPARATE = [
|
||||
"system/controllers/controllerScripts.js",
|
||||
"communityModules/notificationCore/notificationCore.js",
|
||||
"communityScripts/notificationCore/notificationCore.js",
|
||||
"simplifiedUI/ui/simplifiedNametag/simplifiedNametag.js",
|
||||
{"stable": "system/more/app-more.js", "beta": "https://cdn.vircadia.com/community-apps/more/app-more.js"},
|
||||
{"stable": "communityScripts/explore/explore.js", "beta": "https://metaverse.vircadia.com/interim/d-goto/app/explore.js"},
|
||||
{"stable": "communityModules/chat/FloofChat.js", "beta": "https://content.fluffy.ws/scripts/chat/FloofChat.js"}
|
||||
{"stable": "communityScripts/chat/FloofChat.js", "beta": "https://content.fluffy.ws/scripts/chat/FloofChat.js"}
|
||||
//"system/chat.js"
|
||||
];
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Created by Keb Helion, February 2020.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
//
|
||||
// This script adds a "More Apps" selector to "Vircadia" to allow the user to add optional functionalities to the tablet.
|
||||
// This script adds a "More Apps" selector to Vircadia to allow the user to add optional functionalities to the tablet.
|
||||
// This application has been designed to work directly from the Github repository.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
|
|
@ -42,6 +42,10 @@ p a {
|
|||
color: SteelBlue;
|
||||
}
|
||||
|
||||
.appdesc a {
|
||||
color: LightBlue;
|
||||
}
|
||||
|
||||
font.appname {
|
||||
font-family: 'Merriweather', sans-serif;
|
||||
font-size: 18px;
|
||||
|
|
Loading…
Reference in a new issue