diff --git a/.github/workflows/master_build.yml b/.github/workflows/master_build.yml
index 2caddef182..ee6ef88d0e 100644
--- a/.github/workflows/master_build.yml
+++ b/.github/workflows/master_build.yml
@@ -83,15 +83,15 @@ jobs:
shell: bash
run: |
echo "${{ steps.buildenv1.outputs.symbols_archive }}"
- echo "ARTIFACT_PATTERN=Vircadia-Alpha-*.$INSTALLER_EXT" >> $GITHUB_ENV
+ echo "ARTIFACT_PATTERN=Vircadia-*.$INSTALLER_EXT" >> $GITHUB_ENV
# Build type variables
echo "GIT_COMMIT_SHORT=${{ steps.buildenv1.outputs.github_sha_short }}" >> $GITHUB_ENV
if [ "${{ matrix.build_type }}" = "full" ]; then
echo "CLIENT_ONLY=FALSE" >> $GITHUB_ENV
- echo "INSTALLER=Vircadia-Alpha-$BUILD_NUMBER-$GIT_COMMIT_SHORT.$INSTALLER_EXT" >> $GITHUB_ENV
+ echo "INSTALLER=Vircadia-$BUILD_NUMBER-$GIT_COMMIT_SHORT.$INSTALLER_EXT" >> $GITHUB_ENV
else
echo "CLIENT_ONLY=TRUE" >> $GITHUB_ENV
- echo "INSTALLER=Vircadia-Alpha-Interface-$BUILD_NUMBER-$GIT_COMMIT_SHORT.$INSTALLER_EXT" >> $GITHUB_ENV
+ echo "INSTALLER=Vircadia-Interface-$BUILD_NUMBER-$GIT_COMMIT_SHORT.$INSTALLER_EXT" >> $GITHUB_ENV
fi
- name: Clear working directory
if: startsWith(matrix.os, 'windows')
diff --git a/.github/workflows/pr_build.yml b/.github/workflows/pr_build.yml
index 757a6fd7c8..9d6984b5b2 100644
--- a/.github/workflows/pr_build.yml
+++ b/.github/workflows/pr_build.yml
@@ -14,7 +14,9 @@ env:
RELEASE_TYPE: PR
RELEASE_NUMBER: ${{ github.event.number }}
VERSION_CODE: ${{ github.event.number }}
-
+ # Sentry Crash Reporting
+ CMAKE_BACKTRACE_URL: ${{ secrets.MINIDUMP_TOKEN }}
+ CMAKE_BACKTRACE_TOKEN: PR_${{ github.event.number }}_${{ github.sha }}
# OSX specific variables
DEVELOPER_DIR: /Applications/Xcode_11.2.app/Contents/Developer
@@ -84,9 +86,9 @@ jobs:
echo "${{ steps.buildenv1.outputs.symbols_archive }}"
echo "GIT_COMMIT_SHORT=${{ steps.buildenv1.outputs.github_sha_short }}" >> $GITHUB_ENV
if [[ "${{ matrix.build_type }}" != "android" ]]; then
- echo "ARTIFACT_PATTERN=Vircadia-Alpha-PR${{ github.event.number }}-*.$INSTALLER_EXT" >> $GITHUB_ENV
+ echo "ARTIFACT_PATTERN=Vircadia-PR${{ github.event.number }}-*.$INSTALLER_EXT" >> $GITHUB_ENV
# Build type variables
- echo "INSTALLER=Vircadia-Alpha-$RELEASE_NUMBER-$GIT_COMMIT_SHORT.$INSTALLER_EXT" >> $GITHUB_ENV
+ echo "INSTALLER=Vircadia-$RELEASE_NUMBER-$GIT_COMMIT_SHORT.$INSTALLER_EXT" >> $GITHUB_ENV
else
echo "ARTIFACT_PATTERN=*.$INSTALLER_EXT" >> $GITHUB_ENV
fi
@@ -169,7 +171,7 @@ jobs:
- name: Build for Android + Quest
if: matrix.build_type == 'android'
shell: bash
- working-directory: ${{runner.workspace}}/project-athena
+ working-directory: ${{runner.workspace}}/vircadia
run: |
echo "Pre-cache the vcpkg managed dependencies"
$PYTHON_EXEC prebuild.py --build-root ${{runner.workspace}}/build --android interface
diff --git a/BUILD.md b/BUILD.md
index 9b31c4895b..2ec0cbfa6e 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -60,9 +60,9 @@ You do not need to install vcpkg.
Building the dependencies can be lengthy and the resulting files will be stored in your OS temp directory.
However, those files can potentially get cleaned up by the OS, so in order to avoid this and having to redo the lengthy build step, you can set the following environment variable:
-export HIFI_VCPKG_BASE=/path/to/directory
+ export HIFI_VCPKG_BASE=/path/to/directory
-Where /path/to/directory is the path to a directory where you wish the build files to get stored.
+Where `/path/to/directory` is the path to a directory where you wish the build files to get stored.
#### Generating Build Files
diff --git a/BUILD_ANDROID.md b/BUILD_ANDROID.md
index 0bea3e5a90..fc73d7905e 100644
--- a/BUILD_ANDROID.md
+++ b/BUILD_ANDROID.md
@@ -66,7 +66,7 @@ The above code to suppress modules is not necessary, but will speed up the build
### Clone the repository
-`git clone https://github.com/kasenvr/project-athena.git`
+`git clone https://github.com/vircadia/vircadia.git`
## Building & Running
@@ -119,4 +119,4 @@ Some things you can try if you want to do a clean build
* In Android Studio, click _File > Invalidate Caches / Restart_ and select _Invalidate and Restart_
If you see lots of "couldn't acquire lock" errors,
-* Open Task Manager and close any running Clang / Gradle processes
\ No newline at end of file
+* Open Task Manager and close any running Clang / Gradle processes
diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md
index 8d6062f5e6..90782e90b4 100644
--- a/BUILD_LINUX.md
+++ b/BUILD_LINUX.md
@@ -4,7 +4,7 @@
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file.
-You can use the [Vircadia Builder](https://github.com/kasenvr/vircadia-builder) to build on Linux more easily. Alternatively, you can follow the manual steps below.
+You can use the [Vircadia Builder](https://github.com/vircadia/vircadia-builder) to build on Linux more easily. Alternatively, you can follow the manual steps below.
## Ubuntu 16.04/18.04 specific build guide
### Ubuntu 16.04 only
@@ -78,7 +78,7 @@ sudo apt-get install nodejs
Clone this repository:
```bash
-git clone https://github.com/kasenvr/project-athena.git
+git clone https://github.com/vircadia/vircadia.git
```
To compile a DEV version checkout the branch you need. To get a list of all tags:
@@ -105,7 +105,7 @@ Qt must be installed in `$HIFI_QT_BASE/$VIRCADIA_USE_QT_VERSION/qt5-install`.
Create the build directory:
```bash
-cd project-athena
+cd vircadia
mkdir build
cd build
```
diff --git a/BUILD_WIN.md b/BUILD_WIN.md
index c057d9ca5d..96f570981a 100644
--- a/BUILD_WIN.md
+++ b/BUILD_WIN.md
@@ -7,38 +7,41 @@ This is a stand-alone guide for creating your first Vircadia build for Windows 6
Note: We are now using Visual Studio 2017 or 2019 and Qt 5.12.3.
If you are upgrading from previous versions, do a clean uninstall of those versions before going through this guide.
-Note: The prerequisites will require about 10 GB of space on your drive. You will also need a system with at least 8GB of main memory.
+**Note: The prerequisites will require about 10 GB of space on your drive. You will also need a system with at least 8GB of main memory.**
### Step 1. Visual Studio & Python 3.x
If you don’t have Community or Professional edition of Visual Studio, download [Visual Studio Community 2019](https://visualstudio.microsoft.com/vs/). If you have Visual Studio 2017, you are not required to download Visual Studio 2019.
-When selecting components, check "Desktop development with C++". On the right on the Summary toolbar, select the following components.
+When selecting components, check "Desktop development with C++".
-#### If you're installing Visual Studio 2017,
+If you do not already have a Python 3.x development environment installed and want to install it with Visual Studio, check "Python Development". If you already have Visual Studio installed and need to add Python, open the "Add or remove programs" control panel and find the "Microsoft Visual Studio Installer". Select it and click "Modify". In the installer, select "Modify" again, then check "Python Development" and allow the installer to apply the changes.
+
+On the right on the Summary toolbar, select the following components based on your Visual Studio version.
+
+#### If you're installing Visual Studio 2017
* Windows 8.1 SDK and UCRT SDK
* VC++ 2015.3 v14.00 (v140) toolset for desktop
-#### If you're installing Visual Studio 2019,
+#### If you're installing Visual Studio 2019
+* MSVC v142 - VS 2019 C++ X64/x86 build tools
* MSVC v141 - VS 2017 C++ x64/x86 build tools
* MSVC v140 - VS 2015 C++ build tools (v14.00)
-If you do not already have a Python 3.x development environment installed, also check "Python Development" in this screen.
+### Step 1a. Alternate Python
-If you already have Visual Studio installed and need to add Python, open the "Add or remove programs" control panel and find the "Microsoft Visual Studio Installer". Select it and click "Modify". In the installer, select "Modify" again, then check "Python Development" and allow the installer to apply the changes.
-
-### Step 1a. Alternate Python
-
-If you do not wish to use the Python installation bundled with Visual Studio, you can download the installer from [here](https://www.python.org/downloads/). Ensure you get version 3.6.6 or higher.
+If you do not wish to use the Python installation bundled with Visual Studio, you can download the installer from [here](https://www.python.org/downloads/). Ensure that you get version 3.6.6 or higher.
### Step 2. Python Dependencies
-In a command-line that can access Python's pip you will need to run the following command:
+In an administrator command-line that can access Python's pip you will need to run the following command:
`pip install distro`
+If you do not use an administrator command-line, you will get errors.
+
### Step 3. Installing CMake
Download and install the latest version of CMake 3.15.
@@ -46,7 +49,11 @@ Download and install the latest version of CMake 3.15.
Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.15 Version page](https://cmake.org/files/v3.15/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted.
-### Step 4. Create VCPKG environment variable
+### Step 4. Node.JS and NPM
+
+Install version 10.15.0 LTS (or greater) of [Node.JS and NPM]().
+
+### Step 5. Create VCPKG environment variable
In the next step, you will use CMake to build Vircadia. By default, the CMake process builds dependency files in Windows' `%TEMP%` directory, which is periodically cleared by the operating system. To prevent you from having to re-build the dependencies in the event that Windows clears that directory, we recommend that you create a `HIFI_VCPKG_BASE` environment variable linked to a directory somewhere on your machine. That directory will contain all dependency files until you manually remove them.
To create this variable:
@@ -65,7 +72,7 @@ To create this variable:
* Set "Variable name" to `HIFI_VCPKG_BOOTSTRAP`
* Set "Variable value" to `1`
-### Step 5. Running CMake to Generate Build Files
+### Step 6. Running CMake to Generate Build Files
Run Command Prompt from Start and run the following commands:
`cd "%VIRCADIA_DIR%"`
@@ -80,7 +87,7 @@ Run `cmake .. -G "Visual Studio 16 2019" -A x64`.
Where `%VIRCADIA_DIR%` is the directory for the Vircadia repository.
-### Step 6. Making a Build
+### Step 7. Making a Build
Open `%VIRCADIA_DIR%\build\vircadia.sln` using Visual Studio.
@@ -88,7 +95,7 @@ Change the Solution Configuration (menu ribbon under the menu bar, next to the g
Run from the menu bar `Build > Build Solution`.
-### Step 7. Testing Interface
+### Step 8. Testing Interface
Create another environment variable (see Step #3)
* Set "Variable name": `_NO_DEBUG_HEAP`
@@ -104,11 +111,11 @@ Note: You can also run Interface by launching it from command line or File Explo
## Troubleshooting
-For any problems after Step #6, first try this:
+For any problems after Step #7, first try this:
* Delete your locally cloned copy of the Vircadia repository
* Restart your computer
-* Redownload the [repository](https://github.com/kasenvr/project-athena)
-* Restart directions from Step #6
+* Redownload the [repository](https://github.com/vircadia/vircadia)
+* Restart directions from Step #7
#### CMake gives you the same error message repeatedly after the build fails
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 424fbdc940..f111f482ae 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,6 +41,12 @@ endif()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/_env/EXTERNAL_BUILD_ASSETS.txt" "${EXTERNAL_BUILD_ASSETS}")
MESSAGE(STATUS "EXTERNAL_BUILD_ASSETS: ${EXTERNAL_BUILD_ASSETS}")
+set(GLES_OPTION "$ENV{USE_GLES}")
+
+# Will affect VCPKG dependencies
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/_env/USE_GLES.txt" "${GLES_OPTION}")
+MESSAGE(STATUS "GLES_OPTION: ${GLES_OPTION}")
+
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros/TargetPython.cmake")
target_python()
@@ -129,7 +135,6 @@ set(BUILD_TESTS_OPTION OFF)
set(BUILD_MANUAL_TESTS_OPTION ${BUILD_TESTS_OPTION})
set(BUILD_TOOLS_OPTION ON)
set(BUILD_INSTALLER_OPTION ON)
-set(GLES_OPTION OFF)
set(DISABLE_QML_OPTION OFF)
set(DOWNLOAD_SERVERLESS_CONTENT_OPTION OFF)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index aeb6f49280..72f296e92e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,3 +1,4 @@
+
The project embraces distributed development and if you'd like to help, it would be greatly appreciated. Just open a pull request with the revisions.
Contributing
@@ -6,7 +7,7 @@ Contributing
2. Clone your fork of the repository locally
```
- git clone git://github.com/USERNAME/project-athena.git
+ git clone git://github.com/USERNAME/vircadia.git
```
3. Create a new branch
@@ -20,7 +21,7 @@ Contributing
6. Update your branch
```
- git remote add upstream https://github.com/kasenvr/project-athena
+ git remote add upstream https://github.com/vircadia/vircadia
git pull upstream master
```
@@ -35,13 +36,22 @@ Contributing
*You can follow [GitHub's guide](https://help.github.com/articles/creating-a-pull-request) to find out how to create a pull request.*
+Tips for Pull Requests
+===
+To make the QA process go as smoothly as possible.
+
+1. Have a basic description in your pull request.
+2. Write a basic test plan if you are altering or adding features.
+3. If a new API is added, try to make sure that some level of basic documentation on how you can utilize it is included.
+4. If an added API or feature requires an external service, try to document or link to instructions on how to create a basic working setup.
+
Reporting Bugs
===
1. Always update to the latest code on master, we make many merges every day and it is possible the bug has already been fixed!
-2. Search [issues](https://github.com/kasenvr/project-athena/issues) to make sure that somebody has not already reported the same bug.
-3. [Add](https://github.com/kasenvr/project-athena/issues/new) your report to the issues list!
+2. Search [issues](https://github.com/vircadia/vircadia/issues) to make sure that somebody has not already reported the same bug.
+3. [Add](https://github.com/vircadia/vircadia/issues/new) your report to the issues list!
Requesting a Feature
===
-1. Search [issues](https://github.com/kasenvr/project-athena/issues) to make sure that somebody has not already requested the same feature.
-2. [Add](https://github.com/kasenvr/project-athena/issues/new) your request to the issues list!
+1. Search [issues](https://github.com/vircadia/vircadia/issues) to make sure that somebody has not already requested the same feature.
+2. [Add](https://github.com/vircadia/vircadia/issues/new) your request to the issues list!
diff --git a/INSTALL.md b/INSTALLER.md
similarity index 98%
rename from INSTALL.md
rename to INSTALLER.md
index 6f58ec7b81..a96af042b5 100644
--- a/INSTALL.md
+++ b/INSTALLER.md
@@ -60,8 +60,8 @@ To produce an executable installer on Windows, the following are required:
1. Copy `Release\ApplicationID.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-ansi\`
1. Copy `ReleaseUnicode\ApplicationID.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-unicode\`
-1. [Node.JS and NPM]()
- 1. Install version 10.15.0 LTS
+1. [Node.JS and NPM]()
+ 1. Install version 10.15.0 LTS (or greater)
#### Code Signing (optional)
diff --git a/LICENSE b/LICENSE
index 8dfe384174..d5ca6ae075 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
Copyright (c) 2013-2019, High Fidelity, Inc.
-Copyright (c) 2019-2020, Vircadia contributors.
+Copyright (c) 2019-2021, Vircadia contributors.
All rights reserved.
https://vircadia.com
diff --git a/README.md b/README.md
index baf333d81f..d260c76d0d 100644
--- a/README.md
+++ b/README.md
@@ -1,61 +1,57 @@
-# Vircadia
+# Vircadia (Codename Athena)
### What is this?
-Vircadia is a 3D social software project seeking to incrementally bring about a truly free and open metaverse, in desktop and XR.
+Vircadia™ is a 3D social software project seeking to incrementally bring about a truly free and open metaverse, in desktop and XR.
-### [Download](https://vircadia.com/download-vircadia/)
+### [Website](https://vircadia.com/) | [Discord](https://discordapp.com/invite/Pvx2vke) | [Download](https://vircadia.com/download-vircadia/)
### Releases
-[View Releases here](https://github.com/kasenvr/project-athena/releases/)
+[View Releases here](https://github.com/vircadia/vircadia/releases/)
### How to build the Interface
-[For Windows](https://github.com/kasenvr/project-athena/blob/master/BUILD_WIN.md)
-
-[For Mac](https://github.com/kasenvr/project-athena/blob/master/BUILD_OSX.md)
-
-[For Linux](https://github.com/kasenvr/project-athena/blob/master/BUILD_LINUX.md)
-
-[For Linux - Vircadia Builder](https://github.com/kasenvr/vircadia-builder)
+- [For Windows](https://github.com/vircadia/vircadia/blob/master/BUILD_WIN.md)
+- [For Mac](https://github.com/vircadia/vircadia/blob/master/BUILD_OSX.md)
+- [For Linux](https://github.com/vircadia/vircadia/blob/master/BUILD_LINUX.md)
+- [For Linux - Vircadia Builder](https://github.com/vircadia/vircadia-builder)
### How to deploy a Server
-[For Windows and Linux](https://vircadia.com/deploy-a-server/)
+- [For Windows and Linux](https://vircadia.com/deploy-a-server/)
### How to build a Server
-[For Linux - Vircadia Builder](https://github.com/kasenvr/vircadia-builder)
+- [For Windows](https://github.com/vircadia/vircadia/blob/master/BUILD_WIN.md)
+- [For Linux](https://github.com/vircadia/vircadia/blob/master/BUILD_LINUX.md)
+- [For Linux - Vircadia Builder](https://github.com/vircadia/vircadia-builder)
### How to generate an Installer
-[For Windows](https://github.com/kasenvr/project-athena/blob/master/INSTALL.md)
+- [For Windows](https://github.com/vircadia/vircadia/blob/master/INSTALLER.md)
+- [For Mac](https://github.com/vircadia/vircadia/blob/master/INSTALLER.md#os-x)
+- [For Linux - AppImage - Vircadia Builder](https://github.com/vircadia/vircadia-builder/blob/master/README.md#building-appimages)
-[For Linux - AppImage - Vircadia Builder](https://github.com/kasenvr/vircadia-builder/blob/master/README.md#building-appimages)
-
-### Boot to Metaverse: The Goal
+### Boot to Metaverse: [The Goal](https://vircadia.com/vision/)
Having a place to experience adventure, a place to relax with calm breath, that's a world to live in. An engine to support infinite combinations and possibilities of worlds without censorship and interruption, that's a metaverse. Finding a way to make infinite realities our reality is the dream.
### Boot to Metaverse: The Technicals
-Many developers have had personal combinations of High Fidelity from C++ modifications to different default scripts, all of which are lost to time as their fullest potential is never truly shared and propagated through the system.
+Vircadia consists of many projects and codebases with its unifying structure's goal being a decentralized metaverse.
-The goal of this project is to achieve the metaverse dream through shared contribution and building. Setting goals that are achievable yet meaningful is key to making proper forward progress on the technical front whilst maintaining morale.
+- The Interface (Codename Athena) - You are here!
+- The Server (Codename Athena) - You are also here!
+- The UI Framework (Codename Nyx) - Codebase coming soon.
+- [The Metaverse (Codename Iamus)](https://github.com/vircadia/Iamus/)
+- [The Metaverse Dashboard (Codename Iamus)](https://github.com/vircadia/project-iamus-dashboard/)
+- [The Launcher (Codename Pantheon)](https://github.com/vircadia/pantheon-launcher/)
-### Why High Fidelity's Virtual Reality Platform?
-
-Because of all the options, it is the only starting point that is open-source, cross-platform, fully VR integrated + fully desktop integrated with an aim for quality visuals and performance. It also provides a foundation to build from including components like entity management, full body IK, etc.
-
-WebXR offers the open-source and decentralized aspect but does not have any of the full featured starting points such as avatars, IK, etc. which means that a lot of ground work will have to be laid to make something functional. Far more work will need to be done to create a truly seamless and extensive experience as well.
-
-Platforms like NeosVR or VRChat are not viable from go due to their fundamental closed-source and centralized nature. A metaverse to live in cannot have the keys handed over to any singular entity, if any at all.
-
-We need to do the best we can with what we've got and our best bet as open source developers is to not redesign the wheel if we can help it!
+#### Child Projects
+- [Vircadia Builder for Linux](https://github.com/vircadia/vircadia-builder/)
+- [General Documentation](https://github.com/vircadia/vircadia-docs-sphinx/)
### Contribution
-A special thanks to the contributors of Vircadia.
-
-[Contribution](CONTRIBUTING.md)
+There are many contributors to Vircadia. Code writers, reviewers, testers, documentation writers, modelers, and general supporters of the project are all integral to its development and success towards its goals. Find out how you can [contribute](CONTRIBUTING.md)!
diff --git a/android/build_android.sh b/android/build_android.sh
index 9cf1b9e2ab..d3c79afdbe 100755
--- a/android/build_android.sh
+++ b/android/build_android.sh
@@ -17,7 +17,7 @@ fi
ANDROID_APP=interface
ANDROID_OUTPUT_DIR=./apps/${ANDROID_APP}/build/outputs/apk/${ANDROID_BUILD_TYPE}
ANDROID_OUTPUT_FILE=${ANDROID_APP}-${ANDROID_BUILD_TYPE}.apk
-ANDROID_APK_NAME=Vircadia-Alpha-${ANDROID_APK_SUFFIX}
+ANDROID_APK_NAME=Vircadia-${ANDROID_APK_SUFFIX}
./gradlew -PHIFI_ANDROID_PRECOMPILED=${HIFI_ANDROID_PRECOMPILED} -PVERSION_CODE=${VERSION_CODE} -PRELEASE_NUMBER=${RELEASE_NUMBER} -PRELEASE_TYPE=${RELEASE_TYPE} ${ANDROID_APP}:${ANDROID_BUILD_TARGET}
cp ${ANDROID_OUTPUT_DIR}/${ANDROID_OUTPUT_FILE} ./${ANDROID_APK_NAME}
diff --git a/android/containerized_build.sh b/android/containerized_build.sh
index 94b5b28831..bbf0b605d8 100755
--- a/android/containerized_build.sh
+++ b/android/containerized_build.sh
@@ -17,7 +17,7 @@ test -z "$STABLE_BUILD" && export STABLE_BUILD=0
docker run \
--rm \
--security-opt seccomp:unconfined \
- -v "${WORKSPACE}":/home/gha/project-athena \
+ -v "${WORKSPACE}":/home/gha/vircadia \
-e RELEASE_NUMBER \
-e RELEASE_TYPE \
-e ANDROID_APP \
diff --git a/android/docker/Dockerfile b/android/docker/Dockerfile
index 144f6caffa..ab5ddb562d 100644
--- a/android/docker/Dockerfile
+++ b/android/docker/Dockerfile
@@ -72,17 +72,17 @@ RUN mkdir "$HIFI_BASE" && \
mkdir "$HIFI_ANDROID_PRECOMPILED"
# Download the repo
-RUN git clone https://github.com/kasenvr/project-athena.git
+RUN git clone https://github.com/vircadia/vircadia.git
-WORKDIR /home/gha/project-athena
+WORKDIR /home/gha/vircadia
RUN mkdir build
# Pre-cache the vcpkg managed dependencies
-WORKDIR /home/gha/project-athena/build
+WORKDIR /home/gha/vircadia/build
RUN python3 ../prebuild.py --build-root `pwd` --android interface
# Pre-cache the gradle dependencies
-WORKDIR /home/gha/project-athena/android
+WORKDIR /home/gha/vircadia/android
RUN ./gradlew -m tasks -PHIFI_ANDROID_PRECOMPILED=$HIFI_ANDROID_PRECOMPILED
#RUN ./gradlew extractDependencies -PHIFI_ANDROID_PRECOMPILED=$HIFI_ANDROID_PRECOMPILED
diff --git a/cmake/installer/installer-header.bmp b/cmake/installer/installer-header.bmp
index de8448ed44..99862ffdb4 100644
Binary files a/cmake/installer/installer-header.bmp and b/cmake/installer/installer-header.bmp differ
diff --git a/cmake/installer/uninstaller-header.bmp b/cmake/installer/uninstaller-header.bmp
index de8448ed44..99862ffdb4 100644
Binary files a/cmake/installer/uninstaller-header.bmp and b/cmake/installer/uninstaller-header.bmp differ
diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake
index 0442df55cf..640cc1720f 100644
--- a/cmake/macros/GenerateInstallers.cmake
+++ b/cmake/macros/GenerateInstallers.cmake
@@ -31,7 +31,7 @@ macro(GENERATE_INSTALLERS)
set(CPACK_PACKAGE_NAME ${_DISPLAY_NAME})
set(CPACK_PACKAGE_VENDOR "Vircadia")
set(CPACK_PACKAGE_VERSION ${BUILD_VERSION})
- set(CPACK_PACKAGE_FILE_NAME "Vircadia-Alpha${_PACKAGE_NAME_EXTRA}-${BUILD_VERSION}")
+ set(CPACK_PACKAGE_FILE_NAME "Vircadia${_PACKAGE_NAME_EXTRA}-${BUILD_VERSION}")
set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME})
set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME})
if (PR_BUILD)
diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake
index cbefdaea8f..8f9fde672c 100644
--- a/cmake/macros/OptionalWinExecutableSigning.cmake
+++ b/cmake/macros/OptionalWinExecutableSigning.cmake
@@ -10,7 +10,7 @@
#
macro(optional_win_executable_signing)
- if (WIN32 AND PRODUCTION_BUILD)
+ if (WIN32 AND PRODUCTION_BUILD AND NOT BYPASS_SIGNING)
if (DEFINED ENV{HF_PFX_FILE})
if (DEFINED ENV{HF_PFX_PASSPHRASE})
message(STATUS "Executable for ${TARGET_NAME} will be signed with SignTool.")
diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake
index 1e05cad109..9311594938 100644
--- a/cmake/macros/SetPackagingParameters.cmake
+++ b/cmake/macros/SetPackagingParameters.cmake
@@ -23,8 +23,10 @@ macro(SET_PACKAGING_PARAMETERS)
set_from_env(RELEASE_TYPE RELEASE_TYPE "DEV")
set_from_env(RELEASE_NUMBER RELEASE_NUMBER "")
+ set_from_env(RELEASE_NAME RELEASE_NAME "")
set_from_env(STABLE_BUILD STABLE_BUILD 0)
set_from_env(INITIAL_STARTUP_LOCATION INITIAL_STARTUP_LOCATION "")
+ set_from_env(BYPASS_SIGNING BYPASS_SIGNING 0)
message(STATUS "The RELEASE_TYPE variable is: ${RELEASE_TYPE}")
diff --git a/cmake/macros/TargetOculusMobile.cmake b/cmake/macros/TargetOculusMobile.cmake
index f5229845a9..34d5e33058 100644
--- a/cmake/macros/TargetOculusMobile.cmake
+++ b/cmake/macros/TargetOculusMobile.cmake
@@ -1,6 +1,6 @@
macro(target_oculus_mobile)
- set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/oculus_1.22/VrApi)
+ set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/ovr_sdk_mobile_1.37.0/VrApi)
# Mobile SDK
set(OVR_MOBILE_INCLUDE_DIRS ${INSTALL_DIR}/Include)
@@ -12,7 +12,7 @@ macro(target_oculus_mobile)
target_link_libraries(${TARGET_NAME} ${OVR_MOBILE_LIBRARIES})
# Platform SDK
- set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/oculusPlatform)
+ set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/ovr_platform_sdk_23.0.0)
set(OVR_PLATFORM_INCLUDE_DIRS ${INSTALL_DIR}/Include)
target_include_directories(${TARGET_NAME} PRIVATE ${OVR_PLATFORM_INCLUDE_DIRS})
set(OVR_PLATFORM_LIBRARIES ${INSTALL_DIR}/Android/libs/arm64-v8a/libovrplatformloader.so)
diff --git a/cmake/ports/etc2comp/portfile.cmake b/cmake/ports/etc2comp/portfile.cmake
index 343f67169b..1369492599 100644
--- a/cmake/ports/etc2comp/portfile.cmake
+++ b/cmake/ports/etc2comp/portfile.cmake
@@ -19,7 +19,7 @@ include(vcpkg_common_functions)
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
- REPO kasenvr/etc2comp
+ REPO vircadia/etc2comp
REF 7f1843bf07825c21cab711360c1ddbad04641036
SHA512 d747076acda8537d39585858c793a35c3dcc9ef283d723619a47f8c81ec1454c95b3340ad35f0655a939eae5b8271c801c48a9a7568311a01903a344c44af25b
HEAD_REF master
diff --git a/cmake/ports/glad/portfile.cmake b/cmake/ports/glad/portfile.cmake
index 54b1d91c89..6e3118b31e 100644
--- a/cmake/ports/glad/portfile.cmake
+++ b/cmake/ports/glad/portfile.cmake
@@ -2,13 +2,22 @@ include(vcpkg_common_functions)
vcpkg_check_linkage(ONLY_STATIC_LIBRARY)
file(READ "${VCPKG_ROOT_DIR}/_env/EXTERNAL_BUILD_ASSETS.txt" EXTERNAL_BUILD_ASSETS)
+file(READ "${VCPKG_ROOT_DIR}/_env/USE_GLES.txt" USE_GLES)
+# GitHub Actions Android builds fail with `FILENAME` set while desktop builds with GLES fail without a set `FILENAME`.
if (ANDROID)
vcpkg_download_distfile(
SOURCE_ARCHIVE
URLS ${EXTERNAL_BUILD_ASSETS}/dependencies/glad/glad32es.zip
SHA512 2e02ac633eed8f2ba2adbf96ea85d08998f48dd2e9ec9a88ec3c25f48eaf1405371d258066327c783772fcb3793bdb82bd7375fdabb2ba5e2ce0835468b17f65
)
+elseif (USE_GLES)
+ vcpkg_download_distfile(
+ SOURCE_ARCHIVE
+ URLS ${EXTERNAL_BUILD_ASSETS}/dependencies/glad/glad32es.zip
+ SHA512 2e02ac633eed8f2ba2adbf96ea85d08998f48dd2e9ec9a88ec3c25f48eaf1405371d258066327c783772fcb3793bdb82bd7375fdabb2ba5e2ce0835468b17f65
+ FILENAME glad32es.zip
+ )
else()
# else Linux desktop
vcpkg_download_distfile(
diff --git a/cmake/ports/hifi-scribe/portfile.cmake b/cmake/ports/hifi-scribe/portfile.cmake
index 498e8a455b..19d03b5db4 100644
--- a/cmake/ports/hifi-scribe/portfile.cmake
+++ b/cmake/ports/hifi-scribe/portfile.cmake
@@ -3,7 +3,7 @@ include(vcpkg_common_functions)
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
- REPO kasenvr/scribe
+ REPO vircadia/scribe
REF 1bd638a36ca771e5a68d01985b6389b71835cbd2
SHA512 dbe241d86df3912e544f6b9839873f9875df54efc93822b145e7b13243eaf2e3d690bc8a28b1e52d05bdcd7e68fca6b0b2f5c43ffd0f56a9b7a50d54dcf9e31e
HEAD_REF master
diff --git a/cmake/ports/nvtt/portfile.cmake b/cmake/ports/nvtt/portfile.cmake
index c7bf068e13..b21bb5609c 100644
--- a/cmake/ports/nvtt/portfile.cmake
+++ b/cmake/ports/nvtt/portfile.cmake
@@ -9,7 +9,7 @@ include(vcpkg_common_functions)
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
- REPO kasenvr/nvidia-texture-tools
+ REPO vircadia/nvidia-texture-tools
REF 330c4d56274a0f602a5c70596e2eb670a4ed56c2
SHA512 4c0bc2f369120d696cc27710b6d33086b27eef55f537ec66b9a5c8b1839bc2426c0413670b0f65be52c5d353468f0126dfe024be1f0690611d4d7e33ac530127
HEAD_REF master
diff --git a/cmake/templates/BuildInfo.h.in b/cmake/templates/BuildInfo.h.in
index 02f6a50919..7f3a63d4b4 100644
--- a/cmake/templates/BuildInfo.h.in
+++ b/cmake/templates/BuildInfo.h.in
@@ -4,6 +4,7 @@
//
// Created by Stephen Birarda on 1/14/16.
// Copyright 2015 High Fidelity, Inc.
+// Copyright 2021 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
@@ -24,6 +25,7 @@ namespace BuildInfo {
const QString MODIFIED_ORGANIZATION = "@BUILD_ORGANIZATION@";
const QString ORGANIZATION_DOMAIN = "vircadia.com";
const QString VERSION = "@BUILD_VERSION@";
+ const QString RELEASE_NAME = "@RELEASE_NAME@";
const QString BUILD_NUMBER = "@BUILD_NUMBER@";
const QString BUILD_GLOBAL_SERVICES = "@BUILD_GLOBAL_SERVICES@";
const QString BUILD_TIME = "@BUILD_TIME@";
diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in
index 752fb25d20..4c44ed1fbd 100644
--- a/cmake/templates/NSIS.template.in
+++ b/cmake/templates/NSIS.template.in
@@ -837,16 +837,24 @@ Function PostInstallOptionsPage
!insertmacro SetInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED}
${EndIf}
+ ; FIXME: Re-enable or permanently remove system tray "Console" for Interface-only installs.
+ ;${If} @SERVER_COMPONENT_CONDITIONAL@
+ ; ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @SANDBOX_HF_SHORTCUT_NAME@"
+ ;${Else}
+ ; ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@"
+ ;${EndIf}
+ ;Pop $DesktopConsoleCheckbox
+ ;IntOp $CurrentOffset $CurrentOffset + 15
+ ;
+ ;; set the checkbox state depending on what is present in the registry
+ ;!insertmacro SetInstallOption $DesktopConsoleCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED}
${If} @SERVER_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @SANDBOX_HF_SHORTCUT_NAME@"
- ${Else}
- ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@"
+ Pop $DesktopConsoleCheckbox
+ IntOp $CurrentOffset $CurrentOffset + 15
+ ; set the checkbox state depending on what is present in the registry
+ !insertmacro SetInstallOption $DesktopConsoleCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED}
${EndIf}
-
- Pop $DesktopConsoleCheckbox
- IntOp $CurrentOffset $CurrentOffset + 15
- ; set the checkbox state depending on what is present in the registry
- !insertmacro SetInstallOption $DesktopConsoleCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED}
${If} @CLIENT_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install"
@@ -861,31 +869,54 @@ Function PostInstallOptionsPage
${EndIf}
${EndIf}
+ ; FIXME: Re-enable or permanently remove system tray "Console" for Interface-only installs.
+ ;${If} @SERVER_COMPONENT_CONDITIONAL@
+ ; ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @SANDBOX_HF_SHORTCUT_NAME@ after install"
+ ;${Else}
+ ; ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install"
+ ;${EndIf}
+ ;Pop $LaunchConsoleNowCheckbox
+ ;
+ ;; set the checkbox state depending on what is present in the registry
+ ;!insertmacro SetInstallOption $LaunchConsoleNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_UNCHECKED}
+ ;${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE
+ ;${IfNot} $substringResult == ""
+ ; ${NSD_SetState} $LaunchConsoleNowCheckbox ${BST_UNCHECKED}
+ ;${EndIf}
+ ;IntOp $CurrentOffset $CurrentOffset + 15
${If} @SERVER_COMPONENT_CONDITIONAL@
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @SANDBOX_HF_SHORTCUT_NAME@ after install"
- ${Else}
- ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install"
- ${EndIf}
- Pop $LaunchConsoleNowCheckbox
-
- ; set the checkbox state depending on what is present in the registry
- !insertmacro SetInstallOption $LaunchConsoleNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_UNCHECKED}
- ${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE
- ${IfNot} $substringResult == ""
+ Pop $LaunchConsoleNowCheckbox
+
+ ; set the checkbox state depending on what is present in the registry
+ !insertmacro SetInstallOption $LaunchConsoleNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_UNCHECKED}
+ ${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE
+ ${IfNot} $substringResult == ""
${NSD_SetState} $LaunchConsoleNowCheckbox ${BST_UNCHECKED}
+ ${EndIf}
+ IntOp $CurrentOffset $CurrentOffset + 15
${EndIf}
- IntOp $CurrentOffset $CurrentOffset + 30
-
- ${If} @SERVER_COMPONENT_CONDITIONAL@
- ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @SANDBOX_HF_SHORTCUT_NAME@ on startup"
- ${Else}
- ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup"
- ${EndIf}
- Pop $ConsoleStartupCheckbox
IntOp $CurrentOffset $CurrentOffset + 15
- ; set the checkbox state depending on what is present in the registry
- !insertmacro SetInstallOption $ConsoleStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_UNCHECKED}
+ ; FIXME: Re-enable or permanently remove system tray "Console" for Interface-only installs.
+ ;${If} @SERVER_COMPONENT_CONDITIONAL@
+ ; ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @SANDBOX_HF_SHORTCUT_NAME@ on startup"
+ ;${Else}
+ ; ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup"
+ ;${EndIf}
+ ;Pop $ConsoleStartupCheckbox
+ ;IntOp $CurrentOffset $CurrentOffset + 15
+ ;
+ ;; set the checkbox state depending on what is present in the registry
+ ;!insertmacro SetInstallOption $ConsoleStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_UNCHECKED}
+ ${If} @SERVER_COMPONENT_CONDITIONAL@
+ ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @SANDBOX_HF_SHORTCUT_NAME@ on startup"
+ Pop $ConsoleStartupCheckbox
+ IntOp $CurrentOffset $CurrentOffset + 15
+
+ ; set the checkbox state depending on what is present in the registry
+ !insertmacro SetInstallOption $ConsoleStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_UNCHECKED}
+ ${EndIf}
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)"
Pop $CleanInstallCheckbox
@@ -957,13 +988,29 @@ FunctionEnd
Function ReadPostInstallOptions
- ; check if the user asked for a desktop shortcut to console
- ${NSD_GetState} $DesktopConsoleCheckbox $DesktopConsoleState
- ${LogText} "Option: Start Desktop Console: $DesktopConsoleState"
+ ; FIXME: Re-enable or permanently remove system tray "Console" for Interface-only installs.
+ ;; check if the user asked for a desktop shortcut to console
+ ;${NSD_GetState} $DesktopConsoleCheckbox $DesktopConsoleState
+ ;${LogText} "Option: Start Desktop Console: $DesktopConsoleState"
+ ${If} @SERVER_COMPONENT_CONDITIONAL@
+ ; check if the user asked for a desktop shortcut to console
+ ${NSD_GetState} $DesktopConsoleCheckbox $DesktopConsoleState
+ ${LogText} "Option: Start Desktop Console: $DesktopConsoleState"
+ ${Else}
+ StrCpy $DesktopConsoleState ${BST_UNCHECKED}
+ ${EndIf}
- ; check if the user asked to have console launched every startup
- ${NSD_GetState} $ConsoleStartupCheckbox $ConsoleStartupState
- ${LogText} "Option: Start Desktop Console On Startup: $ConsoleStartupState"
+ ; FIXME: Re-enable or permanently remove system tray "Console" for Interface-only installs.
+ ;; check if the user asked to have console launched every startup
+ ;${NSD_GetState} $ConsoleStartupCheckbox $ConsoleStartupState
+ ;${LogText} "Option: Start Desktop Console On Startup: $ConsoleStartupState"
+ ${If} @SERVER_COMPONENT_CONDITIONAL@
+ ; check if the user asked to have console launched every startup
+ ${NSD_GetState} $ConsoleStartupCheckbox $ConsoleStartupState
+ ${LogText} "Option: Start Desktop Console On Startup: $ConsoleStartupState"
+ ${Else}
+ StrCpy $ConsoleStartupState ${BST_UNCHECKED}
+ ${EndIf}
${If} @SERVER_COMPONENT_CONDITIONAL@
${LogText} "Option: Install Server"
@@ -1308,10 +1355,13 @@ Section "-Core installation"
${Else}
; handling for interface only console shortcut
Delete "$SMPROGRAMS\$STARTMENU_FOLDER\@SANDBOX_HF_SHORTCUT_NAME@.lnk"
- CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \
- "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
- ; Set appUserModelId
- ApplicationID::Set "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@"
+
+ ; FIXME: Re-enable or permanently remove system tray "Console" for Interface-only installs.
+ ;CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \
+ ; "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
+ ;; Set appUserModelId
+ ;ApplicationID::Set "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@"
+
${EndIf}
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\@UNINSTALLER_NAME@"
diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json
index 42b15adefe..bb7acf344c 100644
--- a/domain-server/resources/describe-settings.json
+++ b/domain-server/resources/describe-settings.json
@@ -2013,6 +2013,23 @@
}
]
},
+ {
+ "name": "domain_server",
+ "label": "Setup Domain Server",
+ "restart": false,
+ "hidden": true,
+ "settings": [
+ {
+ "name": "network_address",
+ "default": ""
+ },
+ {
+ "name": "network_port",
+ "type": "int",
+ "default": 0
+ }
+ ]
+ },
{
"name": "installed_content",
"label": "Installed Content",
diff --git a/domain-server/resources/metadata_exporter/index.html b/domain-server/resources/metadata_exporter/index.html
index a22d50fe22..1b18c508cc 100644
--- a/domain-server/resources/metadata_exporter/index.html
+++ b/domain-server/resources/metadata_exporter/index.html
@@ -2,7 +2,7 @@
//
// index.html
//
-// Created by kasenvr@gmail.com on 21 Jul 2020
+// Created by somnilibertas@gmail.com on 21 Jul 2020
// Copyright 2020 Vircadia and contributors.
//
// Distributed under the Apache License, Version 2.0.
diff --git a/domain-server/resources/web/assignment/placeholder.js b/domain-server/resources/web/assignment/placeholder.js
index 95c9903e32..3666396d6e 100644
--- a/domain-server/resources/web/assignment/placeholder.js
+++ b/domain-server/resources/web/assignment/placeholder.js
@@ -1,3 +1,3 @@
// Here you can put a script that will be run by an assignment-client (AC)
-// For examples, please go to https://github.com/kasenvr/project-athena/tree/master/script-archive/acScripts
+// For examples, please go to https://github.com/vircadia/vircadia/tree/master/script-archive/acScripts
// The directory named acScripts contains assignment-client specific scripts you can try.
diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js
index bffd512890..bec8d19119 100644
--- a/domain-server/resources/web/js/shared.js
+++ b/domain-server/resources/web/js/shared.js
@@ -129,9 +129,10 @@ function getCurrentDomainIDType() {
return DOMAIN_ID_TYPE_UNKNOWN;
}
if (DomainInfo !== null) {
- if (DomainInfo.name !== undefined) {
- return DOMAIN_ID_TYPE_TEMP;
- }
+ // Disabled because detecting as temp domain... and we're not even using temp domains right now.
+ // if (DomainInfo.name !== undefined) {
+ // return DOMAIN_ID_TYPE_TEMP;
+ // }
return DOMAIN_ID_TYPE_FULL;
}
return DOMAIN_ID_TYPE_UNKNOWN;
@@ -504,7 +505,7 @@ function createDomainIDPrompt(callback) {
swal({
title: 'Finish Registering Domain',
type: 'input',
- text: 'Enter a label for this machine.This will help you identify which domain ID belongs to which machine.This is a required step for registration.',
+ text: 'Enter a label for this Domain Server.This will help you identify which domain ID belongs to which server.This is a required step for registration.Acceptable characters are [A-Z][a-z0-9]+-_.();
+
+ // send any public socket changes to the data server so nodes can find us at our new IP
+ connect(nodeList.data(), &LimitedNodeList::publicSockAddrChanged, this,
+ &DomainServer::performIPAddressPortUpdate);
+
if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) {
-
- auto nodeList = DependencyManager::get();
-
- // send any public socket changes to the data server so nodes can find us at our new IP
- connect(nodeList.data(), &LimitedNodeList::publicSockAddrChanged,
- this, &DomainServer::performIPAddressUpdate);
-
// have the LNL enable public socket updating via STUN
nodeList->startSTUNPublicSocketUpdate();
}
@@ -1504,13 +1506,23 @@ QJsonObject jsonForDomainSocketUpdate(const HifiSockAddr& socket) {
return socketObject;
}
-const QString DOMAIN_UPDATE_AUTOMATIC_NETWORKING_KEY = "automatic_networking";
+void DomainServer::performIPAddressPortUpdate(const HifiSockAddr& newPublicSockAddr) {
+ const QString& DOMAIN_SERVER_SETTINGS_KEY = "domain_server";
+ const QString& publicSocketAddress = newPublicSockAddr.getAddress().toString();
+ const int publicSocketPort = newPublicSockAddr.getPort();
-void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr) {
- sendHeartbeatToMetaverse(newPublicSockAddr.getAddress().toString());
+ sendHeartbeatToMetaverse(publicSocketAddress, publicSocketPort);
+
+ QJsonObject rootObject;
+ QJsonObject domainServerObject;
+ domainServerObject.insert(PUBLIC_SOCKET_ADDRESS_KEY, publicSocketAddress);
+ domainServerObject.insert(PUBLIC_SOCKET_PORT_KEY, publicSocketPort);
+ rootObject.insert(DOMAIN_SERVER_SETTINGS_KEY, domainServerObject);
+ QJsonDocument doc(rootObject);
+ _settingsManager.recurseJSONObjectAndOverwriteSettings(rootObject, DomainSettings);
}
-void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) {
+void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress, const int port) {
// Setup the domain object to send to the data server
QJsonObject domainObject;
@@ -1520,10 +1532,20 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) {
static const QString PROTOCOL_VERSION_KEY = "protocol";
domainObject[PROTOCOL_VERSION_KEY] = protocolVersionsSignatureBase64();
- // add networking
+ static const QString NETWORK_ADDRESS_SETTINGS_KEY = "domain_server." + PUBLIC_SOCKET_ADDRESS_KEY;
+ const QString networkAddressFromSettings = _settingsManager.valueForKeyPath(NETWORK_ADDRESS_SETTINGS_KEY).toString();
if (!networkAddress.isEmpty()) {
- static const QString PUBLIC_NETWORK_ADDRESS_KEY = "network_address";
- domainObject[PUBLIC_NETWORK_ADDRESS_KEY] = networkAddress;
+ domainObject[PUBLIC_SOCKET_ADDRESS_KEY] = networkAddress;
+ } else if (!networkAddressFromSettings.isEmpty()) {
+ domainObject[PUBLIC_SOCKET_ADDRESS_KEY] = networkAddressFromSettings;
+ }
+
+ static const QString PORT_SETTINGS_KEY = "domain_server." + PUBLIC_SOCKET_PORT_KEY;
+ const int portFromSettings = _settingsManager.valueForKeyPath(PORT_SETTINGS_KEY).toInt();
+ if (port != NULL) {
+ domainObject[PUBLIC_SOCKET_PORT_KEY] = port;
+ } else if (portFromSettings != NULL) {
+ domainObject[PUBLIC_SOCKET_PORT_KEY] = portFromSettings;
}
static const QString AUTOMATIC_NETWORKING_KEY = "automatic_networking";
diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h
index 7a09141db6..24d26540c1 100644
--- a/domain-server/src/DomainServer.h
+++ b/domain-server/src/DomainServer.h
@@ -112,8 +112,8 @@ private slots:
void setupPendingAssignmentCredits();
void sendPendingTransactionsToServer();
- void performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr);
- void sendHeartbeatToMetaverse() { sendHeartbeatToMetaverse(QString()); }
+ void performIPAddressPortUpdate(const HifiSockAddr& newPublicSockAddr);
+ void sendHeartbeatToMetaverse() { sendHeartbeatToMetaverse(QString(), int()); }
void sendHeartbeatToIceServer();
void nodePingMonitor();
@@ -176,7 +176,7 @@ private:
void setupAutomaticNetworking();
void setupICEHeartbeatForFullNetworking();
void setupHeartbeatToMetaverse();
- void sendHeartbeatToMetaverse(const QString& networkAddress);
+ void sendHeartbeatToMetaverse(const QString& networkAddress, const int port);
void randomizeICEServerAddress(bool shouldTriggerHostLookup);
diff --git a/hifi_android.py b/hifi_android.py
index 06640390d4..07ea00d270 100644
--- a/hifi_android.py
+++ b/hifi_android.py
@@ -39,15 +39,15 @@ ANDROID_PACKAGES = {
'sharedLibFolder': 'lib',
'includeLibs': ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so']
},
- 'oculus_1.22': {
- 'file': 'ovr_sdk_mobile_1.22.zip',
- 'checksum': '1ac3c5b0521e5406f287f351015daff8',
+ 'ovr_sdk_mobile_1.37.0': {
+ 'file': 'ovr_sdk_mobile_1.37.0.zip',
+ 'checksum': '6040e1966f335a3e5015295154cd7383',
'sharedLibFolder': 'VrApi/Libs/Android/arm64-v8a/Release',
'includeLibs': ['libvrapi.so']
},
- 'oculusPlatform': {
- 'file': 'OVRPlatformSDK_v1.34.0.zip',
- 'checksum': '16e4c5f39520f122bc49cb6d5bb88289',
+ 'ovr_platform_sdk_23.0.0': {
+ 'file': 'ovr_platform_sdk_23.0.0.zip',
+ 'checksum': '29d02b560f60d0fa7b8a64cd965dd55b',
'sharedLibFolder': 'Android/libs/arm64-v8a',
'includeLibs': ['libovrplatformloader.so']
},
diff --git a/hifi_qt.py b/hifi_qt.py
index b3b3681049..48e9b337a6 100644
--- a/hifi_qt.py
+++ b/hifi_qt.py
@@ -12,7 +12,7 @@ import functools
print = functools.partial(print, flush=True)
-# Encapsulates the vcpkg system
+# Encapsulates the vcpkg system
class QtDownloader:
CMAKE_TEMPLATE = """
# this file auto-generated by hifi_qt.py
@@ -72,7 +72,7 @@ endif()
self.qtUrl = self.assets_url + '/dependencies/vcpkg/qt5-install-5.12.3-ubuntu-18.04.tar.gz'
elif u_major == 19 and u_minor == 10:
self.qtUrl = self.assets_url + '/dependencies/vcpkg/qt5-install-5.12.6-ubuntu-19.10.tar.xz'
- elif u_major > 18 and ( u_major != 19 and u_minor != 4):
+ elif u_major > 19:
print("We don't support " + distro.name(pretty=True) + " yet. Perhaps consider helping us out?")
raise Exception('LINUX DISTRO IS NOT SUPPORTED YET!!!')
else:
@@ -81,7 +81,7 @@ endif()
else:
print("Sorry, " + distro.name(pretty=True) + " is not supported. Please consider helping us out.")
print("It's also possible to build Qt for your distribution, please see the documentation at:")
- print("https://github.com/kasenvr/project-athena/tree/master/tools/qt-builder")
+ print("https://github.com/vircadia/vircadia/tree/master/tools/qt-builder")
raise Exception('UNKNOWN LINUX VERSION!!!')
else:
print("System : " + platform.system())
diff --git a/hifi_vcpkg.py b/hifi_vcpkg.py
index 1b9976da6e..ebdfb6c972 100644
--- a/hifi_vcpkg.py
+++ b/hifi_vcpkg.py
@@ -90,8 +90,8 @@ endif()
if 'Windows' == system:
self.exe = os.path.join(self.path, 'vcpkg.exe')
self.bootstrapCmds = [ os.path.join(self.path, 'bootstrap-vcpkg.bat'), '-disableMetrics' ]
- self.vcpkgUrl = self.assets_url + '/dependencies/vcpkg/builds/vcpkg-win32-client.zip%3FversionId=tSFzbw01VkkVFeRQ6YuAY4dro2HxJR9U'
- self.vcpkgHash = 'a650db47a63ccdc9904b68ddd16af74772e7e78170b513ea8de5a3b47d032751a3b73dcc7526d88bcb500753ea3dd9880639ca842bb176e2bddb1710f9a58cd3'
+ self.vcpkgUrl = self.assets_url + '/dependencies/vcpkg/vcpkg-win32-client-20210122.zip'
+ self.vcpkgHash = '3df86b7d58c827bf08b3b7744f456f414b86a6d9bd58a507924103bc5a88f01ee495ce1f0fbf2f5b27f1ef6bfb1526e580ec13d3b9f87a89a462b3c50589fd6a'
self.hostTriplet = 'x64-windows'
if usePrebuilt:
self.prebuiltArchive = self.assets_url + "/dependencies/vcpkg/builds/vcpkg-win32.zip%3FversionId=3SF3mDC8dkQH1JP041m88xnYmWNzZflx"
diff --git a/interface/resources/fonts/vircadia_glyphs.ttf b/interface/resources/fonts/vircadia_glyphs.ttf
index 7d3fe9d913..ed89c2719a 100644
Binary files a/interface/resources/fonts/vircadia_glyphs.ttf and b/interface/resources/fonts/vircadia_glyphs.ttf differ
diff --git a/interface/resources/qml/Web3DSurface.qml b/interface/resources/qml/Web3DSurface.qml
index e9c8d119d6..3bee87d669 100644
--- a/interface/resources/qml/Web3DSurface.qml
+++ b/interface/resources/qml/Web3DSurface.qml
@@ -19,16 +19,17 @@ Item {
property string url: ""
property string scriptUrl: null
property bool useBackground: true
+ property string userAgent: ""
onUrlChanged: {
- load(root.url, root.scriptUrl, root.useBackground);
+ load(root.url, root.scriptUrl, root.useBackground, root.userAgent);
}
onScriptUrlChanged: {
if (root.item) {
root.item.scriptUrl = root.scriptUrl;
} else {
- load(root.url, root.scriptUrl, root.useBackground);
+ load(root.url, root.scriptUrl, root.useBackground, root.userAgent);
}
}
@@ -36,13 +37,21 @@ Item {
if (root.item) {
root.item.useBackground = root.useBackground;
} else {
- load(root.url, root.scriptUrl, root.useBackground);
+ load(root.url, root.scriptUrl, root.useBackground, root.userAgent);
+ }
+ }
+
+ onUserAgentChanged: {
+ if (root.item) {
+ root.item.userAgent = root.userAgent;
+ } else {
+ load(root.url, root.scriptUrl, root.useBackground, root.userAgent);
}
}
property var item: null
- function load(url, scriptUrl, useBackground) {
+ function load(url, scriptUrl, useBackground, userAgent) {
// Ensure we reset any existing item to "about:blank" to ensure web audio stops: DEV-2375
if (root.item != null) {
root.item.url = "about:blank"
@@ -54,11 +63,12 @@ Item {
root.item.url = url
root.item.scriptUrl = scriptUrl
root.item.useBackground = useBackground
+ root.item.userAgent = userAgent
})
}
Component.onCompleted: {
- load(root.url, root.scriptUrl, root.useBackground);
+ load(root.url, root.scriptUrl, root.useBackground, root.userAgent);
}
signal sendToScript(var message);
diff --git a/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml b/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml
index a0585ae053..e7d4f645aa 100644
--- a/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml
+++ b/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml
@@ -13,10 +13,10 @@ Item {
property alias url: webViewCore.url
property alias canGoBack: webViewCore.canGoBack
property alias webViewCore: webViewCore
- property alias webViewCoreProfile: webViewCore.profile
property string webViewCoreUserAgent
property bool useBackground: webViewCore.useBackground
+ property string userAgent: webViewCore.profile.httpUserAgent
property string userScriptUrl: ""
property string urlTag: "noDownload=false";
@@ -34,6 +34,10 @@ Item {
permissionPopupBackground.visible = false;
}
+ onUserAgentChanged: {
+ webViewCore.profile.httpUserAgent = flick.userAgent;
+ }
+
StylesUIt.HifiConstants {
id: hifi
}
@@ -74,7 +78,7 @@ Item {
function onLoadingChanged(loadRequest) {
if (WebEngineView.LoadStartedStatus === loadRequest.status) {
-
+ webViewCore.profile.httpUserAgent = flick.userAgent;
// Required to support clicking on "hifi://" links
var url = loadRequest.url.toString();
url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag;
@@ -101,7 +105,6 @@ Item {
height: parent.height
backgroundColor: (flick.useBackground) ? "white" : "transparent"
- profile: HFWebEngineProfile;
settings.pluginsEnabled: true
settings.touchIconsEnabled: true
settings.allowRunningInsecureContent: true
@@ -136,8 +139,10 @@ Item {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
- if (webViewCoreUserAgent !== undefined) {
- webViewCore.profile.httpUserAgent = webViewCoreUserAgent
+ if (flick.userAgent !== undefined) {
+ webViewCore.profile.httpUserAgent = flick.userAgent;
+ webViewCore.profile.offTheRecord = false;
+ webViewCore.profile.storageName = "qmlWebEngine";
} else {
webViewCore.profile.httpUserAgent += " (VircadiaInterface)";
}
diff --git a/interface/resources/qml/controls/FlickableWebViewCore.qml b/interface/resources/qml/controls/FlickableWebViewCore.qml
index 35f3182f98..3e2e74b3d5 100644
--- a/interface/resources/qml/controls/FlickableWebViewCore.qml
+++ b/interface/resources/qml/controls/FlickableWebViewCore.qml
@@ -11,12 +11,11 @@ Item {
property alias url: webViewCore.url
property alias canGoBack: webViewCore.canGoBack
property alias webViewCore: webViewCore
- property alias webViewCoreProfile: webViewCore.profile
- property string webViewCoreUserAgent
- property bool useBackground: webViewCore.useBackground
+ property alias useBackground: webViewCore.useBackground
+ property alias userAgent: webViewCore.userAgent
property string userScriptUrl: ""
- property string urlTag: "noDownload=false";
+ property string urlTag: "noDownload=false"
signal newViewRequestedCallback(var request)
signal loadingChangedCallback(var loadRequest)
diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml
index b46c8c904d..ebef5f85c5 100644
--- a/interface/resources/qml/controls/WebView.qml
+++ b/interface/resources/qml/controls/WebView.qml
@@ -24,6 +24,7 @@ Item {
property alias flickable: webroot.interactive
property alias blurOnCtrlShift: webroot.blurOnCtrlShift
property alias useBackground: webroot.useBackground
+ property alias userAgent: webroot.userAgent
function stop() {
webroot.stop();
@@ -37,8 +38,6 @@ Item {
}
*/
- property alias viewProfile: webroot.webViewCoreProfile
-
FlickableWebViewCore {
id: webroot
width: parent.width
diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml
index 9a9252112c..971fb06414 100644
--- a/interface/resources/qml/desktop/Desktop.qml
+++ b/interface/resources/qml/desktop/Desktop.qml
@@ -309,8 +309,8 @@ FocusScope {
if (child.hasOwnProperty("modality")) {
var mappedPoint = mapToItem(child, point.x, point.y);
if (child.hasOwnProperty("frame")) {
- var outLine = child.frame.children[2];
- var framePoint = outLine.mapFromGlobal(point.x, point.y);
+ var outLine = child.frame.children[2]; // sizeOutline
+ var framePoint = mapToItem(outLine, point.x, point.y);
if (outLine.contains(framePoint)) {
return true;
}
diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml
index 2cf07e32bf..0dd29b9e0f 100644
--- a/interface/resources/qml/hifi/NameCard.qml
+++ b/interface/resources/qml/hifi/NameCard.qml
@@ -244,7 +244,7 @@ Item {
color: hifi.colors.darkGray;
MouseArea {
anchors.fill: parent
- enabled: selected && pal.activeTab == "nearbyTab" && thisNameCard.userName !== "" && isPresent;
+ enabled: selected && pal.activeTab == "nearbyTab" && isPresent;
hoverEnabled: enabled
onClicked: {
goToUserInDomain(thisNameCard.uuid);
diff --git a/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml b/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml
index a943da32a0..d8f157c813 100644
--- a/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml
+++ b/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml
@@ -28,13 +28,18 @@ Rectangle {
fillMode: Image.PreserveAspectFit
source: "../../../images/vircadia-banner.svg"
}
- Item { height: 30; width: 1 }
+ Item { height: 25; width: 1 }
Column {
- id: buildColumm
+ id: buildColumn
anchors.left: parent.left
- anchors.leftMargin: 70
+ anchors.leftMargin: 0
RalewayRegular {
- text: "Build " + About.buildVersion
+ text: "Interface"
+ size: 16
+ color: "white"
+ }
+ RalewayRegular {
+ text: "Build " + About.buildVersion + " " + About.releaseName
size: 16
color: "white"
}
@@ -54,14 +59,25 @@ Rectangle {
textFormat: Text.StyledText
linkColor: "#00B4EF"
color: "white"
- text: "Vircadia Github."
+ text: "Website"
size: 20
onLinkActivated: {
- About.openUrl("https:/github.com/kasenvr/project-athena");
+ About.openUrl("https://vircadia.com");
}
}
- Item { height: 40; width: 1 }
+ RalewayRegular {
+ textFormat: Text.StyledText
+ linkColor: "#00B4EF"
+ color: "white"
+ text: "Source"
+ size: 20
+ onLinkActivated: {
+ About.openUrl("https://github.com/vircadia/vircadia");
+ }
+
+ }
+ Item { height: 25; width: 1 }
Row {
spacing: 5
Image {
@@ -117,7 +133,7 @@ Rectangle {
Item { height: 20; width: 1 }
RalewayRegular {
color: "white"
- text: "© 2019-2020 Vircadia contributors."
+ text: "© 2019 - 2021 Vircadia contributors."
size: 14
}
RalewayRegular {
@@ -135,5 +151,23 @@ Rectangle {
About.openUrl("http://www.apache.org/licenses/LICENSE-2.0.html");
}
}
+ Item { height: 35; width: 1 }
+ RalewayRegular {
+ color: "white"
+ text: "In memoriam,"
+ size: 14
+ }
+ RalewayRegular {
+ color: "white"
+ text: "2012 - 2019 the High Fidelity virtual reality project."
+ size: 14
+ }
+ Item { height: 5; width: 1 }
+ Image {
+ id: hifiLogo
+ width: 200; height: 50
+ fillMode: Image.PreserveAspectFit
+ source: "../../../images/about-highfidelity.png"
+ }
}
}
diff --git a/interface/resources/qml/hifi/dialogs/security/EntityScriptQMLWhitelist.qml b/interface/resources/qml/hifi/dialogs/security/EntityScriptQMLWhitelist.qml
index 9e0b6ba4cf..8180475527 100644
--- a/interface/resources/qml/hifi/dialogs/security/EntityScriptQMLWhitelist.qml
+++ b/interface/resources/qml/hifi/dialogs/security/EntityScriptQMLWhitelist.qml
@@ -2,8 +2,8 @@
// EntityScriptQMLWhitelist.qml
// interface/resources/qml/hifi/dialogs/security
//
-// Created by Kasen IO on 2019.12.05 | realities.dev | kasenvr@gmail.com
-// Copyright 2019 Kasen IO
+// Created by Kalila L. on 2019.12.05 | realities.dev | somnilibertas@gmail.com
+// Copyright 2019 Kalila L.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
diff --git a/interface/resources/qml/hifi/dialogs/security/Security.qml b/interface/resources/qml/hifi/dialogs/security/Security.qml
index 918a0a2ca6..b109f83a23 100644
--- a/interface/resources/qml/hifi/dialogs/security/Security.qml
+++ b/interface/resources/qml/hifi/dialogs/security/Security.qml
@@ -314,7 +314,7 @@ Rectangle {
onClicked: {
lightboxPopup.titleText = "Script Plugin Infrastructure";
lightboxPopup.bodyText = "Toggles the activation of scripting plugins in the 'plugins/scripting' folder. \n\n"
- + "Created by:\n humbletim@gmail.com\n kasenvr@gmail.com";
+ + "Created by:\n humbletim@gmail.com\n somnilibertas@gmail.com";
lightboxPopup.button1text = "OK";
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;
diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml
index 7b0fbf8d8c..cfff40bbf6 100644
--- a/interface/resources/qml/windows/Frame.qml
+++ b/interface/resources/qml/windows/Frame.qml
@@ -27,7 +27,6 @@ Item {
readonly property int frameMarginRight: frame.decoration ? frame.decoration.frameMarginRight : 0
readonly property int frameMarginTop: frame.decoration ? frame.decoration.frameMarginTop : 0
readonly property int frameMarginBottom: frame.decoration ? frame.decoration.frameMarginBottom : 0
- readonly property int offsetCorrection: 20
// Frames always fill their parents, but their decorations may extend
// beyond the window via negative margin sizes
@@ -76,7 +75,7 @@ Item {
Rectangle {
id: sizeOutline
x: -frameMarginLeft
- y: -frameMarginTop - offsetCorrection
+ y: -frameMarginTop
width: window ? window.width + frameMarginLeft + frameMarginRight + 2 : 0
height: window ? window.height + frameMarginTop + frameMarginBottom + 2 : 0
color: hifi.colors.baseGrayHighlight15
diff --git a/interface/src/AboutUtil.cpp b/interface/src/AboutUtil.cpp
index b9bea2d85c..d2a00854b5 100644
--- a/interface/src/AboutUtil.cpp
+++ b/interface/src/AboutUtil.cpp
@@ -4,6 +4,7 @@
//
// Created by Vlad Stelmahovsky on 15/5/2018.
// Copyright 2018 High Fidelity, Inc.
+// Copyright 2021 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
@@ -40,6 +41,10 @@ QString AboutUtil::getBuildVersion() const {
return BuildInfo::VERSION;
}
+QString AboutUtil::getReleaseName() const {
+ return BuildInfo::RELEASE_NAME;
+}
+
QString AboutUtil::getQtVersion() const {
return qVersion();
}
@@ -57,15 +62,15 @@ void AboutUtil::openUrl(const QString& url) const {
auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system");
auto hmd = DependencyManager::get();
- auto offscreenUi = DependencyManager::get();
+ auto offscreenUI = DependencyManager::get();
- if (tablet->getToolbarMode()) {
- offscreenUi->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
+ if (tablet->getToolbarMode() && offscreenUI) {
+ offscreenUI->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
newObject->setProperty("url", url);
});
} else {
- if (!hmd->getShouldShowTablet() && !qApp->isHMDMode()) {
- offscreenUi->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
+ if (!hmd->getShouldShowTablet() && !qApp->isHMDMode() && offscreenUI) {
+ offscreenUI->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
newObject->setProperty("url", url);
});
} else {
diff --git a/interface/src/AboutUtil.h b/interface/src/AboutUtil.h
index 8cc76dad1e..f072ae8b4a 100644
--- a/interface/src/AboutUtil.h
+++ b/interface/src/AboutUtil.h
@@ -30,12 +30,14 @@
* Read-only.
* @property {string} buildDate - The build date of Interface that is currently running. Read-only.
* @property {string} buildVersion - The build version of Interface that is currently running. Read-only.
+ * @property {string} releaseName - The release codename of the version that Interface is currently running. Read-only.
* @property {string} qtVersion - The Qt version used in Interface that is currently running. Read-only.
*
* @example Report information on the version of Interface currently running.
* print("Interface platform: " + About.platform);
* print("Interface build date: " + About.buildDate);
* print("Interface version: " + About.buildVersion);
+ * print("Interface release name: " + About.releaseName);
* print("Qt version: " + About.qtVersion);
*/
@@ -66,6 +68,7 @@ class AboutUtil : public QObject {
Q_PROPERTY(QString platform READ getPlatformName CONSTANT)
Q_PROPERTY(QString buildDate READ getBuildDate CONSTANT)
Q_PROPERTY(QString buildVersion READ getBuildVersion CONSTANT)
+ Q_PROPERTY(QString releaseName READ getReleaseName CONSTANT)
Q_PROPERTY(QString qtVersion READ getQtVersion CONSTANT)
public:
static AboutUtil* getInstance();
@@ -74,6 +77,7 @@ public:
QString getPlatformName() const { return "Vircadia"; }
QString getBuildDate() const;
QString getBuildVersion() const;
+ QString getReleaseName() const;
QString getQtVersion() const;
public slots:
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index c1f972eb30..07fecc13dc 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2455,13 +2455,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
DependencyManager::get()->setPrecisionPicking(rayPickID, value);
});
- EntityItem::setBillboardRotationOperator([](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos) {
+ BillboardModeHelpers::setBillboardRotationOperator([](const glm::vec3& position, const glm::quat& rotation,
+ BillboardMode billboardMode, const glm::vec3& frustumPos, bool rotate90x) {
+ const glm::quat ROTATE_90X = glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
if (billboardMode == BillboardMode::YAW) {
//rotate about vertical to face the camera
glm::vec3 dPosition = frustumPos - position;
// If x and z are 0, atan(x, z) is undefined, so default to 0 degrees
float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z);
- return glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
+ glm::quat result = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)) * rotation;
+ if (rotate90x) {
+ result *= ROTATE_90X;
+ }
+ return result;
} else if (billboardMode == BillboardMode::FULL) {
// use the referencial from the avatar, y isn't always up
glm::vec3 avatarUP = DependencyManager::get()->getMyAvatar()->getWorldOrientation() * Vectors::UP;
@@ -2470,12 +2476,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// make sure s is not NaN for any component
if (glm::length2(s) > 0.0f) {
- return glm::conjugate(glm::toQuat(glm::lookAt(frustumPos, position, avatarUP)));
+ glm::quat result = glm::conjugate(glm::toQuat(glm::lookAt(frustumPos, position, avatarUP))) * rotation;
+ if (rotate90x) {
+ result *= ROTATE_90X;
+ }
+ return result;
}
}
return rotation;
});
- EntityItem::setPrimaryViewFrustumPositionOperator([this]() {
+ BillboardModeHelpers::setPrimaryViewFrustumPositionOperator([this]() {
ViewFrustum viewFrustum;
copyViewFrustum(viewFrustum);
return viewFrustum.getPosition();
@@ -7180,6 +7190,10 @@ void Application::updateWindowTitle() const {
QString buildVersion = " - Vircadia - "
+ (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable ? QString("Version") : QString("Build"))
+ " " + applicationVersion();
+
+ if (BuildInfo::RELEASE_NAME != "") {
+ buildVersion += " - " + BuildInfo::RELEASE_NAME;
+ }
QString connectionStatus = isInErrorState ? " (ERROR CONNECTING)" :
nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED)";
@@ -8712,7 +8726,7 @@ void Application::notifyPacketVersionMismatch() {
}
void Application::checkSkeleton() const {
- if (getMyAvatar()->getSkeletonModel()->isActive() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) {
+ if (getMyAvatar()->getSkeletonModel()->isLoaded() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) {
qCDebug(interfaceapp) << "MyAvatar model has no skeleton";
QString message = "Your selected avatar body has no skeleton.\n\nThe default body will be loaded...";
diff --git a/interface/src/Bookmarks.cpp b/interface/src/Bookmarks.cpp
index 9a8d8eb279..263723ebe0 100644
--- a/interface/src/Bookmarks.cpp
+++ b/interface/src/Bookmarks.cpp
@@ -61,7 +61,6 @@ void Bookmarks::deleteBookmark(const QString& bookmarkName) {
void Bookmarks::addBookmarkToFile(const QString& bookmarkName, const QVariant& bookmark) {
Menu* menubar = Menu::getInstance();
if (contains(bookmarkName)) {
- auto offscreenUi = DependencyManager::get();
ModalDialogListener* dlg = OffscreenUi::asyncWarning("Duplicate Bookmark",
"The bookmark name you entered already exists in your list.",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index 19cc7eacaa..471645e342 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -509,7 +509,7 @@ Menu::Menu() {
action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::MaterialProceduralShaders, 0, false);
connect(action, &QAction::triggered, [action] {
- MeshPartPayload::enableMaterialProceduralShaders = action->isChecked();
+ ModelMeshPartPayload::enableMaterialProceduralShaders = action->isChecked();
});
{
diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index 32e725388c..91d339a38d 100755
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -767,6 +767,7 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
glm::vec3 rayDirectionInv = { rayDirection.x != 0.0f ? 1.0f / rayDirection.x : INFINITY,
rayDirection.y != 0.0f ? 1.0f / rayDirection.y : INFINITY,
rayDirection.z != 0.0f ? 1.0f / rayDirection.z : INFINITY };
+ glm::vec3 viewFrustumPos = BillboardModeHelpers::getPrimaryViewFrustumPosition();
for (auto &hit : physicsResults) {
auto avatarID = hit._intersectWithAvatar;
@@ -842,7 +843,8 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
BoxFace subMeshFace = BoxFace::UNKNOWN_FACE;
glm::vec3 subMeshSurfaceNormal;
QVariantMap subMeshExtraInfo;
- if (avatar->getSkeletonModel()->findRayIntersectionAgainstSubMeshes(defaultFrameRayOrigin, defaultFrameRayDirection, subMeshDistance, subMeshFace, subMeshSurfaceNormal, subMeshExtraInfo, true, false)) {
+ if (avatar->getSkeletonModel()->findRayIntersectionAgainstSubMeshes(defaultFrameRayOrigin, defaultFrameRayDirection, viewFrustumPos, subMeshDistance,
+ subMeshFace, subMeshSurfaceNormal, subMeshExtraInfo, true, false)) {
rayAvatarResult._distance = subMeshDistance;
rayAvatarResult._intersectionPoint = ray.origin + subMeshDistance * rayDirection;
rayAvatarResult._intersectionNormal = subMeshSurfaceNormal;
@@ -932,6 +934,7 @@ ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector
std::sort(sortedAvatars.begin(), sortedAvatars.end(), comparator);
}
+ glm::vec3 viewFrustumPos = BillboardModeHelpers::getPrimaryViewFrustumPosition();
for (auto it = sortedAvatars.begin(); it != sortedAvatars.end(); ++it) {
const SortedAvatar& sortedAvatar = *it;
// We can exit once avatarCapsuleDistance > bestDistance
@@ -944,7 +947,7 @@ ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector
glm::vec3 surfaceNormal;
QVariantMap extraInfo;
SkeletonModelPointer avatarModel = sortedAvatar.second->getSkeletonModel();
- if (avatarModel->findParabolaIntersectionAgainstSubMeshes(pick.origin, pick.velocity, pick.acceleration, parabolicDistance, face, surfaceNormal, extraInfo, true)) {
+ if (avatarModel->findParabolaIntersectionAgainstSubMeshes(pick.origin, pick.velocity, pick.acceleration, viewFrustumPos, parabolicDistance, face, surfaceNormal, extraInfo, true)) {
if (parabolicDistance < result.parabolicDistance) {
result.intersects = true;
result.avatarID = sortedAvatar.second->getID();
diff --git a/interface/src/avatar/AvatarPackager.cpp b/interface/src/avatar/AvatarPackager.cpp
index 90def7ad43..d43b7d9575 100644
--- a/interface/src/avatar/AvatarPackager.cpp
+++ b/interface/src/avatar/AvatarPackager.cpp
@@ -58,7 +58,9 @@ bool AvatarPackager::open() {
if (tablet->getToolbarMode()) {
static const QUrl url{ "hifi/AvatarPackagerWindow.qml" };
- DependencyManager::get()->show(url, "AvatarPackager", packageModelDialogCreated);
+ if (auto offscreenUI = DependencyManager::get()) {
+ offscreenUI->show(url, "AvatarPackager", packageModelDialogCreated);
+ }
return true;
}
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index b3231b906d..0f66f3bb41 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -96,10 +96,8 @@ const float CENTIMETERS_PER_METER = 100.0f;
const QString AVATAR_SETTINGS_GROUP_NAME { "Avatar" };
-static const QString USER_RECENTER_MODEL_FORCE_SIT = QStringLiteral("ForceSit");
-static const QString USER_RECENTER_MODEL_FORCE_STAND = QStringLiteral("ForceStand");
-static const QString USER_RECENTER_MODEL_AUTO = QStringLiteral("Auto");
-static const QString USER_RECENTER_MODEL_DISABLE_HMD_LEAN = QStringLiteral("DisableHMDLean");
+static const QString ALLOW_AVATAR_STANDING_ALWAYS = QStringLiteral("Always");
+static const QString ALLOW_AVATAR_STANDING_WHEN_USER_IS_STANDING = QStringLiteral("UserStanding");
const QString HEAD_BLEND_DIRECTIONAL_ALPHA_NAME = "lookAroundAlpha";
const QString HEAD_BLEND_LINEAR_ALPHA_NAME = "lookBlendAlpha";
@@ -111,30 +109,38 @@ const QString POINT_BLEND_LINEAR_ALPHA_NAME = "pointBlendAlpha";
const QString POINT_REF_JOINT_NAME = "RightShoulder";
const float POINT_ALPHA_BLENDING = 1.0f;
-MyAvatar::SitStandModelType stringToUserRecenterModel(const QString& str) {
- if (str == USER_RECENTER_MODEL_FORCE_SIT) {
- return MyAvatar::ForceSit;
- } else if (str == USER_RECENTER_MODEL_FORCE_STAND) {
- return MyAvatar::ForceStand;
- } else if (str == USER_RECENTER_MODEL_DISABLE_HMD_LEAN) {
- return MyAvatar::DisableHMDLean;
- } else {
- return MyAvatar::Auto;
+const std::array(MyAvatar::AllowAvatarStandingPreference::Count)>
+ MyAvatar::allowAvatarStandingPreferenceStrings = {
+ QStringLiteral("WhenUserIsStanding"),
+ QStringLiteral("Always")
+};
+
+const std::array(MyAvatar::AllowAvatarLeaningPreference::Count)>
+ MyAvatar::allowAvatarLeaningPreferenceStrings = {
+ QStringLiteral("WhenUserIsStanding"),
+ QStringLiteral("Always"),
+ QStringLiteral("Never"),
+ QStringLiteral("AlwaysNoRecenter")
+};
+
+MyAvatar::AllowAvatarStandingPreference stringToAllowAvatarStandingPreference(const QString& str) {
+ for (uint stringIndex = 0; stringIndex < static_cast(MyAvatar::AllowAvatarStandingPreference::Count); stringIndex++) {
+ if (MyAvatar::allowAvatarStandingPreferenceStrings[stringIndex] == str) {
+ return static_cast(stringIndex);
+ }
}
+
+ return MyAvatar::AllowAvatarStandingPreference::Default;
}
-QString userRecenterModelToString(MyAvatar::SitStandModelType model) {
- switch (model) {
- case MyAvatar::ForceSit:
- return USER_RECENTER_MODEL_FORCE_SIT;
- case MyAvatar::ForceStand:
- return USER_RECENTER_MODEL_FORCE_STAND;
- case MyAvatar::DisableHMDLean:
- return USER_RECENTER_MODEL_DISABLE_HMD_LEAN;
- case MyAvatar::Auto:
- default:
- return USER_RECENTER_MODEL_AUTO;
+MyAvatar::AllowAvatarLeaningPreference stringToAllowAvatarLeaningPreference(const QString& str) {
+ for (uint stringIndex = 0; stringIndex < static_cast(MyAvatar::AllowAvatarLeaningPreference::Count); stringIndex++) {
+ if (MyAvatar::allowAvatarLeaningPreferenceStrings[stringIndex] == str) {
+ return static_cast(stringIndex);
+ }
}
+
+ return MyAvatar::AllowAvatarLeaningPreference::Default;
}
static const QStringList TRIGGER_REACTION_NAMES = {
@@ -166,7 +172,7 @@ MyAvatar::MyAvatar(QThread* thread) :
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
_scriptedMotorMode(SCRIPTED_MOTOR_SIMPLE_MODE),
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
- _characterController(std::shared_ptr(this)),
+ _characterController(std::shared_ptr(this), _follow._timeRemaining),
_eyeContactTarget(LEFT_EYE),
_realWorldFieldOfView("realWorldFieldOfView",
DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES),
@@ -214,8 +220,12 @@ MyAvatar::MyAvatar(QThread* thread) :
_analogWalkSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "analogWalkSpeed", _analogWalkSpeed.get()),
_analogPlusWalkSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "analogPlusWalkSpeed", _analogPlusWalkSpeed.get()),
_controlSchemeIndexSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "controlSchemeIndex", _controlSchemeIndex),
- _userRecenterModelSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "userRecenterModel", USER_RECENTER_MODEL_AUTO)
-{
+ _allowAvatarStandingPreferenceSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "allowAvatarStandingPreference",
+ allowAvatarStandingPreferenceStrings[static_cast(
+ AllowAvatarStandingPreference::Default)]),
+ _allowAvatarLeaningPreferenceSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "allowAvatarLeaningPreference",
+ allowAvatarLeaningPreferenceStrings[static_cast(
+ AllowAvatarLeaningPreference::Default)]) {
_clientTraitsHandler.reset(new ClientTraitsHandler(this));
// give the pointer to our head to inherited _headData variable from AvatarData
@@ -493,8 +503,15 @@ void MyAvatar::centerBody() {
return;
}
+ centerBodyInternal(false);
+}
+
+// forceFollowYPos (default false): true to force the body matrix to be affected by the HMD's
+// vertical position, even if crouch recentering is disabled.
+void MyAvatar::centerBodyInternal(const bool forceFollowYPos) {
// derive the desired body orientation from the current hmd orientation, before the sensor reset.
- auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation..
+ auto newBodySensorMatrix =
+ deriveBodyFromHMDSensor(forceFollowYPos); // Based on current cached HMD position/rotation..
// transform this body into world space
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
@@ -571,64 +588,63 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
}
}
+// Determine if the user is sitting or standing in the real world.
void MyAvatar::updateSitStandState(float newHeightReading, float dt) {
const float STANDING_HEIGHT_MULTIPLE = 1.2f;
const float SITTING_HEIGHT_MULTIPLE = 0.833f;
const float SITTING_TIMEOUT = 4.0f; // 4 seconds
const float STANDING_TIMEOUT = 0.3333f; // 1/3 second
const float SITTING_UPPER_BOUND = 1.52f;
- if (!getIsSitStandStateLocked()) {
- if (!getIsAway() && getControllerPoseInAvatarFrame(controller::Action::HEAD).isValid()) {
- if (getIsInSittingState()) {
- if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) {
- // if we recenter upwards then no longer in sitting state
- _sitStandStateTimer += dt;
- if (_sitStandStateTimer > STANDING_TIMEOUT) {
- _averageUserHeightSensorSpace = newHeightReading;
- _tippingPoint = newHeightReading;
- setIsInSittingState(false);
- }
- } else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) {
- // if we are mis labelled as sitting but we are standing in the real world this will
- // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state
- _sitStandStateTimer += dt;
- if (_sitStandStateTimer > SITTING_TIMEOUT) {
- _averageUserHeightSensorSpace = newHeightReading;
- _tippingPoint = newHeightReading;
- // here we stay in sit state but reset the average height
- setIsInSittingState(true);
- }
- } else {
- // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please)
- if (_averageUserHeightSensorSpace > SITTING_UPPER_BOUND) {
- setIsInSittingState(false);
- } else {
- // tipping point is average height when sitting.
- _tippingPoint = _averageUserHeightSensorSpace;
- _sitStandStateTimer = 0.0f;
- }
+ if (!getIsAway() && _isBodyPartTracked._head) {
+ if (getIsInSittingState()) {
+ if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) {
+ // if we recenter upwards then no longer in sitting state
+ _sitStandStateTimer += dt;
+ if (_sitStandStateTimer > STANDING_TIMEOUT) {
+ _averageUserHeightSensorSpace = newHeightReading;
+ _tippingPoint = newHeightReading;
+ setIsInSittingState(false);
+ }
+ } else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) {
+ // if we are mis labelled as sitting but we are standing in the real world this will
+ // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state
+ _sitStandStateTimer += dt;
+ if (_sitStandStateTimer > SITTING_TIMEOUT) {
+ _averageUserHeightSensorSpace = newHeightReading;
+ _tippingPoint = newHeightReading;
+ // here we stay in sit state but reset the average height
+ setIsInSittingState(true);
}
} else {
- // in the standing state
- if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) {
- _sitStandStateTimer += dt;
- if (_sitStandStateTimer > SITTING_TIMEOUT) {
- _averageUserHeightSensorSpace = newHeightReading;
- _tippingPoint = newHeightReading;
- setIsInSittingState(true);
- }
+ // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please)
+ if (_averageUserHeightSensorSpace > SITTING_UPPER_BOUND) {
+ setIsInSittingState(false);
} else {
- // use the mode height for the tipping point when we are standing.
- _tippingPoint = getCurrentStandingHeight();
+ // tipping point is average height when sitting.
+ _tippingPoint = _averageUserHeightSensorSpace;
_sitStandStateTimer = 0.0f;
}
}
} else {
- //if you are away then reset the average and set state to standing.
- _averageUserHeightSensorSpace = _userHeight.get();
- _tippingPoint = _userHeight.get();
- setIsInSittingState(false);
+ // in the standing state
+ if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) {
+ _sitStandStateTimer += dt;
+ if (_sitStandStateTimer > SITTING_TIMEOUT) {
+ _averageUserHeightSensorSpace = newHeightReading;
+ _tippingPoint = newHeightReading;
+ setIsInSittingState(true);
+ }
+ } else {
+ // use the mode height for the tipping point when we are standing.
+ _tippingPoint = getCurrentStandingHeight();
+ _sitStandStateTimer = 0.0f;
+ }
}
+ } else {
+ //if you are away then reset the average and set state to standing.
+ _averageUserHeightSensorSpace = _userHeight.get();
+ _tippingPoint = _userHeight.get();
+ setIsInSittingState(false);
}
}
@@ -636,17 +652,37 @@ void MyAvatar::update(float deltaTime) {
// update moving average of HMD facing in xz plane.
const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength();
const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders
- const float COSINE_THIRTY_DEGREES = 0.866f;
- const float SQUATTY_TIMEOUT = 30.0f; // 30 seconds
const float HEIGHT_FILTER_COEFFICIENT = 0.01f;
float tau = deltaTime / HMD_FACING_TIMESCALE;
setHipToHandController(computeHandAzimuth());
+ // Determine which body parts are under direct control (tracked).
+ {
+ _isBodyPartTracked._leftHand = getControllerPoseInSensorFrame(controller::Action::LEFT_HAND).isValid();
+ _isBodyPartTracked._rightHand = getControllerPoseInSensorFrame(controller::Action::RIGHT_HAND).isValid();
+ _isBodyPartTracked._head = getControllerPoseInSensorFrame(controller::Action::HEAD).isValid();
+
+ // Check for either foot so that if one foot loses tracking, we don't break out of foot-tracking behaviour
+ // (in terms of avatar recentering for example).
+ _isBodyPartTracked._feet = _isBodyPartTracked._head && // Feet can't be tracked unless head is tracked.
+ (getControllerPoseInSensorFrame(controller::Action::LEFT_FOOT).isValid() ||
+ getControllerPoseInSensorFrame(controller::Action::RIGHT_FOOT).isValid());
+
+ _isBodyPartTracked._hips = _isBodyPartTracked._feet && // Hips can't be tracked unless feet are tracked.
+ getControllerPoseInSensorFrame(controller::Action::HIPS).isValid();
+ }
+
+ // Recenter the body when foot tracking starts or ends.
+ if (_isBodyPartTracked._feet != _isBodyPartTracked._feetPreviousUpdate) {
+ centerBodyInternal(false);
+ _isBodyPartTracked._feetPreviousUpdate = _isBodyPartTracked._feet;
+ }
+
// put the average hand azimuth into sensor space.
// then mix it with head facing direction to determine rotation recenter
int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2");
- if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && !(spine2Index < 0)) {
+ if (_isBodyPartTracked._leftHand && _isBodyPartTracked._rightHand && !(spine2Index < 0)) {
// use the spine for the azimuth origin.
glm::quat spine2Rot = getAbsoluteJointRotationInObjectFrame(spine2Index);
@@ -682,29 +718,6 @@ void MyAvatar::update(float deltaTime) {
setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD)));
}
- // if the spine is straight and the head is below the default position by 5 cm then increment squatty count.
- const float SQUAT_THRESHOLD = 0.05f;
- glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head"));
- glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2"));
- glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f);
- if (glm::length(upSpine2) > 0.0f) {
- upSpine2 = glm::normalize(upSpine2);
- }
- float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f));
-
- if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) &&
- (angleSpine2 > COSINE_THIRTY_DEGREES) &&
- (getUserRecenterModel() != MyAvatar::SitStandModelType::ForceStand)) {
-
- _squatTimer += deltaTime;
- if (_squatTimer > SQUATTY_TIMEOUT) {
- _squatTimer = 0.0f;
- _follow._squatDetected = true;
- }
- } else {
- _squatTimer = 0.0f;
- }
-
// put update sit stand state counts here
updateSitStandState(newHeightReading.getTranslation().y, deltaTime);
@@ -832,7 +845,7 @@ void MyAvatar::recalculateChildCauterization() const {
_cauterizationNeedsUpdate = true;
}
-bool MyAvatar::isFollowActive(FollowHelper::FollowType followType) const {
+bool MyAvatar::isFollowActive(CharacterController::FollowType followType) const {
return _follow.isActive(followType);
}
@@ -1277,6 +1290,10 @@ void MyAvatar::resizeAvatarEntitySettingHandles(uint32_t maxIndex) {
void MyAvatar::saveData() {
_dominantHandSetting.set(getDominantHand());
+ _allowAvatarStandingPreferenceSetting.set(
+ allowAvatarStandingPreferenceStrings[static_cast(getAllowAvatarStandingPreference())]);
+ _allowAvatarLeaningPreferenceSetting.set(
+ allowAvatarLeaningPreferenceStrings[static_cast(getAllowAvatarLeaningPreference())]);
_strafeEnabledSetting.set(getStrafeEnabled());
_hmdAvatarAlignmentTypeSetting.set(getHmdAvatarAlignmentType());
_headPitchSetting.set(getHead()->getBasePitch());
@@ -1311,7 +1328,10 @@ void MyAvatar::saveData() {
_analogWalkSpeedSetting.set(getAnalogWalkSpeed());
_analogPlusWalkSpeedSetting.set(getAnalogPlusWalkSpeed());
_controlSchemeIndexSetting.set(getControlSchemeIndex());
- _userRecenterModelSetting.set(userRecenterModelToString(getUserRecenterModel()));
+ _allowAvatarStandingPreferenceSetting.set(
+ allowAvatarStandingPreferenceStrings[static_cast(getAllowAvatarStandingPreference())]);
+ _allowAvatarLeaningPreferenceSetting.set(
+ allowAvatarLeaningPreferenceStrings[static_cast(getAllowAvatarLeaningPreference())]);
auto hmdInterface = DependencyManager::get();
saveAvatarEntityDataToSettings();
@@ -2004,7 +2024,10 @@ void MyAvatar::loadData() {
setUserHeight(_userHeightSetting.get(DEFAULT_AVATAR_HEIGHT));
setTargetScale(_scaleSetting.get());
- setUserRecenterModel(stringToUserRecenterModel(_userRecenterModelSetting.get(USER_RECENTER_MODEL_AUTO)));
+ setAllowAvatarStandingPreference(stringToAllowAvatarStandingPreference(_allowAvatarStandingPreferenceSetting.get(
+ allowAvatarStandingPreferenceStrings[static_cast(AllowAvatarStandingPreference::Default)])));
+ setAllowAvatarLeaningPreference(stringToAllowAvatarLeaningPreference(_allowAvatarLeaningPreferenceSetting.get(
+ allowAvatarLeaningPreferenceStrings[static_cast(AllowAvatarLeaningPreference::Default)])));
setEnableMeshVisible(Menu::getInstance()->isOptionChecked(MenuOption::MeshVisible));
_follow.setToggleHipsFollowing (Menu::getInstance()->isOptionChecked(MenuOption::ToggleHipsFollowing));
@@ -2666,15 +2689,8 @@ controller::Pose MyAvatar::getControllerPoseInAvatarFrame(controller::Action act
}
}
-glm::quat MyAvatar::getOffHandRotation() const {
- auto hand = (getDominantHand() == DOMINANT_RIGHT_HAND) ? controller::Action::LEFT_HAND : controller::Action::RIGHT_HAND;
- auto pose = getControllerPoseInAvatarFrame(hand);
- return pose.rotation;
-}
-
void MyAvatar::updateMotors() {
_characterController.clearMotors();
- glm::quat motorRotation;
const float FLYING_MOTOR_TIMESCALE = 0.05f;
const float WALKING_MOTOR_TIMESCALE = 0.2f;
@@ -2693,35 +2709,17 @@ void MyAvatar::updateMotors() {
}
if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) {
- if (_characterController.getState() == CharacterController::State::Hover ||
- _characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) {
- CameraMode mode = qApp->getCamera().getMode();
- if (!qApp->isHMDMode() && (mode == CAMERA_MODE_FIRST_PERSON_LOOK_AT || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE)) {
- motorRotation = getLookAtRotation();
- } else {
- motorRotation = getMyHead()->getHeadOrientation();
- }
- } else {
- // non-hovering = walking: follow camera twist about vertical but not lift
- // we decompose camera's rotation and store the twist part in motorRotation
- // however, we need to perform the decomposition in the avatar-frame
- // using the local UP axis and then transform back into world-frame
- glm::quat orientation = getWorldOrientation();
- glm::quat headOrientation = glm::inverse(orientation) * getMyHead()->getHeadOrientation(); // avatar-frame
- glm::quat liftRotation;
- swingTwistDecomposition(headOrientation, Vectors::UNIT_Y, liftRotation, motorRotation);
- motorRotation = orientation * motorRotation;
- }
-
if (_isPushing || _isBraking || !_isBeingPushed) {
- _characterController.addMotor(_actionMotorVelocity, motorRotation, horizontalMotorTimescale, verticalMotorTimescale);
+ _characterController.addMotor(_actionMotorVelocity, Quaternions::IDENTITY, horizontalMotorTimescale,
+ verticalMotorTimescale);
} else {
// _isBeingPushed must be true --> disable action motor by giving it a long timescale,
// otherwise it's attempt to "stand in in place" could defeat scripted motor/thrusts
- _characterController.addMotor(_actionMotorVelocity, motorRotation, INVALID_MOTOR_TIMESCALE);
+ _characterController.addMotor(_actionMotorVelocity, Quaternions::IDENTITY, INVALID_MOTOR_TIMESCALE);
}
}
if (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED) {
+ glm::quat motorRotation;
if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) {
motorRotation = getMyHead()->getHeadOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y);
} else if (_scriptedMotorFrame == SCRIPTED_MOTOR_AVATAR_FRAME) {
@@ -2759,8 +2757,7 @@ void MyAvatar::prepareForPhysicsSimulation() {
_characterController.setScaleFactor(getSensorToWorldScale());
_characterController.setPositionAndOrientation(getWorldPosition(), getWorldOrientation());
- auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD);
- if (headPose.isValid()) {
+ if (_isBodyPartTracked._head) {
_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput());
} else {
_follow.deactivate();
@@ -3757,15 +3754,15 @@ glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 rig
if (length > EPSILON) {
direction /= length;
}
- return getSensorToWorldScale() * direction * getSprintSpeed() * _walkSpeedScalar;
+ return direction * getSprintSpeed() * _walkSpeedScalar;
} else {
return Vectors::ZERO;
}
case LocomotionControlsMode::CONTROLS_ANALOG:
case LocomotionControlsMode::CONTROLS_ANALOG_PLUS:
if (zSpeed || xSpeed) {
- glm::vec3 scaledForward = getSensorToWorldScale() * calculateGearedSpeed(zSpeed) * _walkSpeedScalar * ((zSpeed >= stickFullOn) ? getSprintSpeed() : getWalkSpeed()) * forward;
- glm::vec3 scaledRight = getSensorToWorldScale() * calculateGearedSpeed(xSpeed) * _walkSpeedScalar * ((xSpeed > stickFullOn) ? getSprintSpeed() : getWalkSpeed()) * right;
+ glm::vec3 scaledForward = calculateGearedSpeed(zSpeed) * _walkSpeedScalar * ((zSpeed >= stickFullOn) ? getSprintSpeed() : getWalkSpeed()) * forward;
+ glm::vec3 scaledRight = calculateGearedSpeed(xSpeed) * _walkSpeedScalar * ((xSpeed > stickFullOn) ? getSprintSpeed() : getWalkSpeed()) * right;
direction = scaledForward + scaledRight;
return direction;
} else {
@@ -3793,54 +3790,114 @@ glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 rig
}
}
-glm::vec3 MyAvatar::calculateScaledDirection(){
+// Calculate the world-space motor velocity for the avatar.
+glm::vec3 MyAvatar::calculateScaledDirection() {
CharacterController::State state = _characterController.getState();
// compute action input
// Determine if we're head or controller relative...
glm::vec3 forward, right;
- if (qApp->isHMDMode()) {
- auto handRotation = getOffHandRotation();
- glm::vec3 controllerForward(0.0f, 1.0f, 0.0f);
- glm::vec3 controllerRight(0.0f, 0.0f, (getDominantHand() == DOMINANT_RIGHT_HAND ? 1.0f : -1.0f));
- glm::vec3 transform;
- switch (getMovementReference()) {
- case LocomotionRelativeMovementMode::MOVEMENT_HAND_RELATIVE:
- forward = (handRotation * controllerForward);
- right = (handRotation * controllerRight);
- break;
- case LocomotionRelativeMovementMode::MOVEMENT_HAND_RELATIVE_LEVELED:
- forward = (handRotation * controllerForward);
- transform = forward - (glm::dot(forward, Vectors::UNIT_Y) * Vectors::UNIT_Y);
- if (glm::length(transform) > EPSILON) {
- forward = glm::normalize(transform);
- } else {
- forward = Vectors::ZERO;
- }
- right = (handRotation * controllerRight);
- transform = right - (glm::dot(right, Vectors::UNIT_Y) * Vectors::UNIT_Y);
- if (glm::length(transform) > EPSILON) {
- right = glm::normalize(transform);
- } else {
- right = Vectors::ZERO;
- }
- break;
- case LocomotionRelativeMovementMode::MOVEMENT_HMD_RELATIVE:
- default:
- forward = IDENTITY_FORWARD;
- right = IDENTITY_RIGHT;
+ int movementReference = getMovementReference();
+ CameraMode cameraMode = qApp->getCamera().getMode();
+
+ bool vectorsAreInAvatarFrame = true;
+ bool removeLocalYComponent = false;
+
+ bool HMDHandRelativeMovement =
+ qApp->isHMDMode() && (movementReference == LocomotionRelativeMovementMode::MOVEMENT_HAND_RELATIVE ||
+ movementReference == LocomotionRelativeMovementMode::MOVEMENT_HAND_RELATIVE_LEVELED);
+
+ bool desktopLookatOrSelfieMode =
+ !qApp->isHMDMode() && (cameraMode == CAMERA_MODE_FIRST_PERSON_LOOK_AT || cameraMode == CAMERA_MODE_LOOK_AT ||
+ cameraMode == CAMERA_MODE_SELFIE);
+
+ bool hoveringOrCollisionless = _characterController.getState() == CharacterController::State::Hover ||
+ _characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS;
+
+ if (HMDHandRelativeMovement) {
+ controller::Action directionHand =
+ (getDominantHand() == DOMINANT_RIGHT_HAND) ? controller::Action::LEFT_HAND : controller::Action::RIGHT_HAND;
+ controller::Pose handPoseInAvatarFrame = getControllerPoseInAvatarFrame(directionHand);
+
+ if (handPoseInAvatarFrame.isValid()) {
+ glm::vec3 controllerForward(0.0f, 1.0f, 0.0f);
+ glm::vec3 controllerRight(0.0f, 0.0f, (directionHand == controller::Action::LEFT_HAND) ? 1.0f : -1.0f);
+
+ forward = (handPoseInAvatarFrame.rotation * controllerForward);
+ right = (handPoseInAvatarFrame.rotation * controllerRight);
+
+ removeLocalYComponent = (movementReference == LocomotionRelativeMovementMode::MOVEMENT_HAND_RELATIVE_LEVELED);
+ }
+ } else { // MOVEMENT_HMD_RELATIVE or desktop mode
+ if (qApp->isHMDMode()) {
+ forward = -IDENTITY_FORWARD;
+ right = -IDENTITY_RIGHT;
+ } else {
+ forward = IDENTITY_FORWARD;
+ right = IDENTITY_RIGHT;
+ }
+
+ glm::quat rotation = Quaternions::IDENTITY;
+
+ if (hoveringOrCollisionless && desktopLookatOrSelfieMode) {
+ rotation = getLookAtRotation();
+ removeLocalYComponent = false;
+ vectorsAreInAvatarFrame = false;
+ } else {
+ controller::Pose headPoseLocal = getControllerPoseInAvatarFrame(controller::Action::HEAD);
+ if (headPoseLocal.isValid()) {
+ rotation = headPoseLocal.rotation;
+ }
+ removeLocalYComponent = !hoveringOrCollisionless;
+ }
+
+ forward = rotation * forward;
+ right = rotation * right;
+ }
+
+ if (removeLocalYComponent) {
+ assert(vectorsAreInAvatarFrame);
+
+ auto removeYAndNormalize = [](glm::vec3& vector) {
+ vector.y = 0.f;
+ // Normalize if the remaining components are large enough to get a reliable direction.
+ float length = glm::length(vector);
+ const float MIN_LENGTH_FOR_NORMALIZE = 0.061f; // sin(3.5 degrees)
+ if (length > MIN_LENGTH_FOR_NORMALIZE) {
+ vector /= length;
+ } else {
+ vector = Vectors::ZERO;
+ }
+ };
+
+ removeYAndNormalize(forward);
+ removeYAndNormalize(right);
+ }
+
+ // In HMD, we combine the head pitch into the flying direction even when using hand-relative movement.
+ // Todo: Option to ignore head pitch in hand-relative flying (MOVEMENT_HAND_RELATIVE_LEVELED would then act like MOVEMENT_HAND_RELATIVE when flying).
+ if (HMDHandRelativeMovement && hoveringOrCollisionless) {
+ controller::Pose headPoseLocal = getControllerPoseInAvatarFrame(controller::Action::HEAD);
+
+ if (headPoseLocal.isValid()) {
+ glm::quat headLocalPitchRotation;
+ glm::quat headLocalYawRotation_unused;
+ swingTwistDecomposition(headPoseLocal.rotation, Vectors::UP, headLocalPitchRotation, headLocalYawRotation_unused);
+
+ forward = headLocalPitchRotation * forward;
+ right = headLocalPitchRotation * right;
}
- } else {
- forward = IDENTITY_FORWARD;
- right = IDENTITY_RIGHT;
}
glm::vec3 direction = scaleMotorSpeed(forward, right);
- if (state == CharacterController::State::Hover ||
- _characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) {
- glm::vec3 up = (getDriveKey(TRANSLATE_Y)) * IDENTITY_UP;
+ if (vectorsAreInAvatarFrame) {
+ direction = getWorldOrientation() * direction;
+ }
+
+ if (hoveringOrCollisionless) {
+ glm::vec3 up = getDriveKey(TRANSLATE_Y) * IDENTITY_UP;
direction += up;
}
@@ -4562,7 +4619,7 @@ bool MyAvatar::getFlyingHMDPref() {
}
// Public interface for targetscale
-float MyAvatar::getAvatarScale() {
+float MyAvatar::getAvatarScale() const {
return getTargetScale();
}
@@ -4723,8 +4780,11 @@ void MyAvatar::triggerRotationRecenter() {
_follow.setForceActivateRotation(true);
}
+// Derive the sensor-space matrix for the body, based on the pose of the HMD and hips tracker.
// old school meat hook style
-glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
+// forceFollowYPos (default false): true to force the body matrix to be affected by the HMD's
+// vertical position, even if crouch recentering is disabled.
+glm::mat4 MyAvatar::deriveBodyFromHMDSensor(const bool forceFollowYPos) const {
glm::vec3 headPosition(0.0f, _userHeight.get(), 0.0f);
glm::quat headOrientation;
auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
@@ -4758,10 +4818,33 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
glm::vec3 headToNeck = headOrientation * Quaternions::Y_180 * (localNeck - localHead);
glm::vec3 neckToRoot = headOrientationYawOnly * Quaternions::Y_180 * -localNeck;
- float invSensorToWorldScale = getUserEyeHeight() / getEyeHeight();
- glm::vec3 bodyPos = headPosition + invSensorToWorldScale * (headToNeck + neckToRoot);
+ float worldToSensorScale = getUserEyeHeight() / getEyeHeight();
+ glm::vec3 bodyPos = headPosition + worldToSensorScale * (headToNeck + neckToRoot);
+ glm::quat bodyQuat;
- return createMatFromQuatAndPos(headOrientationYawOnly, bodyPos);
+ controller::Pose hipsControllerPose = getControllerPoseInSensorFrame(controller::Action::HIPS);
+ if (hipsControllerPose.isValid()) {
+ glm::quat hipsOrientation = hipsControllerPose.rotation * Quaternions::Y_180;
+ glm::quat hipsOrientationYawOnly = cancelOutRollAndPitch(hipsOrientation);
+
+ glm::vec3 hipsPos = hipsControllerPose.getTranslation();
+ bodyPos.x = hipsPos.x;
+ bodyPos.z = hipsPos.z;
+
+ bodyQuat = hipsOrientationYawOnly;
+ } else {
+ bodyQuat = headOrientationYawOnly;
+ }
+
+ if (!forceFollowYPos && !getHMDCrouchRecenterEnabled()) {
+ // Set the body's vertical position as if it were standing in its T-pose.
+ float rigToUserScale = getUserEyeHeight() / getUnscaledEyeHeight();
+ bodyPos.y = rigToUserScale * rig.getUnscaledHipsHeight();
+ }
+
+ glm::mat4 bodyMat = createMatFromQuatAndPos(bodyQuat, bodyPos);
+
+ return bodyMat;
}
glm::mat4 MyAvatar::getSpine2RotationRigSpace() const {
@@ -4893,11 +4976,11 @@ glm::vec3 MyAvatar::computeCounterBalance() {
glm::vec3 currentCg = (1.0f / totalMass) * sumOfMoments;
currentCg.y = 0.0f;
// dampening the center of gravity, in effect, limits the value to the perimeter of the base of support
- float baseScale = 1.0f;
+ float baseAndAvatarScale = getAvatarScale();
if (getUserEyeHeight() > 0.0f) {
- baseScale = getUserEyeHeight() / DEFAULT_AVATAR_EYE_HEIGHT;
+ baseAndAvatarScale *= getUserEyeHeight() / DEFAULT_AVATAR_EYE_HEIGHT;
}
- glm::vec3 desiredCg = dampenCgMovement(currentCg, baseScale);
+ glm::vec3 desiredCg = dampenCgMovement(currentCg, baseAndAvatarScale);
// compute hips position to maintain desiredCg
glm::vec3 counterBalancedForHead = (totalMass + DEFAULT_AVATAR_HIPS_MASS) * desiredCg;
@@ -4916,9 +4999,10 @@ glm::vec3 MyAvatar::computeCounterBalance() {
// this is to be sure that the feet don't lift off the floor.
// add 5 centimeters to allow for going up on the toes.
- if (counterBalancedCg.y > (tposeHips.y + 0.05f)) {
+ float maxCounterBalancedCGY = (tposeHips.y + 0.05f) * baseAndAvatarScale;
+ if (counterBalancedCg.y > maxCounterBalancedCGY) {
// if the height is higher than default hips, clamp to default hips
- counterBalancedCg.y = tposeHips.y + 0.05f;
+ counterBalancedCg.y = maxCounterBalancedCGY;
}
return counterBalancedCg;
}
@@ -4949,7 +5033,7 @@ static void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::ma
float clampBack = DEFAULT_AVATAR_SUPPORT_BASE_BACK * baseOfSupportScale;
float clampLeft = DEFAULT_AVATAR_SUPPORT_BASE_LEFT * baseOfSupportScale;
float clampRight = DEFAULT_AVATAR_SUPPORT_BASE_RIGHT * baseOfSupportScale;
- float floor = footLocal + 0.05f;
+ float floor = footLocal;
// transform the base of support corners to world space
glm::vec3 frontRight = transformPoint(avatarToWorld, { clampRight, floor, clampFront });
@@ -4980,7 +5064,7 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() {
glm::mat4 avatarHeadMat = glm::inverse(avatarToWorldMat) * sensorToWorldMat * sensorHeadMat;
if (_enableDebugDrawBaseOfSupport) {
- float scaleBaseOfSupport = getUserEyeHeight() / DEFAULT_AVATAR_EYE_HEIGHT;
+ float scaleBaseOfSupport = (getUserEyeHeight() / DEFAULT_AVATAR_EYE_HEIGHT) * getAvatarScale();
glm::vec3 rightFootPositionLocal = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("RightFoot"));
drawBaseOfSupport(scaleBaseOfSupport, rightFootPositionLocal.y, avatarToWorldMat);
}
@@ -4996,26 +5080,16 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() {
return worldToSensorMat * avatarToWorldMat * avatarHipsMat;
}
-static bool isInsideLine(const glm::vec3& a, const glm::vec3& b, const glm::vec3& c) {
- return (((b.x - a.x) * (c.z - a.z) - (b.z - a.z) * (c.x - a.x)) > 0);
-}
-
-static bool withinBaseOfSupport(const controller::Pose& head) {
- float userScale = 1.0f;
-
- glm::vec3 frontLeft(-DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD, 0.0f, -DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD);
- glm::vec3 frontRight(DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD, 0.0f, -DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD);
- glm::vec3 backLeft(-DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD, 0.0f, DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD);
- glm::vec3 backRight(DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD, 0.0f, DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD);
-
- bool isWithinSupport = false;
- if (head.isValid()) {
- bool withinFrontBase = isInsideLine(userScale * frontLeft, userScale * frontRight, head.getTranslation());
- bool withinBackBase = isInsideLine(userScale * backRight, userScale * backLeft, head.getTranslation());
- bool withinLateralBase = (isInsideLine(userScale * frontRight, userScale * backRight, head.getTranslation()) &&
- isInsideLine(userScale * backLeft, userScale * frontLeft, head.getTranslation()));
- isWithinSupport = (withinFrontBase && withinBackBase && withinLateralBase);
+static bool withinBaseOfSupport(const controller::Pose& head, const float avatarScale) {
+ if (!head.isValid()) {
+ return false;
}
+
+ vec3 headPosScaled = head.getTranslation() / avatarScale;
+ bool isWithinSupport = (headPosScaled.x > -DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD) &&
+ (headPosScaled.x < DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD) &&
+ (headPosScaled.z > -DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD) &&
+ (headPosScaled.z < DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD);
return isWithinSupport;
}
@@ -5031,10 +5105,10 @@ static bool headAngularVelocityBelowThreshold(const controller::Pose& head) {
return isBelowThreshold;
}
-static bool isWithinThresholdHeightMode(const controller::Pose& head, const float& newMode, const float& scale) {
+static bool isWithinThresholdHeightMode(const controller::Pose& head, const float newMode, const float avatarScale) {
bool isWithinThreshold = true;
if (head.isValid()) {
- isWithinThreshold = (head.getTranslation().y - newMode) > (DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD * scale);
+ isWithinThreshold = head.getTranslation().y > ((DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD + newMode) * avatarScale);
}
return isWithinThreshold;
}
@@ -5058,7 +5132,7 @@ float MyAvatar::computeStandingHeightMode(const controller::Pose& head) {
modeInMeters = ((float)mode) / CENTIMETERS_PER_METER;
if (!(modeInMeters > getCurrentStandingHeight())) {
// if not greater check for a reset
- if (getResetMode() && getControllerPoseInAvatarFrame(controller::Action::HEAD).isValid()) {
+ if (getResetMode() && _isBodyPartTracked._head) {
setResetMode(false);
float resetModeInCentimeters = glm::floor((head.getTranslation().y - MODE_CORRECTION_FACTOR)*CENTIMETERS_PER_METER);
modeInMeters = (resetModeInCentimeters / CENTIMETERS_PER_METER);
@@ -5115,12 +5189,12 @@ static bool handAngularVelocityBelowThreshold(const controller::Pose& leftHand,
(rightHandXZAngularVelocity < DEFAULT_HANDS_ANGULAR_VELOCITY_STEPPING_THRESHOLD));
}
-static bool headVelocityGreaterThanThreshold(const controller::Pose& head) {
+static bool headVelocityGreaterThanThreshold(const controller::Pose& head, const float avatarScale) {
float headVelocityMagnitude = 0.0f;
if (head.isValid()) {
headVelocityMagnitude = glm::length(head.getVelocity());
}
- return headVelocityMagnitude > DEFAULT_HEAD_VELOCITY_STEPPING_THRESHOLD;
+ return headVelocityMagnitude > (DEFAULT_HEAD_VELOCITY_STEPPING_THRESHOLD * avatarScale);
}
glm::quat MyAvatar::computeAverageHeadRotation(const controller::Pose& head) {
@@ -5144,6 +5218,7 @@ float MyAvatar::getUserHeight() const {
void MyAvatar::setUserHeight(float value) {
_userHeight.set(value);
+ centerBodyInternal(false);
float sensorToWorldScale = getEyeHeight() / getUserEyeHeight();
emit sensorToWorldScaleChanged(sensorToWorldScale);
@@ -5159,16 +5234,45 @@ bool MyAvatar::getIsInWalkingState() const {
return _isInWalkingState;
}
+// Determine if the user is sitting in the real world.
bool MyAvatar::getIsInSittingState() const {
return _isInSittingState.get();
}
+// Deprecated, will be removed.
MyAvatar::SitStandModelType MyAvatar::getUserRecenterModel() const {
- return _userRecenterModel.get();
+ qCDebug(interfaceapp)
+ << "MyAvatar.getUserRecenterModel is deprecated and will be removed.";
+
+ // The legacy SitStandModelType corresponding to each AllowAvatarLeaningPreference.
+ std::array(AllowAvatarLeaningPreference::Count)> legacySitStandModels = {
+ SitStandModelType::Auto, // AllowAvatarLeaningPreference::WhenUserIsStanding
+ SitStandModelType::ForceStand, // AllowAvatarLeaningPreference::Always
+ SitStandModelType::ForceSit, // AllowAvatarLeaningPreference::Never
+ SitStandModelType::DisableHMDLean // AllowAvatarLeaningPreference::AlwaysNoRecenter
+ };
+
+ return legacySitStandModels[static_cast(_allowAvatarLeaningPreference.get())];
}
+// Deprecated, will be removed.
bool MyAvatar::getIsSitStandStateLocked() const {
- return _lockSitStandState.get();
+ qCDebug(interfaceapp) << "MyAvatar.getIsSitStandStateLocked is deprecated and will be removed.";
+
+ // In the old code, the record of the user's sit/stand state was locked except when using
+ // SitStandModelType::Auto or SitStandModelType::DisableHMDLean.
+ return (_allowAvatarStandingPreference.get() != AllowAvatarStandingPreference::WhenUserIsStanding) &&
+ (_allowAvatarLeaningPreference.get() != AllowAvatarLeaningPreference::AlwaysNoRecenter);
+}
+
+// Get the user preference of when MyAvatar may stand.
+MyAvatar::AllowAvatarStandingPreference MyAvatar::getAllowAvatarStandingPreference() const {
+ return _allowAvatarStandingPreference.get();
+}
+
+// Get the user preference of when MyAvatar may lean.
+MyAvatar::AllowAvatarLeaningPreference MyAvatar::getAllowAvatarLeaningPreference() const {
+ return _allowAvatarLeaningPreference.get();
}
float MyAvatar::getWalkSpeed() const {
@@ -5221,59 +5325,61 @@ void MyAvatar::setIsInWalkingState(bool isWalking) {
_isInWalkingState = isWalking;
}
+// Specify whether the user is sitting or standing in the real world.
void MyAvatar::setIsInSittingState(bool isSitting) {
+ // In updateSitStandState, we only change state if this timer is above a threshold (STANDING_TIMEOUT, SITTING_TIMEOUT).
+ // This avoids changing state if the user sits and stands up quickly.
_sitStandStateTimer = 0.0f;
- _squatTimer = 0.0f;
- // on reset height we need the count to be more than one in case the user sits and stands up quickly.
+
_isInSittingState.set(isSitting);
setResetMode(true);
- if (isSitting) {
- setCenterOfGravityModelEnabled(false);
- } else {
- setCenterOfGravityModelEnabled(true);
- }
setSitStandStateChange(true);
}
+// Deprecated, will be removed.
void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) {
-
- _userRecenterModel.set(modelName);
+ qCDebug(interfaceapp)
+ << "MyAvatar.setUserRecenterModel is deprecated and will be removed.";
switch (modelName) {
- case MyAvatar::SitStandModelType::ForceSit:
- setHMDLeanRecenterEnabled(true);
- setIsInSittingState(true);
- setIsSitStandStateLocked(true);
+ case SitStandModelType::ForceSit:
+ setAllowAvatarStandingPreference(AllowAvatarStandingPreference::Always);
+ setAllowAvatarLeaningPreference(AllowAvatarLeaningPreference::Never);
break;
- case MyAvatar::SitStandModelType::ForceStand:
- setHMDLeanRecenterEnabled(true);
- setIsInSittingState(false);
- setIsSitStandStateLocked(true);
+ case SitStandModelType::ForceStand:
+ setAllowAvatarStandingPreference(AllowAvatarStandingPreference::Always);
+ setAllowAvatarLeaningPreference(AllowAvatarLeaningPreference::Always);
break;
- case MyAvatar::SitStandModelType::Auto:
+ case SitStandModelType::Auto:
default:
- setHMDLeanRecenterEnabled(true);
- setIsInSittingState(false);
- setIsSitStandStateLocked(false);
+ setAllowAvatarStandingPreference(AllowAvatarStandingPreference::Always);
+ setAllowAvatarLeaningPreference(AllowAvatarLeaningPreference::WhenUserIsStanding);
break;
- case MyAvatar::SitStandModelType::DisableHMDLean:
- setHMDLeanRecenterEnabled(false);
- setIsInSittingState(false);
- setIsSitStandStateLocked(false);
+ case SitStandModelType::DisableHMDLean:
+ setAllowAvatarStandingPreference(AllowAvatarStandingPreference::WhenUserIsStanding);
+ setAllowAvatarLeaningPreference(AllowAvatarLeaningPreference::AlwaysNoRecenter);
break;
}
}
+// Set the user preference of when the avatar may stand.
+void MyAvatar::setAllowAvatarStandingPreference(const MyAvatar::AllowAvatarStandingPreference preference) {
+ _allowAvatarStandingPreference.set(preference);
+
+ // Set the correct vertical position for the avatar body relative to the HMD,
+ // according to the newly-selected avatar standing preference.
+ centerBodyInternal(false);
+}
+
+// Deprecated, will be removed.
void MyAvatar::setIsSitStandStateLocked(bool isLocked) {
- _lockSitStandState.set(isLocked);
- _sitStandStateTimer = 0.0f;
- _squatTimer = 0.0f;
- _averageUserHeightSensorSpace = _userHeight.get();
- _tippingPoint = _userHeight.get();
- if (!isLocked) {
- // always start the auto transition mode in standing state.
- setIsInSittingState(false);
- }
+ Q_UNUSED(isLocked);
+ qCDebug(interfaceapp) << "MyAvatar.setIsSitStandStateLocked is deprecated and will be removed.";
+}
+
+// Set the user preference of when the avatar may lean.
+void MyAvatar::setAllowAvatarLeaningPreference(const MyAvatar::AllowAvatarLeaningPreference preference) {
+ _allowAvatarLeaningPreference.set(preference);
}
void MyAvatar::setWalkSpeed(float value) {
@@ -5402,10 +5508,12 @@ float MyAvatar::getAnalogPlusSprintSpeed() const {
return _analogPlusSprintSpeed.get();
}
+// Indicate whether the user's real-world sit/stand state has changed or not.
void MyAvatar::setSitStandStateChange(bool stateChanged) {
_sitStandStateChange = stateChanged;
}
+// Determine if the user's real-world sit/stand state has changed.
float MyAvatar::getSitStandStateChange() const {
return _sitStandStateChange;
}
@@ -5499,65 +5607,84 @@ MyAvatar::FollowHelper::FollowHelper() {
}
void MyAvatar::FollowHelper::deactivate() {
- for (int i = 0; i < NumFollowTypes; i++) {
- deactivate((FollowType)i);
+ for (uint i = 0; i < static_cast(CharacterController::FollowType::Count); i++) {
+ deactivate(static_cast(i));
}
}
-void MyAvatar::FollowHelper::deactivate(FollowType type) {
- assert(type >= 0 && type < NumFollowTypes);
+void MyAvatar::FollowHelper::deactivate(CharacterController::FollowType type) {
+ assert(static_cast(type) >= 0 && type < CharacterController::FollowType::Count);
_timeRemaining[(int)type] = 0.0f;
}
-void MyAvatar::FollowHelper::activate(FollowType type) {
- assert(type >= 0 && type < NumFollowTypes);
+// snapFollow: true to snap immediately to the desired transform with regard to 'type',
+// eg. activate(FollowType::Rotation, true) snaps the FollowHelper's rotation immediately
+// to the rotation of its _followDesiredBodyTransform.
+void MyAvatar::FollowHelper::activate(CharacterController::FollowType type, const bool snapFollow) {
+ assert(static_cast(type) >= 0 && type < CharacterController::FollowType::Count);
+
// TODO: Perhaps, the follow time should be proportional to the displacement.
- _timeRemaining[(int)type] = FOLLOW_TIME;
+ _timeRemaining[(int)type] = snapFollow ? CharacterController::FOLLOW_TIME_IMMEDIATE_SNAP : FOLLOW_TIME;
}
-bool MyAvatar::FollowHelper::isActive(FollowType type) const {
- assert(type >= 0 && type < NumFollowTypes);
+bool MyAvatar::FollowHelper::isActive(CharacterController::FollowType type) const {
+ assert(static_cast(type) >= 0 && type < CharacterController::FollowType::Count);
return _timeRemaining[(int)type] > 0.0f;
}
bool MyAvatar::FollowHelper::isActive() const {
- for (int i = 0; i < NumFollowTypes; i++) {
- if (isActive((FollowType)i)) {
+ for (uint i = 0; i < static_cast(CharacterController::FollowType::Count); i++) {
+ if (isActive(static_cast(i))) {
return true;
}
}
return false;
}
-float MyAvatar::FollowHelper::getMaxTimeRemaining() const {
- float max = 0.0f;
- for (int i = 0; i < NumFollowTypes; i++) {
- if (_timeRemaining[i] > max) {
- max = _timeRemaining[i];
+void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) {
+ for (auto& time : _timeRemaining) {
+ if (time == CharacterController::FOLLOW_TIME_IMMEDIATE_SNAP) {
+ time = 0.0f;
+ } else {
+ time -= dt;
}
}
- return max;
}
-void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) {
- for (int i = 0; i < NumFollowTypes; i++) {
- _timeRemaining[i] -= dt;
+// shouldSnapOut: (out) true if the FollowHelper should snap immediately to its desired rotation.
+bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar,
+ const glm::mat4& desiredBodyMatrix,
+ const glm::mat4& currentBodyMatrix,
+ bool& shouldSnapOut) const {
+ // If hips are under direct control (tracked), they give our desired body rotation and we snap to it every frame.
+ if (myAvatar.areHipsTracked()) {
+ shouldSnapOut = true;
+ return true;
+ } else {
+ shouldSnapOut = false;
}
-}
-bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
const float FOLLOW_ROTATION_THRESHOLD = cosf(myAvatar.getRotationThreshold());
glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix);
return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD;
}
-bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
+// Determine if the horizontal following should activate, for a user who is sitting in the real world.
+bool MyAvatar::FollowHelper::shouldActivateHorizontal_userSitting(const MyAvatar& myAvatar,
+ const glm::mat4& desiredBodyMatrix,
+ const glm::mat4& currentBodyMatrix) const {
+ if (!myAvatar.isAllowedToLean()) {
+ controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD);
+ if (!withinBaseOfSupport(currentHeadPose, myAvatar.getAvatarScale())) {
+ return true;
+ }
+ }
+
// -z axis of currentBodyMatrix in world space.
glm::vec3 forward = glm::normalize(glm::vec3(-currentBodyMatrix[0][2], -currentBodyMatrix[1][2], -currentBodyMatrix[2][2]));
// x axis of currentBodyMatrix in world space.
glm::vec3 right = glm::normalize(glm::vec3(currentBodyMatrix[0][0], currentBodyMatrix[1][0], currentBodyMatrix[2][0]));
glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);
- controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD);
float forwardLeanAmount = glm::dot(forward, offset);
float lateralLeanAmount = glm::dot(right, offset);
@@ -5567,11 +5694,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
const float MAX_BACKWARD_LEAN = 0.1f;
bool stepDetected = false;
- if (myAvatar.getIsInSittingState()) {
- if (!withinBaseOfSupport(currentHeadPose)) {
- stepDetected = true;
- }
- } else if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) {
+ if (forwardLeanAmount > MAX_FORWARD_LEAN) {
stepDetected = true;
} else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) {
stepDetected = true;
@@ -5581,52 +5704,82 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
return stepDetected;
}
-bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const {
-
- // get the current readings
- controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD);
- controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND);
- controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND);
- controller::Pose currentHeadSensorPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD);
-
- bool stepDetected = false;
- float myScale = myAvatar.getAvatarScale();
+// Determine if the horizontal following should activate, for a user who is standing in the real world.
+// resetModeOut: (out) true if setResetMode(true) should be called if this function returns true.
+// goToWalkingStateOut: (out) true if setIsInWalkingState(true) should be called if this function returns true.
+bool MyAvatar::FollowHelper::shouldActivateHorizontal_userStanding(
+ const MyAvatar& myAvatar,
+ bool& resetModeOut,
+ bool& goToWalkingStateOut) const {
if (myAvatar.getIsInWalkingState()) {
- stepDetected = true;
- } else {
- if (!withinBaseOfSupport(currentHeadPose) &&
- headAngularVelocityBelowThreshold(currentHeadPose) &&
- isWithinThresholdHeightMode(currentHeadSensorPose, myAvatar.getCurrentStandingHeight(), myScale) &&
- handDirectionMatchesHeadDirection(currentLeftHandPose, currentRightHandPose, currentHeadPose) &&
- handAngularVelocityBelowThreshold(currentLeftHandPose, currentRightHandPose) &&
- headVelocityGreaterThanThreshold(currentHeadPose) &&
- isHeadLevel(currentHeadPose, myAvatar.getAverageHeadRotation())) {
- // a step is detected
+ return true;
+ }
+
+ controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD);
+ bool stepDetected = false;
+ float avatarScale = myAvatar.getAvatarScale();
+
+ if (!withinBaseOfSupport(currentHeadPose, avatarScale)) {
+ if (!myAvatar.isAllowedToLean()) {
stepDetected = true;
- if (glm::length(currentHeadPose.velocity) > DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) {
- myAvatar.setIsInWalkingState(true);
- }
} else {
- glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips"));
- glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head"));
- glm::vec3 currentHeadPosition = currentHeadPose.getTranslation();
- float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition);
- if (!isActive(Horizontal) &&
- (!isActive(Vertical)) &&
- (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) {
- myAvatar.setResetMode(true);
+ // get the current readings
+ controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND);
+ controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND);
+ controller::Pose currentHeadSensorPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD);
+
+ if (headAngularVelocityBelowThreshold(currentHeadPose) &&
+ isWithinThresholdHeightMode(currentHeadSensorPose, myAvatar.getCurrentStandingHeight(), avatarScale) &&
+ handDirectionMatchesHeadDirection(currentLeftHandPose, currentRightHandPose, currentHeadPose) &&
+ handAngularVelocityBelowThreshold(currentLeftHandPose, currentRightHandPose) &&
+ headVelocityGreaterThanThreshold(currentHeadPose, avatarScale) &&
+ isHeadLevel(currentHeadPose, myAvatar.getAverageHeadRotation())) {
+ // a step is detected
stepDetected = true;
- if (glm::length(currentHeadPose.velocity) > DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) {
- myAvatar.setIsInWalkingState(true);
+ }
+ }
+ }
+
+ if (!stepDetected) {
+ glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips"));
+ glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head"));
+ glm::vec3 currentHeadPosition = currentHeadPose.getTranslation();
+ float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition);
+ if (!isActive(CharacterController::FollowType::Horizontal) && (!isActive(CharacterController::FollowType::Vertical)) &&
+ (glm::length(currentHeadPosition - defaultHipsPosition) >
+ (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) {
+ resetModeOut = true;
+ stepDetected = true;
+ if (currentHeadPose.isValid()) {
+ if (glm::length(currentHeadPose.velocity) > (DEFAULT_AVATAR_WALK_SPEED_THRESHOLD * avatarScale)) {
+ goToWalkingStateOut = true;
}
}
}
}
+
return stepDetected;
}
-bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
+// Determine if the horizontal following should activate.
+// resetModeOut: (out) true if setResetMode(true) should be called if this function returns true.
+// goToWalkingStateOut: (out) true if setIsInWalkingState(true) should be called if this function returns true.
+bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
+ const glm::mat4& desiredBodyMatrix,
+ const glm::mat4& currentBodyMatrix,
+ bool& resetModeOut,
+ bool& goToWalkingStateOut) const {
+ if (myAvatar.getIsInSittingState()) {
+ return shouldActivateHorizontal_userSitting(myAvatar, desiredBodyMatrix, currentBodyMatrix);
+ } else {
+ return shouldActivateHorizontal_userStanding(myAvatar, resetModeOut, goToWalkingStateOut);
+ }
+}
+
+bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar,
+ const glm::mat4& desiredBodyMatrix,
+ const glm::mat4& currentBodyMatrix) const {
const float CYLINDER_TOP = 2.0f;
const float CYLINDER_BOTTOM = -1.5f;
const float SITTING_BOTTOM = -0.02f;
@@ -5638,9 +5791,6 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co
returnValue = true;
} else {
if (myAvatar.getIsInSittingState()) {
- if (myAvatar.getIsSitStandStateLocked()) {
- returnValue = (offset.y > CYLINDER_TOP);
- }
if (offset.y < SITTING_BOTTOM) {
// we recenter more easily when in sitting state.
returnValue = true;
@@ -5648,60 +5798,89 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co
} else {
// in the standing state
returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM);
- // finally check for squats in standing
- if (_squatDetected) {
- returnValue = true;
- }
}
}
return returnValue;
}
-void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix,
- const glm::mat4& currentBodyMatrix, bool hasDriveInput) {
+void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar,
+ const glm::mat4& desiredBodyMatrix,
+ const glm::mat4& currentBodyMatrix,
+ bool hasDriveInput) {
+ if (myAvatar.getHMDLeanRecenterEnabled()) {
- if (myAvatar.getHMDLeanRecenterEnabled() &&
- qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) {
- if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
- activate(Rotation);
- myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing());
- }
- if (myAvatar.getCenterOfGravityModelEnabled()) {
- if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) {
- activate(Horizontal);
- if (myAvatar.getEnableStepResetRotation()) {
- activate(Rotation);
- myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing());
- }
+ // Rotation recenter
+
+ {
+ bool snapFollow = false;
+ if (!isActive(CharacterController::FollowType::Rotation) &&
+ (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix, snapFollow) || hasDriveInput)) {
+ activate(CharacterController::FollowType::Rotation, snapFollow);
+ myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing());
}
+ }
+
+ // Lean recenter
+
+ if ((myAvatar.areFeetTracked() || getForceActivateHorizontal()) && !isActive(CharacterController::FollowType::Horizontal)) {
+ activate(CharacterController::FollowType::Horizontal, myAvatar.areFeetTracked());
+ setForceActivateHorizontal(false);
} else {
- // center of gravity model is not enabled
- if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
- activate(Horizontal);
- if (myAvatar.getEnableStepResetRotation() && !myAvatar.getIsInSittingState()) {
- activate(Rotation);
- myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing());
+ if ((myAvatar.getAllowAvatarLeaningPreference() != MyAvatar::AllowAvatarLeaningPreference::AlwaysNoRecenter) &&
+ qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) {
+
+ bool resetModeOut = false;
+ bool goToWalkingStateOut = false;
+
+ // True if the user can turn their body while sitting (eg. swivel chair).
+ // Todo?: We could expose this as an option.
+ // (Regardless, rotation recentering does kick-in if they turn too far).
+ constexpr bool USER_CAN_TURN_BODY_WHILE_SITTING = false;
+
+ if (!isActive(CharacterController::FollowType::Horizontal) &&
+ (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix, resetModeOut,
+ goToWalkingStateOut) ||
+ hasDriveInput)) {
+ activate(CharacterController::FollowType::Horizontal, false);
+ if (myAvatar.getEnableStepResetRotation() &&
+ (USER_CAN_TURN_BODY_WHILE_SITTING || !myAvatar.getIsInSittingState())) {
+ activate(CharacterController::FollowType::Rotation, false);
+ myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing());
+ }
+
+ if (resetModeOut) {
+ myAvatar.setResetMode(true);
+ }
+
+ if (goToWalkingStateOut) {
+ myAvatar.setIsInWalkingState(true);
+ }
}
}
}
- if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
- activate(Vertical);
- if (_squatDetected) {
- _squatDetected = false;
+
+ // Vertical recenter
+
+ if (myAvatar.getHMDCrouchRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) {
+ if (!isActive(CharacterController::FollowType::Vertical) &&
+ (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
+ activate(CharacterController::FollowType::Vertical, false);
}
}
} else {
- if (!isActive(Rotation) && getForceActivateRotation()) {
- activate(Rotation);
+ // Forced activations can be requested by MyAvatar::triggerVerticalRecenter, callable from scripts.
+
+ if (!isActive(CharacterController::FollowType::Rotation) && getForceActivateRotation()) {
+ activate(CharacterController::FollowType::Rotation, true);
myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing());
setForceActivateRotation(false);
}
- if (!isActive(Horizontal) && getForceActivateHorizontal()) {
- activate(Horizontal);
+ if (!isActive(CharacterController::FollowType::Horizontal) && getForceActivateHorizontal()) {
+ activate(CharacterController::FollowType::Horizontal, true);
setForceActivateHorizontal(false);
}
- if (!isActive(Vertical) && getForceActivateVertical()) {
- activate(Vertical);
+ if (!isActive(CharacterController::FollowType::Vertical) && getForceActivateVertical()) {
+ activate(CharacterController::FollowType::Vertical, true);
setForceActivateVertical(false);
}
}
@@ -5721,21 +5900,21 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
// remove scale present from sensorToWorldMatrix
followWorldPose.scale() = glm::vec3(1.0f);
- if (isActive(Rotation)) {
- //use the hmd reading for the hips follow
- followWorldPose.rot() = glmExtractRotation(desiredWorldMatrix);
+ if (isActive(CharacterController::FollowType::Rotation)) {
+ //use the hmd reading for the hips follow
+ followWorldPose.rot() = glmExtractRotation(desiredWorldMatrix);
}
- if (isActive(Horizontal)) {
+ if (isActive(CharacterController::FollowType::Horizontal)) {
glm::vec3 desiredTranslation = extractTranslation(desiredWorldMatrix);
followWorldPose.trans().x = desiredTranslation.x;
followWorldPose.trans().z = desiredTranslation.z;
}
- if (isActive(Vertical)) {
+ if (isActive(CharacterController::FollowType::Vertical)) {
glm::vec3 desiredTranslation = extractTranslation(desiredWorldMatrix);
followWorldPose.trans().y = desiredTranslation.y;
}
- myAvatar.getCharacterController()->setFollowParameters(followWorldPose, getMaxTimeRemaining());
+ myAvatar.getCharacterController()->setFollowParameters(followWorldPose);
}
glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) {
@@ -5755,10 +5934,13 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar, const gl
glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix),
sensorLinearDisplacement + extractTranslation(currentBodyMatrix));
- if (myAvatar.getSitStandStateChange()) {
- myAvatar.setSitStandStateChange(false);
- deactivate(Vertical);
- setTranslation(newBodyMat, extractTranslation(myAvatar.deriveBodyFromHMDSensor()));
+
+ if (myAvatar.getHMDCrouchRecenterEnabled()) {
+ if (myAvatar.getSitStandStateChange()) {
+ myAvatar.setSitStandStateChange(false);
+ deactivate(CharacterController::FollowType::Vertical);
+ setTranslation(newBodyMat, extractTranslation(myAvatar.deriveBodyFromHMDSensor()));
+ }
}
return newBodyMat;
} else {
@@ -6127,7 +6309,7 @@ void MyAvatar::updateHoldActions(const AnimPose& prePhysicsPose, const AnimPose&
}
bool MyAvatar::isRecenteringHorizontally() const {
- return _follow.isActive(FollowHelper::Horizontal);
+ return _follow.isActive(CharacterController::FollowType::Horizontal);
}
const MyHead* MyAvatar::getMyHead() const {
@@ -6583,7 +6765,7 @@ void MyAvatar::beginSit(const glm::vec3& position, const glm::quat& rotation) {
setHMDLeanRecenterEnabled(false);
// Disable movement
setSitDriveKeysStatus(false);
- centerBody();
+ centerBodyInternal(true);
int hipIndex = getJointIndex("Hips");
clearPinOnJoint(hipIndex);
pinJoint(hipIndex, position, rotation);
@@ -6601,7 +6783,7 @@ void MyAvatar::endSit(const glm::vec3& position, const glm::quat& rotation) {
_characterController.setSeated(false);
setCollisionsEnabled(true);
setHMDLeanRecenterEnabled(true);
- centerBody();
+ centerBodyInternal(false);
slamPosition(position);
setWorldOrientation(rotation);
@@ -6906,6 +7088,19 @@ bool MyAvatar::isJumping() {
_characterController.getState() == CharacterController::State::Takeoff) && !isFlying();
}
+// Determine if the avatar is allowed to lean in its current situation.
+bool MyAvatar::isAllowedToLean() const {
+ return (getAllowAvatarLeaningPreference() == MyAvatar::AllowAvatarLeaningPreference::Always) ||
+ ((getAllowAvatarLeaningPreference() == MyAvatar::AllowAvatarLeaningPreference::WhenUserIsStanding) &&
+ !getIsInSittingState());
+}
+
+// Determine if crouch recentering is enabled (making the avatar stand when the user is sitting in the real world).
+bool MyAvatar::getHMDCrouchRecenterEnabled() const {
+ return (!_characterController.getSeated() &&
+ (_allowAvatarStandingPreference.get() == AllowAvatarStandingPreference::Always) && !_isBodyPartTracked._feet);
+}
+
bool MyAvatar::setPointAt(const glm::vec3& pointAtTarget) {
if (QThread::currentThread() != thread()) {
bool result = false;
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 3140c68f88..3d278cf983 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -283,15 +283,16 @@ class MyAvatar : public Avatar {
* the value.
* @property {number} analogPlusSprintSpeed - The sprint (run) speed of your avatar for the "AnalogPlus" control scheme.
* @property {MyAvatar.SitStandModelType} userRecenterModel - Controls avatar leaning and recentering behavior.
- * @property {number} isInSittingState - true
if the user wearing the HMD is determined to be sitting
- * (avatar leaning is disabled, recentering is enabled), false
if the user wearing the HMD is
- * determined to be standing (avatar leaning is enabled, and avatar recenters if it leans too far).
- * If userRecenterModel == 2
(i.e., "auto") the property value automatically updates as the user sits
- * or stands, unless isSitStandStateLocked == true
. Setting the property value overrides the current
- * sitting / standing state, which is updated when the user next sits or stands unless
- * isSitStandStateLocked == true
.
+ * Deprecated: This property is deprecated and will be removed.
+ * @property {boolean} isInSittingState - true
if the user wearing the HMD is determined to be sitting;
+ * false
if the user wearing the HMD is determined to be standing. This can affect whether the avatar
+ * is allowed to stand, lean or recenter its footing, depending on user preferences.
+ * The property value automatically updates as the user sits or stands. Setting the property value overrides the current
+ * sitting / standing state, which is updated when the user next sits or stands.
* @property {boolean} isSitStandStateLocked - true
to lock the avatar sitting/standing state, i.e., use this
* to disable automatically changing state.
+ * Deprecated: This property is deprecated and will be removed.
+ * See also: getUserRecenterModel
and setUserRecenterModel
.
* @property {boolean} allowTeleporting - true
if teleporting is enabled in the Interface settings,
* false
if it isn't. Read-only.
*
@@ -413,8 +414,8 @@ class MyAvatar : public Avatar {
Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed NOTIFY walkBackwardSpeedChanged);
Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed NOTIFY sprintSpeedChanged);
Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState);
- Q_PROPERTY(MyAvatar::SitStandModelType userRecenterModel READ getUserRecenterModel WRITE setUserRecenterModel);
- Q_PROPERTY(bool isSitStandStateLocked READ getIsSitStandStateLocked WRITE setIsSitStandStateLocked);
+ Q_PROPERTY(MyAvatar::SitStandModelType userRecenterModel READ getUserRecenterModel WRITE setUserRecenterModel); // Deprecated
+ Q_PROPERTY(bool isSitStandStateLocked READ getIsSitStandStateLocked WRITE setIsSitStandStateLocked); // Deprecated
Q_PROPERTY(bool allowTeleporting READ getAllowTeleporting)
const QString DOMINANT_LEFT_HAND = "left";
@@ -519,6 +520,7 @@ public:
/**jsdoc
* Specifies different avatar leaning and recentering behaviors.
+ * Deprecated: This type is deprecated and will be removed.
*
*
* Value | Name | Description |
@@ -549,6 +551,29 @@ public:
};
Q_ENUM(SitStandModelType)
+ // Note: The option strings in setupPreferences (PreferencesDialog.cpp) must match this order.
+ enum class AllowAvatarStandingPreference : uint {
+ WhenUserIsStanding,
+ Always,
+ Count,
+ Default = Always
+ };
+ Q_ENUM(AllowAvatarStandingPreference)
+
+ // Note: The option strings in setupPreferences (PreferencesDialog.cpp) must match this order.
+ enum class AllowAvatarLeaningPreference : uint {
+ WhenUserIsStanding,
+ Always,
+ Never,
+ AlwaysNoRecenter, // experimental
+ Count,
+ Default = WhenUserIsStanding
+ };
+ Q_ENUM(AllowAvatarLeaningPreference)
+
+ static const std::array allowAvatarStandingPreferenceStrings;
+ static const std::array allowAvatarLeaningPreferenceStrings;
+
explicit MyAvatar(QThread* thread);
virtual ~MyAvatar();
@@ -1417,7 +1442,6 @@ public:
controller::Pose getControllerPoseInSensorFrame(controller::Action action) const;
controller::Pose getControllerPoseInWorldFrame(controller::Action action) const;
controller::Pose getControllerPoseInAvatarFrame(controller::Action action) const;
- glm::quat getOffHandRotation() const;
bool hasDriveInput() const;
@@ -1596,7 +1620,7 @@ public:
* @function MyAvatar.getAvatarScale
* @returns {number} The target scale for the avatar, range 0.005
– 1000.0
.
*/
- Q_INVOKABLE float getAvatarScale();
+ Q_INVOKABLE float getAvatarScale() const;
/**jsdoc
* Sets the target scale of the avatar. The target scale is the desired scale of the avatar without any restrictions on
@@ -1709,7 +1733,7 @@ public:
// derive avatar body position and orientation from the current HMD Sensor location.
// results are in sensor frame (-z forward)
- glm::mat4 deriveBodyFromHMDSensor() const;
+ glm::mat4 deriveBodyFromHMDSensor(const bool forceFollowYPos = false) const;
glm::mat4 getSpine2RotationRigSpace() const;
@@ -1753,10 +1777,14 @@ public:
bool getIsInWalkingState() const;
void setIsInSittingState(bool isSitting);
bool getIsInSittingState() const;
- void setUserRecenterModel(MyAvatar::SitStandModelType modelName);
- MyAvatar::SitStandModelType getUserRecenterModel() const;
- void setIsSitStandStateLocked(bool isLocked);
- bool getIsSitStandStateLocked() const;
+ void setUserRecenterModel(MyAvatar::SitStandModelType modelName); // Deprecated, will be removed.
+ MyAvatar::SitStandModelType getUserRecenterModel() const; // Deprecated, will be removed.
+ void setIsSitStandStateLocked(bool isLocked); // Deprecated, will be removed.
+ bool getIsSitStandStateLocked() const; // Deprecated, will be removed.
+ void setAllowAvatarStandingPreference(const AllowAvatarStandingPreference preference);
+ AllowAvatarStandingPreference getAllowAvatarStandingPreference() const;
+ void setAllowAvatarLeaningPreference(const AllowAvatarLeaningPreference preference);
+ AllowAvatarLeaningPreference getAllowAvatarLeaningPreference() const;
void setWalkSpeed(float value);
float getWalkSpeed() const;
void setWalkBackwardSpeed(float value);
@@ -1989,6 +2017,10 @@ public:
glm::vec3 getLookAtPivotPoint();
glm::vec3 getCameraEyesPosition(float deltaTime);
bool isJumping();
+ bool getHMDCrouchRecenterEnabled() const;
+ bool isAllowedToLean() const;
+ bool areFeetTracked() const { return _isBodyPartTracked._feet; }; // Determine if the feet are under direct control.
+ bool areHipsTracked() const { return _isBodyPartTracked._hips; }; // Determine if the hips are under direct control.
public slots:
@@ -2709,6 +2741,16 @@ private:
bool _isBraking { false };
bool _isAway { false };
+ // Indicates which parts of the body are under direct control (tracked).
+ struct {
+ bool _feet { false }; // Left or right foot.
+ bool _feetPreviousUpdate{ false };// Value of _feet on the previous update.
+ bool _hips{ false };
+ bool _leftHand{ false };
+ bool _rightHand{ false };
+ bool _head{ false };
+ } _isBodyPartTracked;
+
float _boomLength { ZOOM_DEFAULT };
float _yawSpeed; // degrees/sec
float _pitchSpeed; // degrees/sec
@@ -2791,6 +2833,7 @@ private:
void resetLookAtRotation(const glm::vec3& avatarPosition, const glm::quat& avatarOrientation);
void resetPointAt();
static glm::vec3 aimToBlendValues(const glm::vec3& aimVector, const glm::quat& frameOrientation);
+ void centerBodyInternal(const bool forceFollowYPos = false);
// Avatar Preferences
QUrl _fullAvatarURLFromPreferences;
@@ -2841,26 +2884,21 @@ private:
struct FollowHelper {
FollowHelper();
- enum FollowType {
- Rotation = 0,
- Horizontal,
- Vertical,
- NumFollowTypes
- };
- float _timeRemaining[NumFollowTypes];
+ CharacterController::FollowTimePerType _timeRemaining;
void deactivate();
- void deactivate(FollowType type);
- void activate();
- void activate(FollowType type);
+ void deactivate(CharacterController::FollowType type);
+ void activate(CharacterController::FollowType type, const bool snapFollow);
bool isActive() const;
- bool isActive(FollowType followType) const;
- float getMaxTimeRemaining() const;
+ bool isActive(CharacterController::FollowType followType) const;
void decrementTimeRemaining(float dt);
- bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
+ bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool& shouldSnapOut) const;
bool shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
- bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
- bool shouldActivateHorizontalCG(MyAvatar& myAvatar) const;
+ bool shouldActivateHorizontal(const MyAvatar& myAvatar,
+ const glm::mat4& desiredBodyMatrix,
+ const glm::mat4& currentBodyMatrix,
+ bool& resetModeOut,
+ bool& goToWalkingStateOut) const;
void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput);
glm::mat4 postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix);
bool getForceActivateRotation() const;
@@ -2871,16 +2909,23 @@ private:
void setForceActivateHorizontal(bool val);
bool getToggleHipsFollowing() const;
void setToggleHipsFollowing(bool followHead);
- bool _squatDetected { false };
std::atomic _forceActivateRotation { false };
std::atomic _forceActivateVertical { false };
std::atomic _forceActivateHorizontal { false };
std::atomic _toggleHipsFollowing { true };
+
+ private:
+ bool shouldActivateHorizontal_userSitting(const MyAvatar& myAvatar,
+ const glm::mat4& desiredBodyMatrix,
+ const glm::mat4& currentBodyMatrix) const;
+ bool shouldActivateHorizontal_userStanding(const MyAvatar& myAvatar,
+ bool& resetModeOut,
+ bool& goToWalkingStateOut) const;
};
FollowHelper _follow;
- bool isFollowActive(FollowHelper::FollowType followType) const;
+ bool isFollowActive(CharacterController::FollowType followType) const;
bool _goToPending { false };
bool _physicsSafetyPending { false };
@@ -2922,6 +2967,9 @@ private:
bool _centerOfGravityModelEnabled { true };
bool _hmdLeanRecenterEnabled { true };
+ bool _hmdCrouchRecenterEnabled {
+ true
+ }; // Is MyAvatar allowed to recenter vertically (stand) when the user is sitting in the real world.
bool _sprint { false };
AnimPose _prePhysicsRoomPose;
@@ -2953,7 +3001,6 @@ private:
ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT };
float _averageUserHeightSensorSpace { _userHeight.get() };
bool _sitStandStateChange { false };
- ThreadSafeValueCache _lockSitStandState { false };
// max unscaled forward movement speed
ThreadSafeValueCache _defaultWalkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED };
@@ -2969,9 +3016,13 @@ private:
float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR };
bool _isInWalkingState { false };
ThreadSafeValueCache _isInSittingState { false };
- ThreadSafeValueCache _userRecenterModel { MyAvatar::SitStandModelType::Auto };
+ ThreadSafeValueCache _allowAvatarStandingPreference{
+ MyAvatar::AllowAvatarStandingPreference::Default
+ }; // The user preference of when MyAvatar may stand.
+ ThreadSafeValueCache _allowAvatarLeaningPreference{
+ MyAvatar::AllowAvatarLeaningPreference::Default
+ }; // The user preference of when MyAvatar may lean.
float _sitStandStateTimer { 0.0f };
- float _squatTimer { 0.0f };
float _tippingPoint { _userHeight.get() };
// load avatar scripts once when rig is ready
@@ -3012,7 +3063,8 @@ private:
Setting::Handle _controlSchemeIndexSetting;
std::vector> _avatarEntityIDSettings;
std::vector> _avatarEntityDataSettings;
- Setting::Handle _userRecenterModelSetting;
+ Setting::Handle _allowAvatarStandingPreferenceSetting;
+ Setting::Handle _allowAvatarLeaningPreferenceSetting;
// AvatarEntities stuff:
// We cache the "map of unfortunately-formatted-binary-blobs" because they are expensive to compute
diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp
index 997dcfe685..0d382934b8 100755
--- a/interface/src/avatar/MyCharacterController.cpp
+++ b/interface/src/avatar/MyCharacterController.cpp
@@ -26,7 +26,9 @@ void MyCharacterController::RayShotgunResult::reset() {
walkable = true;
}
-MyCharacterController::MyCharacterController(std::shared_ptr avatar) {
+MyCharacterController::MyCharacterController(std::shared_ptr avatar,
+ const FollowTimePerType& followTimeRemainingPerType) :
+ CharacterController(followTimeRemainingPerType) {
assert(avatar);
_avatar = avatar;
diff --git a/interface/src/avatar/MyCharacterController.h b/interface/src/avatar/MyCharacterController.h
index eefcc92637..b25c2412a0 100644
--- a/interface/src/avatar/MyCharacterController.h
+++ b/interface/src/avatar/MyCharacterController.h
@@ -23,7 +23,7 @@ class DetailedMotionState;
class MyCharacterController : public CharacterController {
public:
- explicit MyCharacterController(std::shared_ptr avatar);
+ explicit MyCharacterController(std::shared_ptr avatar, const FollowTimePerType& followTimeRemainingPerType);
~MyCharacterController ();
void addToWorld() override;
diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp
index 6fe199aaba..4984c1d335 100755
--- a/interface/src/avatar/MySkeletonModel.cpp
+++ b/interface/src/avatar/MySkeletonModel.cpp
@@ -65,13 +65,21 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
return result;
}
+ // Use the center-of-gravity model if the user and the avatar are standing, unless flying or walking.
+ // If artificial standing is disabled, use center-of-gravity regardless of the user's sit/stand state.
+ bool useCenterOfGravityModel =
+ myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !myAvatar->getIsInWalkingState() &&
+ (!myAvatar->getHMDCrouchRecenterEnabled() || !myAvatar->getIsInSittingState()) &&
+ myAvatar->getHMDLeanRecenterEnabled() &&
+ (myAvatar->getAllowAvatarLeaningPreference() != MyAvatar::AllowAvatarLeaningPreference::AlwaysNoRecenter);
+
glm::mat4 hipsMat;
- if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && !(myAvatar->getIsInSittingState()) && myAvatar->getHMDLeanRecenterEnabled()) {
+ if (useCenterOfGravityModel) {
// then we use center of gravity model
hipsMat = myAvatar->deriveBodyUsingCgModel();
} else {
// otherwise use the default of putting the hips under the head
- hipsMat = myAvatar->deriveBodyFromHMDSensor();
+ hipsMat = myAvatar->deriveBodyFromHMDSensor(true);
}
glm::vec3 hipsPos = extractTranslation(hipsMat);
glm::quat hipsRot = glmExtractRotation(hipsMat);
@@ -82,7 +90,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
// dampen hips rotation, by mixing it with the avatar orientation in sensor space
// turning this off for center of gravity model because it is already mixed in there
- if (!(myAvatar->getCenterOfGravityModelEnabled())) {
+ if (!useCenterOfGravityModel) {
const float MIX_RATIO = 0.5f;
hipsRot = safeLerp(glmExtractRotation(avatarToSensorMat), hipsRot, MIX_RATIO);
}
diff --git a/interface/src/graphics/WorldBox.cpp b/interface/src/graphics/WorldBox.cpp
index 0e15d9da86..a627cf75e4 100644
--- a/interface/src/graphics/WorldBox.cpp
+++ b/interface/src/graphics/WorldBox.cpp
@@ -16,7 +16,7 @@ render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
namespace render {
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
- template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
+ template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) { return Item::Bound(); }
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
PerformanceTimer perfTimer("worldBox");
diff --git a/interface/src/graphics/WorldBox.h b/interface/src/graphics/WorldBox.h
index 4d53652c0e..0d697eb133 100644
--- a/interface/src/graphics/WorldBox.h
+++ b/interface/src/graphics/WorldBox.h
@@ -32,7 +32,7 @@ public:
namespace render {
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff);
- template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff);
+ template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args);
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args);
}
diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index c14d22bdbb..d190e3f3da 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -89,6 +89,7 @@ int main(int argc, const char* argv[]) {
QCommandLineOption displayNameOption("displayName", "set user display name ", "string");
QCommandLineOption setBookmarkOption("setBookmark", "set bookmark key=value pair", "string");
QCommandLineOption defaultScriptOverrideOption("defaultScriptsOverride", "override defaultsScripts.js", "string");
+ QCommandLineOption forceCrashReportingOption("forceCrashReporting", "Force crash reporting to initialize");
parser.addOption(urlOption);
parser.addOption(noLauncherOption);
@@ -103,6 +104,7 @@ int main(int argc, const char* argv[]) {
parser.addOption(displayNameOption);
parser.addOption(setBookmarkOption);
parser.addOption(defaultScriptOverrideOption);
+ parser.addOption(forceCrashReportingOption);
if (!parser.parse(arguments)) {
std::cout << parser.errorText().toStdString() << std::endl; // Avoid Qt log spam
@@ -218,8 +220,9 @@ int main(int argc, const char* argv[]) {
}
qDebug() << "UserActivityLogger is enabled:" << ual.isEnabled();
- qDebug() << "Crash handler logger is enabled:" << ual.isCrashMonitorEnabled();
- if (ual.isCrashMonitorEnabled()) {
+ bool isCrashHandlerEnabled = ual.isCrashMonitorEnabled() || parser.isSet(forceCrashReportingOption);
+ qDebug() << "Crash handler logger is enabled:" << isCrashHandlerEnabled;
+ if (isCrashHandlerEnabled) {
auto crashHandlerStarted = startCrashHandler(argv[0]);
qDebug() << "Crash handler started:" << crashHandlerStarted;
}
diff --git a/interface/src/raypick/ParabolaPointer.cpp b/interface/src/raypick/ParabolaPointer.cpp
index 216248f8b5..959125ba7c 100644
--- a/interface/src/raypick/ParabolaPointer.cpp
+++ b/interface/src/raypick/ParabolaPointer.cpp
@@ -415,7 +415,7 @@ gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabo
for (auto& key : keys) {
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
- state->setDepthTest(true, true, gpu::LESS_EQUAL);
+ state->setDepthTest(true, !std::get<0>(key), gpu::LESS_EQUAL);
if (std::get<0>(key)) {
PrepareStencil::testMask(*state);
} else {
@@ -462,9 +462,9 @@ namespace render {
template <> const ItemKey payloadGetKey(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload) {
return payload->getKey();
}
- template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload) {
+ template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload, RenderArgs* args) {
if (payload) {
- return payload->getBound();
+ return payload->getBound(args);
}
return Item::Bound();
}
diff --git a/interface/src/raypick/ParabolaPointer.h b/interface/src/raypick/ParabolaPointer.h
index 85d09adbdb..1701e4dcfa 100644
--- a/interface/src/raypick/ParabolaPointer.h
+++ b/interface/src/raypick/ParabolaPointer.h
@@ -31,7 +31,7 @@ public:
void render(RenderArgs* args);
render::Item::Bound& editBound() { return _bound; }
- const render::Item::Bound& getBound() { return _bound; }
+ const render::Item::Bound& getBound(RenderArgs* args) { return _bound; }
render::ItemKey getKey() const { return _key; }
void setVisible(bool visible);
@@ -128,7 +128,7 @@ private:
namespace render {
template <> const ItemKey payloadGetKey(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload);
- template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload);
+ template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload, RenderArgs* args);
template <> void payloadRender(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload, RenderArgs* args);
template <> const ShapeKey shapeGetShapeKey(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload);
}
diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp
index c5769ef4bb..5b90474d23 100644
--- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp
+++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp
@@ -76,8 +76,13 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping,
"Use the field below to place your file in a specific folder or to rename it. "
"Specifying a new folder name will automatically create that folder for you.";
- auto offscreenUi = DependencyManager::get();
- auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path",
+ auto offscreenUI = DependencyManager::get();
+ if (!offscreenUI) {
+ completedCallback.call({ -1 });
+ return;
+ }
+
+ auto result = offscreenUI->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path",
dropEvent ? dropHelpText : helpText, mapping);
if (!result.isValid() || result.toString() == "") {
@@ -94,7 +99,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping,
// Check for override
if (isKnownMapping(mapping)) {
auto message = mapping + "\n" + "This file already exists. Do you want to overwrite it?";
- auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message,
+ auto button = offscreenUI->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (button == QMessageBox::No) {
completedCallback.call({ -1 });
diff --git a/interface/src/scripting/DesktopScriptingInterface.cpp b/interface/src/scripting/DesktopScriptingInterface.cpp
index f78f7853ca..e527561b05 100644
--- a/interface/src/scripting/DesktopScriptingInterface.cpp
+++ b/interface/src/scripting/DesktopScriptingInterface.cpp
@@ -99,11 +99,16 @@ void DesktopScriptingInterface::setHUDAlpha(float alpha) {
}
void DesktopScriptingInterface::show(const QString& path, const QString& title) {
+ auto offscreenUI = DependencyManager::get();
+ if (!offscreenUI) {
+ return;
+ }
+
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "show", Qt::QueuedConnection, Q_ARG(QString, path), Q_ARG(QString, title));
return;
}
- DependencyManager::get()->show(path, title);
+ offscreenUI->show(path, title);
}
InteractiveWindowPointer DesktopScriptingInterface::createWindow(const QString& sourceUrl, const QVariantMap& properties) {
diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp
index 8f7ae7c4dc..79c0452a45 100644
--- a/interface/src/scripting/HMDScriptingInterface.cpp
+++ b/interface/src/scripting/HMDScriptingInterface.cpp
@@ -96,8 +96,9 @@ bool HMDScriptingInterface::shouldShowHandControllers() const {
void HMDScriptingInterface::activateHMDHandMouse() {
QWriteLocker lock(&_hmdHandMouseLock);
- auto offscreenUi = DependencyManager::get();
- offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", true);
+ if (auto offscreenUI = DependencyManager::get()) {
+ offscreenUI->getDesktop()->setProperty("hmdHandMouseActive", true);
+ }
_hmdHandMouseCount++;
}
@@ -105,8 +106,9 @@ void HMDScriptingInterface::deactivateHMDHandMouse() {
QWriteLocker lock(&_hmdHandMouseLock);
_hmdHandMouseCount = std::max(_hmdHandMouseCount - 1, 0);
if (_hmdHandMouseCount == 0) {
- auto offscreenUi = DependencyManager::get();
- offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", false);
+ if (auto offscreenUI = DependencyManager::get()) {
+ offscreenUI->getDesktop()->setProperty("hmdHandMouseActive", false);
+ }
}
}
diff --git a/interface/src/scripting/PlatformInfoScriptingInterface.cpp b/interface/src/scripting/PlatformInfoScriptingInterface.cpp
index 9adf514718..c1f325237e 100644
--- a/interface/src/scripting/PlatformInfoScriptingInterface.cpp
+++ b/interface/src/scripting/PlatformInfoScriptingInterface.cpp
@@ -217,7 +217,7 @@ PlatformInfoScriptingInterface::PlatformTier PlatformInfoScriptingInterface::get
}
QStringList PlatformInfoScriptingInterface::getPlatformTierNames() {
- static const QStringList platformTierNames = { "UNKNWON", "LOW", "MID", "HIGH" };
+ static const QStringList platformTierNames = { "UNKNOWN", "LOW", "MID", "HIGH" };
return platformTierNames;
}
diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp
index 14a0d04023..98335e5d3a 100644
--- a/interface/src/scripting/WindowScriptingInterface.cpp
+++ b/interface/src/scripting/WindowScriptingInterface.cpp
@@ -199,9 +199,9 @@ void WindowScriptingInterface::setInterstitialModeEnabled(bool enableInterstitia
DependencyManager::get()->getDomainHandler().setInterstitialModeEnabled(enableInterstitialMode);
}
-bool WindowScriptingInterface::isPointOnDesktopWindow(QVariant point) {
- auto offscreenUi = DependencyManager::get();
- return offscreenUi->isPointOnDesktopWindow(point);
+bool WindowScriptingInterface::isPointOnDesktopWindow(QVariant point) {
+ auto offscreenUI = DependencyManager::get();
+ return offscreenUI ? offscreenUI->isPointOnDesktopWindow(point) : false;
}
/// Makes sure that the reticle is visible, use this in blocking forms that require a reticle and
@@ -553,12 +553,14 @@ int WindowScriptingInterface::openMessageBox(QString title, QString text, int bu
* @typedef {number} Window.MessageBoxButton
*/
int WindowScriptingInterface::createMessageBox(QString title, QString text, int buttons, int defaultButton) {
- auto messageBox = DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, title, text,
- static_cast>(buttons), static_cast(defaultButton));
- connect(messageBox, SIGNAL(selected(int)), this, SLOT(onMessageBoxSelected(int)));
+ if (auto offscreenUI = DependencyManager::get()) {
+ auto messageBox = offscreenUI->createMessageBox(OffscreenUi::ICON_INFORMATION, title, text,
+ static_cast>(buttons), static_cast(defaultButton));
+ connect(messageBox, SIGNAL(selected(int)), this, SLOT(onMessageBoxSelected(int)));
- _lastMessageBoxID += 1;
- _messageBoxes.insert(_lastMessageBoxID, messageBox);
+ _lastMessageBoxID += 1;
+ _messageBoxes.insert(_lastMessageBoxID, messageBox);
+ }
return _lastMessageBoxID;
}
@@ -646,13 +648,17 @@ void WindowScriptingInterface::setActiveDisplayPlugin(int index) {
}
void WindowScriptingInterface::openWebBrowser(const QString& url) {
+ auto offscreenUI = DependencyManager::get();
+ if (!offscreenUI) {
+ return;
+ }
+
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "openWebBrowser", Q_ARG(const QString&, url));
return;
}
- auto offscreenUi = DependencyManager::get();
- offscreenUi->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
+ offscreenUI->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
if (!url.isEmpty()) {
newObject->setProperty("url", url);
}
diff --git a/interface/src/ui/AnimStats.cpp b/interface/src/ui/AnimStats.cpp
index 2a355e48d1..fff69cb1c0 100644
--- a/interface/src/ui/AnimStats.cpp
+++ b/interface/src/ui/AnimStats.cpp
@@ -67,13 +67,13 @@ void AnimStats::updateStats(bool force) {
// print if we are recentering or not.
_recenterText = "Recenter: ";
- if (myAvatar->isFollowActive(MyAvatar::FollowHelper::Rotation)) {
+ if (myAvatar->isFollowActive(CharacterController::FollowType::Rotation)) {
_recenterText += "Rotation ";
}
- if (myAvatar->isFollowActive(MyAvatar::FollowHelper::Horizontal)) {
+ if (myAvatar->isFollowActive(CharacterController::FollowType::Horizontal)) {
_recenterText += "Horizontal ";
}
- if (myAvatar->isFollowActive(MyAvatar::FollowHelper::Vertical)) {
+ if (myAvatar->isFollowActive(CharacterController::FollowType::Vertical)) {
_recenterText += "Vertical ";
}
emit recenterTextChanged();
diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp
index e91b1d725c..144f64c385 100644
--- a/interface/src/ui/ApplicationOverlay.cpp
+++ b/interface/src/ui/ApplicationOverlay.cpp
@@ -100,10 +100,10 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
// threads, we need to use a sync object to deteremine when
// the current UI texture is no longer being read from, and only
// then release it back to the UI for re-use
- auto offscreenUi = DependencyManager::get();
+ auto offscreenUI = DependencyManager::get();
OffscreenQmlSurface::TextureAndFence newTextureAndFence;
- bool newTextureAvailable = offscreenUi->fetchTexture(newTextureAndFence);
+ bool newTextureAvailable = offscreenUI ? offscreenUI->fetchTexture(newTextureAndFence) : false;
if (newTextureAvailable) {
_uiTexture->setExternalTexture(newTextureAndFence.first, newTextureAndFence.second);
}
diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp
index 0ac1f05737..daf80acf00 100644
--- a/interface/src/ui/InteractiveWindow.cpp
+++ b/interface/src/ui/InteractiveWindow.cpp
@@ -362,10 +362,11 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
object->setObjectName("InteractiveWindow");
object->setProperty(SOURCE_PROPERTY, sourceURL);
};
- auto offscreenUi = DependencyManager::get();
- // Build the event bridge and wrapper on the main thread
- offscreenUi->loadInNewContext(CONTENT_WINDOW_QML, objectInitLambda, contextInitLambda);
+ if (auto offscreenUI = DependencyManager::get()) {
+ // Build the event bridge and wrapper on the main thread
+ offscreenUI->loadInNewContext(CONTENT_WINDOW_QML, objectInitLambda, contextInitLambda);
+ }
}
}
diff --git a/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp
index 8edd8ee3a5..557b4d09bf 100644
--- a/interface/src/ui/OverlayConductor.cpp
+++ b/interface/src/ui/OverlayConductor.cpp
@@ -23,7 +23,7 @@ OverlayConductor::OverlayConductor() {
OverlayConductor::~OverlayConductor() {
}
-bool OverlayConductor::headOutsideOverlay() const {
+bool OverlayConductor::headNotCenteredInOverlay() const {
glm::mat4 hmdMat = qApp->getHMDSensorPose();
glm::vec3 hmdPos = extractTranslation(hmdMat);
glm::vec3 hmdForward = transformVectorFast(hmdMat, glm::vec3(0.0f, 0.0f, -1.0f));
@@ -32,8 +32,8 @@ bool OverlayConductor::headOutsideOverlay() const {
glm::vec3 uiPos = uiTransform.getTranslation();
glm::vec3 uiForward = uiTransform.getRotation() * glm::vec3(0.0f, 0.0f, -1.0f);
- const float MAX_COMPOSITOR_DISTANCE = 0.99f; // If you're 1m from center of ui sphere, you're at the surface.
- const float MAX_COMPOSITOR_ANGLE = 180.0f; // rotation check is effectively disabled
+ const float MAX_COMPOSITOR_DISTANCE = 0.33f;
+ const float MAX_COMPOSITOR_ANGLE = 90.0f;
if (glm::distance(uiPos, hmdPos) > MAX_COMPOSITOR_DISTANCE ||
glm::dot(uiForward, hmdForward) < cosf(glm::radians(MAX_COMPOSITOR_ANGLE))) {
return true;
@@ -70,6 +70,8 @@ bool OverlayConductor::updateAvatarIsAtRest() {
void OverlayConductor::centerUI() {
// place the overlay at the current hmd position in sensor space
auto camMat = cancelOutRollAndPitch(qApp->getHMDSensorPose());
+ // Set its radius.
+ camMat = glm::scale(camMat, glm::vec3(HUD_RADIUS));
qApp->getApplicationCompositor().setModelTransform(Transform(camMat));
}
@@ -83,7 +85,6 @@ void OverlayConductor::update(float dt) {
if (!desktop) {
return;
}
- bool currentVisible = !desktop->property("pinned").toBool();
auto myAvatar = DependencyManager::get()->getMyAvatar();
// centerUI when hmd mode is first enabled and mounted
@@ -96,24 +97,24 @@ void OverlayConductor::update(float dt) {
_hmdMode = false;
}
- bool shouldRecenter = false;
-
- if (_suppressedByHead) {
- if (updateAvatarIsAtRest()) {
- _suppressedByHead = false;
- shouldRecenter = true;
- }
- } else {
- if (_hmdMode && headOutsideOverlay()) {
- _suppressedByHead = true;
- }
+ bool initiateRecenter = false;
+ if (_hmdMode && headNotCenteredInOverlay()) {
+ initiateRecenter = true;
}
+ bool shouldRecenter = false;
+ if (initiateRecenter || _suppressedByHead) {
+ _suppressedByHead = !updateAvatarIsAtRest();
+ shouldRecenter = !_suppressedByHead;
+ }
+
+ bool currentVisible = !desktop->property("pinned").toBool();
bool targetVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays) && !_suppressedByHead;
if (targetVisible != currentVisible) {
offscreenUi->setPinned(!targetVisible);
}
- if (shouldRecenter && !_suppressedByHead) {
+
+ if (shouldRecenter) {
centerUI();
}
#endif
diff --git a/interface/src/ui/OverlayConductor.h b/interface/src/ui/OverlayConductor.h
index 6c3732cf3c..7e7cf5bd3c 100644
--- a/interface/src/ui/OverlayConductor.h
+++ b/interface/src/ui/OverlayConductor.h
@@ -22,7 +22,7 @@ public:
void centerUI();
private:
- bool headOutsideOverlay() const;
+ bool headNotCenteredInOverlay() const;
bool updateAvatarIsAtRest();
#if !defined(DISABLE_QML)
diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index 79d9ebaa5c..9c53060f31 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -422,40 +422,40 @@ void setupPreferences() {
preferences->addPreference(preference);
}
{
- auto getter = [myAvatar]()->int {
- switch (myAvatar->getUserRecenterModel()) {
- case MyAvatar::SitStandModelType::Auto:
- default:
- return 0;
- case MyAvatar::SitStandModelType::ForceSit:
- return 1;
- case MyAvatar::SitStandModelType::ForceStand:
- return 2;
- case MyAvatar::SitStandModelType::DisableHMDLean:
- return 3;
- }
+ IntPreference::Getter getter = [myAvatar]() -> int {
+ return static_cast(myAvatar->getAllowAvatarStandingPreference());
};
- auto setter = [myAvatar](int value) {
- switch (value) {
- case 0:
- default:
- myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto);
- break;
- case 1:
- myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit);
- break;
- case 2:
- myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceStand);
- break;
- case 3:
- myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean);
- break;
- }
+
+ IntPreference::Setter setter = [myAvatar](const int& value) {
+ myAvatar->setAllowAvatarStandingPreference(static_cast(value));
};
- auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Force Stand / Disable Recenter", getter, setter);
+
+ auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Allow my avatar to stand", getter, setter);
QStringList items;
- items << "Auto - turns on avatar leaning when standing in real world" << "Seated - disables all avatar leaning while sitting in real world" << "Standing - enables avatar leaning while sitting in real world" << "Disabled - allows avatar sitting on the floor [Experimental]";
- preference->setHeading("Avatar leaning behavior");
+ items << "When I'm standing"
+ << "Always"; // Must match the order in MyAvatar::AllowAvatarStandingPreference.
+ assert(items.size() == static_cast(MyAvatar::AllowAvatarStandingPreference::Count));
+ preference->setHeading("Allow my avatar to stand:");
+ preference->setItems(items);
+ preferences->addPreference(preference);
+ }
+ {
+ IntPreference::Getter getter = [myAvatar]() -> int {
+ return static_cast(myAvatar->getAllowAvatarLeaningPreference());
+ };
+
+ IntPreference::Setter setter = [myAvatar](const int& value) {
+ myAvatar->setAllowAvatarLeaningPreference(static_cast(value));
+ };
+
+ auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Allow my avatar to lean", getter, setter);
+ QStringList items;
+ items << "When I'm standing"
+ << "Always"
+ << "Never"
+ << "Always, no recenter (Experimental)"; // Must match the order in MyAvatar::AllowAvatarLeaningPreference.
+ assert(items.size() == static_cast(MyAvatar::AllowAvatarLeaningPreference::Count));
+ preference->setHeading("Allow my avatar to lean:");
preference->setItems(items);
preferences->addPreference(preference);
}
diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h
index 27ab375a42..ebd65de612 100644
--- a/interface/src/ui/Stats.h
+++ b/interface/src/ui/Stats.h
@@ -248,9 +248,9 @@ private: \
* Read-only.
* @property {string} lodStatus - Description of the current LOD.
* Read-only.
- * @property {string} numEntityUpdates - The number of entity updates that happened last frame.
+ * @property {number} numEntityUpdates - The number of entity updates that happened last frame.
* Read-only.
- * @property {string} numNeededEntityUpdates - The total number of entity updates scheduled for last frame.
+ * @property {number} numNeededEntityUpdates - The total number of entity updates scheduled for last frame.
* Read-only.
* @property {string} timingStats - Details of the average time (ms) spent in and number of calls made to different parts of
* the code. Provided only if timingExpanded
is true
. Only the top 10 items are provided if
@@ -547,8 +547,8 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, lodAngle, 0)
STATS_PROPERTY(int, lodTargetFramerate, 0)
STATS_PROPERTY(QString, lodStatus, QString())
- STATS_PROPERTY(int, numEntityUpdates, 0)
- STATS_PROPERTY(int, numNeededEntityUpdates, 0)
+ STATS_PROPERTY(quint64, numEntityUpdates, 0)
+ STATS_PROPERTY(quint64, numNeededEntityUpdates, 0)
STATS_PROPERTY(QString, timingStats, QString())
STATS_PROPERTY(QString, gameUpdateStats, QString())
STATS_PROPERTY(int, serverElements, 0)
diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h
index 72373d2d20..5c92cfce00 100644
--- a/interface/src/ui/overlays/Overlay.h
+++ b/interface/src/ui/overlays/Overlay.h
@@ -66,7 +66,7 @@ private:
namespace render {
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay);
- template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay);
+ template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay, RenderArgs* args);
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args);
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay);
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems);
diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp
index 5e43c5df8d..e9e310e68b 100644
--- a/interface/src/ui/overlays/Overlays.cpp
+++ b/interface/src/ui/overlays/Overlays.cpp
@@ -1212,8 +1212,8 @@ float Overlays::width() {
return result;
}
- auto offscreenUi = DependencyManager::get();
- return offscreenUi->getWindow()->size().width();
+ auto offscreenUI = DependencyManager::get();
+ return offscreenUI ? offscreenUI->getWindow()->size().width() : -1.0f;
}
float Overlays::height() {
@@ -1224,8 +1224,8 @@ float Overlays::height() {
return result;
}
- auto offscreenUi = DependencyManager::get();
- return offscreenUi->getWindow()->size().height();
+ auto offscreenUI = DependencyManager::get();
+ return offscreenUI ? offscreenUI->getWindow()->size().height() : -1.0f;
}
void Overlays::mousePressOnPointerEvent(const QUuid& id, const PointerEvent& event) {
diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp
index 0d1bcdd071..fdcd4f7205 100644
--- a/interface/src/ui/overlays/OverlaysPayload.cpp
+++ b/interface/src/ui/overlays/OverlaysPayload.cpp
@@ -14,7 +14,7 @@ namespace render {
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay) {
return overlay->getKey();
}
- template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
+ template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay, RenderArgs* args) {
return overlay->getBounds();
}
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
diff --git a/interface/src/ui/overlays/QmlOverlay.cpp b/interface/src/ui/overlays/QmlOverlay.cpp
index 2afb29bb91..c097e7dd97 100644
--- a/interface/src/ui/overlays/QmlOverlay.cpp
+++ b/interface/src/ui/overlays/QmlOverlay.cpp
@@ -24,13 +24,17 @@ QmlOverlay::QmlOverlay(const QUrl& url, const QmlOverlay* overlay)
}
void QmlOverlay::buildQmlElement(const QUrl& url) {
+ auto offscreenUI = DependencyManager::get();
+ if (!offscreenUI) {
+ return;
+ }
+
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "buildQmlElement", Q_ARG(QUrl, url));
return;
}
- auto offscreenUi = DependencyManager::get();
- offscreenUi->load(url, [=](QQmlContext* context, QObject* object) {
+ offscreenUI->load(url, [=](QQmlContext* context, QObject* object) {
_qmlElement = dynamic_cast(object);
connect(_qmlElement, &QObject::destroyed, this, &QmlOverlay::qmlElementDestroyed);
});
diff --git a/interface/src/workload/GameWorkloadRenderer.cpp b/interface/src/workload/GameWorkloadRenderer.cpp
index f65bf88754..1310baf4b3 100644
--- a/interface/src/workload/GameWorkloadRenderer.cpp
+++ b/interface/src/workload/GameWorkloadRenderer.cpp
@@ -82,9 +82,9 @@ namespace render {
template <> const ItemKey payloadGetKey(const GameWorkloadRenderItem::Pointer& payload) {
return payload->getKey();
}
- template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload) {
+ template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args) {
if (payload) {
- return payload->getBound();
+ return payload->getBound(args);
}
return Item::Bound();
}
diff --git a/interface/src/workload/GameWorkloadRenderer.h b/interface/src/workload/GameWorkloadRenderer.h
index a25598821e..ad33425774 100644
--- a/interface/src/workload/GameWorkloadRenderer.h
+++ b/interface/src/workload/GameWorkloadRenderer.h
@@ -57,7 +57,7 @@ public:
void render(RenderArgs* args);
render::Item::Bound& editBound() { return _bound; }
- const render::Item::Bound& getBound() { return _bound; }
+ const render::Item::Bound& getBound(RenderArgs* args) { return _bound; }
void setVisible(bool visible);
void showProxies(bool show);
@@ -96,7 +96,7 @@ protected:
namespace render {
template <> const ItemKey payloadGetKey(const GameWorkloadRenderItem::Pointer& payload);
- template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload);
+ template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args);
template <> void payloadRender(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args);
template <> const ShapeKey shapeGetShapeKey(const GameWorkloadRenderItem::Pointer& payload);
}
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 06fe558964..6dc378a32f 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -1855,6 +1855,16 @@ glm::vec3 Rig::deflectHandFromTorso(const glm::vec3& handPosition, const HFMJoin
return position;
}
+// Get the scale factor to convert distances in the geometry frame into the unscaled rig frame.
+// Typically it will be the unit conversion from cm to m.
+float Rig::GetScaleFactorGeometryToUnscaledRig() const {
+ // Normally the model offset transform will contain the avatar scale factor; we explicitly remove it here.
+ AnimPose modelOffsetWithoutAvatarScale(glm::vec3(1.0f), getModelOffsetPose().rot(), getModelOffsetPose().trans());
+ AnimPose geomToRigWithoutAvatarScale = modelOffsetWithoutAvatarScale * getGeometryOffsetPose();
+
+ return geomToRigWithoutAvatarScale.scale().x; // in practice this is always a uniform scale factor.
+}
+
void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool hipsEstimated,
bool leftArmEnabled, bool rightArmEnabled, bool headEnabled, float dt,
const AnimPose& leftHandPose, const AnimPose& rightHandPose,
@@ -2703,10 +2713,10 @@ void Rig::computeAvatarBoundingCapsule(
Extents totalExtents;
totalExtents.reset();
- // HACK by convention our Avatars are always modeled such that y=0 is the ground plane.
- // add the zero point so that our avatars will always have bounding volumes that are flush with the ground
+ // HACK by convention our Avatars are always modeled such that y=0 (GEOMETRY_GROUND_Y) is the ground plane.
+ // add the ground point so that our avatars will always have bounding volumes that are flush with the ground
// even if they do not have legs (default robot)
- totalExtents.addPoint(glm::vec3(0.0f));
+ totalExtents.addPoint(glm::vec3(0.0f, GEOMETRY_GROUND_Y, 0.0f));
// To reduce the radius of the bounding capsule to be tight with the torso, we only consider joints
// from the head to the hips when computing the rest of the bounding capsule.
@@ -2747,24 +2757,20 @@ void Rig::initFlow(bool isActive) {
}
}
+// Get the vertical position of eye joints, in the rig coordinate frame, ignoring the avatar scale.
float Rig::getUnscaledEyeHeight() const {
// Normally the model offset transform will contain the avatar scale factor, we explicitly remove it here.
AnimPose modelOffsetWithoutAvatarScale(glm::vec3(1.0f), getModelOffsetPose().rot(), getModelOffsetPose().trans());
AnimPose geomToRigWithoutAvatarScale = modelOffsetWithoutAvatarScale * getGeometryOffsetPose();
- // This factor can be used to scale distances in the geometry frame into the unscaled rig frame.
- // Typically it will be the unit conversion from cm to m.
- float scaleFactor = geomToRigWithoutAvatarScale.scale().x; // in practice this always a uniform scale factor.
+ // Factor to scale distances in the geometry frame into the unscaled rig frame.
+ float scaleFactor = GetScaleFactorGeometryToUnscaledRig();
int headTopJoint = indexOfJoint("HeadTop_End");
int headJoint = indexOfJoint("Head");
int eyeJoint = indexOfJoint("LeftEye") != -1 ? indexOfJoint("LeftEye") : indexOfJoint("RightEye");
int toeJoint = indexOfJoint("LeftToeBase") != -1 ? indexOfJoint("LeftToeBase") : indexOfJoint("RightToeBase");
- // Makes assumption that the y = 0 plane in geometry is the ground plane.
- // We also make that assumption in Rig::computeAvatarBoundingCapsule()
- const float GROUND_Y = 0.0f;
-
// Values from the skeleton are in the geometry coordinate frame.
auto skeleton = getAnimSkeleton();
if (eyeJoint >= 0 && toeJoint >= 0) {
@@ -2772,8 +2778,8 @@ float Rig::getUnscaledEyeHeight() const {
float eyeHeight = skeleton->getAbsoluteDefaultPose(eyeJoint).trans().y - skeleton->getAbsoluteDefaultPose(toeJoint).trans().y;
return scaleFactor * eyeHeight;
} else if (eyeJoint >= 0) {
- // Measure Eye joint to y = 0 plane.
- float eyeHeight = skeleton->getAbsoluteDefaultPose(eyeJoint).trans().y - GROUND_Y;
+ // Measure Eye joint to ground plane.
+ float eyeHeight = skeleton->getAbsoluteDefaultPose(eyeJoint).trans().y - GEOMETRY_GROUND_Y;
return scaleFactor * eyeHeight;
} else if (headTopJoint >= 0 && toeJoint >= 0) {
// Measure from ToeBase joint to HeadTop_End joint, then remove forehead distance.
@@ -2783,19 +2789,36 @@ float Rig::getUnscaledEyeHeight() const {
} else if (headTopJoint >= 0) {
// Measure from HeadTop_End joint to the ground, then remove forehead distance.
const float ratio = DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD / DEFAULT_AVATAR_HEIGHT;
- float headHeight = skeleton->getAbsoluteDefaultPose(headTopJoint).trans().y - GROUND_Y;
+ float headHeight = skeleton->getAbsoluteDefaultPose(headTopJoint).trans().y - GEOMETRY_GROUND_Y;
return scaleFactor * (headHeight - headHeight * ratio);
} else if (headJoint >= 0) {
// Measure Head joint to the ground, then add in distance from neck to eye.
const float DEFAULT_AVATAR_NECK_TO_EYE = DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD - DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD;
const float ratio = DEFAULT_AVATAR_NECK_TO_EYE / DEFAULT_AVATAR_NECK_HEIGHT;
- float neckHeight = skeleton->getAbsoluteDefaultPose(headJoint).trans().y - GROUND_Y;
+ float neckHeight = skeleton->getAbsoluteDefaultPose(headJoint).trans().y - GEOMETRY_GROUND_Y;
return scaleFactor * (neckHeight + neckHeight * ratio);
} else {
return DEFAULT_AVATAR_EYE_HEIGHT;
}
}
+// Get the vertical position of the hips joint, in the rig coordinate frame, ignoring the avatar scale.
+float Rig::getUnscaledHipsHeight() const {
+ // This factor can be used to scale distances in the geometry frame into the unscaled rig frame.
+ float scaleFactor = GetScaleFactorGeometryToUnscaledRig();
+
+ int hipsJoint = indexOfJoint("Hips");
+
+ // Values from the skeleton are in the geometry coordinate frame.
+ if (hipsJoint >= 0) {
+ // Measure hip joint to ground plane.
+ float hipsHeight = getAnimSkeleton()->getAbsoluteDefaultPose(hipsJoint).trans().y - GEOMETRY_GROUND_Y;
+ return scaleFactor * hipsHeight;
+ } else {
+ return DEFAULT_AVATAR_HIPS_HEIGHT;
+ }
+}
+
void Rig::setDirectionalBlending(const QString& targetName, const glm::vec3& blendingTarget, const QString& alphaName, float alpha) {
_animVars.set(targetName, blendingTarget);
_animVars.set(alphaName, alpha);
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index 60a2602316..c58be799cf 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -251,6 +251,7 @@ public:
Flow& getFlow() { return _internalFlow; }
float getUnscaledEyeHeight() const;
+ float getUnscaledHipsHeight() const;
void buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut) const;
int getOverrideJointCount() const;
@@ -287,6 +288,11 @@ protected:
glm::vec3 deflectHandFromTorso(const glm::vec3& handPosition, const HFMJointShapeInfo& hipsShapeInfo, const HFMJointShapeInfo& spineShapeInfo,
const HFMJointShapeInfo& spine1ShapeInfo, const HFMJointShapeInfo& spine2ShapeInfo) const;
+ // Get the scale factor to convert distances in the geometry frame into the unscaled rig frame.
+ float GetScaleFactorGeometryToUnscaledRig() const;
+
+ // The ground plane Y position in geometry space.
+ static constexpr float GEOMETRY_GROUND_Y = 0.0f;
AnimPose _modelOffset; // model to rig space
AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets)
diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
index 16dc99ab49..f361e15999 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
@@ -63,7 +63,7 @@ namespace render {
}
return keyBuilder.build();
}
- template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
+ template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar, RenderArgs* args) {
auto avatarPtr = static_pointer_cast(avatar);
if (avatarPtr) {
return avatarPtr->getRenderBounds();
@@ -1246,7 +1246,7 @@ glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
}
case CAMERA_MATRIX_INDEX: {
glm::quat rotation;
- if (_skeletonModel && _skeletonModel->isActive()) {
+ if (_skeletonModel && _skeletonModel->isLoaded()) {
int headJointIndex = getJointIndex("Head");
if (headJointIndex >= 0) {
_skeletonModel->getAbsoluteJointRotationInRigFrame(headJointIndex, rotation);
@@ -1298,7 +1298,7 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
}
case CAMERA_MATRIX_INDEX: {
glm::vec3 translation;
- if (_skeletonModel && _skeletonModel->isActive()) {
+ if (_skeletonModel && _skeletonModel->isLoaded()) {
int headJointIndex = getJointIndex("Head");
if (headJointIndex >= 0) {
_skeletonModel->getAbsoluteJointTranslationInRigFrame(headJointIndex, translation);
@@ -1427,7 +1427,7 @@ void Avatar::withValidJointIndicesCache(std::function const& worker) con
QWriteLocker writeLock(&_modelJointIndicesCacheLock);
if (!_modelJointsCached) {
_modelJointIndicesCache.clear();
- if (_skeletonModel && _skeletonModel->isActive()) {
+ if (_skeletonModel && _skeletonModel->isLoaded()) {
_modelJointIndicesCache = _skeletonModel->getHFMModel().jointIndices;
_modelJointsCached = true;
}
diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h
index 25dd347484..4fc9c25595 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h
@@ -39,7 +39,7 @@
namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar);
- template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar);
+ template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar, RenderArgs* args);
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args);
template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems);
}
diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp
index ccc87c28f3..15ff09d13d 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp
@@ -33,6 +33,7 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
{
// SkeletonModels, and by extention Avatars, use Dual Quaternion skinning.
_useDualQuaternionSkinning = true;
+ _forceOffset = true;
// Avatars all cast shadow
setCanCastShadow(true);
@@ -156,17 +157,13 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
updateAttitude(_owningAvatar->getWorldOrientation());
setBlendshapeCoefficients(_owningAvatar->getHead()->getSummedBlendshapeCoefficients());
+ Parent::simulate(deltaTime, fullUpdate);
if (fullUpdate) {
-
- Parent::simulate(deltaTime, fullUpdate);
-
// let rig compute the model offset
glm::vec3 registrationPoint;
if (_rig.getModelRegistrationPoint(registrationPoint)) {
setOffset(registrationPoint);
}
- } else {
- Parent::simulate(deltaTime, fullUpdate);
}
// FIXME: This texture loading logic should probably live in Avatar, to mirror RenderableModelEntityItem,
@@ -176,7 +173,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
updateRenderItems();
}
- if (!isActive() || !_owningAvatar->isMyAvatar()) {
+ if (!isLoaded() || !_owningAvatar->isMyAvatar()) {
return; // only simulate for own avatar
}
@@ -255,19 +252,19 @@ bool SkeletonModel::getRightHandPosition(glm::vec3& position) const {
}
bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const {
- return isActive() && getJointPositionInWorldFrame(_rig.indexOfJoint("Head"), headPosition);
+ return isLoaded() && getJointPositionInWorldFrame(_rig.indexOfJoint("Head"), headPosition);
}
bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const {
- return isActive() && getJointPositionInWorldFrame(_rig.indexOfJoint("Neck"), neckPosition);
+ return isLoaded() && getJointPositionInWorldFrame(_rig.indexOfJoint("Neck"), neckPosition);
}
bool SkeletonModel::getLocalNeckPosition(glm::vec3& neckPosition) const {
- return isActive() && getJointPosition(_rig.indexOfJoint("Neck"), neckPosition);
+ return isLoaded() && getJointPosition(_rig.indexOfJoint("Neck"), neckPosition);
}
bool SkeletonModel::getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
- if (!isActive()) {
+ if (!isLoaded()) {
return false;
}
@@ -361,7 +358,7 @@ void SkeletonModel::renderBoundingCollisionShapes(RenderArgs* args, gpu::Batch&
}
bool SkeletonModel::hasSkeleton() {
- return isActive() ? _rig.indexOfJoint("Hips") != -1 : false;
+ return isLoaded() ? _rig.indexOfJoint("Hips") != -1 : false;
}
void SkeletonModel::onInvalidate() {
diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h
index 6b0bd79f0b..e24d969461 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h
+++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h
@@ -44,10 +44,10 @@ public:
bool getIsJointOverridden(int jointIndex) const;
/// Returns the index of the left hand joint, or -1 if not found.
- int getLeftHandJointIndex() const { return isActive() ? _rig.indexOfJoint("LeftHand") : -1; }
+ int getLeftHandJointIndex() const { return isLoaded() ? _rig.indexOfJoint("LeftHand") : -1; }
/// Returns the index of the right hand joint, or -1 if not found.
- int getRightHandJointIndex() const { return isActive() ? _rig.indexOfJoint("RightHand") : -1; }
+ int getRightHandJointIndex() const { return isLoaded() ? _rig.indexOfJoint("RightHand") : -1; }
bool getLeftGrabPosition(glm::vec3& position) const;
bool getRightGrabPosition(glm::vec3& position) const;
diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp
index 9b6946bbcc..c645c39eb4 100644
--- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp
+++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp
@@ -41,10 +41,10 @@ static const float reticleSize = TWO_PI / 100.0f;
//EntityItemID CompositorHelper::_noItemId;
static QString _tooltipId;
-const uvec2 CompositorHelper::VIRTUAL_SCREEN_SIZE = uvec2(3960, 1188); // ~10% more pixel density than old version, 72dx240d FOV
-const QRect CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT = QRect(956, 0, 2048, 1188); // don't include entire width only center 2048
+const uvec2 CompositorHelper::VIRTUAL_SCREEN_SIZE = uvec2(2640, 1188);
+const QRect CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT = QRect(296, 0, 2048, 1188); // Center 2048 pixels.
const float CompositorHelper::VIRTUAL_UI_ASPECT_RATIO = (float)VIRTUAL_SCREEN_SIZE.x / (float)VIRTUAL_SCREEN_SIZE.y;
-const vec2 CompositorHelper::VIRTUAL_UI_TARGET_FOV = vec2(PI * 3.0f / 2.0f, PI * 3.0f / 2.0f / VIRTUAL_UI_ASPECT_RATIO);
+const vec2 CompositorHelper::VIRTUAL_UI_TARGET_FOV = vec2(PI, PI / VIRTUAL_UI_ASPECT_RATIO);
const vec2 CompositorHelper::MOUSE_EXTENTS_ANGULAR_SIZE = vec2(PI * 2.0f, PI * 0.95f); // horizontal: full sphere, vertical: ~5deg from poles
const vec2 CompositorHelper::MOUSE_EXTENTS_PIXELS = vec2(VIRTUAL_SCREEN_SIZE) * (MOUSE_EXTENTS_ANGULAR_SIZE / VIRTUAL_UI_TARGET_FOV);
@@ -384,9 +384,9 @@ bool CompositorHelper::calculateRayUICollisionPoint(const glm::vec3& position, c
glm::vec3 localPosition = transformPoint(worldToUi, position);
glm::vec3 localDirection = glm::normalize(transformVectorFast(worldToUi, direction));
- const float UI_RADIUS = 1.0f;
+ const float UNIT_RADIUS = 1.0f;
float intersectionDistance;
- if (raySphereIntersect(localDirection, localPosition, UI_RADIUS, &intersectionDistance)) {
+ if (raySphereIntersect(localDirection, localPosition, UNIT_RADIUS, &intersectionDistance)) {
result = transformPoint(uiToWorld, localPosition + localDirection * intersectionDistance);
#ifdef WANT_DEBUG
DebugDraw::getInstance().drawRay(position, result, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
@@ -407,9 +407,8 @@ bool CompositorHelper::calculateParabolaUICollisionPoint(const glm::vec3& origin
glm::vec3 localVelocity = glm::normalize(transformVectorFast(worldToUi, velocity));
glm::vec3 localAcceleration = glm::normalize(transformVectorFast(worldToUi, acceleration));
- const float UI_RADIUS = 1.0f;
float intersectionDistance;
- if (findParabolaSphereIntersection(localOrigin, localVelocity, localAcceleration, glm::vec3(0.0f), UI_RADIUS, intersectionDistance)) {
+ if (findParabolaSphereIntersection(localOrigin, localVelocity, localAcceleration, glm::vec3(0.0f), HUD_RADIUS, intersectionDistance)) {
result = origin + velocity * intersectionDistance + 0.5f * acceleration * intersectionDistance * intersectionDistance;
parabolicDistance = intersectionDistance;
return true;
diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.h b/libraries/display-plugins/src/display-plugins/CompositorHelper.h
index c45119fd63..b44d6ffbd9 100644
--- a/libraries/display-plugins/src/display-plugins/CompositorHelper.h
+++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.h
@@ -27,7 +27,8 @@
class ReticleInterface;
-const float DEFAULT_RETICLE_DEPTH = 1.0f; // FIXME - probably should be based on UI radius
+const float HUD_RADIUS = 1.5f;
+const float DEFAULT_RETICLE_DEPTH = HUD_RADIUS;
const float MAGNIFY_WIDTH = 220.0f;
const float MAGNIFY_HEIGHT = 100.0f;
@@ -154,7 +155,7 @@ private:
std::unique_ptr _alphaPropertyAnimation;
std::atomic _reticleVisible { true };
- std::atomic _reticleDepth { 1.0f };
+ std::atomic _reticleDepth { DEFAULT_RETICLE_DEPTH };
// NOTE: when the compositor is running in HMD mode, it will control the reticle position as a custom
// application specific position, when it's in desktop mode, the reticle position will simply move
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h
index f7623aad10..009e5f6c4f 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.h
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.h
@@ -136,8 +136,8 @@ public:
static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName);
static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName);
- int getPrevNumEntityUpdates() const { return _prevNumEntityUpdates; }
- int getPrevTotalNeededEntityUpdates() const { return _prevTotalNeededEntityUpdates; }
+ size_t getPrevNumEntityUpdates() const { return _prevNumEntityUpdates; }
+ size_t getPrevTotalNeededEntityUpdates() const { return _prevTotalNeededEntityUpdates; }
signals:
void enterEntity(const EntityItemID& entityItemID);
@@ -253,8 +253,8 @@ private:
ReadWriteLockable _changedEntitiesGuard;
std::unordered_set _changedEntities;
- int _prevNumEntityUpdates { 0 };
- int _prevTotalNeededEntityUpdates { 0 };
+ size_t _prevNumEntityUpdates { 0 };
+ size_t _prevTotalNeededEntityUpdates { 0 };
std::unordered_set _renderablesToUpdate;
std::unordered_map _entitiesInScene;
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index 807a240763..b2670e3bce 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -137,8 +137,15 @@ EntityRenderer::~EntityRenderer() {}
// Smart payload proxy members, implementing the payload interface
//
-Item::Bound EntityRenderer::getBound() {
- return _bound;
+Item::Bound EntityRenderer::getBound(RenderArgs* args) {
+ auto bound = _bound;
+ if (_billboardMode != BillboardMode::NONE) {
+ glm::vec3 dimensions = bound.getScale();
+ float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
+ const float SQRT_2 = 1.41421356237f;
+ bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
+ }
+ return bound;
}
ShapeKey EntityRenderer::getShapeKey() {
@@ -198,12 +205,9 @@ uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
}
bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set& containingZones) const {
- auto renderWithZones = resultWithReadLock>([&] {
- return _renderWithZones;
- });
- if (!renderWithZones.isEmpty()) {
+ if (!_renderWithZones.isEmpty()) {
if (!containingZones.empty()) {
- for (auto renderWithZone : renderWithZones) {
+ for (auto renderWithZone : _renderWithZones) {
if (containingZones.find(renderWithZone) != containingZones.end()) {
return true;
}
@@ -429,20 +433,24 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
_moving = entity->isMovingRelativeToParent();
_visible = entity->getVisible();
- setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
- setRenderLayer(entity->getRenderLayer());
- setPrimitiveMode(entity->getPrimitiveMode());
- _canCastShadow = entity->getCanCastShadow();
- setCullWithParent(entity->getCullWithParent());
- _cauterized = entity->getCauterized();
- if (entity->needsZoneOcclusionUpdate()) {
- entity->resetNeedsZoneOcclusionUpdate();
- setRenderWithZones(entity->getRenderWithZones());
- }
entity->setNeedsRenderUpdate(false);
});
}
+void EntityRenderer::doRenderUpdateAsynchronous(const EntityItemPointer& entity) {
+ setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
+ setRenderLayer(entity->getRenderLayer());
+ _billboardMode = entity->getBillboardMode();
+ _primitiveMode = entity->getPrimitiveMode();
+ _canCastShadow = entity->getCanCastShadow();
+ setCullWithParent(entity->getCullWithParent());
+ _cauterized = entity->getCauterized();
+ if (entity->needsZoneOcclusionUpdate()) {
+ entity->resetNeedsZoneOcclusionUpdate();
+ _renderWithZones = entity->getRenderWithZones();
+ }
+}
+
void EntityRenderer::onAddToScene(const EntityItemPointer& entity) {
QObject::connect(this, &EntityRenderer::requestRenderUpdate, this, [this] {
auto renderer = DependencyManager::get();
@@ -469,11 +477,13 @@ void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) {
void EntityRenderer::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
std::lock_guard lock(_materialsLock);
_materials[parentMaterialName].push(material);
+ emit requestRenderUpdate();
}
void EntityRenderer::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
std::lock_guard lock(_materialsLock);
_materials[parentMaterialName].remove(material);
+ emit requestRenderUpdate();
}
glm::vec4 EntityRenderer::calculatePulseColor(const glm::vec4& color, const PulsePropertyGroup& pulseProperties, quint64 start) {
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h
index 69fb9aca23..7f0e1e16ee 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableEntityItem.h
@@ -64,7 +64,7 @@ public:
static glm::vec3 calculatePulseColor(const glm::vec3& color, const PulsePropertyGroup& pulseProperties, quint64 start);
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
- virtual Item::Bound getBound() override;
+ virtual Item::Bound getBound(RenderArgs* args) override;
bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override;
protected:
@@ -95,8 +95,7 @@ protected:
// Will be called by the lambda posted to the scene in updateInScene.
// This function will execute on the rendering thread, so you cannot use network caches to fetch
// data in this method if using multi-threaded rendering
-
- virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity) { }
+ virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity);
// Called by the `render` method after `needsRenderUpdate`
virtual void doRender(RenderArgs* args) = 0;
@@ -108,18 +107,7 @@ protected:
virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; }
virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; }
- virtual void setPrimitiveMode(PrimitiveMode value) { _primitiveMode = value; }
virtual void setCullWithParent(bool value) { _cullWithParent = value; }
- virtual void setRenderWithZones(const QVector& renderWithZones) { _renderWithZones = renderWithZones; }
-
- template
- T withReadLockResult(const std::function& f) {
- T result;
- withReadLock([&] {
- result = f();
- });
- return result;
- }
signals:
void requestRenderUpdate();
@@ -146,6 +134,7 @@ protected:
RenderLayer _renderLayer { RenderLayer::WORLD };
PrimitiveMode _primitiveMode { PrimitiveMode::SOLID };
QVector _renderWithZones;
+ BillboardMode _billboardMode;
bool _cauterized { false };
bool _moving { false };
Transform _renderTransform;
diff --git a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp
index 7a36ae2707..bf005ae2e5 100644
--- a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp
@@ -52,14 +52,11 @@ void GizmoEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
bool dirty = false;
RingGizmoPropertyGroup ringProperties = entity->getRingProperties();
- withWriteLock([&] {
- _gizmoType = entity->getGizmoType();
- if (_ringProperties != ringProperties) {
- _ringProperties = ringProperties;
- dirty = true;
-
- }
- });
+ _gizmoType = entity->getGizmoType();
+ if (_ringProperties != ringProperties) {
+ _ringProperties = ringProperties;
+ dirty = true;
+ }
if (dirty || _prevPrimitiveMode != _primitiveMode || !_ringGeometryID || !_majorTicksGeometryID || !_minorTicksGeometryID) {
_prevPrimitiveMode = _primitiveMode;
@@ -198,8 +195,8 @@ void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
}
}
-Item::Bound GizmoEntityRenderer::getBound() {
- auto bound = Parent::getBound();
+Item::Bound GizmoEntityRenderer::getBound(RenderArgs* args) {
+ auto bound = Parent::getBound(args);
if (_ringProperties.getHasTickMarks()) {
glm::vec3 scale = bound.getScale();
for (int i = 0; i < 3; i += 2) {
@@ -242,20 +239,23 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
if (_gizmoType == GizmoType::RING) {
Transform transform;
- bool hasTickMarks;
- glm::vec4 tickProperties;
- bool forward;
+ bool hasTickMarks = _ringProperties.getHasTickMarks();
+ glm::vec4 tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(),
+ _ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
+
+ bool transparent;
withReadLock([&] {
transform = _renderTransform;
- hasTickMarks = _ringProperties.getHasTickMarks();
- tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(),
- _ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
- forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
+ transparent = isTransparent();
});
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
- geometryCache->bindSimpleProgram(batch, false, isTransparent(), wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
+ bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
+ geometryCache->bindSimpleProgram(batch, false, transparent, wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
+
+ transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true));
batch.setModelTransform(transform);
// Background circle
diff --git a/libraries/entities-renderer/src/RenderableGizmoEntityItem.h b/libraries/entities-renderer/src/RenderableGizmoEntityItem.h
index 8593348bde..6a09d1a047 100644
--- a/libraries/entities-renderer/src/RenderableGizmoEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableGizmoEntityItem.h
@@ -23,7 +23,7 @@ public:
~GizmoEntityRenderer();
protected:
- Item::Bound getBound() override;
+ Item::Bound getBound(RenderArgs* args) override;
ShapeKey getShapeKey() override;
bool isTransparent() const override;
diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp
index 52900d0798..e374fe29c0 100644
--- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp
@@ -30,16 +30,6 @@ bool GridEntityRenderer::isTransparent() const {
}
void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
- withWriteLock([&] {
- _color = entity->getColor();
- _alpha = entity->getAlpha();
- _pulseProperties = entity->getPulseProperties();
-
- _followCamera = entity->getFollowCamera();
- _majorGridEvery = entity->getMajorGridEvery();
- _minorGridEvery = entity->getMinorGridEvery();
- });
-
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
withWriteLock([&] {
@@ -49,13 +39,23 @@ void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
});
}
-Item::Bound GridEntityRenderer::getBound() {
+void GridEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+ _color = entity->getColor();
+ _alpha = entity->getAlpha();
+ _pulseProperties = entity->getPulseProperties();
+
+ _followCamera = entity->getFollowCamera();
+ _majorGridEvery = entity->getMajorGridEvery();
+ _minorGridEvery = entity->getMinorGridEvery();
+}
+
+Item::Bound GridEntityRenderer::getBound(RenderArgs* args) {
if (_followCamera) {
// This is a UI element that should always be in view, lie to the octree to avoid culling
const AABox DOMAIN_BOX = AABox(glm::vec3(-TREE_SCALE / 2), TREE_SCALE);
return DOMAIN_BOX;
}
- return Parent::getBound();
+ return Parent::getBound(args);
}
ShapeKey GridEntityRenderer::getShapeKey() {
@@ -73,22 +73,21 @@ ShapeKey GridEntityRenderer::getShapeKey() {
}
void GridEntityRenderer::doRender(RenderArgs* args) {
- glm::vec4 color;
+ glm::vec4 color = glm::vec4(toGlm(_color), _alpha);
+ color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
glm::vec3 dimensions;
Transform renderTransform;
- bool forward;
withReadLock([&] {
- color = glm::vec4(toGlm(_color), _alpha);
- color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
dimensions = _dimensions;
renderTransform = _renderTransform;
- forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
});
if (!_visible || color.a == 0.0f) {
return;
}
+ bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
+
auto batch = args->_batch;
Transform transform;
@@ -104,6 +103,8 @@ void GridEntityRenderer::doRender(RenderArgs* args) {
} else {
transform.setTranslation(renderTransform.getTranslation());
}
+ transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch->setModelTransform(transform);
auto minCorner = glm::vec2(-0.5f, -0.5f);
diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.h b/libraries/entities-renderer/src/RenderableGridEntityItem.h
index 2ecff01d01..fd5b397424 100644
--- a/libraries/entities-renderer/src/RenderableGridEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableGridEntityItem.h
@@ -23,17 +23,18 @@ public:
~GridEntityRenderer();
protected:
- Item::Bound getBound() override;
+ Item::Bound getBound(RenderArgs* args) override;
ShapeKey getShapeKey() override;
bool isTransparent() const override;
private:
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
+ virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
glm::u8vec3 _color;
- float _alpha;
+ float _alpha { NAN };
PulsePropertyGroup _pulseProperties;
bool _followCamera;
diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp
index 4d19a83ae6..e03655f09c 100644
--- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp
@@ -29,44 +29,7 @@ bool ImageEntityRenderer::isTransparent() const {
return Parent::isTransparent() || (_textureIsLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha()) || _alpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE;
}
-bool ImageEntityRenderer::needsRenderUpdate() const {
- if (resultWithReadLock([&] {
- return !_textureIsLoaded;
- })) {
- return true;
- }
-
- return Parent::needsRenderUpdate();
-}
-
void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
- withWriteLock([&] {
- auto imageURL = entity->getImageURL();
- if (_imageURL != imageURL) {
- _imageURL = imageURL;
- if (imageURL.isEmpty()) {
- _texture.reset();
- } else {
- _texture = DependencyManager::get()->getTexture(_imageURL);
- }
- _textureIsLoaded = false;
- }
-
- _emissive = entity->getEmissive();
- _keepAspectRatio = entity->getKeepAspectRatio();
- _subImage = entity->getSubImage();
-
- _color = entity->getColor();
- _alpha = entity->getAlpha();
- _pulseProperties = entity->getPulseProperties();
- _billboardMode = entity->getBillboardMode();
-
- if (!_textureIsLoaded) {
- emit requestRenderUpdate();
- }
- _textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
- });
-
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
withWriteLock([&] {
@@ -76,15 +39,30 @@ void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
});
}
-Item::Bound ImageEntityRenderer::getBound() {
- auto bound = Parent::getBound();
- if (_billboardMode != BillboardMode::NONE) {
- glm::vec3 dimensions = bound.getScale();
- float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
- const float SQRT_2 = 1.41421356237f;
- bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
+void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+ auto imageURL = entity->getImageURL();
+ if (_imageURL != imageURL) {
+ _imageURL = imageURL;
+ if (imageURL.isEmpty()) {
+ _texture.reset();
+ } else {
+ _texture = DependencyManager::get()->getTexture(_imageURL);
+ }
+ _textureIsLoaded = false;
}
- return bound;
+
+ _emissive = entity->getEmissive();
+ _keepAspectRatio = entity->getKeepAspectRatio();
+ _subImage = entity->getSubImage();
+
+ _color = entity->getColor();
+ _alpha = entity->getAlpha();
+ _pulseProperties = entity->getPulseProperties();
+
+ if (!_textureIsLoaded) {
+ emit requestRenderUpdate();
+ }
+ _textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
}
ShapeKey ImageEntityRenderer::getShapeKey() {
@@ -93,64 +71,58 @@ ShapeKey ImageEntityRenderer::getShapeKey() {
builder.withTranslucent();
}
- withReadLock([&] {
- if (_emissive) {
- builder.withUnlit();
- }
+ if (_emissive) {
+ builder.withUnlit();
+ }
- if (_primitiveMode == PrimitiveMode::LINES) {
- builder.withWireframe();
- }
- });
+ if (_primitiveMode == PrimitiveMode::LINES) {
+ builder.withWireframe();
+ }
return builder.build();
}
void ImageEntityRenderer::doRender(RenderArgs* args) {
- NetworkTexturePointer texture;
- QRect subImage;
- glm::vec4 color;
+ glm::vec4 color = glm::vec4(toGlm(_color), _alpha);
+ color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
Transform transform;
withReadLock([&] {
- texture = _texture;
- subImage = _subImage;
- color = glm::vec4(toGlm(_color), _alpha);
- color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
transform = _renderTransform;
});
- if (!_visible || !texture || !texture->isLoaded() || color.a == 0.0f) {
+ if (!_visible || !_texture || !_texture->isLoaded() || color.a == 0.0f) {
return;
}
Q_ASSERT(args->_batch);
gpu::Batch* batch = args->_batch;
- transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
+ transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch->setModelTransform(transform);
- batch->setResourceTexture(0, texture->getGPUTexture());
+ batch->setResourceTexture(0, _texture->getGPUTexture());
- float imageWidth = texture->getWidth();
- float imageHeight = texture->getHeight();
+ float imageWidth = _texture->getWidth();
+ float imageHeight = _texture->getHeight();
QRect fromImage;
- if (subImage.width() <= 0) {
+ if (_subImage.width() <= 0) {
fromImage.setX(0);
fromImage.setWidth(imageWidth);
} else {
- float scaleX = imageWidth / texture->getOriginalWidth();
- fromImage.setX(scaleX * subImage.x());
- fromImage.setWidth(scaleX * subImage.width());
+ float scaleX = imageWidth / _texture->getOriginalWidth();
+ fromImage.setX(scaleX * _subImage.x());
+ fromImage.setWidth(scaleX * _subImage.width());
}
- if (subImage.height() <= 0) {
+ if (_subImage.height() <= 0) {
fromImage.setY(0);
fromImage.setHeight(imageHeight);
} else {
- float scaleY = imageHeight / texture->getOriginalHeight();
- fromImage.setY(scaleY * subImage.y());
- fromImage.setHeight(scaleY * subImage.height());
+ float scaleY = imageHeight / _texture->getOriginalHeight();
+ fromImage.setY(scaleY * _subImage.y());
+ fromImage.setHeight(scaleY * _subImage.height());
}
float maxSize = glm::max(fromImage.width(), fromImage.height());
diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.h b/libraries/entities-renderer/src/RenderableImageEntityItem.h
index d73bc9bc05..2359dcc6d1 100644
--- a/libraries/entities-renderer/src/RenderableImageEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableImageEntityItem.h
@@ -23,14 +23,13 @@ public:
~ImageEntityRenderer();
protected:
- Item::Bound getBound() override;
ShapeKey getShapeKey() override;
bool isTransparent() const override;
private:
- virtual bool needsRenderUpdate() const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
+ virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
QString _imageURL;
@@ -44,7 +43,6 @@ private:
glm::u8vec3 _color;
float _alpha;
PulsePropertyGroup _pulseProperties;
- BillboardMode _billboardMode;
int _geometryId { 0 };
};
diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp
index 9eb2e8428d..2ab2051fcf 100644
--- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp
@@ -60,8 +60,8 @@ ItemKey LightEntityRenderer::getKey() {
return payloadGetKey(_lightPayload);
}
-Item::Bound LightEntityRenderer::getBound() {
- return payloadGetBound(_lightPayload);
+Item::Bound LightEntityRenderer::getBound(RenderArgs* args) {
+ return payloadGetBound(_lightPayload, args);
}
void LightEntityRenderer::doRender(RenderArgs* args) {
diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h
index 323f280795..bbb5ec346a 100644
--- a/libraries/entities-renderer/src/RenderableLightEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h
@@ -29,7 +29,7 @@ protected:
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual ItemKey getKey() override;
- virtual Item::Bound getBound() override;
+ virtual Item::Bound getBound(RenderArgs* args) override;
virtual void doRender(RenderArgs* args) override;
private:
diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp
index 6e2be1b41e..a36cdde212 100644
--- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp
@@ -47,7 +47,8 @@ void LineEntityRenderer::doRender(RenderArgs* args) {
const auto& modelTransform = getModelTransform();
Transform transform = Transform();
transform.setTranslation(modelTransform.getTranslation());
- transform.setRotation(modelTransform.getRotation());
+ transform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch.setModelTransform(transform);
if (_linePoints.size() > 1) {
DependencyManager::get()->bindSimpleProgram(batch, false, false, false, false, true,
diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
index c1b024a478..714defe817 100644
--- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
@@ -16,197 +16,177 @@
using namespace render;
using namespace render::entities;
-bool MaterialEntityRenderer::needsRenderUpdate() const {
- if (_retryApply) {
- return true;
- }
- if (!_texturesLoaded) {
- return true;
- }
- return Parent::needsRenderUpdate();
-}
-
-bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
- if (resultWithReadLock([&] {
- if (entity->getTransform() != _transform) {
- return true;
- }
- if (entity->getUnscaledDimensions() != _dimensions) {
- return true;
- }
- if (entity->getParentID() != _parentID) {
- return true;
- }
-
- return false;
- })) {
- return true;
- }
- return false;
+void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
+ void* key = (void*)this;
+ AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
+ withWriteLock([&] {
+ _renderTransform = getModelTransform();
+ // Material entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1
+ // is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
+ const float MATERIAL_ENTITY_SCALE = 0.5f;
+ _renderTransform.postScale(MATERIAL_ENTITY_SCALE);
+ _renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
+ });
+ });
}
void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
- withWriteLock([&] {
- bool deleteNeeded = false;
- bool addNeeded = _retryApply;
- bool transformChanged = false;
- {
- MaterialMappingMode mode = entity->getMaterialMappingMode();
- if (mode != _materialMappingMode) {
- _materialMappingMode = mode;
- transformChanged = true;
- }
+ bool deleteNeeded = false;
+ bool addNeeded = _retryApply;
+ bool transformChanged = false;
+ {
+ MaterialMappingMode mode = entity->getMaterialMappingMode();
+ if (mode != _materialMappingMode) {
+ _materialMappingMode = mode;
+ transformChanged = true;
}
- {
- bool repeat = entity->getMaterialRepeat();
- if (repeat != _materialRepeat) {
- _materialRepeat = repeat;
- transformChanged = true;
- }
+ }
+ {
+ bool repeat = entity->getMaterialRepeat();
+ if (repeat != _materialRepeat) {
+ _materialRepeat = repeat;
+ transformChanged = true;
}
- {
- glm::vec2 mappingPos = entity->getMaterialMappingPos();
- glm::vec2 mappingScale = entity->getMaterialMappingScale();
- float mappingRot = entity->getMaterialMappingRot();
- if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) {
- _materialMappingPos = mappingPos;
- _materialMappingScale = mappingScale;
- _materialMappingRot = mappingRot;
- transformChanged |= _materialMappingMode == MaterialMappingMode::UV;
- }
+ }
+ {
+ glm::vec2 mappingPos = entity->getMaterialMappingPos();
+ glm::vec2 mappingScale = entity->getMaterialMappingScale();
+ float mappingRot = entity->getMaterialMappingRot();
+ if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) {
+ _materialMappingPos = mappingPos;
+ _materialMappingScale = mappingScale;
+ _materialMappingRot = mappingRot;
+ transformChanged |= _materialMappingMode == MaterialMappingMode::UV;
}
- {
- Transform transform = entity->getTransform();
- glm::vec3 dimensions = entity->getUnscaledDimensions();
- if (transform != _transform || dimensions != _dimensions) {
- _transform = transform;
- _dimensions = dimensions;
- transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED;
- }
+ }
+ {
+ Transform transform = entity->getTransform();
+ glm::vec3 dimensions = entity->getUnscaledDimensions();
+ if (transform != _transform || dimensions != _dimensions) {
+ _transform = transform;
+ _dimensions = dimensions;
+ transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED;
}
+ }
- {
- auto material = getMaterial();
- // Update the old material regardless of if it's going to change
- if (transformChanged && material && !_parentID.isNull()) {
- deleteNeeded = true;
- addNeeded = true;
- applyTextureTransform(material);
- }
+ {
+ auto material = getMaterial();
+ // Update the old material regardless of if it's going to change
+ if (transformChanged && material && !_parentID.isNull()) {
+ deleteNeeded = true;
+ addNeeded = true;
+ applyTextureTransform(material);
}
+ }
- bool urlChanged = false;
- std::string newCurrentMaterialName = _currentMaterialName;
- {
- QString materialURL = entity->getMaterialURL();
- if (materialURL != _materialURL) {
- _materialURL = materialURL;
- if (_materialURL.contains("#")) {
- auto split = _materialURL.split("#");
- newCurrentMaterialName = split.last().toStdString();
- } else if (_materialURL.contains("?")) {
- qDebug() << "DEPRECATED: Use # instead of ? for material URLS:" << _materialURL;
- auto split = _materialURL.split("?");
- newCurrentMaterialName = split.last().toStdString();
- }
- urlChanged = true;
+ bool urlChanged = false;
+ std::string newCurrentMaterialName = _currentMaterialName;
+ {
+ QString materialURL = entity->getMaterialURL();
+ if (materialURL != _materialURL) {
+ _materialURL = materialURL;
+ if (_materialURL.contains("#")) {
+ auto split = _materialURL.split("#");
+ newCurrentMaterialName = split.last().toStdString();
+ } else if (_materialURL.contains("?")) {
+ qDebug() << "DEPRECATED: Use # instead of ? for material URLS:" << _materialURL;
+ auto split = _materialURL.split("?");
+ newCurrentMaterialName = split.last().toStdString();
}
+ urlChanged = true;
}
+ }
- bool usingMaterialData = _materialURL.startsWith("materialData");
- bool materialDataChanged = false;
- QUuid oldParentID = _parentID;
- QString oldParentMaterialName = _parentMaterialName;
- {
- QString materialData = entity->getMaterialData();
- if (materialData != _materialData) {
- _materialData = materialData;
- if (usingMaterialData) {
- materialDataChanged = true;
- }
+ bool usingMaterialData = _materialURL.startsWith("materialData");
+ bool materialDataChanged = false;
+ QUuid oldParentID = _parentID;
+ QString oldParentMaterialName = _parentMaterialName;
+ {
+ QString materialData = entity->getMaterialData();
+ if (materialData != _materialData) {
+ _materialData = materialData;
+ if (usingMaterialData) {
+ materialDataChanged = true;
}
}
- {
- QString parentMaterialName = entity->getParentMaterialName();
- if (parentMaterialName != _parentMaterialName) {
- _parentMaterialName = parentMaterialName;
- deleteNeeded = true;
- addNeeded = true;
- }
+ }
+ {
+ QString parentMaterialName = entity->getParentMaterialName();
+ if (parentMaterialName != _parentMaterialName) {
+ _parentMaterialName = parentMaterialName;
+ deleteNeeded = true;
+ addNeeded = true;
}
- {
- QUuid parentID = entity->getParentID();
- if (parentID != _parentID) {
- _parentID = parentID;
- deleteNeeded = true;
- addNeeded = true;
- }
+ }
+ {
+ QUuid parentID = entity->getParentID();
+ if (parentID != _parentID) {
+ _parentID = parentID;
+ deleteNeeded = true;
+ addNeeded = true;
}
- {
- quint16 priority = entity->getPriority();
- if (priority != _priority) {
- _priority = priority;
- deleteNeeded = true;
- addNeeded = true;
- }
+ }
+ {
+ quint16 priority = entity->getPriority();
+ if (priority != _priority) {
+ _priority = priority;
+ deleteNeeded = true;
+ addNeeded = true;
}
+ }
- if (urlChanged && !usingMaterialData) {
- _networkMaterial = DependencyManager::get()->getMaterial(_materialURL);
- auto onMaterialRequestFinished = [this, entity, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
- if (success) {
- deleteMaterial(oldParentID, oldParentMaterialName);
- _texturesLoaded = false;
- _parsedMaterials = _networkMaterial->parsedMaterials;
- setCurrentMaterialName(newCurrentMaterialName);
- applyMaterial(entity);
- } else {
- deleteMaterial(oldParentID, oldParentMaterialName);
- _retryApply = false;
- _texturesLoaded = true;
- }
- };
- if (_networkMaterial) {
- if (_networkMaterial->isLoaded()) {
- onMaterialRequestFinished(!_networkMaterial->isFailed());
- } else {
- connect(_networkMaterial.data(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) {
- withWriteLock([&] {
- onMaterialRequestFinished(success);
- });
- });
- }
- }
- } else if (materialDataChanged && usingMaterialData) {
+ if (urlChanged && !usingMaterialData) {
+ _networkMaterial = DependencyManager::get()->getMaterial(_materialURL);
+ auto onMaterialRequestFinished = [this, entity, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
deleteMaterial(oldParentID, oldParentMaterialName);
- _texturesLoaded = false;
- _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL);
- // Since our material changed, the current name might not be valid anymore, so we need to update
- setCurrentMaterialName(newCurrentMaterialName);
- applyMaterial(entity);
- } else {
- if (deleteNeeded) {
- deleteMaterial(oldParentID, oldParentMaterialName);
- }
- if (addNeeded) {
+ if (success) {
+ _texturesLoaded = false;
+ _parsedMaterials = _networkMaterial->parsedMaterials;
+ setCurrentMaterialName(newCurrentMaterialName);
applyMaterial(entity);
+ emit requestRenderUpdate();
+ } else {
+ _retryApply = false;
+ _texturesLoaded = true;
+ }
+ };
+ if (_networkMaterial) {
+ if (_networkMaterial->isLoaded()) {
+ onMaterialRequestFinished(!_networkMaterial->isFailed());
+ } else {
+ connect(_networkMaterial.data(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) {
+ onMaterialRequestFinished(success);
+ });
}
}
-
- {
- auto material = getMaterial();
- bool newTexturesLoaded = material ? !material->isMissingTexture() : false;
- if (!_texturesLoaded && newTexturesLoaded) {
- material->checkResetOpacityMap();
- }
- _texturesLoaded = newTexturesLoaded;
+ } else if (materialDataChanged && usingMaterialData) {
+ deleteMaterial(oldParentID, oldParentMaterialName);
+ _texturesLoaded = false;
+ _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL);
+ // Since our material changed, the current name might not be valid anymore, so we need to update
+ setCurrentMaterialName(newCurrentMaterialName);
+ applyMaterial(entity);
+ } else {
+ if (deleteNeeded) {
+ deleteMaterial(oldParentID, oldParentMaterialName);
}
+ if (addNeeded) {
+ applyMaterial(entity);
+ }
+ }
- _renderTransform = getModelTransform();
- const float MATERIAL_ENTITY_SCALE = 0.5f;
- _renderTransform.postScale(MATERIAL_ENTITY_SCALE);
- _renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
- });
+ {
+ auto material = getMaterial();
+ bool newTexturesLoaded = material ? !material->isMissingTexture() : false;
+ if (!_texturesLoaded && newTexturesLoaded) {
+ material->checkResetOpacityMap();
+ }
+ _texturesLoaded = newTexturesLoaded;
+ }
+
+ if (!_texturesLoaded || _retryApply) {
+ emit requestRenderUpdate();
+ }
}
ItemKey MaterialEntityRenderer::getKey() {
@@ -268,34 +248,33 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
gpu::Batch& batch = *args->_batch;
// Don't render if our parent is set or our material is null
- QUuid parentID;
- withReadLock([&] {
- parentID = _parentID;
- });
- if (!parentID.isNull()) {
+ if (!_parentID.isNull()) {
return;
}
- Transform renderTransform;
- graphics::MaterialPointer drawMaterial;
+ graphics::MaterialPointer drawMaterial = getMaterial();
bool proceduralRender = false;
Transform textureTransform;
- withReadLock([&] {
- renderTransform = _renderTransform;
- drawMaterial = getMaterial();
- textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
- textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
- textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
+ textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
+ textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
+ textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
- if (drawMaterial && drawMaterial->isProcedural() && drawMaterial->isReady()) {
- proceduralRender = true;
- }
+ Transform transform;
+ withReadLock([&] {
+ transform = _renderTransform;
});
+
if (!drawMaterial) {
return;
}
- batch.setModelTransform(renderTransform);
+ if (drawMaterial->isProcedural() && drawMaterial->isReady()) {
+ proceduralRender = true;
+ }
+
+ transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
+ batch.setModelTransform(transform);
if (!proceduralRender) {
drawMaterial->setTextureTransforms(textureTransform, MaterialMappingMode::UV, true);
@@ -310,8 +289,8 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
auto proceduralDrawMaterial = std::static_pointer_cast(drawMaterial);
glm::vec4 outColor = glm::vec4(drawMaterial->getAlbedo(), drawMaterial->getOpacity());
outColor = proceduralDrawMaterial->getColor(outColor);
- proceduralDrawMaterial->prepare(batch, renderTransform.getTranslation(), renderTransform.getScale(),
- renderTransform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
+ proceduralDrawMaterial->prepare(batch, transform.getTranslation(), transform.getScale(),
+ transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
DependencyManager::get()->renderWireSphere(batch, outColor);
} else {
@@ -397,7 +376,7 @@ void MaterialEntityRenderer::applyMaterial(const TypedEntityPointer& entity) {
if (material->isProcedural()) {
auto procedural = std::static_pointer_cast(material);
- procedural->setBoundOperator([this] { return getBound(); });
+ procedural->setBoundOperator([this](RenderArgs* args) { return getBound(args); });
entity->setHasVertexShader(procedural->hasVertexShader());
}
diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h
index 3a73c988eb..340d169f29 100644
--- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h
@@ -27,8 +27,7 @@ public:
~MaterialEntityRenderer() { deleteMaterial(_parentID, _parentMaterialName); }
private:
- virtual bool needsRenderUpdate() const override;
- virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
+ virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 8c766d0ab8..4d3a79c9af 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -51,12 +51,6 @@ ModelPointer ModelEntityWrapper::getModel() const {
});
}
-bool ModelEntityWrapper::isModelLoaded() const {
- return resultWithReadLock([&] {
- return _model.operator bool() && _model->isLoaded();
- });
-}
-
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer entity(new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()),
[](EntityItem* ptr) { ptr->deleteLater(); });
@@ -69,8 +63,7 @@ EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityI
RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) :
ModelEntityWrapper(entityItemID),
_dimensionsInitialized(dimensionsInitialized) {
-
-
+
}
RenderableModelEntityItem::~RenderableModelEntityItem() { }
@@ -83,34 +76,6 @@ void RenderableModelEntityItem::setUnscaledDimensions(const glm::vec3& value) {
}
}
-void RenderableModelEntityItem::doInitialModelSimulation() {
- DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
- ModelPointer model = getModel();
- if (!model) {
- return;
- }
- // The machinery for updateModelBounds will give existing models the opportunity to fix their
- // translation/rotation/scale/registration. The first two are straightforward, but the latter two have guards to
- // make sure they don't happen after they've already been set. Here we reset those guards. This doesn't cause the
- // entity values to change -- it just allows the model to match once it comes in.
- model->setScaleToFit(false, getScaledDimensions());
- model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
-
- // now recalculate the bounds and registration
- model->setScaleToFit(true, getScaledDimensions());
- model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
- model->setRotation(getWorldOrientation());
- model->setTranslation(getWorldPosition());
-
- glm::vec3 scale = model->getScale();
- model->setUseDualQuaternionSkinning(!isNonUniformScale(scale));
-
- if (_needsInitialSimulation) {
- model->simulate(0.0f);
- _needsInitialSimulation = false;
- }
-}
-
void RenderableModelEntityItem::autoResizeJointArrays() {
ModelPointer model = getModel();
if (model && model->isLoaded() && !_needsInitialSimulation) {
@@ -125,7 +90,7 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
return false;
}
- if (!_dimensionsInitialized || !model->isActive()) {
+ if (!_dimensionsInitialized || !model->isLoaded()) {
return false;
}
@@ -182,22 +147,27 @@ void RenderableModelEntityItem::updateModelBounds() {
}
bool overridingModelTransform = model->isOverridingModelTransformAndOffset();
+ glm::vec3 scaledDimensions = getScaledDimensions();
+ glm::vec3 registrationPoint = getRegistrationPoint();
+ bool needsSimulate = false;
if (!overridingModelTransform &&
- (model->getScaleToFitDimensions() != getScaledDimensions() ||
- model->getRegistrationPoint() != getRegistrationPoint() ||
- !model->getIsScaledToFit())) {
+ (model->getScaleToFitDimensions() != scaledDimensions ||
+ model->getRegistrationPoint() != registrationPoint ||
+ !model->getIsScaledToFit() || _needsToRescaleModel ||
+ _useOriginalPivot == model->getSnapModelToRegistrationPoint())) {
// The machinery for updateModelBounds will give existing models the opportunity to fix their
// translation/rotation/scale/registration. The first two are straightforward, but the latter two
// have guards to make sure they don't happen after they've already been set. Here we reset those guards.
// This doesn't cause the entity values to change -- it just allows the model to match once it comes in.
- model->setScaleToFit(false, getScaledDimensions());
- model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
+ model->setScaleToFit(false, scaledDimensions);
+ model->setSnapModelToRegistrationPoint(false, registrationPoint);
// now recalculate the bounds and registration
- model->setScaleToFit(true, getScaledDimensions());
- model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
+ model->setScaleToFit(true, scaledDimensions);
+ model->setSnapModelToRegistrationPoint(!_useOriginalPivot, registrationPoint);
updateRenderItems = true;
- model->scaleToFit();
+ needsSimulate = true;
+ _needsToRescaleModel = false;
}
bool success;
@@ -208,10 +178,11 @@ void RenderableModelEntityItem::updateModelBounds() {
updateRenderItems = true;
}
- if (_needsInitialSimulation || _needsJointSimulation || isAnimatingSomething()) {
+ if (_needsInitialSimulation || _needsJointSimulation || needsSimulate || isAnimatingSomething()) {
// NOTE: on isAnimatingSomething() we need to call Model::simulate() which calls Rig::updateRig()
// TODO: there is opportunity to further optimize the isAnimatingSomething() case.
model->simulate(0.0f);
+ locationChanged();
_needsInitialSimulation = false;
_needsJointSimulation = false;
updateRenderItems = true;
@@ -248,41 +219,64 @@ EntityItemProperties RenderableModelEntityItem::getProperties(const EntityProper
}
}
-
-
return properties;
}
+glm::vec3 RenderableModelEntityItem::getPivot() const {
+ auto model = getModel();
+ auto pivot = EntityItem::getPivot();
+ if (!model || !model->isLoaded() || !_useOriginalPivot) {
+ return pivot;
+ }
+
+ return pivot + model->getOriginalOffset();
+}
+
bool RenderableModelEntityItem::supportsDetailedIntersection() const {
return true;
}
bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance, BoxFace& face,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance, BoxFace& face,
glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
auto model = getModel();
- if (!model || !isModelLoaded()) {
+ if (!model || !model->isLoaded()) {
return false;
}
- return model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
+ return model->findRayIntersectionAgainstSubMeshes(origin, direction, viewFrustumPos, distance,
face, surfaceNormal, extraInfo, precisionPicking, false);
}
bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face,
- glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
auto model = getModel();
- if (!model || !isModelLoaded()) {
+ if (!model || !model->isLoaded()) {
return false;
}
- return model->findParabolaIntersectionAgainstSubMeshes(origin, velocity, acceleration, parabolicDistance,
+ return model->findParabolaIntersectionAgainstSubMeshes(origin, velocity, acceleration, viewFrustumPos, parabolicDistance,
face, surfaceNormal, extraInfo, precisionPicking, false);
}
+QString RenderableModelEntityItem::getCollisionShapeURL() const {
+ return getShapeType() == SHAPE_TYPE_COMPOUND ? getCompoundShapeURL() : getModelURL();
+}
+
void RenderableModelEntityItem::fetchCollisionGeometryResource() {
_collisionGeometryResource = DependencyManager::get()->getCollisionGeometryResource(getCollisionShapeURL());
+ if (_collisionGeometryResource) {
+ if (_collisionGeometryResource->isLoaded()) {
+ markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+ locationChanged();
+ } else {
+ connect(_collisionGeometryResource.get(), &GeometryResource::finished, this, [&] {
+ markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+ locationChanged();
+ });
+ }
+ }
}
bool RenderableModelEntityItem::unableToLoadCollisionShape() {
@@ -299,7 +293,7 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) {
if (!_collisionGeometryResource && !getCollisionShapeURL().isEmpty()) {
fetchCollisionGeometryResource();
}
- } else if (_collisionGeometryResource && !getCompoundShapeURL().isEmpty()) {
+ } else if (_collisionGeometryResource) {
// the compoundURL has been set but the shapeType does not agree
_collisionGeometryResource.reset();
}
@@ -308,49 +302,43 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) {
void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
auto currentCompoundShapeURL = getCompoundShapeURL();
ModelEntityItem::setCompoundShapeURL(url);
- if (getCompoundShapeURL() != currentCompoundShapeURL || !getModel()) {
- if (getShapeType() == SHAPE_TYPE_COMPOUND) {
+ if (url != currentCompoundShapeURL && !url.isEmpty()) {
+ auto shapeType = getShapeType();
+ if (shapeType == SHAPE_TYPE_COMPOUND) {
+ fetchCollisionGeometryResource();
+ }
+ }
+}
+
+void RenderableModelEntityItem::setModelURL(const QString& url) {
+ auto currentModelURL = getModelURL();
+ ModelEntityItem::setModelURL(url);
+ if (url != currentModelURL && !url.isEmpty()) {
+ auto shapeType = getShapeType();
+ if (shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
fetchCollisionGeometryResource();
}
}
}
bool RenderableModelEntityItem::isReadyToComputeShape() const {
- ShapeType type = getShapeType();
auto model = getModel();
auto shapeType = getShapeType();
if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
auto shapeURL = getCollisionShapeURL();
-
- if (!model || shapeURL.isEmpty()) {
- return false;
- }
-
- if (model->getURL().isEmpty() || !_dimensionsInitialized) {
- // we need a render geometry with a scale to proceed, so give up.
- return false;
- }
-
- if (model->isLoaded()) {
- if (!shapeURL.isEmpty() && !_collisionGeometryResource) {
+ // we need a render geometry with a scale to proceed
+ if (model && !model->getURL().isEmpty() && !shapeURL.isEmpty() && _dimensionsInitialized && model->isLoaded()) {
+ if (!_collisionGeometryResource) {
const_cast(this)->fetchCollisionGeometryResource();
}
- if (_collisionGeometryResource && _collisionGeometryResource->isLoaded()) {
- // we have both URLs AND both geometries AND they are both fully loaded.
- if (_needsInitialSimulation) {
- // the _model's offset will be wrong until _needsInitialSimulation is false
- DETAILED_PERFORMANCE_TIMER("_model->simulate");
- const_cast(this)->doInitialModelSimulation();
- }
- return true;
- }
+ // do we have both URLs AND both geometries AND they are both fully loaded?
+ return _collisionGeometryResource && _collisionGeometryResource->isLoaded() && _collisionGeometryResource->isHFMModelLoaded();
}
- // the model is still being downloaded.
return false;
- } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
- return isModelLoaded();
+ } else if (shapeType >= SHAPE_TYPE_SIMPLE_HULL && shapeType <= SHAPE_TYPE_STATIC_MESH) {
+ return model && model->isLoaded() && _dimensionsInitialized;
}
return true;
}
@@ -362,20 +350,31 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
ShapeType type = getShapeType();
auto model = getModel();
- if (!model || !model->isLoaded()) {
- type = SHAPE_TYPE_NONE;
+ if (type >= SHAPE_TYPE_COMPOUND && type <= SHAPE_TYPE_STATIC_MESH) {
+ if (!model) {
+ type = SHAPE_TYPE_NONE;
+ } else if (!model->isLoaded()) {
+ type = SHAPE_TYPE_NONE;
+ if (!model->didVisualGeometryRequestFail()) {
+ markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+ locationChanged();
+ }
+ }
+ }
+
+ if (type == SHAPE_TYPE_COMPOUND || type == SHAPE_TYPE_SIMPLE_COMPOUND) {
+ if (!_collisionGeometryResource || !_collisionGeometryResource->isLoaded() || !_collisionGeometryResource->isHFMModelLoaded()) {
+ type = SHAPE_TYPE_NONE;
+ if (!_collisionGeometryResource->isFailed()) {
+ markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+ locationChanged();
+ }
+ }
}
if (type == SHAPE_TYPE_COMPOUND) {
- if (!_collisionGeometryResource || !_collisionGeometryResource->isLoaded()) {
- return;
- }
-
updateModelBounds();
- // should never fall in here when collision model not fully loaded
- // TODO: assert that all geometries exist and are loaded
- //assert(_model && _model->isLoaded() && _collisionGeometryResource && _collisionGeometryResource->isLoaded());
const HFMModel& collisionGeometry = _collisionGeometryResource->getHFMModel();
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
@@ -452,22 +451,22 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
// collision model's extents).
glm::vec3 dimensions = getScaledDimensions();
- glm::vec3 scaleToFit = dimensions / model->getHFMModel().getUnscaledMeshExtents().size();
+ glm::vec3 extents = model->getHFMModel().getUnscaledMeshExtents().size();
+ glm::vec3 scaleToFit = dimensions / extents;
// multiply each point by scale before handing the point-set off to the physics engine.
// also determine the extents of the collision model.
glm::vec3 registrationOffset = dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
+ glm::vec3 offset = model->getSnapModelToRegistrationPoint() ? model->getOffset() : glm::vec3(0.0f);
for (int32_t i = 0; i < pointCollection.size(); i++) {
for (int32_t j = 0; j < pointCollection[i].size(); j++) {
// back compensate for registration so we can apply that offset to the shapeInfo later
- pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + model->getOffset()) - registrationOffset;
+ pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + offset) - registrationOffset;
}
}
- shapeInfo.setParams(type, dimensions, getCompoundShapeURL());
- adjustShapeInfoByRegistration(shapeInfo);
+ shapeInfo.setParams(type, 0.5f * extents, getCompoundShapeURL() + model->getSnapModelToRegistrationPoint());
+ adjustShapeInfoByRegistration(shapeInfo, model->getSnapModelToRegistrationPoint());
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
updateModelBounds();
- // assert we never fall in here when model not fully loaded
- assert(model && model->isLoaded());
model->updateGeometry();
// compute meshPart local transforms
@@ -476,16 +475,16 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
int numHFMMeshes = hfmModel.meshes.size();
int totalNumVertices = 0;
glm::vec3 dimensions = getScaledDimensions();
- glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
+ glm::mat4 invRegistrationOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
for (int i = 0; i < numHFMMeshes; i++) {
const HFMMesh& mesh = hfmModel.meshes.at(i);
if (mesh.clusters.size() > 0) {
const HFMCluster& cluster = mesh.clusters.at(0);
auto jointMatrix = model->getRig().getJointTransform(cluster.jointIndex);
// we backtranslate by the registration offset so we can apply that offset to the shapeInfo later
- localTransforms.push_back(invRegistraionOffset * jointMatrix * cluster.inverseBindMatrix);
+ localTransforms.push_back(invRegistrationOffset * jointMatrix * cluster.inverseBindMatrix);
} else {
- localTransforms.push_back(invRegistraionOffset);
+ localTransforms.push_back(invRegistrationOffset);
}
totalNumVertices += mesh.vertices.size();
}
@@ -697,8 +696,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
}
}
- shapeInfo.setParams(type, 0.5f * dimensions, getModelURL());
- adjustShapeInfoByRegistration(shapeInfo);
+ shapeInfo.setParams(type, 0.5f * extents.size(), getModelURL() + model->getSnapModelToRegistrationPoint());
+ adjustShapeInfoByRegistration(shapeInfo, model->getSnapModelToRegistrationPoint());
} else {
EntityItem::computeShapeInfo(shapeInfo);
}
@@ -716,8 +715,8 @@ void RenderableModelEntityItem::setJointMap(std::vector jointMap) {
int RenderableModelEntityItem::avatarJointIndex(int modelJointIndex) {
int result = -1;
- int mapSize = (int) _jointMap.size();
- if (modelJointIndex >=0 && modelJointIndex < mapSize) {
+ int mapSize = (int)_jointMap.size();
+ if (modelJointIndex >= 0 && modelJointIndex < mapSize) {
result = _jointMap[modelJointIndex];
}
@@ -726,28 +725,44 @@ int RenderableModelEntityItem::avatarJointIndex(int modelJointIndex) {
bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
auto model = getModel();
- if (EntityItem::contains(point) && model && _collisionGeometryResource && _collisionGeometryResource->isLoaded()) {
- glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
- glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
- return _collisionGeometryResource->getHFMModel().convexHullContains(hfmPoint);
+ if (model && model->isLoaded()) {
+ auto shapeType = getShapeType();
+ if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
+ if (_collisionGeometryResource && _collisionGeometryResource->isLoaded() && _collisionGeometryResource->isHFMModelLoaded() && EntityItem::contains(point)) {
+ glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
+ glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
+ return _collisionGeometryResource->getHFMModel().convexHullContains(hfmPoint);
+ }
+ } else if (shapeType >= SHAPE_TYPE_SIMPLE_HULL && shapeType <= SHAPE_TYPE_STATIC_MESH) {
+ if (EntityItem::contains(point)) {
+ glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
+ glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
+ return model->getHFMModel().convexHullContains(hfmPoint);
+ }
+ } else {
+ return EntityItem::contains(point);
+ }
}
return false;
}
bool RenderableModelEntityItem::shouldBePhysical() const {
- auto model = getModel();
- // If we have a model, make sure it hasn't failed to download.
- // If it has, we'll report back that we shouldn't be physical so that physics aren't held waiting for us to be ready.
+ bool physicalModelLoaded = false;
ShapeType shapeType = getShapeType();
- if (model) {
- if ((shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) && model->didCollisionGeometryRequestFail()) {
- return false;
- } else if (shapeType != SHAPE_TYPE_NONE && model->didVisualGeometryRequestFail()) {
- return false;
+ if (shapeType >= SHAPE_TYPE_COMPOUND && shapeType <= SHAPE_TYPE_STATIC_MESH) {
+ auto model = getModel();
+ // If we have a model, make sure it hasn't failed to download.
+ // If it has, we'll report back that we shouldn't be physical so that physics aren't held waiting for us to be ready.
+ physicalModelLoaded = model && !model->didVisualGeometryRequestFail();
+ if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
+ physicalModelLoaded &= _collisionGeometryResource && !_collisionGeometryResource->isFailed();
}
+ } else if (shapeType != SHAPE_TYPE_NONE) {
+ physicalModelLoaded = true;
}
- return !isDead() && shapeType != SHAPE_TYPE_NONE && !isLocalEntity() && QUrl(_modelURL).isValid();
+
+ return physicalModelLoaded && !isDead() && !isLocalEntity() && QUrl(getModelURL()).isValid();
}
int RenderableModelEntityItem::getJointParent(int index) const {
@@ -943,13 +958,13 @@ void RenderableModelEntityItem::locationChanged(bool tellPhysics, bool tellChild
int RenderableModelEntityItem::getJointIndex(const QString& name) const {
auto model = getModel();
- return (model && model->isActive()) ? model->getRig().indexOfJoint(name) : -1;
+ return (model && model->isLoaded()) ? model->getRig().indexOfJoint(name) : -1;
}
QStringList RenderableModelEntityItem::getJointNames() const {
QStringList result;
auto model = getModel();
- if (model && model->isActive()) {
+ if (model && model->isLoaded()) {
const Rig& rig = model->getRig();
int jointCount = rig.getJointStateCount();
for (int jointIndex = 0; jointIndex < jointCount; jointIndex++) {
@@ -960,13 +975,13 @@ QStringList RenderableModelEntityItem::getJointNames() const {
}
scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScriptableModel() {
- auto model = resultWithReadLock([this]{ return _model; });
+ auto model = resultWithReadLock([&] { return _model; });
if (!model || !model->isLoaded()) {
return scriptable::ScriptableModelBase();
}
- auto result = _model->getScriptableModel();
+ auto result = model->getScriptableModel();
result.objectID = getEntity()->getID();
{
std::lock_guard lock(_materialsLock);
@@ -1036,7 +1051,7 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
});
if (changed) {
- locationChanged(true, true);
+ locationChanged();
}
}
@@ -1054,10 +1069,14 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
}
-void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
+void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed, const ModelPointer& model) {
auto builder = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
- if (!_cullWithParent && _model && _model->isGroupCulled()) {
+ if (!_visible) {
+ builder.withInvisible();
+ }
+
+ if (!_cullWithParent && model && model->isGroupCulled()) {
builder.withMetaCullGroup();
} else if (_cullWithParent) {
builder.withSubMetaCulled();
@@ -1075,8 +1094,9 @@ ItemKey ModelEntityRenderer::getKey() {
}
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
- if (_model) {
- auto metaSubItems = _model->fetchRenderItemIDs();
+ auto model = resultWithReadLock([&] { return _model; });
+ if (model) {
+ auto metaSubItems = model->fetchRenderItemIDs();
subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end());
return (uint32_t)metaSubItems.size();
}
@@ -1089,8 +1109,9 @@ void ModelEntityRenderer::handleBlendedVertices(int blendshapeNumber, const QVec
}
void ModelEntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& transaction) {
- if (_model) {
- _model->removeFromScene(scene, transaction);
+ auto model = resultWithReadLock([&] { return _model; });
+ if (model) {
+ model->removeFromScene(scene, transaction);
}
Parent::removeFromScene(scene, transaction);
}
@@ -1099,14 +1120,14 @@ void ModelEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entit
entity->setModel({});
}
-void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
+void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelPointer& model) {
if (!_animation || !_animation->isLoaded()) {
return;
}
QVector jointsData;
- const QVector& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
+ const QVector& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
int frameCount = frames.size();
if (frameCount <= 0) {
return;
@@ -1124,17 +1145,17 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
_lastKnownCurrentFrame = currentIntegerFrame;
}
- if (_jointMapping.size() != _model->getJointStateCount()) {
+ if (_jointMapping.size() != model->getJointStateCount()) {
qCWarning(entitiesrenderer) << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch"
- << _jointMapping.size() << _model->getJointStateCount();
+ << _jointMapping.size() << model->getJointStateCount();
return;
}
QStringList animationJointNames = _animation->getHFMModel().getJointNames();
auto& hfmJoints = _animation->getHFMModel().joints;
- auto& originalHFMJoints = _model->getHFMModel().joints;
- auto& originalHFMIndices = _model->getHFMModel().jointIndices;
+ auto& originalHFMJoints = model->getHFMModel().joints;
+ auto& originalHFMIndices = model->getHFMModel().jointIndices;
bool allowTranslation = entity->getAnimationAllowTranslation();
@@ -1182,146 +1203,49 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
entity->copyAnimationJointDataToModel();
}
-bool ModelEntityRenderer::needsRenderUpdate() const {
- if (resultWithReadLock([&] {
- if (_moving || _animating) {
- return true;
- }
-
- if (!_texturesLoaded) {
- return true;
- }
-
- if (!_prevModelLoaded) {
- return true;
- }
-
- return false;
- })) {
+bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
+ if (entity->blendshapesChanged()) {
return true;
}
- ModelPointer model;
- QUrl parsedModelURL;
- withReadLock([&] {
- model = _model;
- parsedModelURL = _parsedModelURL;
- });
-
- if (model) {
- // When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
- // we will watch for that and ask the model to update it's render items
- if (parsedModelURL != model->getURL()) {
- return true;
- }
-
- if (model->needsReload()) {
- return true;
- }
-
- if (model->needsFixupInScene()) {
- return true;
- }
-
- if (model->getRenderItemsNeedUpdate()) {
- return true;
- }
- }
- return Parent::needsRenderUpdate();
-}
-
-bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
- if (resultWithReadLock([&] {
- if (entity->hasModel() != _hasModel) {
- return true;
- }
-
- // No model to render, early exit
- if (!_hasModel) {
- return false;
- }
-
- if (_animating != entity->isAnimatingSomething()) {
- return true;
- }
-
- return false;
- })) { return true; }
-
- ModelPointer model;
- withReadLock([&] {
- model = _model;
- });
-
- if (model && model->isLoaded()) {
- if (!entity->_dimensionsInitialized || entity->_needsInitialSimulation || !entity->_originalTexturesRead) {
- return true;
- }
-
- if (entity->blendshapesChanged()) {
- return true;
- }
-
- // Check to see if we need to update the model bounds
- if (entity->needsUpdateModelBounds()) {
- return true;
- }
-
- // Check to see if we need to update the model bounds
- auto transform = entity->getTransform();
- if (model->getTranslation() != transform.getTranslation() ||
- model->getRotation() != transform.getRotation()) {
- return true;
- }
-
- if (model->getScaleToFitDimensions() != entity->getScaledDimensions() ||
- model->getRegistrationPoint() != entity->getRegistrationPoint()) {
- return true;
- }
+ // Check to see if we need to update the model bounds
+ if (entity->needsUpdateModelBounds()) {
+ return true;
}
- return false;
+ return Parent::needsRenderUpdateFromTypedEntity(entity);
}
-void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
+void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
- if (_hasModel != entity->hasModel()) {
- withWriteLock([&] {
- _hasModel = entity->hasModel();
- });
+
+ _hasModel = entity->hasModel();
+ QUrl modelURL = QUrl(entity->getModelURL());
+ if (_parsedModelURL != modelURL) {
+ _parsedModelURL = modelURL;
}
- withWriteLock([&] {
- _animating = entity->isAnimatingSomething();
- if (_parsedModelURL != entity->getModelURL()) {
- _parsedModelURL = QUrl(entity->getModelURL());
- }
+ ModelPointer model = resultWithReadLock([&] {
+ return _model;
});
- ModelPointer model;
- withReadLock([&] { model = _model; });
+ bool visuallyReady = model && model->isLoaded() && _didLastVisualGeometryRequestSucceed && _texturesLoaded;
+ entity->setVisuallyReady(visuallyReady);
- withWriteLock([&] {
- bool visuallyReady = true;
- if (_hasModel) {
- if (model && _didLastVisualGeometryRequestSucceed) {
- visuallyReady = (_prevModelLoaded && _texturesLoaded);
- }
- }
- entity->setVisuallyReady(visuallyReady);
- });
+ const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
+ render::Transaction transaction;
// Check for removal
if (!_hasModel) {
if (model) {
model->removeFromScene(scene, transaction);
entity->bumpAncestorChainRenderableVersion();
- withWriteLock([&] { _model.reset(); });
emit DependencyManager::get()->
- modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, _model);
+ modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, model);
+ withWriteLock([&] { _model.reset(); });
}
- setKey(false);
_didLastVisualGeometryRequestSucceed = false;
+ setKey(_didLastVisualGeometryRequestSucceed, model);
return;
}
@@ -1330,48 +1254,56 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
model = std::make_shared(nullptr, entity.get(), _created);
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
connect(model.get(), &Model::setURLFinished, this, [&](bool didVisualGeometryRequestSucceed) {
- setKey(didVisualGeometryRequestSucceed);
- _model->setTagMask(getTagMask());
- _model->setHifiRenderLayer(getHifiRenderLayer());
- _model->setPrimitiveMode(_primitiveMode);
- _model->setCullWithParent(_cullWithParent);
- _model->setRenderWithZones(_renderWithZones);
- emit requestRenderUpdate();
- if (didVisualGeometryRequestSucceed) {
- emit DependencyManager::get()->
- modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, _model);
- }
_didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed;
+ const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
+ render::Transaction transaction;
+ transaction.updateItem(_renderItemID, [&](PayloadProxyInterface& self) {
+ const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
+ withWriteLock([&] {
+ setKey(didVisualGeometryRequestSucceed, _model);
+ _model->setVisibleInScene(_visible, scene);
+ _model->setCauterized(_cauterized, scene);
+ _model->setCanCastShadow(_canCastShadow, scene);
+ _model->setGroupCulled(entity->getGroupCulled(), scene);
+ _model->setTagMask(getTagMask(), scene);
+ _model->setHifiRenderLayer(getHifiRenderLayer(), scene);
+ _model->setPrimitiveMode(_primitiveMode, scene);
+ _model->setBillboardMode(_billboardMode, scene);
+ _model->setCullWithParent(_cullWithParent, scene);
+ _model->setRenderWithZones(_renderWithZones, scene);
+ });
+ if (didVisualGeometryRequestSucceed) {
+ emit DependencyManager::get()->
+ modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, model);
+ }
+ entity->_originalTexturesRead = false;
+ entity->_needsJointSimulation = true;
+ entity->_needsToRescaleModel = true;
+
+ entity->markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+ entity->locationChanged();
+ emit requestRenderUpdate();
+ });
+ scene->enqueueTransaction(transaction);
});
- model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
entity->setModel(model);
withWriteLock([&] { _model = model; });
}
// From here on, we are guaranteed a populated model
if (_parsedModelURL != model->getURL()) {
- withWriteLock([&] {
- _texturesLoaded = false;
- _jointMappingCompleted = false;
- model->setURL(_parsedModelURL);
- });
+ _texturesLoaded = false;
+ _jointMappingCompleted = false;
+ model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
+ model->setURL(_parsedModelURL);
}
// Nothing else to do unless the model is loaded
if (!model->isLoaded()) {
- withWriteLock([&] {
- _prevModelLoaded = false;
- });
- emit requestRenderUpdate();
return;
- } else if (!_prevModelLoaded) {
- withWriteLock([&] {
- _prevModelLoaded = true;
- });
}
// Check for initializing the model
- // FIXME: There are several places below here where we are modifying the entity, which we should not be doing from the renderable
if (!entity->_dimensionsInitialized) {
EntityItemProperties properties;
properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
@@ -1391,53 +1323,40 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
entity->_originalTexturesRead = true;
}
- if (_textures != entity->getTextures()) {
+ auto textures = entity->getTextures();
+ if (_textures != textures) {
QVariantMap newTextures;
- withWriteLock([&] {
- _texturesLoaded = false;
- _textures = entity->getTextures();
- newTextures = parseTexturesToMap(_textures, entity->_originalTextures);
- });
+ _texturesLoaded = false;
+ _textures = textures;
+ newTextures = parseTexturesToMap(_textures, entity->_originalTextures);
model->setTextures(newTextures);
}
+
if (entity->_needsJointSimulation) {
entity->copyAnimationJointDataToModel();
}
entity->updateModelBounds();
entity->stopModelOverrideIfNoParent();
- if (model->isVisible() != _visible) {
+ withWriteLock([&] {
+ setKey(_didLastVisualGeometryRequestSucceed, model);
model->setVisibleInScene(_visible, scene);
- }
-
- if (model->isCauterized() != _cauterized) {
model->setCauterized(_cauterized, scene);
- }
-
- render::hifi::Tag tagMask = getTagMask();
- if (model->getTagMask() != tagMask) {
- model->setTagMask(tagMask, scene);
- }
+ model->setCanCastShadow(_canCastShadow, scene);
+ model->setGroupCulled(entity->getGroupCulled(), scene);
+ model->setTagMask(getTagMask(), scene);
+ model->setHifiRenderLayer(getHifiRenderLayer(), scene);
+ model->setPrimitiveMode(_primitiveMode, scene);
+ model->setBillboardMode(_billboardMode, scene);
+ model->setCullWithParent(_cullWithParent, scene);
+ model->setRenderWithZones(_renderWithZones, scene);
+ });
if (entity->blendshapesChanged()) {
model->setBlendshapeCoefficients(entity->getBlendshapeCoefficientVector());
model->updateBlendshapes();
}
- // TODO? early exit here when not visible?
-
- if (model->canCastShadow() != _canCastShadow) {
- model->setCanCastShadow(_canCastShadow, scene);
- }
-
- {
- bool groupCulled = entity->getGroupCulled();
- if (model->isGroupCulled() != groupCulled) {
- model->setGroupCulled(groupCulled);
- setKey(_didLastVisualGeometryRequestSucceed);
- }
- }
-
{
DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
if (model->needsFixupInScene()) {
@@ -1451,11 +1370,10 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
}
+ bool needsUpdate = false;
if (!_texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) {
- withWriteLock([&] {
- _texturesLoaded = true;
- });
- model->updateRenderItems();
+ _texturesLoaded = true;
+ needsUpdate = true;
} else if (!_texturesLoaded) {
emit requestRenderUpdate();
}
@@ -1481,19 +1399,23 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
emit requestRenderUpdate();
} else {
_allProceduralMaterialsLoaded = true;
- model->setRenderItemsNeedUpdate();
+ needsUpdate = true;
}
}
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
// we will watch for that and ask the model to update it's render items
- if (model->getRenderItemsNeedUpdate()) {
+ if (needsUpdate || model->getRenderItemsNeedUpdate()) {
model->updateRenderItems();
}
+ scene->enqueueTransaction(transaction);
+}
+
+void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
// The code to deal with the change of properties is now in ModelEntityItem.cpp
// That is where _currentFrame and _lastAnimated were updated.
- if (_animating) {
+ if (entity->isAnimatingSomething()) {
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
auto animationURL = entity->getAnimationURL();
@@ -1502,18 +1424,22 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
_animationURL = animationURL;
if (_animation) {
- //(_animation->getURL().toString() != entity->getAnimationURL())) { // bad check
// the joints have been mapped before but we have a new animation to load
_animation.reset();
_jointMappingCompleted = false;
}
}
-
- if (!_jointMappingCompleted) {
- mapJoints(entity, model);
- }
- if (entity->readyToAnimate()) {
- animate(entity);
+
+ ModelPointer model = resultWithReadLock([&] {
+ return _model;
+ });
+ if (model && model->isLoaded()) {
+ if (!_jointMappingCompleted) {
+ mapJoints(entity, model);
+ }
+ if (entity->readyToAnimate()) {
+ animate(entity, model);
+ }
}
emit requestRenderUpdate();
}
@@ -1521,40 +1447,20 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) {
Parent::setIsVisibleInSecondaryCamera(value);
- setKey(_didLastVisualGeometryRequestSucceed);
- if (_model) {
- _model->setTagMask(getTagMask());
- }
+ // called within a lock so no need to lock for _model
+ setKey(_didLastVisualGeometryRequestSucceed, _model);
}
void ModelEntityRenderer::setRenderLayer(RenderLayer value) {
Parent::setRenderLayer(value);
- setKey(_didLastVisualGeometryRequestSucceed);
- if (_model) {
- _model->setHifiRenderLayer(getHifiRenderLayer());
- }
-}
-
-void ModelEntityRenderer::setPrimitiveMode(PrimitiveMode value) {
- Parent::setPrimitiveMode(value);
- if (_model) {
- _model->setPrimitiveMode(_primitiveMode);
- }
+ // called within a lock so no need to lock for _model
+ setKey(_didLastVisualGeometryRequestSucceed, _model);
}
void ModelEntityRenderer::setCullWithParent(bool value) {
Parent::setCullWithParent(value);
- setKey(_didLastVisualGeometryRequestSucceed);
- if (_model) {
- _model->setCullWithParent(_cullWithParent);
- }
-}
-
-void ModelEntityRenderer::setRenderWithZones(const QVector& renderWithZones) {
- Parent::setRenderWithZones(renderWithZones);
- if (_model) {
- _model->setRenderWithZones(renderWithZones);
- }
+ // called within a lock so no need to lock for _model
+ setKey(_didLastVisualGeometryRequestSucceed, _model);
}
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
@@ -1570,9 +1476,8 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
geometryCache->renderWireCubeInstance(args, batch, greenColor, geometryCache->getShapePipelinePointer(false, false, args->_renderMethod == Args::RenderMethod::FORWARD));
#if WANT_EXTRA_DEBUGGING
- ModelPointer model;
- withReadLock([&] {
- model = _model;
+ ModelPointer model = resultWithReadLock([&] {
+ return _model;
});
if (model) {
model->renderDebugMeshBoxes(batch, args->_renderMethod == Args::RenderMethod::FORWARD);
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h
index 850617d1af..f394d389f5 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h
@@ -41,9 +41,8 @@ protected:
ModelEntityWrapper(const EntityItemID& entityItemID) : Parent(entityItemID) {}
void setModel(const ModelPointer& model);
ModelPointer getModel() const;
- bool isModelLoaded() const;
- bool _needsInitialSimulation{ true };
+ bool _needsInitialSimulation { true };
private:
ModelPointer _model;
};
@@ -62,21 +61,22 @@ public:
virtual void setUnscaledDimensions(const glm::vec3& value) override;
virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
- void doInitialModelSimulation();
void updateModelBounds();
+ glm::vec3 getPivot() const override;
virtual bool supportsDetailedIntersection() const override;
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
virtual void setShapeType(ShapeType type) override;
virtual void setCompoundShapeURL(const QString& url) override;
+ virtual void setModelURL(const QString& url) override;
virtual bool isReadyToComputeShape() const override;
virtual void computeShapeInfo(ShapeInfo& shapeInfo) override;
@@ -121,6 +121,8 @@ private:
bool readyToAnimate() const;
void fetchCollisionGeometryResource();
+ QString getCollisionShapeURL() const;
+
GeometryResource::Pointer _collisionGeometryResource;
std::vector _jointMap;
QVariantMap _originalTextures;
@@ -128,6 +130,7 @@ private:
bool _originalTexturesRead { false };
bool _dimensionsInitialized { true };
bool _needsJointSimulation { false };
+ bool _needsToRescaleModel { false };
};
namespace render { namespace entities {
@@ -153,25 +156,23 @@ protected:
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
- void setKey(bool didVisualGeometryRequestSucceed);
+ void setKey(bool didVisualGeometryRequestSucceed, const ModelPointer& model);
virtual ItemKey getKey() override;
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
virtual void handleBlendedVertices(int blendshapeNumber, const QVector& blendshapeOffsets,
const QVector& blendedMeshSizes, const render::ItemIDs& subItemIDs) override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
- virtual bool needsRenderUpdate() const override;
- virtual void doRender(RenderArgs* args) override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
+ virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
+ virtual void doRender(RenderArgs* args) override;
void setIsVisibleInSecondaryCamera(bool value) override;
void setRenderLayer(RenderLayer value) override;
- void setPrimitiveMode(PrimitiveMode value) override;
void setCullWithParent(bool value) override;
- void setRenderWithZones(const QVector& renderWithZones) override;
private:
- void animate(const TypedEntityPointer& entity);
+ void animate(const TypedEntityPointer& entity, const ModelPointer& model);
void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model);
// Transparency is handled in ModelMeshPartPayload
@@ -186,20 +187,16 @@ private:
bool _hasTransitioned{ false };
#endif
- const void* _collisionMeshKey { nullptr };
-
QUrl _parsedModelURL;
bool _jointMappingCompleted { false };
QVector _jointMapping; // domain is index into model-joints, range is index into animation-joints
AnimationPointer _animation;
- bool _animating { false };
QString _animationURL;
uint64_t _lastAnimated { 0 };
render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() };
bool _didLastVisualGeometryRequestSucceed { true };
- bool _prevModelLoaded { false };
void processMaterials();
bool _allProceduralMaterialsLoaded { false };
diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
index 8bca6cbe96..e2a57840d9 100644
--- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
@@ -64,84 +64,7 @@ ParticleEffectEntityRenderer::ParticleEffectEntityRenderer(const EntityItemPoint
});
}
-bool ParticleEffectEntityRenderer::needsRenderUpdate() const {
- if (resultWithReadLock([&] {
- return !_textureLoaded;
- })) {
- return true;
- }
-
- return Parent::needsRenderUpdate();
-}
-
void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
- auto newParticleProperties = entity->getParticleProperties();
- if (!newParticleProperties.valid()) {
- qCWarning(entitiesrenderer) << "Bad particle properties";
- }
-
- if (resultWithReadLock([&] { return _particleProperties != newParticleProperties; })) {
- _timeUntilNextEmit = 0;
- withWriteLock([&] {
- _particleProperties = newParticleProperties;
- if (!_prevEmitterShouldTrailInitialized) {
- _prevEmitterShouldTrailInitialized = true;
- _prevEmitterShouldTrail = _particleProperties.emission.shouldTrail;
- }
- });
- }
-
- withWriteLock([&] {
- _pulseProperties = entity->getPulseProperties();
- _shapeType = entity->getShapeType();
- QString compoundShapeURL = entity->getCompoundShapeURL();
- if (_compoundShapeURL != compoundShapeURL) {
- _compoundShapeURL = compoundShapeURL;
- _hasComputedTriangles = false;
- fetchGeometryResource();
- }
- });
- _emitting = entity->getIsEmitting();
-
- bool textureEmpty = resultWithReadLock([&] { return _particleProperties.textures.isEmpty(); });
- if (textureEmpty) {
- if (_networkTexture) {
- withWriteLock([&] {
- _networkTexture.reset();
- });
- }
-
- withWriteLock([&] {
- _textureLoaded = true;
- entity->setVisuallyReady(true);
- });
- } else {
- bool textureNeedsUpdate = resultWithReadLock([&] {
- return !_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures);
- });
- if (textureNeedsUpdate) {
- withWriteLock([&] {
- _networkTexture = DependencyManager::get()->getTexture(_particleProperties.textures);
- _textureLoaded = false;
- entity->setVisuallyReady(false);
- });
- }
-
- if (!_textureLoaded) {
- emit requestRenderUpdate();
- }
-
- bool textureLoaded = resultWithReadLock([&] {
- return _networkTexture && (_networkTexture->isLoaded() || _networkTexture->isFailed());
- });
- if (textureLoaded) {
- withWriteLock([&] {
- entity->setVisuallyReady(true);
- _textureLoaded = true;
- });
- }
- }
-
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] {
withWriteLock([&] {
@@ -151,20 +74,66 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
}
void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+ auto newParticleProperties = entity->getParticleProperties();
+ if (!newParticleProperties.valid()) {
+ qCWarning(entitiesrenderer) << "Bad particle properties";
+ }
+
+ if (_particleProperties != newParticleProperties) {
+ _timeUntilNextEmit = 0;
+ _particleProperties = newParticleProperties;
+ if (!_prevEmitterShouldTrailInitialized) {
+ _prevEmitterShouldTrailInitialized = true;
+ _prevEmitterShouldTrail = _particleProperties.emission.shouldTrail;
+ }
+ }
+
+ _pulseProperties = entity->getPulseProperties();
+ _shapeType = entity->getShapeType();
+ QString compoundShapeURL = entity->getCompoundShapeURL();
+ if (_compoundShapeURL != compoundShapeURL) {
+ _compoundShapeURL = compoundShapeURL;
+ _hasComputedTriangles = false;
+ fetchGeometryResource();
+ }
+ _emitting = entity->getIsEmitting();
+
+ if (_particleProperties.textures.isEmpty()) {
+ if (_networkTexture) {
+ _networkTexture.reset();
+ }
+
+ _textureLoaded = true;
+ entity->setVisuallyReady(true);
+ } else {
+ if (!_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures)) {
+ _networkTexture = DependencyManager::get()->getTexture(_particleProperties.textures);
+ _textureLoaded = false;
+ entity->setVisuallyReady(false);
+ }
+
+ if (!_textureLoaded) {
+ emit requestRenderUpdate();
+ }
+
+ if (_networkTexture && (_networkTexture->isLoaded() || _networkTexture->isFailed())) {
+ entity->setVisuallyReady(true);
+ _textureLoaded = true;
+ }
+ }
+
// Fill in Uniforms structure
ParticleUniforms particleUniforms;
- withReadLock([&] {
- particleUniforms.radius.start = _particleProperties.radius.range.start;
- particleUniforms.radius.middle = _particleProperties.radius.gradient.target;
- particleUniforms.radius.finish = _particleProperties.radius.range.finish;
- particleUniforms.radius.spread = _particleProperties.radius.gradient.spread;
- particleUniforms.spin.start = _particleProperties.spin.range.start;
- particleUniforms.spin.middle = _particleProperties.spin.gradient.target;
- particleUniforms.spin.finish = _particleProperties.spin.range.finish;
- particleUniforms.spin.spread = _particleProperties.spin.gradient.spread;
- particleUniforms.lifespan = _particleProperties.lifespan;
- particleUniforms.rotateWithEntity = _particleProperties.rotateWithEntity ? 1 : 0;
- });
+ particleUniforms.radius.start = _particleProperties.radius.range.start;
+ particleUniforms.radius.middle = _particleProperties.radius.gradient.target;
+ particleUniforms.radius.finish = _particleProperties.radius.range.finish;
+ particleUniforms.radius.spread = _particleProperties.radius.gradient.spread;
+ particleUniforms.spin.start = _particleProperties.spin.range.start;
+ particleUniforms.spin.middle = _particleProperties.spin.gradient.target;
+ particleUniforms.spin.finish = _particleProperties.spin.range.finish;
+ particleUniforms.spin.spread = _particleProperties.spin.gradient.spread;
+ particleUniforms.lifespan = _particleProperties.lifespan;
+ particleUniforms.rotateWithEntity = _particleProperties.rotateWithEntity ? 1 : 0;
// Update particle uniforms
_uniformBuffer.edit() = particleUniforms;
}
@@ -192,7 +161,7 @@ ShapeKey ParticleEffectEntityRenderer::getShapeKey() {
return builder.build();
}
-Item::Bound ParticleEffectEntityRenderer::getBound() {
+Item::Bound ParticleEffectEntityRenderer::getBound(RenderArgs* args) {
return _bound;
}
@@ -403,27 +372,18 @@ void ParticleEffectEntityRenderer::stepSimulation() {
const auto interval = std::min(USECS_PER_SECOND / 60, now - _lastSimulated);
_lastSimulated = now;
- particle::Properties particleProperties;
- ShapeType shapeType;
- GeometryResource::Pointer geometryResource;
- withReadLock([&] {
- particleProperties = _particleProperties;
- shapeType = _shapeType;
- geometryResource = _geometryResource;
- });
-
const auto& modelTransform = getModelTransform();
- if (_emitting && particleProperties.emitting() &&
- (shapeType != SHAPE_TYPE_COMPOUND || (geometryResource && geometryResource->isLoaded()))) {
- uint64_t emitInterval = particleProperties.emitIntervalUsecs();
+ if (_emitting && _particleProperties.emitting() &&
+ (_shapeType != SHAPE_TYPE_COMPOUND || (_geometryResource && _geometryResource->isLoaded()))) {
+ uint64_t emitInterval = _particleProperties.emitIntervalUsecs();
if (emitInterval > 0 && interval >= _timeUntilNextEmit) {
auto timeRemaining = interval;
while (timeRemaining > _timeUntilNextEmit) {
if (_shapeType == SHAPE_TYPE_COMPOUND && !_hasComputedTriangles) {
- computeTriangles(geometryResource->getHFMModel());
+ computeTriangles(_geometryResource->getHFMModel());
}
// emit particle
- _cpuParticles.push_back(createParticle(modelTransform, particleProperties, shapeType, geometryResource, _triangleInfo));
+ _cpuParticles.push_back(createParticle(modelTransform, _particleProperties, _shapeType, _geometryResource, _triangleInfo));
_timeUntilNextEmit = emitInterval;
if (emitInterval < timeRemaining) {
timeRemaining -= emitInterval;
@@ -435,14 +395,14 @@ 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 == 0)) {
+ while (_cpuParticles.size() > _particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration == 0)) {
_cpuParticles.pop_front();
}
const float deltaTime = (float)interval / (float)USECS_PER_SECOND;
// update the particles
for (auto& particle : _cpuParticles) {
- if (_prevEmitterShouldTrail != particleProperties.emission.shouldTrail) {
+ if (_prevEmitterShouldTrail != _particleProperties.emission.shouldTrail) {
if (_prevEmitterShouldTrail) {
particle.relativePosition = particle.relativePosition + particle.basePosition - modelTransform.getTranslation();
}
@@ -451,14 +411,14 @@ void ParticleEffectEntityRenderer::stepSimulation() {
particle.expiration = particle.expiration >= interval ? particle.expiration - interval : 0;
particle.integrate(deltaTime);
}
- _prevEmitterShouldTrail = particleProperties.emission.shouldTrail;
+ _prevEmitterShouldTrail = _particleProperties.emission.shouldTrail;
// Build particle primitives
static GpuParticles gpuParticles;
gpuParticles.clear();
gpuParticles.reserve(_cpuParticles.size()); // Reserve space
- std::transform(_cpuParticles.begin(), _cpuParticles.end(), std::back_inserter(gpuParticles), [&particleProperties, &modelTransform] (const CpuParticle& particle) {
- glm::vec3 position = particle.relativePosition + (particleProperties.emission.shouldTrail ? particle.basePosition : modelTransform.getTranslation());
+ std::transform(_cpuParticles.begin(), _cpuParticles.end(), std::back_inserter(gpuParticles), [this, &modelTransform] (const CpuParticle& particle) {
+ glm::vec3 position = particle.relativePosition + (_particleProperties.emission.shouldTrail ? particle.basePosition : modelTransform.getTranslation());
return GpuParticle(position, glm::vec2(particle.lifetime, particle.seed));
});
@@ -487,14 +447,16 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
// if the particles are marked rotateWithEntity
withReadLock([&] {
transform.setRotation(_renderTransform.getRotation());
- auto& color = _uniformBuffer.edit().color;
- color.start = EntityRenderer::calculatePulseColor(_particleProperties.getColorStart(), _pulseProperties, _created);
- color.middle = EntityRenderer::calculatePulseColor(_particleProperties.getColorMiddle(), _pulseProperties, _created);
- color.finish = EntityRenderer::calculatePulseColor(_particleProperties.getColorFinish(), _pulseProperties, _created);
- color.spread = EntityRenderer::calculatePulseColor(_particleProperties.getColorSpread(), _pulseProperties, _created);
});
+ auto& color = _uniformBuffer.edit().color;
+ color.start = EntityRenderer::calculatePulseColor(_particleProperties.getColorStart(), _pulseProperties, _created);
+ color.middle = EntityRenderer::calculatePulseColor(_particleProperties.getColorMiddle(), _pulseProperties, _created);
+ color.finish = EntityRenderer::calculatePulseColor(_particleProperties.getColorFinish(), _pulseProperties, _created);
+ color.spread = EntityRenderer::calculatePulseColor(_particleProperties.getColorSpread(), _pulseProperties, _created);
+
batch.setModelTransform(transform);
+
batch.setUniformBuffer(0, _uniformBuffer);
batch.setInputFormat(_vertexFormat);
batch.setInputBuffer(0, _particleBuffer, 0, sizeof(GpuParticle));
diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h
index 0811b231d8..547d654486 100644
--- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h
@@ -25,13 +25,12 @@ public:
ParticleEffectEntityRenderer(const EntityItemPointer& entity);
protected:
- virtual bool needsRenderUpdate() const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual ItemKey getKey() override;
virtual ShapeKey getShapeKey() override;
- virtual Item::Bound getBound() override;
+ virtual Item::Bound getBound(RenderArgs* args) override;
virtual void doRender(RenderArgs* args) override;
private:
diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
index a843083831..65e9f57b02 100644
--- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
@@ -121,16 +121,6 @@ ShapeKey PolyLineEntityRenderer::getShapeKey() {
return builder.build();
}
-bool PolyLineEntityRenderer::needsRenderUpdate() const {
- if (resultWithReadLock([&] {
- return (!_textureLoaded && _texture && _texture->isLoaded());
- })) {
- return true;
- }
-
- return Parent::needsRenderUpdate();
-}
-
bool PolyLineEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (entity->pointsChanged() || entity->widthsChanged() || entity->normalsChanged() || entity->texturesChanged() || entity->colorsChanged()) {
return true;
@@ -140,6 +130,15 @@ bool PolyLineEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP
}
void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
+ void* key = (void*)this;
+ AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] {
+ withWriteLock([&] {
+ _renderTransform = getModelTransform();
+ });
+ });
+}
+
+void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
auto pointsChanged = entity->pointsChanged();
auto widthsChanged = entity->widthsChanged();
auto normalsChanged = entity->normalsChanged();
@@ -159,13 +158,15 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
if (!textures.isEmpty()) {
entityTextures = QUrl(textures);
}
- withWriteLock([&] {
- _texture = DependencyManager::get()->getTexture(entityTextures);
- });
+ _texture = DependencyManager::get()->getTexture(entityTextures);
_textureAspectRatio = 1.0f;
_textureLoaded = false;
}
+ if (!_textureLoaded) {
+ emit requestRenderUpdate();
+ }
+
bool textureChanged = false;
if (!_textureLoaded && _texture && _texture->isLoaded()) {
textureChanged = true;
@@ -175,13 +176,11 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
// Data
bool faceCameraChanged = faceCamera != _faceCamera;
- withWriteLock([&] {
- if (faceCameraChanged || glow != _glow) {
- _faceCamera = faceCamera;
- _glow = glow;
- updateData();
- }
- });
+ if (faceCameraChanged || glow != _glow) {
+ _faceCamera = faceCamera;
+ _glow = glow;
+ updateData();
+ }
// Geometry
if (pointsChanged) {
@@ -200,19 +199,10 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
bool uvModeStretchChanged = _isUVModeStretch != isUVModeStretch;
_isUVModeStretch = isUVModeStretch;
-
- bool geometryChanged = uvModeStretchChanged || pointsChanged || widthsChanged || normalsChanged || colorsChanged || textureChanged || faceCameraChanged;
- void* key = (void*)this;
- AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, geometryChanged] {
- withWriteLock([&] {
- _renderTransform = getModelTransform();
-
- if (geometryChanged) {
- updateGeometry();
- }
- });
- });
+ if (uvModeStretchChanged || pointsChanged || widthsChanged || normalsChanged || colorsChanged || textureChanged || faceCameraChanged) {
+ updateGeometry();
+ }
}
void PolyLineEntityRenderer::updateGeometry() {
@@ -318,19 +308,16 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
- size_t numVertices;
Transform transform;
- gpu::TexturePointer texture;
+ gpu::TexturePointer texture = _textureLoaded ? _texture->getGPUTexture() : DependencyManager::get()->getWhiteTexture();
withReadLock([&] {
- numVertices = _numVertices;
transform = _renderTransform;
- texture = _textureLoaded ? _texture->getGPUTexture() : DependencyManager::get()->getWhiteTexture();
-
- batch.setResourceBuffer(0, _polylineGeometryBuffer);
- batch.setUniformBuffer(0, _polylineDataBuffer);
});
- if (numVertices < 2) {
+ batch.setResourceBuffer(0, _polylineGeometryBuffer);
+ batch.setUniformBuffer(0, _polylineDataBuffer);
+
+ if (_numVertices < 2) {
return;
}
@@ -338,8 +325,11 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
buildPipelines();
}
- batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]);
+ transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch.setModelTransform(transform);
+
+ batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]);
batch.setResourceTexture(0, texture);
- batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * numVertices), 0);
+ batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * _numVertices), 0);
}
diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h
index 41b66c0e51..c4fbb9a776 100644
--- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h
+++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h
@@ -30,9 +30,9 @@ public:
virtual bool isTransparent() const override;
protected:
- virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
+ virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual ItemKey getKey() override;
virtual ShapeKey getShapeKey() override;
diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
index 1555604604..859accf01a 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
@@ -238,53 +238,6 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel
startUpdates();
}
-glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
- glm::vec3 result;
- withReadLock([&] {
- glm::vec3 scale = getScaledDimensions() / _voxelVolumeSize; // meters / voxel-units
- if (isEdged(_voxelSurfaceStyle)) {
- result = scale / -2.0f;
- }
- return scale / 2.0f;
- });
- return result;
-}
-
-glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
- glm::vec3 voxelVolumeSize;
- withReadLock([&] {
- voxelVolumeSize = _voxelVolumeSize;
- });
-
- glm::vec3 dimensions = getScaledDimensions();
- glm::vec3 scale = dimensions / voxelVolumeSize; // meters / voxel-units
- bool success; // TODO -- Does this actually have to happen in world space?
- glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes
- glm::vec3 position = getWorldPosition(success);
- glm::vec3 positionToCenter = center - position;
-
- positionToCenter -= dimensions * Vectors::HALF - getSurfacePositionAdjustment();
- glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
- glm::mat4 scaled = glm::scale(centerToCorner, scale);
- return scaled;
-}
-
-glm::mat4 RenderablePolyVoxEntityItem::localToVoxelMatrix() const {
- glm::mat4 localToModelMatrix = glm::inverse(voxelToLocalMatrix());
- return localToModelMatrix;
-}
-
-glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const {
- glm::mat4 rotation = glm::mat4_cast(getWorldOrientation());
- glm::mat4 translation = glm::translate(getWorldPosition());
- return translation * rotation * voxelToLocalMatrix();
-}
-
-glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const {
- glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix());
- return worldToModelMatrix;
-}
-
bool RenderablePolyVoxEntityItem::setVoxel(const ivec3& v, uint8_t toValue) {
if (_locked) {
return false;
@@ -573,7 +526,7 @@ public:
#endif
bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const {
// TODO -- correctly pick against marching-cube generated meshes
@@ -582,7 +535,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
return true;
}
- glm::mat4 wtvMatrix = worldToVoxelMatrix();
+ glm::mat4 wtvMatrix = worldToVoxelMatrix(true);
glm::vec3 normDirection = glm::normalize(direction);
// the PolyVox ray intersection code requires a near and far point.
@@ -614,7 +567,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
}
bool RenderablePolyVoxEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const {
// TODO -- correctly pick against marching-cube generated meshes
@@ -623,7 +576,7 @@ bool RenderablePolyVoxEntityItem::findDetailedParabolaIntersection(const glm::ve
return true;
}
- glm::mat4 wtvMatrix = worldToVoxelMatrix();
+ glm::mat4 wtvMatrix = worldToVoxelMatrix(true);
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
glm::vec4 velocityInVoxel = wtvMatrix * glm::vec4(velocity, 0.0f);
glm::vec4 accelerationInVoxel = wtvMatrix * glm::vec4(acceleration, 0.0f);
@@ -723,8 +676,10 @@ ShapeType RenderablePolyVoxEntityItem::getShapeType() const {
}
void RenderablePolyVoxEntityItem::setRegistrationPoint(const glm::vec3& value) {
- if (value != _registrationPoint) {
- _shapeReady = false;
+ if (value != getRegistrationPoint()) {
+ withWriteLock([&] {
+ _shapeReady = false;
+ });
EntityItem::setRegistrationPoint(value);
startUpdates();
}
@@ -1802,25 +1757,46 @@ ShapeKey PolyVoxEntityRenderer::getShapeKey() {
}
bool PolyVoxEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
- if (entity->voxelToWorldMatrix() != _lastVoxelToWorldMatrix) {
+ if (resultWithReadLock([&] {
+ if (entity->voxelToLocalMatrix() != _lastVoxelToLocalMatrix) {
+ return true;
+ }
+
+ if (entity->_mesh != _mesh) {
+ return true;
+ }
+
+ return false;
+ })) {
return true;
}
- if (entity->_mesh != _mesh) {
- return true;
- }
-
- return false;
+ return Parent::needsRenderUpdateFromTypedEntity(entity);
}
void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
-
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
if (!_hasTransitioned) {
transaction.resetTransitionOnItem(_renderItemID, render::Transition::ELEMENT_ENTER_DOMAIN);
_hasTransitioned = true;
}
#endif
+}
+
+void PolyVoxEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+ _lastVoxelToLocalMatrix = entity->voxelToLocalMatrix();
+ _position = entity->getWorldPosition();
+ _orientation = entity->getWorldOrientation();
+ _lastVoxelVolumeSize = entity->getVoxelVolumeSize();
+ _params->setSubData(0, vec4(_lastVoxelVolumeSize, 0.0));
+ graphics::MeshPointer newMesh;
+ entity->withReadLock([&] {
+ newMesh = entity->_mesh;
+ });
+
+ if (newMesh && newMesh->getIndexBuffer()._buffer) {
+ _mesh = newMesh;
+ }
std::array xyzTextureURLs{ {
entity->getXTextureURL(),
@@ -1838,36 +1814,23 @@ void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& s
}
}
-void PolyVoxEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
- _lastVoxelToWorldMatrix = entity->voxelToWorldMatrix();
- _lastVoxelVolumeSize = entity->getVoxelVolumeSize();
- _params->setSubData(0, vec4(_lastVoxelVolumeSize, 0.0));
- graphics::MeshPointer newMesh;
- entity->withReadLock([&] {
- newMesh = entity->_mesh;
- });
-
- if (newMesh && newMesh->getIndexBuffer()._buffer) {
- _mesh = newMesh;
- }
-}
-
void PolyVoxEntityRenderer::doRender(RenderArgs* args) {
if (!_mesh || !_mesh->getIndexBuffer()._buffer) {
return;
}
-
PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render");
gpu::Batch& batch = *args->_batch;
- Transform transform(_lastVoxelToWorldMatrix);
+ glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(_position, _orientation, _billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
+ Transform transform(glm::translate(_position) * rotation * _lastVoxelToLocalMatrix);
batch.setModelTransform(transform);
+
batch.setInputFormat(_vertexFormat);
batch.setInputBuffer(gpu::Stream::POSITION, _mesh->getVertexBuffer()._buffer, 0,
sizeof(PolyVox::PositionMaterialNormal));
-
// TODO -- should we be setting this?
// batch.setInputBuffer(gpu::Stream::NORMAL, mesh->getVertexBuffer()._buffer,
// 12,
diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
index 825b4429cd..c1c35a21c8 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
@@ -71,24 +71,18 @@ public:
virtual bool supportsDetailedIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const vec3& accleration,
- OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
virtual void setVoxelData(const QByteArray& voxelData) override;
virtual void setVoxelVolumeSize(const glm::vec3& voxelVolumeSize) override;
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) override;
- glm::vec3 getSurfacePositionAdjustment() const;
- glm::mat4 voxelToWorldMatrix() const;
- glm::mat4 worldToVoxelMatrix() const;
- glm::mat4 voxelToLocalMatrix() const;
- glm::mat4 localToVoxelMatrix() const;
-
virtual ShapeType getShapeType() const override;
virtual bool isReadyToComputeShape() const override;
virtual void computeShapeInfo(ShapeInfo& info) override;
@@ -226,7 +220,9 @@ private:
gpu::BufferPointer _params;
std::array _xyzTextures;
glm::vec3 _lastVoxelVolumeSize;
- glm::mat4 _lastVoxelToWorldMatrix;
+ glm::mat4 _lastVoxelToLocalMatrix;
+ glm::vec3 _position;
+ glm::quat _orientation;
PolyVoxEntityItem::PolyVoxSurfaceStyle _lastSurfaceStyle { PolyVoxEntityItem::SURFACE_MARCHING_CUBES };
std::array _xyzTextureUrls;
};
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
index 4c6f5adc13..674d7c297d 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
@@ -51,27 +51,11 @@ bool ShapeEntityRenderer::needsRenderUpdate() const {
return Parent::needsRenderUpdate();
}
-bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
- if (_dimensions != entity->getScaledDimensions()) {
- return true;
- }
-
- if (_proceduralData != entity->getUserData()) {
- return true;
- }
-
- return false;
-}
-
void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
- withWriteLock([&] {
- _shape = entity->getShape();
- _pulseProperties = entity->getPulseProperties();
- });
-
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
withWriteLock([&] {
+ _shape = entity->getShape();
_position = entity->getWorldPosition();
_dimensions = entity->getUnscaledDimensions(); // get unscaled to avoid scaling twice
_orientation = entity->getWorldOrientation();
@@ -86,47 +70,52 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+ _pulseProperties = entity->getPulseProperties();
+
+ bool materialChanged = false;
+ glm::vec3 color = toGlm(entity->getColor());
+ if (_color != color) {
+ _color = color;
+ _material->setAlbedo(color);
+ materialChanged = true;
+ }
+
+ float alpha = entity->getAlpha();
+ if (_alpha != alpha) {
+ _alpha = alpha;
+ _material->setOpacity(alpha);
+ materialChanged = true;
+ }
+
+ auto userData = entity->getUserData();
+ if (_proceduralData != userData) {
+ _proceduralData = userData;
+ _material->setProceduralData(_proceduralData);
+ materialChanged = true;
+ }
+
withReadLock([&] {
- auto mat = _materials.find("0");
- if (mat != _materials.end() && mat->second.top().material && mat->second.top().material->isProcedural() && mat->second.top().material->isReady()) {
- auto procedural = std::static_pointer_cast(mat->second.top().material);
- if (procedural->isFading()) {
- procedural->setIsFading(Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) < 1.0f);
- }
- }
- });
-
- withWriteLock([&] {
- bool materialChanged = false;
- glm::vec3 color = toGlm(entity->getColor());
- if (_color != color) {
- _color = color;
- _material->setAlbedo(color);
- materialChanged = true;
- }
-
- float alpha = entity->getAlpha();
- if (_alpha != alpha) {
- _alpha = alpha;
- _material->setOpacity(alpha);
- materialChanged = true;
- }
-
- auto userData = entity->getUserData();
- if (_proceduralData != userData) {
- _proceduralData = userData;
- _material->setProceduralData(_proceduralData);
- materialChanged = true;
- }
-
auto materials = _materials.find("0");
if (materials != _materials.end()) {
if (materialChanged) {
materials->second.setNeedsUpdate(true);
}
+ bool requestUpdate = false;
+ if (materials->second.top().material && materials->second.top().material->isProcedural() && materials->second.top().material->isReady()) {
+ auto procedural = std::static_pointer_cast(materials->second.top().material);
+ if (procedural->isFading()) {
+ procedural->setIsFading(Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) < 1.0f);
+ requestUpdate = true;
+ }
+ }
+
if (materials->second.shouldUpdate()) {
RenderPipelines::updateMultiMaterial(materials->second);
+ requestUpdate = true;
+ }
+
+ if (requestUpdate) {
emit requestRenderUpdate();
}
}
@@ -211,16 +200,16 @@ ShapeKey ShapeEntityRenderer::getShapeKey() {
return builder.build();
}
-Item::Bound ShapeEntityRenderer::getBound() {
+Item::Bound ShapeEntityRenderer::getBound(RenderArgs* args) {
auto mat = _materials.find("0");
if (mat != _materials.end() && mat->second.top().material && mat->second.top().material->isProcedural() &&
mat->second.top().material->isReady()) {
auto procedural = std::static_pointer_cast(mat->second.top().material);
if (procedural->hasVertexShader() && procedural->hasBoundOperator()) {
- return procedural->getBound();
+ return procedural->getBound(args);
}
}
- return Parent::getBound();
+ return Parent::getBound(args);
}
void ShapeEntityRenderer::doRender(RenderArgs* args) {
@@ -231,34 +220,38 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
graphics::MultiMaterial materials;
auto geometryCache = DependencyManager::get();
- GeometryCache::Shape geometryShape;
- PrimitiveMode primitiveMode;
- RenderLayer renderLayer;
+ GeometryCache::Shape geometryShape = geometryCache->getShapeForEntityShape(_shape);
glm::vec4 outColor;
Pipeline pipelineType;
+ Transform transform;
withReadLock([&] {
- geometryShape = geometryCache->getShapeForEntityShape(_shape);
- primitiveMode = _primitiveMode;
- renderLayer = _renderLayer;
- batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
+ transform = _renderTransform;
materials = _materials["0"];
pipelineType = getPipelineType(materials);
auto& schema = materials.getSchemaBuffer().get();
outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
- outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
});
+ outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
+
if (outColor.a == 0.0f) {
return;
}
+ transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(),
+ _shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron));
+ batch.setModelTransform(transform);
+
if (pipelineType == Pipeline::PROCEDURAL) {
auto procedural = std::static_pointer_cast(materials.top().material);
outColor = procedural->getColor(outColor);
outColor.a *= procedural->isFading() ? Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) : 1.0f;
- procedural->prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f));
+ withReadLock([&] {
+ procedural->prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f));
+ });
- if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
+ if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
geometryCache->renderWireShape(batch, geometryShape, outColor);
} else {
geometryCache->renderShape(batch, geometryShape, outColor);
@@ -267,8 +260,8 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
// FIXME, support instanced multi-shape rendering using multidraw indirect
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
render::ShapePipelinePointer pipeline = geometryCache->getShapePipelinePointer(outColor.a < 1.0f, false,
- renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD, materials.top().material->getCullFaceMode());
- if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
+ _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD, materials.top().material->getCullFaceMode());
+ if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline);
} else {
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h
index e4d6d099a6..fe62ad48b9 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h
@@ -26,11 +26,10 @@ public:
protected:
ShapeKey getShapeKey() override;
- Item::Bound getBound() override;
+ Item::Bound getBound(RenderArgs* args) override;
private:
virtual bool needsRenderUpdate() const override;
- virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
index a744fc9a62..16d9afb913 100644
--- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
@@ -54,17 +54,6 @@ bool TextEntityRenderer::isTextTransparent() const {
});
}
-Item::Bound TextEntityRenderer::getBound() {
- auto bound = Parent::getBound();
- if (_billboardMode != BillboardMode::NONE) {
- glm::vec3 dimensions = bound.getScale();
- float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
- const float SQRT_2 = 1.41421356237f;
- bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
- }
- return bound;
-}
-
ItemKey TextEntityRenderer::getKey() {
return ItemKey::Builder(Parent::getKey()).withMetaCullGroup();
}
@@ -92,14 +81,6 @@ uint32_t TextEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
return parentSubs;
}
-bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
- if (_dimensions != entity->getScaledDimensions()) {
- return true;
- }
-
- return false;
-}
-
void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
@@ -112,26 +93,23 @@ void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
}
void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
- withWriteLock([&] {
- _pulseProperties = entity->getPulseProperties();
- _text = entity->getText();
- _lineHeight = entity->getLineHeight();
- _textColor = toGlm(entity->getTextColor());
- _textAlpha = entity->getTextAlpha();
- _backgroundColor = toGlm(entity->getBackgroundColor());
- _backgroundAlpha = entity->getBackgroundAlpha();
- _billboardMode = entity->getBillboardMode();
- _leftMargin = entity->getLeftMargin();
- _rightMargin = entity->getRightMargin();
- _topMargin = entity->getTopMargin();
- _bottomMargin = entity->getBottomMargin();
- _unlit = entity->getUnlit();
- _font = entity->getFont();
- _effect = entity->getTextEffect();
- _effectColor = toGlm(entity->getTextEffectColor());
- _effectThickness = entity->getTextEffectThickness();
- updateTextRenderItem();
- });
+ _pulseProperties = entity->getPulseProperties();
+ _text = entity->getText();
+ _lineHeight = entity->getLineHeight();
+ _textColor = toGlm(entity->getTextColor());
+ _textAlpha = entity->getTextAlpha();
+ _backgroundColor = toGlm(entity->getBackgroundColor());
+ _backgroundAlpha = entity->getBackgroundAlpha();
+ _leftMargin = entity->getLeftMargin();
+ _rightMargin = entity->getRightMargin();
+ _topMargin = entity->getTopMargin();
+ _bottomMargin = entity->getBottomMargin();
+ _unlit = entity->getUnlit();
+ _font = entity->getFont();
+ _effect = entity->getTextEffect();
+ _effectColor = toGlm(entity->getTextEffectColor());
+ _effectThickness = entity->getTextEffectThickness();
+ updateTextRenderItem();
}
void TextEntityRenderer::doRender(RenderArgs* args) {
@@ -140,33 +118,28 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
gpu::Batch& batch = *args->_batch;
glm::vec4 backgroundColor;
- Transform modelTransform;
- BillboardMode billboardMode;
- PrimitiveMode primitiveMode;
- RenderLayer renderLayer;
+ Transform transform;
withReadLock([&] {
- modelTransform = _renderTransform;
- billboardMode = _billboardMode;
- primitiveMode = _primitiveMode;
- renderLayer = _renderLayer;
+ transform = _renderTransform;
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
backgroundColor = glm::vec4(_backgroundColor, fadeRatio * _backgroundAlpha);
- backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
});
+ backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
if (backgroundColor.a <= 0.0f) {
return;
}
- modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), billboardMode, args->getViewFrustum().getPosition()));
- batch.setModelTransform(modelTransform);
+ transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
+ batch.setModelTransform(transform);
auto geometryCache = DependencyManager::get();
// FIXME: we want to use instanced rendering here, but if textAlpha < 1 and backgroundAlpha < 1, the transparency sorting will be wrong
//render::ShapePipelinePointer pipeline = geometryCache->getShapePipelinePointer(backgroundColor.a < 1.0f, _unlit,
- // renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD);
- //if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
+ // _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD);
+ //if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
// geometryCache->renderWireShapeInstance(args, batch, GeometryCache::Quad, backgroundColor, pipeline);
//} else {
// geometryCache->renderSolidShapeInstance(args, batch, GeometryCache::Quad, backgroundColor, pipeline);
@@ -254,12 +227,12 @@ ItemKey entities::TextPayload::getKey() const {
return ItemKey::Builder::opaqueShape();
}
-Item::Bound entities::TextPayload::getBound() const {
+Item::Bound entities::TextPayload::getBound(RenderArgs* args) const {
auto entityTreeRenderer = DependencyManager::get();
if (entityTreeRenderer) {
auto renderable = entityTreeRenderer->renderableForEntityId(_entityID);
if (renderable) {
- return std::static_pointer_cast(renderable)->getBound();
+ return std::static_pointer_cast(renderable)->getBound(args);
}
}
return Item::Bound();
@@ -321,55 +294,36 @@ void entities::TextPayload::render(RenderArgs* args) {
Transform modelTransform;
glm::vec3 dimensions;
- BillboardMode billboardMode;
- QString text;
glm::vec4 textColor;
- QString font;
- TextEffect effect;
- glm::vec3 effectColor;
- float effectThickness;
- float lineHeight, leftMargin, rightMargin, topMargin, bottomMargin;
- bool forward;
textRenderable->withReadLock([&] {
modelTransform = textRenderable->_renderTransform;
dimensions = textRenderable->_dimensions;
- billboardMode = textRenderable->_billboardMode;
-
- text = textRenderable->_text;
- font = textRenderable->_font;
- effect = textRenderable->_effect;
- effectThickness = textRenderable->_effectThickness;
-
- lineHeight = textRenderable->_lineHeight;
- leftMargin = textRenderable->_leftMargin;
- rightMargin = textRenderable->_rightMargin;
- topMargin = textRenderable->_topMargin;
- bottomMargin = textRenderable->_bottomMargin;
float fadeRatio = textRenderable->_isFading ? Interpolate::calculateFadeRatio(textRenderable->_fadeStartTime) : 1.0f;
textColor = glm::vec4(textRenderable->_textColor, fadeRatio * textRenderable->_textAlpha);
- textColor = EntityRenderer::calculatePulseColor(textColor, textRenderable->_pulseProperties, textRenderable->_created);
-
- effectColor = EntityRenderer::calculatePulseColor(textRenderable->_effectColor, textRenderable->_pulseProperties, textRenderable->_created);
-
- forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
});
+ bool forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
+
+ textColor = EntityRenderer::calculatePulseColor(textColor, textRenderable->_pulseProperties, textRenderable->_created);
+ glm::vec3 effectColor = EntityRenderer::calculatePulseColor(textRenderable->_effectColor, textRenderable->_pulseProperties, textRenderable->_created);
+
if (textColor.a <= 0.0f) {
return;
}
- modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), billboardMode, args->getViewFrustum().getPosition()));
+ modelTransform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), textRenderable->_billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
- float scale = lineHeight / textRenderer->getFontSize();
+ float scale = textRenderable->_lineHeight / textRenderer->getFontSize();
modelTransform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z));
modelTransform.setScale(scale);
batch.setModelTransform(modelTransform);
- glm::vec2 bounds = glm::vec2(dimensions.x - (leftMargin + rightMargin), dimensions.y - (topMargin + bottomMargin));
- textRenderer->draw(batch, leftMargin / scale, -topMargin / scale, bounds / scale, scale,
- text, font, textColor, effectColor, effectThickness, effect,
+ glm::vec2 bounds = glm::vec2(dimensions.x - (textRenderable->_leftMargin + textRenderable->_rightMargin), dimensions.y - (textRenderable->_topMargin + textRenderable->_bottomMargin));
+ textRenderer->draw(batch, textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale, bounds / scale, scale,
+ textRenderable->_text, textRenderable->_font, textColor, effectColor, textRenderable->_effectThickness, textRenderable->_effect,
textRenderable->_unlit, forward);
}
@@ -381,9 +335,9 @@ template <> const ItemKey payloadGetKey(const TextPayload::Pointer& payload) {
return ItemKey::Builder::opaqueShape();
}
-template <> const Item::Bound payloadGetBound(const TextPayload::Pointer& payload) {
+template <> const Item::Bound payloadGetBound(const TextPayload::Pointer& payload, RenderArgs* args) {
if (payload) {
- return payload->getBound();
+ return payload->getBound(args);
}
return Item::Bound();
}
diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h
index 87102daa32..0f736d1229 100644
--- a/libraries/entities-renderer/src/RenderableTextEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h
@@ -33,7 +33,6 @@ public:
protected:
bool isTransparent() const override;
bool isTextTransparent() const;
- Item::Bound getBound() override;
ShapeKey getShapeKey() override;
ItemKey getKey() override;
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
@@ -42,7 +41,6 @@ protected:
void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
private:
- virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
@@ -64,7 +62,6 @@ private:
float _topMargin;
float _bottomMargin;
- BillboardMode _billboardMode;
glm::vec3 _dimensions;
QString _font { "" };
@@ -91,7 +88,7 @@ public:
typedef Payload::DataPointer Pointer;
ItemKey getKey() const;
- Item::Bound getBound() const;
+ Item::Bound getBound(RenderArgs* args) const;
ShapeKey getShapeKey() const;
void render(RenderArgs* args);
bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const;
@@ -107,7 +104,7 @@ protected:
namespace render {
template <> const ItemKey payloadGetKey(const entities::TextPayload::Pointer& payload);
- template <> const Item::Bound payloadGetBound(const entities::TextPayload::Pointer& payload);
+ template <> const Item::Bound payloadGetBound(const entities::TextPayload::Pointer& payload, RenderArgs* args);
template <> const ShapeKey shapeGetShapeKey(const entities::TextPayload::Pointer& payload);
template <> void payloadRender(const entities::TextPayload::Pointer& payload, RenderArgs* args);
template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Pointer& payload, const std::unordered_set& containingZones);
diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
index e88ebcf19a..7932a19110 100644
--- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
@@ -39,6 +39,7 @@ const char* WebEntityRenderer::URL_PROPERTY = "url";
const char* WebEntityRenderer::SCRIPT_URL_PROPERTY = "scriptURL";
const char* WebEntityRenderer::GLOBAL_POSITION_PROPERTY = "globalPosition";
const char* WebEntityRenderer::USE_BACKGROUND_PROPERTY = "useBackground";
+const char* WebEntityRenderer::USER_AGENT_PROPERTY = "userAgent";
std::function&, bool&)> WebEntityRenderer::_acquireWebSurfaceOperator = nullptr;
std::function&, bool&, std::vector&)> WebEntityRenderer::_releaseWebSurfaceOperator = nullptr;
@@ -125,16 +126,6 @@ bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointe
return false;
}
-bool WebEntityRenderer::needsRenderUpdate() const {
- if (resultWithReadLock([this] {
- return !_webSurface;
- })) {
- return true;
- }
-
- return Parent::needsRenderUpdate();
-}
-
void WebEntityRenderer::onTimeout() {
uint64_t lastRenderTime;
if (!resultWithReadLock([&] {
@@ -177,7 +168,6 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
_color = entity->getColor();
_alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties();
- _billboardMode = entity->getBillboardMode();
if (_contentType == ContentType::NoContent) {
_tryingToBuildURL = newSourceURL;
@@ -204,6 +194,7 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
_webSurface->getRootItem()->setProperty(URL_PROPERTY, newSourceURL);
_webSurface->getRootItem()->setProperty(SCRIPT_URL_PROPERTY, _scriptURL);
_webSurface->getRootItem()->setProperty(USE_BACKGROUND_PROPERTY, _useBackground);
+ _webSurface->getRootItem()->setProperty(USER_AGENT_PROPERTY, _userAgent);
_webSurface->getSurfaceContext()->setContextProperty(GLOBAL_POSITION_PROPERTY, vec3toVariant(_contextPosition));
_webSurface->setMaxFps((QUrl(newSourceURL).host().endsWith("youtube.com", Qt::CaseInsensitive)) ? YOUTUBE_MAX_FPS : _maxFPS);
::hifi::scripting::setLocalAccessSafeThread(false);
@@ -241,6 +232,14 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
_useBackground = useBackground;
}
}
+
+ {
+ auto userAgent = entity->getUserAgent();
+ if (_userAgent != userAgent) {
+ _webSurface->getRootItem()->setProperty(USER_AGENT_PROPERTY, userAgent);
+ _userAgent = userAgent;
+ }
+ }
{
auto contextPosition = entity->getWorldPosition();
@@ -261,21 +260,12 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
_renderTransform.postScale(entity->getScaledDimensions());
});
});
+ } else {
+ emit requestRenderUpdate();
}
});
}
-Item::Bound WebEntityRenderer::getBound() {
- auto bound = Parent::getBound();
- if (_billboardMode != BillboardMode::NONE) {
- glm::vec3 dimensions = bound.getScale();
- float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
- const float SQRT_2 = 1.41421356237f;
- bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
- }
- return bound;
-}
-
void WebEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("WebEntityRenderer::render");
withWriteLock([&] {
@@ -305,14 +295,12 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
gpu::Batch& batch = *args->_batch;
glm::vec4 color;
Transform transform;
- bool forward;
bool transparent;
withReadLock([&] {
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
color = glm::vec4(toGlm(_color), _alpha * fadeRatio);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
transform = _renderTransform;
- forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
transparent = isTransparent();
});
@@ -320,9 +308,12 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
return;
}
+ bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
+
batch.setResourceTexture(0, _texture);
- transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
+ transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
+ args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch.setModelTransform(transform);
// Turn off jitter for these entities
@@ -339,8 +330,11 @@ void WebEntityRenderer::buildWebSurface(const EntityItemPointer& entity, const Q
return;
}
- ++_currentWebCount;
- WebEntityRenderer::acquireWebSurface(newSourceURL, _contentType == ContentType::HtmlContent, _webSurface, _cachedWebSurface);
+ bool isHTML = _contentType == ContentType::HtmlContent;
+ if (isHTML) {
+ ++_currentWebCount;
+ }
+ WebEntityRenderer::acquireWebSurface(newSourceURL, isHTML, _webSurface, _cachedWebSurface);
_fadeStartTime = usecTimestampNow();
_webSurface->resume();
@@ -358,12 +352,15 @@ void WebEntityRenderer::destroyWebSurface() {
QSharedPointer webSurface;
withWriteLock([&] {
webSurface.swap(_webSurface);
- _contentType = ContentType::NoContent;
if (webSurface) {
- --_currentWebCount;
+ if (_contentType == ContentType::HtmlContent) {
+ --_currentWebCount;
+ }
WebEntityRenderer::releaseWebSurface(webSurface, _cachedWebSurface, _connections);
}
+
+ _contentType = ContentType::NoContent;
});
}
diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h
index ffd5880c1e..1ac415e5e5 100644
--- a/libraries/entities-renderer/src/RenderableWebEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h
@@ -36,6 +36,7 @@ public:
static const char* SCRIPT_URL_PROPERTY;
static const char* GLOBAL_POSITION_PROPERTY;
static const char* USE_BACKGROUND_PROPERTY;
+ static const char* USER_AGENT_PROPERTY;
static void setAcquireWebSurfaceOperator(std::function&, bool&)> acquireWebSurfaceOperator) { _acquireWebSurfaceOperator = acquireWebSurfaceOperator; }
static void acquireWebSurface(const QString& url, bool htmlContent, QSharedPointer& webSurface, bool& cachedWebSurface) {
@@ -55,12 +56,10 @@ public:
virtual QObject* getEventHandler() override;
protected:
- virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
virtual bool isTransparent() const override;
- Item::Bound getBound() override;
virtual bool wantsHandControllerPointerEvents() const override { return true; }
virtual bool wantsKeyboardFocus() const override { return true; }
@@ -91,13 +90,13 @@ private:
glm::u8vec3 _color;
float _alpha { 1.0f };
PulsePropertyGroup _pulseProperties;
- BillboardMode _billboardMode;
QString _sourceURL;
uint16_t _dpi;
QString _scriptURL;
uint8_t _maxFPS;
bool _useBackground;
+ QString _userAgent;
WebInputMode _inputMode;
glm::vec3 _contextPosition;
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
index d3c9225b88..ce2dae8d28 100644
--- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
@@ -189,7 +189,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
CullTest::_containingZones.insert(_entityID);
}
-void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
+void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
auto position = entity->getWorldPosition();
auto rotation = entity->getWorldOrientation();
auto dimensions = entity->getScaledDimensions();
@@ -199,7 +199,11 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
auto visible = entity->getVisible();
if (transformChanged || visible != _lastVisible) {
_lastVisible = visible;
- DependencyManager::get()->updateZone(entity->getID());
+ void* key = (void*)this;
+ EntityItemID id = entity->getID();
+ AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [id] {
+ DependencyManager::get()->updateZone(id);
+ });
}
auto proceduralUserData = entity->getUserData();
@@ -267,10 +271,6 @@ ItemKey ZoneEntityRenderer::getKey() {
}
bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
- if (entity->getVisible() != _lastVisible) {
- return true;
- }
-
if (entity->keyLightPropertiesChanged() ||
entity->ambientLightPropertiesChanged() ||
entity->hazePropertiesChanged() ||
@@ -280,29 +280,11 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
return true;
}
- if (_skyboxTextureURL != entity->getSkyboxProperties().getURL()) {
- return true;
- }
-
- if (entity->getWorldPosition() != _lastPosition) {
- return true;
- }
- if (entity->getScaledDimensions() != _lastDimensions) {
- return true;
- }
- if (entity->getWorldOrientation() != _lastRotation) {
- return true;
- }
-
- if (entity->getUserData() != _proceduralUserData) {
- return true;
- }
-
return false;
}
void ZoneEntityRenderer::updateKeySunFromEntity(const TypedEntityPointer& entity) {
- setKeyLightMode((ComponentMode)entity->getKeyLightMode());
+ _keyLightMode = (ComponentMode)entity->getKeyLightMode();
const auto& sunLight = editSunLight();
sunLight->setType(graphics::Light::SUN);
@@ -319,7 +301,7 @@ void ZoneEntityRenderer::updateKeySunFromEntity(const TypedEntityPointer& entity
}
void ZoneEntityRenderer::updateAmbientLightFromEntity(const TypedEntityPointer& entity) {
- setAmbientLightMode((ComponentMode)entity->getAmbientLightMode());
+ _ambientLightMode = (ComponentMode)entity->getAmbientLightMode();
const auto& ambientLight = editAmbientLight();
ambientLight->setType(graphics::Light::AMBIENT);
@@ -339,11 +321,12 @@ void ZoneEntityRenderer::updateAmbientLightFromEntity(const TypedEntityPointer&
}
void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity) {
- setHazeMode((ComponentMode)entity->getHazeMode());
+ const uint32_t hazeMode = entity->getHazeMode();
+
+ _hazeMode = (ComponentMode)hazeMode;
const auto& haze = editHaze();
- const uint32_t hazeMode = entity->getHazeMode();
haze->setHazeActive(hazeMode == COMPONENT_MODE_ENABLED);
haze->setAltitudeBased(_hazeProperties.getHazeAltitudeEffect());
@@ -367,7 +350,7 @@ void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity)
}
void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity) {
- setBloomMode((ComponentMode)entity->getBloomMode());
+ _bloomMode = (ComponentMode)entity->getBloomMode();
const auto& bloom = editBloom();
@@ -377,7 +360,7 @@ void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity)
}
void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) {
- setSkyboxMode((ComponentMode)entity->getSkyboxMode());
+ _skyboxMode = (ComponentMode)entity->getSkyboxMode();
editBackground();
setSkyboxColor(toGlm(_skyboxProperties.getColor()));
@@ -478,26 +461,6 @@ void ZoneEntityRenderer::updateSkyboxMap() {
}
}
-void ZoneEntityRenderer::setHazeMode(ComponentMode mode) {
- _hazeMode = mode;
-}
-
-void ZoneEntityRenderer::setKeyLightMode(ComponentMode mode) {
- _keyLightMode = mode;
-}
-
-void ZoneEntityRenderer::setAmbientLightMode(ComponentMode mode) {
- _ambientLightMode = mode;
-}
-
-void ZoneEntityRenderer::setSkyboxMode(ComponentMode mode) {
- _skyboxMode = mode;
-}
-
-void ZoneEntityRenderer::setBloomMode(ComponentMode mode) {
- _bloomMode = mode;
-}
-
void ZoneEntityRenderer::setSkyboxColor(const glm::vec3& color) {
editSkybox()->setColor(color);
}
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h
index d4e3d16408..d2ee90b1e4 100644
--- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h
@@ -38,7 +38,7 @@ protected:
virtual ItemKey getKey() override;
virtual void doRender(RenderArgs* args) override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
- virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
+ virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
private:
void updateKeyZoneItemFromEntity(const TypedEntityPointer& entity);
@@ -52,12 +52,6 @@ private:
void setAmbientURL(const QString& ambientUrl);
void setSkyboxURL(const QString& skyboxUrl);
- void setHazeMode(ComponentMode mode);
- void setKeyLightMode(ComponentMode mode);
- void setAmbientLightMode(ComponentMode mode);
- void setSkyboxMode(ComponentMode mode);
- void setBloomMode(ComponentMode mode);
-
void setSkyboxColor(const glm::vec3& color);
void setProceduralUserData(const QString& userData);
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index ddedf0db18..9d3947ab56 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -51,9 +51,6 @@ int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
QString EntityItem::_marketplacePublicKey;
-std::function EntityItem::_getBillboardRotationOperator = [](const glm::vec3&, const glm::quat& rotation, BillboardMode, const glm::vec3&) { return rotation; };
-std::function EntityItem::_getPrimaryViewFrustumPositionOperator = []() { return glm::vec3(0.0f); };
-
EntityItem::EntityItem(const EntityItemID& entityItemID) :
SpatiallyNestable(NestableType::Entity, entityItemID)
{
@@ -107,6 +104,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_PRIMITIVE_MODE;
requestedProperties += PROP_IGNORE_PICK_INTERSECTION;
requestedProperties += PROP_RENDER_WITH_ZONES;
+ requestedProperties += PROP_BILLBOARD_MODE;
requestedProperties += _grabProperties.getEntityProperties(params);
// Physics
@@ -303,6 +301,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, (uint32_t)getPrimitiveMode());
APPEND_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, getIgnorePickIntersection());
APPEND_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, getRenderWithZones());
+ APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
withReadLock([&] {
_grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
@@ -875,6 +874,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, PrimitiveMode, setPrimitiveMode);
READ_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, bool, setIgnorePickIntersection);
READ_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, QVector, setRenderWithZones);
+ READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
withWriteLock([&] {
int bytesFromGrab = _grabProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData,
@@ -1358,6 +1358,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire
COPY_ENTITY_PROPERTY_TO_PROPERTIES(primitiveMode, getPrimitiveMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignorePickIntersection, getIgnorePickIntersection);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(renderWithZones, getRenderWithZones);
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
withReadLock([&] {
_grabProperties.getProperties(properties);
});
@@ -1508,6 +1509,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(primitiveMode, setPrimitiveMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignorePickIntersection, setIgnorePickIntersection);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(renderWithZones, setRenderWithZones);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
withWriteLock([&] {
bool grabPropertiesChanged = _grabProperties.setProperties(properties);
somethingChanged |= grabPropertiesChanged;
@@ -1607,8 +1609,13 @@ void EntityItem::recordCreationTime() {
const Transform EntityItem::getTransformToCenter(bool& success) const {
Transform result = getTransform(success);
- if (getRegistrationPoint() != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center
- result.postTranslate((ENTITY_ITEM_HALF_VEC3 - getRegistrationPoint()) * getScaledDimensions()); // Position to center
+ glm::vec3 pivot = getPivot();
+ if (pivot != ENTITY_ITEM_ZERO_VEC3) {
+ result.postTranslate(pivot);
+ }
+ glm::vec3 registrationPoint = getRegistrationPoint();
+ if (registrationPoint != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center
+ result.postTranslate((ENTITY_ITEM_HALF_VEC3 - registrationPoint) * getScaledDimensions()); // Position to center
}
return result;
}
@@ -1623,15 +1630,16 @@ AACube EntityItem::getMaximumAACube(bool& success) const {
_recalcMaxAACube = false;
// we want to compute the furthestExtent that an entity can extend out from its "position"
// to do this we compute the max of these two vec3s: registration and 1-registration
- // and then scale by dimensions
- glm::vec3 maxExtents = getScaledDimensions() * glm::max(_registrationPoint, glm::vec3(1.0f) - _registrationPoint);
+ // and then scale by dimensions and add the absolute value of the pivot
+ glm::vec3 registrationPoint = getRegistrationPoint();
+ glm::vec3 maxExtents = getScaledDimensions() * glm::max(registrationPoint, glm::vec3(1.0f) - registrationPoint);
// there exists a sphere that contains maxExtents for all rotations
float radius = glm::length(maxExtents);
// put a cube around the sphere
// TODO? replace _maxAACube with _boundingSphereRadius
- glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius);
+ glm::vec3 minimumCorner = (centerOfRotation + getWorldOrientation() * getPivot()) - glm::vec3(radius, radius, radius);
_maxAACube = AACube(minimumCorner, radius * 2.0f);
}
} else {
@@ -1650,9 +1658,12 @@ AACube EntityItem::getMinimumAACube(bool& success) const {
if (success) {
_recalcMinAACube = false;
glm::vec3 dimensions = getScaledDimensions();
- glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint);
- glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint);
+ glm::vec3 registrationPoint = getRegistrationPoint();
+ glm::vec3 pivot = getPivot();
+ glm::vec3 unrotatedMinRelativeToEntity = -(dimensions * registrationPoint);
+ glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (ENTITY_ITEM_ONE_VEC3 - registrationPoint);
Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
+ extents.shiftBy(pivot);
extents.rotate(getWorldOrientation());
// shift the extents to be relative to the position/registration point
@@ -1680,9 +1691,12 @@ AABox EntityItem::getAABox(bool& success) const {
if (success) {
_recalcAABox = false;
glm::vec3 dimensions = getScaledDimensions();
- glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint);
- glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint);
+ glm::vec3 registrationPoint = getRegistrationPoint();
+ glm::vec3 pivot = getPivot();
+ glm::vec3 unrotatedMinRelativeToEntity = -(dimensions * registrationPoint);
+ glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (ENTITY_ITEM_ONE_VEC3 - registrationPoint);
Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
+ extents.shiftBy(pivot);
extents.rotate(getWorldOrientation());
// shift the extents to be relative to the position/registration point
@@ -1722,12 +1736,22 @@ float EntityItem::getRadius() const {
return 0.5f * glm::length(getScaledDimensions());
}
-void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const {
- if (_registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) {
- glm::mat4 scale = glm::scale(getScaledDimensions());
- glm::mat4 registration = scale * glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
- glm::vec3 regTransVec = glm::vec3(registration[3]); // extract position component from matrix
- info.setOffset(regTransVec);
+void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info, bool includePivot) const {
+ glm::vec3 offset;
+ glm::vec3 registrationPoint = getRegistrationPoint();
+ if (registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) {
+ offset += (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - registrationPoint) * getScaledDimensions();
+ }
+
+ if (includePivot) {
+ glm::vec3 pivot = getPivot();
+ if (pivot != ENTITY_ITEM_ZERO_VEC3) {
+ offset += pivot;
+ }
+ }
+
+ if (offset != ENTITY_ITEM_ZERO_VEC3) {
+ info.setOffset(offset);
}
}
@@ -1739,7 +1763,7 @@ bool EntityItem::contains(const glm::vec3& point) const {
// anything with shapeType == SPHERE must collide as a bounding sphere in the world-frame regardless of dimensions
// therefore we must do math using an unscaled localPoint relative to sphere center
glm::vec3 dimensions = getScaledDimensions();
- glm::vec3 localPoint = point - (getWorldPosition() + getWorldOrientation() * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())));
+ glm::vec3 localPoint = point - (getWorldPosition() + getWorldOrientation() * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()) + getPivot()));
const float HALF_SQUARED = 0.25f;
return glm::length2(localPoint) < HALF_SQUARED * glm::length2(dimensions);
}
@@ -1797,11 +1821,16 @@ float EntityItem::getVolumeEstimate() const {
}
void EntityItem::setRegistrationPoint(const glm::vec3& value) {
- if (value != _registrationPoint) {
- withWriteLock([&] {
+ bool changed = false;
+ withWriteLock([&] {
+ if (value != _registrationPoint) {
_registrationPoint = glm::clamp(value, glm::vec3(ENTITY_ITEM_MIN_REGISTRATION_POINT),
glm::vec3(ENTITY_ITEM_MAX_REGISTRATION_POINT));
- });
+ changed = true;
+ }
+ });
+
+ if (changed) {
dimensionsChanged(); // Registration Point affects the bounding box
markDirtyFlags(Simulation::DIRTY_SHAPE);
}
@@ -1911,13 +1940,11 @@ void EntityItem::setUnscaledDimensions(const glm::vec3& value) {
if (glm::length2(getUnscaledDimensions() - newDimensions) > MIN_SCALE_CHANGE_SQUARED) {
withWriteLock([&] {
_unscaledDimensions = newDimensions;
- });
- locationChanged();
- dimensionsChanged();
- withWriteLock([&] {
_flags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
_queryAACubeSet = false;
});
+ locationChanged();
+ dimensionsChanged();
}
}
@@ -2894,11 +2921,9 @@ QString EntityItem::getCollisionSoundURL() const {
}
glm::vec3 EntityItem::getRegistrationPoint() const {
- glm::vec3 result;
- withReadLock([&] {
- result = _registrationPoint;
+ return resultWithReadLock([&] {
+ return _registrationPoint;
});
- return result;
}
float EntityItem::getAngularDamping() const {
@@ -3593,4 +3618,17 @@ QVector EntityItem::getRenderWithZones() const {
return resultWithReadLock>([&] {
return _renderWithZones;
});
-}
\ No newline at end of file
+}
+
+BillboardMode EntityItem::getBillboardMode() const {
+ return resultWithReadLock([&] {
+ return _billboardMode;
+ });
+}
+
+void EntityItem::setBillboardMode(BillboardMode value) {
+ withWriteLock([&] {
+ _needsRenderUpdate |= _billboardMode != value;
+ _billboardMode = value;
+ });
+}
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 2a6952fc0d..152e003913 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -175,12 +175,12 @@ public:
virtual bool supportsDetailedIntersection() const { return false; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const { return true; }
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const { return true; }
// attributes applicable to all entity types
@@ -203,7 +203,8 @@ public:
/// Dimensions in meters (0.0 - TREE_SCALE)
virtual glm::vec3 getScaledDimensions() const;
virtual void setScaledDimensions(const glm::vec3& value);
- virtual glm::vec3 getRaycastDimensions() const { return getScaledDimensions(); }
+
+ virtual glm::vec3 getPivot() const { return glm::vec3(0.0f); } // pivot offset for positioning, mainly for model entities
glm::vec3 getUnscaledDimensions() const;
virtual void setUnscaledDimensions(const glm::vec3& value);
@@ -403,7 +404,7 @@ public:
// TODO: get rid of users of getRadius()...
float getRadius() const;
- virtual void adjustShapeInfoByRegistration(ShapeInfo& info) const;
+ virtual void adjustShapeInfoByRegistration(ShapeInfo& info, bool includePivot = true) const;
virtual bool contains(const glm::vec3& point) const;
virtual bool isReadyToComputeShape() const { return !isDead(); }
@@ -572,11 +573,6 @@ public:
virtual void removeGrab(GrabPointer grab) override;
virtual void disableGrab(GrabPointer grab) override;
- static void setBillboardRotationOperator(std::function getBillboardRotationOperator) { _getBillboardRotationOperator = getBillboardRotationOperator; }
- static glm::quat getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos) { return _getBillboardRotationOperator(position, rotation, billboardMode, frustumPos); }
- static void setPrimaryViewFrustumPositionOperator(std::function getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
- static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
-
bool stillHasMyGrab() const;
bool needsRenderUpdate() const { return _needsRenderUpdate; }
@@ -587,6 +583,10 @@ public:
bool needsZoneOcclusionUpdate() const { return _needsZoneOcclusionUpdate; }
void resetNeedsZoneOcclusionUpdate() { withWriteLock([&] { _needsZoneOcclusionUpdate = false; }); }
+ void setBillboardMode(BillboardMode value);
+ BillboardMode getBillboardMode() const;
+ virtual bool getRotateForPicking() const { return false; }
+
signals:
void spaceUpdate(std::pair data);
@@ -778,13 +778,11 @@ protected:
QVector _renderWithZones;
mutable bool _needsZoneOcclusionUpdate { false };
+ BillboardMode _billboardMode { BillboardMode::NONE };
+
bool _cullWithParent { false };
mutable bool _needsRenderUpdate { false };
-
-private:
- static std::function _getBillboardRotationOperator;
- static std::function _getPrimaryViewFrustumPositionOperator;
};
#endif // hifi_EntityItem_h
diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index ff55137a03..5f925c4b19 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -433,6 +433,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_PRIMITIVE_MODE, primitiveMode);
CHECK_PROPERTY_CHANGE(PROP_IGNORE_PICK_INTERSECTION, ignorePickIntersection);
CHECK_PROPERTY_CHANGE(PROP_RENDER_WITH_ZONES, renderWithZones);
+ CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode);
changedProperties += _grab.getChangedProperties();
// Physics
@@ -493,7 +494,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha);
changedProperties += _pulse.getChangedProperties();
CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures);
- CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode);
// Particles
CHECK_PROPERTY_CHANGE(PROP_MAX_PARTICLES, maxParticles);
@@ -538,6 +538,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_RELAY_PARENT_JOINTS, relayParentJoints);
CHECK_PROPERTY_CHANGE(PROP_GROUP_CULLED, groupCulled);
CHECK_PROPERTY_CHANGE(PROP_BLENDSHAPE_COEFFICIENTS, blendshapeCoefficients);
+ CHECK_PROPERTY_CHANGE(PROP_USE_ORIGINAL_PIVOT, useOriginalPivot);
changedProperties += _animation.getChangedProperties();
// Light
@@ -603,6 +604,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_INPUT_MODE, inputMode);
CHECK_PROPERTY_CHANGE(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, showKeyboardFocusHighlight);
CHECK_PROPERTY_CHANGE(PROP_WEB_USE_BACKGROUND, useBackground);
+ CHECK_PROPERTY_CHANGE(PROP_USER_AGENT, userAgent);
// Polyline
CHECK_PROPERTY_CHANGE(PROP_LINE_POINTS, linePoints);
@@ -811,6 +813,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {Uuid[]} renderWithZones=[]] - A list of entity IDs representing with which zones this entity should render.
* If it is empty, this entity will render normally. Otherwise, this entity will only render if your avatar is within
* one of the zones in this list.
+ * @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera. Use the rotation
+ * property to control which axis is facing you.
*
* @property {Entities.Grab} grab - The entity's grab-related properties.
*
@@ -1002,6 +1006,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {string} blendshapeCoefficients - A JSON string of a map of blendshape names to values. Only stores set values.
* When editing this property, only coefficients that you are editing will change; it will not explicitly reset other
* coefficients.
+ * @property {boolean} useOriginalPivot=false - If false
, the model will be centered based on its content,
+ * ignoring any offset in the model itself. If true
, the model will respect its original offset. Currently,
+ * only pivots relative to {x: 0, y: 0, z: 0}
are supported.
* @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the
* model's original textures. Use a texture name from the originalTextures
property to override that texture.
* Only the texture names and URLs to be overridden need be specified; original textures are used where there are no
@@ -1332,7 +1339,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {Entities.TextEffect} textEffect="none" - The effect that is applied to the text.
* @property {Color} textEffectColor=255,255,255 - The color of the effect.
* @property {number} textEffectThickness=0.2 - The magnitude of the text effect, range 0.0
– 0.5
.
- * @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera.
* @property {boolean} faceCamera - true
if billboardMode
is "yaw"
, false
* if it isn't. Setting this property to false
sets the billboardMode
to "none"
.
* Deprecated: This property is deprecated and will be removed.
@@ -1368,7 +1374,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {number} alpha=1 - The opacity of the web surface.
* @property {Entities.Pulse} pulse - Color and alpha pulse.
* Deprecated: This property is deprecated and will be removed.
- * @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera.
* @property {boolean} faceCamera - true
if billboardMode
is "yaw"
, false
* if it isn't. Setting this property to false
sets the billboardMode
to "none"
.
* Deprecated: This property is deprecated and will be removed.
@@ -1387,6 +1392,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {boolean} useBackground=true - true
if the web entity should have a background,
* false
if the web entity's background should be transparent. The webpage must have CSS properties for transparency set
* on the background-color
for this property to have an effect.
+ * @property {string} userAgent - The user agent for the web entity to use when visiting web pages.
+ * Default value: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko)
+ * Chrome/69.0.3497.113 Mobile Safari/537.36
* @example Create a Web entity displaying at 1920 x 1080 resolution.
* var METERS_TO_INCHES = 39.3701;
* var entity = Entities.addEntity({
@@ -1487,7 +1495,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {number} alpha=1 - The opacity of the image.
* @property {Entities.Pulse} pulse - Color and alpha pulse.
* Deprecated: This property is deprecated and will be removed.
- * @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera.
* @property {boolean} faceCamera - true
if billboardMode
is "yaw"
, false
* if it isn't. Setting this property to false
sets the billboardMode
to "none"
.
* Deprecated: This property is deprecated and will be removed.
@@ -1611,6 +1618,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_PRIMITIVE_MODE, primitiveMode, getPrimitiveModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_PICK_INTERSECTION, ignorePickIntersection);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RENDER_WITH_ZONES, renderWithZones);
+ COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
_grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
// Physics
@@ -1733,6 +1741,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RELAY_PARENT_JOINTS, relayParentJoints);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GROUP_CULLED, groupCulled);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_BLENDSHAPE_COEFFICIENTS, blendshapeCoefficients);
+ COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USE_ORIGINAL_PIVOT, useOriginalPivot);
if (!psuedoPropertyFlagsButDesiredEmpty) {
_animation.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
}
@@ -1766,7 +1775,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
// Text only
if (_type == EntityTypes::Text) {
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
- COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT, text);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight);
@@ -1816,7 +1824,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
- COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DPI, dpi);
@@ -1825,6 +1832,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_INPUT_MODE, inputMode, getInputModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, showKeyboardFocusHighlight);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_WEB_USE_BACKGROUND, useBackground);
+ COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_AGENT, userAgent);
}
// PolyVoxel only
@@ -1884,7 +1892,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
- COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMISSIVE, emissive);
@@ -2032,6 +2039,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(primitiveMode, PrimitiveMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(ignorePickIntersection, bool, setIgnorePickIntersection);
COPY_PROPERTY_FROM_QSCRIPTVALUE(renderWithZones, qVectorQUuid, setRenderWithZones);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode);
_grab.copyFromScriptValue(object, _defaultSettings);
// Physics
@@ -2097,7 +2105,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha);
_pulse.copyFromScriptValue(object, _defaultSettings);
COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures);
- COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode);
// Particles
COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, quint32, setMaxParticles);
@@ -2142,6 +2149,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints);
COPY_PROPERTY_FROM_QSCRIPTVALUE(groupCulled, bool, setGroupCulled);
COPY_PROPERTY_FROM_QSCRIPTVALUE(blendshapeCoefficients, QString, setBlendshapeCoefficients);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE(useOriginalPivot, bool, setUseOriginalPivot);
_animation.copyFromScriptValue(object, _defaultSettings);
// Light
@@ -2207,6 +2215,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(inputMode, InputMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(showKeyboardFocusHighlight, bool, setShowKeyboardFocusHighlight);
COPY_PROPERTY_FROM_QSCRIPTVALUE(useBackground, bool, setUseBackground);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE(userAgent, QString, setUserAgent);
// Polyline
COPY_PROPERTY_FROM_QSCRIPTVALUE(linePoints, qVectorVec3, setLinePoints);
@@ -2329,6 +2338,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(primitiveMode);
COPY_PROPERTY_IF_CHANGED(ignorePickIntersection);
COPY_PROPERTY_IF_CHANGED(renderWithZones);
+ COPY_PROPERTY_IF_CHANGED(billboardMode);
_grab.merge(other._grab);
// Physics
@@ -2389,7 +2399,6 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(alpha);
_pulse.merge(other._pulse);
COPY_PROPERTY_IF_CHANGED(textures);
- COPY_PROPERTY_IF_CHANGED(billboardMode);
// Particles
COPY_PROPERTY_IF_CHANGED(maxParticles);
@@ -2434,6 +2443,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(relayParentJoints);
COPY_PROPERTY_IF_CHANGED(groupCulled);
COPY_PROPERTY_IF_CHANGED(blendshapeCoefficients);
+ COPY_PROPERTY_IF_CHANGED(useOriginalPivot);
_animation.merge(other._animation);
// Light
@@ -2499,6 +2509,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(inputMode);
COPY_PROPERTY_IF_CHANGED(showKeyboardFocusHighlight);
COPY_PROPERTY_IF_CHANGED(useBackground);
+ COPY_PROPERTY_IF_CHANGED(userAgent);
// Polyline
COPY_PROPERTY_IF_CHANGED(linePoints);
@@ -2625,6 +2636,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_PROPERTY_TO_MAP(PROP_PRIMITIVE_MODE, PrimitiveMode, primitiveMode, PrimitiveMode);
ADD_PROPERTY_TO_MAP(PROP_IGNORE_PICK_INTERSECTION, IgnorePickIntersection, ignorePickIntersection, bool);
ADD_PROPERTY_TO_MAP(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector);
+ ADD_PROPERTY_TO_MAP(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode);
{ // Grab
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable);
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic);
@@ -2721,7 +2733,6 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_GROUP_PROPERTY_TO_MAP(PROP_PULSE_ALPHA_MODE, Pulse, pulse, AlphaMode, alphaMode);
}
ADD_PROPERTY_TO_MAP(PROP_TEXTURES, Textures, textures, QString);
- ADD_PROPERTY_TO_MAP(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode);
// Particles
ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32,
@@ -2790,6 +2801,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_PROPERTY_TO_MAP(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool);
ADD_PROPERTY_TO_MAP(PROP_GROUP_CULLED, GroupCulled, groupCulled, bool);
ADD_PROPERTY_TO_MAP(PROP_BLENDSHAPE_COEFFICIENTS, BlendshapeCoefficients, blendshapeCoefficients, QString);
+ ADD_PROPERTY_TO_MAP(PROP_USE_ORIGINAL_PIVOT, UseOriginalPivot, useOriginalPivot, bool);
{ // Animation
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_URL, Animation, animation, URL, url);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);
@@ -2899,6 +2911,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_PROPERTY_TO_MAP(PROP_INPUT_MODE, InputMode, inputMode, WebInputMode);
ADD_PROPERTY_TO_MAP(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, ShowKeyboardFocusHighlight, showKeyboardFocusHighlight, bool);
ADD_PROPERTY_TO_MAP(PROP_WEB_USE_BACKGROUND, useBackground, useBackground, bool);
+ ADD_PROPERTY_TO_MAP(PROP_USER_AGENT, UserAgent, userAgent, QString);
// Polyline
ADD_PROPERTY_TO_MAP(PROP_LINE_POINTS, LinePoints, linePoints, QVector);
@@ -3117,6 +3130,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, (uint32_t)properties.getPrimitiveMode());
APPEND_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, properties.getIgnorePickIntersection());
APPEND_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, properties.getRenderWithZones());
+ APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
_staticGrab.setProperties(properties);
_staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags,
propertiesDidntFit, propertyCount, appendState);
@@ -3231,6 +3245,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, properties.getRelayParentJoints());
APPEND_ENTITY_PROPERTY(PROP_GROUP_CULLED, properties.getGroupCulled());
APPEND_ENTITY_PROPERTY(PROP_BLENDSHAPE_COEFFICIENTS, properties.getBlendshapeCoefficients());
+ APPEND_ENTITY_PROPERTY(PROP_USE_ORIGINAL_PIVOT, properties.getUseOriginalPivot());
_staticAnimation.setProperties(properties);
_staticAnimation.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
@@ -3249,7 +3264,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
_staticPulse.setProperties(properties);
_staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags,
propertiesDidntFit, propertyCount, appendState);
- APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText());
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight());
@@ -3321,7 +3335,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
_staticPulse.setProperties(properties);
_staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags,
propertiesDidntFit, propertyCount, appendState);
- APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl());
APPEND_ENTITY_PROPERTY(PROP_DPI, properties.getDPI());
@@ -3330,6 +3343,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_INPUT_MODE, (uint32_t)properties.getInputMode());
APPEND_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, properties.getShowKeyboardFocusHighlight());
APPEND_ENTITY_PROPERTY(PROP_WEB_USE_BACKGROUND, properties.getUseBackground());
+ APPEND_ENTITY_PROPERTY(PROP_USER_AGENT, properties.getUserAgent());
}
if (properties.getType() == EntityTypes::Line) {
@@ -3384,7 +3398,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
_staticPulse.setProperties(properties);
_staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags,
propertiesDidntFit, propertyCount, appendState);
- APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, properties.getImageURL());
APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, properties.getEmissive());
@@ -3610,6 +3623,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PRIMITIVE_MODE, PrimitiveMode, setPrimitiveMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_PICK_INTERSECTION, bool, setIgnorePickIntersection);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_WITH_ZONES, QVector, setRenderWithZones);
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
// Physics
@@ -3720,6 +3734,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GROUP_CULLED, bool, setGroupCulled);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLENDSHAPE_COEFFICIENTS, QString, setBlendshapeCoefficients);
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USE_ORIGINAL_PIVOT, bool, setUseOriginalPivot);
properties.getAnimation().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
}
@@ -3736,7 +3751,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
if (properties.getType() == EntityTypes::Text) {
properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
- READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight);
@@ -3797,7 +3811,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
- READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DPI, uint16_t, setDPI);
@@ -3806,6 +3819,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_INPUT_MODE, WebInputMode, setInputMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, bool, setShowKeyboardFocusHighlight);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_WEB_USE_BACKGROUND, bool, setUseBackground);
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_AGENT, QString, setUserAgent);
}
if (properties.getType() == EntityTypes::Line) {
@@ -3857,7 +3871,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
- READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IMAGE_URL, QString, setImageURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMISSIVE, bool, setEmissive);
@@ -4031,6 +4044,7 @@ void EntityItemProperties::markAllChanged() {
_primitiveModeChanged = true;
_ignorePickIntersectionChanged = true;
_renderWithZonesChanged = true;
+ _billboardModeChanged = true;
_grab.markAllChanged();
// Physics
@@ -4084,7 +4098,6 @@ void EntityItemProperties::markAllChanged() {
_alphaChanged = true;
_pulse.markAllChanged();
_texturesChanged = true;
- _billboardModeChanged = true;
// Particles
_maxParticlesChanged = true;
@@ -4129,6 +4142,7 @@ void EntityItemProperties::markAllChanged() {
_relayParentJointsChanged = true;
_groupCulledChanged = true;
_blendshapeCoefficientsChanged = true;
+ _useOriginalPivotChanged = true;
_animation.markAllChanged();
// Light
@@ -4194,6 +4208,7 @@ void EntityItemProperties::markAllChanged() {
_inputModeChanged = true;
_showKeyboardFocusHighlightChanged = true;
_useBackgroundChanged = true;
+ _userAgentChanged = true;
// Polyline
_linePointsChanged = true;
@@ -4439,6 +4454,9 @@ QList EntityItemProperties::listChangedProperties() {
if (renderWithZonesChanged()) {
out += "renderWithZones";
}
+ if (billboardModeChanged()) {
+ out += "billboardMode";
+ }
getGrab().listChangedProperties(out);
// Physics
@@ -4574,9 +4592,6 @@ QList EntityItemProperties::listChangedProperties() {
if (texturesChanged()) {
out += "textures";
}
- if (billboardModeChanged()) {
- out += "billboardMode";
- }
// Particles
if (maxParticlesChanged()) {
@@ -4701,6 +4716,9 @@ QList EntityItemProperties::listChangedProperties() {
if (blendshapeCoefficientsChanged()) {
out += "blendshapeCoefficients";
}
+ if (useOriginalPivotChanged()) {
+ out += "useOriginalPivot";
+ }
getAnimation().listChangedProperties(out);
// Light
@@ -4887,6 +4905,9 @@ QList EntityItemProperties::listChangedProperties() {
if (useBackgroundChanged()) {
out += "useBackground";
}
+ if (userAgentChanged()) {
+ out += "userAgent";
+ }
// Shape
if (shapeChanged()) {
diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h
index f7fde73430..0de2998a13 100644
--- a/libraries/entities/src/EntityItemProperties.h
+++ b/libraries/entities/src/EntityItemProperties.h
@@ -197,6 +197,7 @@ public:
DEFINE_PROPERTY_REF_ENUM(PROP_PRIMITIVE_MODE, PrimitiveMode, primitiveMode, PrimitiveMode, PrimitiveMode::SOLID);
DEFINE_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, IgnorePickIntersection, ignorePickIntersection, bool, false);
DEFINE_PROPERTY_REF(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector, QVector());
+ DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE);
DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup);
// Physics
@@ -257,7 +258,6 @@ public:
DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float, ENTITY_ITEM_DEFAULT_ALPHA);
DEFINE_PROPERTY_GROUP(Pulse, pulse, PulsePropertyGroup);
DEFINE_PROPERTY_REF(PROP_TEXTURES, Textures, textures, QString, "");
- DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE);
// Particles
DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32, particle::DEFAULT_MAX_PARTICLES);
@@ -302,6 +302,7 @@ public:
DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS);
DEFINE_PROPERTY_REF(PROP_GROUP_CULLED, GroupCulled, groupCulled, bool, false);
DEFINE_PROPERTY_REF(PROP_BLENDSHAPE_COEFFICIENTS, BlendshapeCoefficients, blendshapeCoefficients, QString, "");
+ DEFINE_PROPERTY_REF(PROP_USE_ORIGINAL_PIVOT, UseOriginalPivot, useOriginalPivot, bool, false);
DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup);
// Light
@@ -367,6 +368,7 @@ public:
DEFINE_PROPERTY_REF_ENUM(PROP_INPUT_MODE, InputMode, inputMode, WebInputMode, WebInputMode::TOUCH);
DEFINE_PROPERTY_REF(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, ShowKeyboardFocusHighlight, showKeyboardFocusHighlight, bool, true);
DEFINE_PROPERTY_REF(PROP_WEB_USE_BACKGROUND, UseBackground, useBackground, bool, true);
+ DEFINE_PROPERTY_REF(PROP_USER_AGENT, UserAgent, userAgent, QString, WebEntityItem::DEFAULT_USER_AGENT);
// Polyline
DEFINE_PROPERTY_REF(PROP_LINE_POINTS, LinePoints, linePoints, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC);
diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h
index 93bb8a89a7..d9337d70b5 100644
--- a/libraries/entities/src/EntityPropertyFlags.h
+++ b/libraries/entities/src/EntityPropertyFlags.h
@@ -45,6 +45,7 @@ enum EntityPropertyList {
PROP_PRIMITIVE_MODE,
PROP_IGNORE_PICK_INTERSECTION,
PROP_RENDER_WITH_ZONES,
+ PROP_BILLBOARD_MODE,
// Grab
PROP_GRAB_GRABBABLE,
PROP_GRAB_KINEMATIC,
@@ -122,7 +123,6 @@ enum EntityPropertyList {
PROP_PULSE_COLOR_MODE,
PROP_PULSE_ALPHA_MODE,
PROP_TEXTURES,
- PROP_BILLBOARD_MODE,
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new shared EntityItem properties to the list ABOVE this line
@@ -218,16 +218,17 @@ enum EntityPropertyList {
PROP_RELAY_PARENT_JOINTS = PROP_DERIVED_6,
PROP_GROUP_CULLED = PROP_DERIVED_7,
PROP_BLENDSHAPE_COEFFICIENTS = PROP_DERIVED_8,
+ PROP_USE_ORIGINAL_PIVOT = PROP_DERIVED_9,
// Animation
- PROP_ANIMATION_URL = PROP_DERIVED_9,
- PROP_ANIMATION_ALLOW_TRANSLATION = PROP_DERIVED_10,
- PROP_ANIMATION_FPS = PROP_DERIVED_11,
- PROP_ANIMATION_FRAME_INDEX = PROP_DERIVED_12,
- PROP_ANIMATION_PLAYING = PROP_DERIVED_13,
- PROP_ANIMATION_LOOP = PROP_DERIVED_14,
- PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_15,
- PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_16,
- PROP_ANIMATION_HOLD = PROP_DERIVED_17,
+ PROP_ANIMATION_URL = PROP_DERIVED_10,
+ PROP_ANIMATION_ALLOW_TRANSLATION = PROP_DERIVED_11,
+ PROP_ANIMATION_FPS = PROP_DERIVED_12,
+ PROP_ANIMATION_FRAME_INDEX = PROP_DERIVED_13,
+ PROP_ANIMATION_PLAYING = PROP_DERIVED_14,
+ PROP_ANIMATION_LOOP = PROP_DERIVED_15,
+ PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_16,
+ PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_17,
+ PROP_ANIMATION_HOLD = PROP_DERIVED_18,
// Light
PROP_IS_SPOTLIGHT = PROP_DERIVED_0,
@@ -319,6 +320,7 @@ enum EntityPropertyList {
PROP_INPUT_MODE = PROP_DERIVED_4,
PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT = PROP_DERIVED_5,
PROP_WEB_USE_BACKGROUND = PROP_DERIVED_6,
+ PROP_USER_AGENT = PROP_DERIVED_7,
// Polyline
PROP_LINE_POINTS = PROP_DERIVED_0,
diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp
index 24b6f7ccd4..eeb42626c2 100644
--- a/libraries/entities/src/EntityTree.cpp
+++ b/libraries/entities/src/EntityTree.cpp
@@ -798,6 +798,7 @@ public:
glm::vec3 origin;
glm::vec3 direction;
glm::vec3 invDirection;
+ glm::vec3 viewFrustumPos;
const QVector& entityIdsToInclude;
const QVector& entityIdsToDiscard;
PickFilter searchFilter;
@@ -815,7 +816,7 @@ bool evalRayIntersectionOp(const OctreeElementPointer& element, void* extraData)
RayArgs* args = static_cast(extraData);
bool keepSearching = true;
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast(element);
- EntityItemID entityID = entityTreeElementPointer->evalRayIntersection(args->origin, args->direction,
+ EntityItemID entityID = entityTreeElementPointer->evalRayIntersection(args->origin, args->direction, args->viewFrustumPos,
args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude,
args->entityIdsToDiscard, args->searchFilter, args->extraInfo);
if (!entityID.isNull()) {
@@ -837,7 +838,8 @@ float evalRayIntersectionSortingOp(const OctreeElementPointer& element, void* ex
float boundDistance = FLT_MAX;
BoxFace face;
glm::vec3 surfaceNormal;
- if (entityTreeElementPointer->getAACube().findRayIntersection(args->origin, args->direction, args->invDirection, boundDistance, face, surfaceNormal)) {
+ if (entityTreeElementPointer->getAACube().findRayIntersection(args->origin, args->direction, args->invDirection,
+ boundDistance, face, surfaceNormal)) {
// Don't add this cell if it's already farther than our best distance so far
if (boundDistance < args->distance) {
distance = boundDistance;
@@ -857,7 +859,7 @@ EntityItemID EntityTree::evalRayIntersection(const glm::vec3& origin, const glm:
vec3 dirReciprocal = glm::vec3(direction.x == 0.0f ? 0.0f : 1.0f / direction.x,
direction.y == 0.0f ? 0.0f : 1.0f / direction.y,
direction.z == 0.0f ? 0.0f : 1.0f / direction.z);
- RayArgs args = { origin, direction, dirReciprocal, entityIdsToInclude, entityIdsToDiscard,
+ RayArgs args = { origin, direction, dirReciprocal, BillboardModeHelpers::getPrimaryViewFrustumPosition(), entityIdsToInclude, entityIdsToDiscard,
searchFilter, element, distance, face, surfaceNormal, extraInfo, EntityItemID() };
distance = FLT_MAX;
@@ -879,6 +881,7 @@ public:
glm::vec3 origin;
glm::vec3 velocity;
glm::vec3 acceleration;
+ glm::vec3 viewFrustumPos;
const QVector& entityIdsToInclude;
const QVector& entityIdsToDiscard;
PickFilter searchFilter;
@@ -896,7 +899,7 @@ bool evalParabolaIntersectionOp(const OctreeElementPointer& element, void* extra
ParabolaArgs* args = static_cast(extraData);
bool keepSearching = true;
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast(element);
- EntityItemID entityID = entityTreeElementPointer->evalParabolaIntersection(args->origin, args->velocity, args->acceleration,
+ EntityItemID entityID = entityTreeElementPointer->evalParabolaIntersection(args->origin, args->velocity, args->acceleration, args->viewFrustumPos,
args->element, args->parabolicDistance, args->face, args->surfaceNormal, args->entityIdsToInclude,
args->entityIdsToDiscard, args->searchFilter, args->extraInfo);
if (!entityID.isNull()) {
@@ -918,7 +921,8 @@ float evalParabolaIntersectionSortingOp(const OctreeElementPointer& element, voi
float boundDistance = FLT_MAX;
BoxFace face;
glm::vec3 surfaceNormal;
- if (entityTreeElementPointer->getAACube().findParabolaIntersection(args->origin, args->velocity, args->acceleration, boundDistance, face, surfaceNormal)) {
+ if (entityTreeElementPointer->getAACube().findParabolaIntersection(args->origin, args->velocity, args->acceleration,
+ boundDistance, face, surfaceNormal)) {
// Don't add this cell if it's already farther than our best distance so far
if (boundDistance < args->parabolicDistance) {
distance = boundDistance;
@@ -934,8 +938,8 @@ EntityItemID EntityTree::evalParabolaIntersection(const PickParabola& parabola,
OctreeElementPointer& element, glm::vec3& intersection, float& distance, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
Octree::lockType lockType, bool* accurateResult) {
- ParabolaArgs args = { parabola.origin, parabola.velocity, parabola.acceleration, entityIdsToInclude, entityIdsToDiscard,
- searchFilter, element, parabolicDistance, face, surfaceNormal, extraInfo, EntityItemID() };
+ ParabolaArgs args = { parabola.origin, parabola.velocity, parabola.acceleration, BillboardModeHelpers::getPrimaryViewFrustumPosition(),
+ entityIdsToInclude, entityIdsToDiscard, searchFilter, element, parabolicDistance, face, surfaceNormal, extraInfo, EntityItemID() };
parabolicDistance = FLT_MAX;
distance = FLT_MAX;
@@ -3137,6 +3141,13 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) {
}
}
+ // Before, billboarded entities ignored rotation. Now, they use it to determine which axis is facing you.
+ if (contentVersion < (int)EntityVersion::AllBillboardMode) {
+ if (properties.getBillboardMode() != BillboardMode::NONE) {
+ properties.setRotation(glm::quat());
+ }
+ }
+
EntityItemPointer entity = addEntity(entityItemID, properties, isImport);
if (!entity) {
qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType();
diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp
index 9af0bbfdb6..90c185be8b 100644
--- a/libraries/entities/src/EntityTreeElement.cpp
+++ b/libraries/entities/src/EntityTreeElement.cpp
@@ -162,7 +162,7 @@ bool EntityTreeElement::checkFilterSettings(const EntityItemPointer& entity, Pic
return true;
}
-EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard,
PickFilter searchFilter, QVariantMap& extraInfo) {
@@ -177,7 +177,7 @@ EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, con
QVariantMap localExtraInfo;
float distanceToElementDetails = distance;
- EntityItemID entityID = evalDetailedRayIntersection(origin, direction, element, distanceToElementDetails,
+ EntityItemID entityID = evalDetailedRayIntersection(origin, direction, viewFrustumPos, element, distanceToElementDetails,
localFace, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, searchFilter, localExtraInfo);
if (!entityID.isNull() && distanceToElementDetails < distance) {
distance = distanceToElementDetails;
@@ -189,7 +189,7 @@ EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, con
return result;
}
-EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
const QVector& entityIdsToInclude, const QVector& entityIDsToDiscard,
PickFilter searchFilter, QVariantMap& extraInfo) {
@@ -205,10 +205,7 @@ EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& ori
// (this is faster and more likely to cull results than the filter check below so we do it first)
bool success;
AABox entityBox = entity->getAABox(success);
- if (!success) {
- return;
- }
- if (!entityBox.rayHitsBoundingSphere(origin, direction)) {
+ if (!success || !entityBox.rayHitsBoundingSphere(origin, direction)) {
return;
}
@@ -219,14 +216,17 @@ EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& ori
}
// extents is the entity relative, scaled, centered extents of the entity
- glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
- glm::mat4 translation = glm::translate(entity->getWorldPosition());
+ glm::vec3 position = entity->getWorldPosition();
+ glm::mat4 translation = glm::translate(position);
+ glm::quat orientation = entity->getWorldOrientation();
+ glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(),
+ viewFrustumPos, entity->getRotateForPicking()));
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
- glm::vec3 dimensions = entity->getRaycastDimensions();
+ glm::vec3 dimensions = entity->getScaledDimensions();
glm::vec3 registrationPoint = entity->getRegistrationPoint();
- glm::vec3 corner = -(dimensions * registrationPoint);
+ glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
@@ -244,7 +244,7 @@ EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& ori
// now ask the entity if we actually intersect
if (entity->supportsDetailedIntersection()) {
QVariantMap localExtraInfo;
- if (entity->findDetailedRayIntersection(origin, direction, element, localDistance,
+ if (entity->findDetailedRayIntersection(origin, direction, viewFrustumPos, element, localDistance,
localFace, localSurfaceNormal, localExtraInfo, searchFilter.isPrecise())) {
if (localDistance < distance) {
distance = localDistance;
@@ -277,11 +277,12 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad
bool result = false;
withReadLock([&] {
foreach(EntityItemPointer entity, _entityItems) {
- glm::vec3 entityCenter = entity->getWorldPosition();
+ bool success;
+ glm::vec3 entityCenter = entity->getCenterPosition(success);
float entityRadius = entity->getRadius();
// don't penetrate yourself
- if (entityCenter == center && entityRadius == radius) {
+ if (!success || (entityCenter == center && entityRadius == radius)) {
return;
}
@@ -298,7 +299,7 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad
}
EntityItemID EntityTreeElement::evalParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude,
const QVector& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo) {
@@ -321,7 +322,7 @@ EntityItemID EntityTreeElement::evalParabolaIntersection(const glm::vec3& origin
}
// Get the normal of the plane, the cross product of two vectors on the plane
glm::vec3 normal = glm::normalize(glm::cross(vectorOnPlane, acceleration));
- EntityItemID entityID = evalDetailedParabolaIntersection(origin, velocity, acceleration, normal, element, distanceToElementDetails,
+ EntityItemID entityID = evalDetailedParabolaIntersection(origin, velocity, acceleration, viewFrustumPos, normal, element, distanceToElementDetails,
localFace, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, searchFilter, localExtraInfo);
if (!entityID.isNull() && distanceToElementDetails < parabolicDistance) {
parabolicDistance = distanceToElementDetails;
@@ -334,9 +335,9 @@ EntityItemID EntityTreeElement::evalParabolaIntersection(const glm::vec3& origin
}
EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
- const glm::vec3& normal, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
- const QVector& entityIdsToInclude, const QVector& entityIDsToDiscard,
- PickFilter searchFilter, QVariantMap& extraInfo) {
+ const glm::vec3& viewFrustumPos,const glm::vec3& normal, OctreeElementPointer& element, float& parabolicDistance,
+ BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude,
+ const QVector& entityIDsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo) {
// only called if we do intersect our bounding cube, but find if we actually intersect with entities...
EntityItemID entityID;
@@ -349,15 +350,12 @@ EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3
// (this is faster and more likely to cull results than the filter check below so we do it first)
bool success;
AABox entityBox = entity->getAABox(success);
- if (!success) {
- return;
- }
// Instead of checking parabolaInstersectsBoundingSphere here, we are just going to check if the plane
// defined by the parabola slices the sphere. The solution to parabolaIntersectsBoundingSphere is cubic,
// the solution to which is more computationally expensive than the quadratic AABox::findParabolaIntersection
// below
- if (!entityBox.parabolaPlaneIntersectsBoundingSphere(origin, velocity, acceleration, normal)) {
+ if (!success || !entityBox.parabolaPlaneIntersectsBoundingSphere(origin, velocity, acceleration, normal)) {
return;
}
@@ -368,14 +366,17 @@ EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3
}
// extents is the entity relative, scaled, centered extents of the entity
- glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
- glm::mat4 translation = glm::translate(entity->getWorldPosition());
+ glm::vec3 position = entity->getWorldPosition();
+ glm::mat4 translation = glm::translate(position);
+ glm::quat orientation = entity->getWorldOrientation();
+ glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(),
+ viewFrustumPos, entity->getRotateForPicking()));
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
- glm::vec3 dimensions = entity->getRaycastDimensions();
+ glm::vec3 dimensions = entity->getScaledDimensions();
glm::vec3 registrationPoint = entity->getRegistrationPoint();
- glm::vec3 corner = -(dimensions * registrationPoint);
+ glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
@@ -394,7 +395,7 @@ EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3
// now ask the entity if we actually intersect
if (entity->supportsDetailedIntersection()) {
QVariantMap localExtraInfo;
- if (entity->findDetailedParabolaIntersection(origin, velocity, acceleration, element, localDistance,
+ if (entity->findDetailedParabolaIntersection(origin, velocity, acceleration, viewFrustumPos, element, localDistance,
localFace, localSurfaceNormal, localExtraInfo, searchFilter.isPrecise())) {
if (localDistance < parabolicDistance) {
parabolicDistance = localDistance;
@@ -445,12 +446,11 @@ void EntityTreeElement::evalEntitiesInSphere(const glm::vec3& position, float ra
bool success;
AABox entityBox = entity->getAABox(success);
-
// if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
glm::vec3 penetration;
if (success && entityBox.findSpherePenetration(position, radius, penetration)) {
- glm::vec3 dimensions = entity->getRaycastDimensions();
+ glm::vec3 dimensions = entity->getScaledDimensions();
// FIXME - consider allowing the entity to determine penetration so that
// entities could presumably do actual hull testing if they wanted to
@@ -464,21 +464,20 @@ void EntityTreeElement::evalEntitiesInSphere(const glm::vec3& position, float ra
float entityTrueRadius = dimensions.x / 2.0f;
bool success;
- if (findSphereSpherePenetration(position, radius, entity->getCenterPosition(success), entityTrueRadius, penetration)) {
- if (success) {
- foundEntities.push_back(entity->getID());
- }
+ glm::vec3 center = entity->getCenterPosition(success);
+ if (success && findSphereSpherePenetration(position, radius, center, entityTrueRadius, penetration)) {
+ foundEntities.push_back(entity->getID());
}
} else {
// determine the worldToEntityMatrix that doesn't include scale because
// we're going to use the registration aware aa box in the entity frame
- glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
glm::mat4 translation = glm::translate(entity->getWorldPosition());
+ glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
glm::vec3 registrationPoint = entity->getRegistrationPoint();
- glm::vec3 corner = -(dimensions * registrationPoint);
+ glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
@@ -499,12 +498,11 @@ void EntityTreeElement::evalEntitiesInSphereWithType(const glm::vec3& position,
bool success;
AABox entityBox = entity->getAABox(success);
-
// if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
glm::vec3 penetration;
if (success && entityBox.findSpherePenetration(position, radius, penetration)) {
- glm::vec3 dimensions = entity->getRaycastDimensions();
+ glm::vec3 dimensions = entity->getScaledDimensions();
// FIXME - consider allowing the entity to determine penetration so that
// entities could presumably do actual hull testing if they wanted to
@@ -518,21 +516,20 @@ void EntityTreeElement::evalEntitiesInSphereWithType(const glm::vec3& position,
float entityTrueRadius = dimensions.x / 2.0f;
bool success;
- if (findSphereSpherePenetration(position, radius, entity->getCenterPosition(success), entityTrueRadius, penetration)) {
- if (success) {
- foundEntities.push_back(entity->getID());
- }
+ glm::vec3 center = entity->getCenterPosition(success);
+ if (success && findSphereSpherePenetration(position, radius, center, entityTrueRadius, penetration)) {
+ foundEntities.push_back(entity->getID());
}
} else {
// determine the worldToEntityMatrix that doesn't include scale because
// we're going to use the registration aware aa box in the entity frame
- glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
glm::mat4 translation = glm::translate(entity->getWorldPosition());
+ glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
glm::vec3 registrationPoint = entity->getRegistrationPoint();
- glm::vec3 corner = -(dimensions * registrationPoint);
+ glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
@@ -563,7 +560,7 @@ void EntityTreeElement::evalEntitiesInSphereWithName(const glm::vec3& position,
glm::vec3 penetration;
if (success && entityBox.findSpherePenetration(position, radius, penetration)) {
- glm::vec3 dimensions = entity->getRaycastDimensions();
+ glm::vec3 dimensions = entity->getScaledDimensions();
// FIXME - consider allowing the entity to determine penetration so that
// entities could presumably do actual hull testing if they wanted to
@@ -575,23 +572,22 @@ void EntityTreeElement::evalEntitiesInSphereWithName(const glm::vec3& position,
// NOTE: entity->getRadius() doesn't return the true radius, it returns the radius of the
// maximum bounding sphere, which is actually larger than our actual radius
float entityTrueRadius = dimensions.x / 2.0f;
-
bool success;
- if (findSphereSpherePenetration(position, radius, entity->getCenterPosition(success), entityTrueRadius, penetration)) {
- if (success) {
- foundEntities.push_back(entity->getID());
- }
+ glm::vec3 center = entity->getCenterPosition(success);
+
+ if (success && findSphereSpherePenetration(position, radius, center, entityTrueRadius, penetration)) {
+ foundEntities.push_back(entity->getID());
}
} else {
// determine the worldToEntityMatrix that doesn't include scale because
// we're going to use the registration aware aa box in the entity frame
- glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
glm::mat4 translation = glm::translate(entity->getWorldPosition());
+ glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
glm::vec3 registrationPoint = entity->getRegistrationPoint();
- glm::vec3 corner = -(dimensions * registrationPoint);
+ glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
@@ -612,6 +608,7 @@ void EntityTreeElement::evalEntitiesInCube(const AACube& cube, PickFilter search
bool success;
AABox entityBox = entity->getAABox(success);
+
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better
// FIXME - consider allowing the entity to determine penetration so that
// entities could presumably dull actuall hull testing if they wanted to
@@ -642,6 +639,7 @@ void EntityTreeElement::evalEntitiesInBox(const AABox& box, PickFilter searchFil
bool success;
AABox entityBox = entity->getAABox(success);
+
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better
// FIXME - consider allowing the entity to determine penetration so that
// entities could presumably dull actuall hull testing if they wanted to
@@ -680,7 +678,7 @@ void EntityTreeElement::evalEntitiesInFrustum(const ViewFrustum& frustum, PickFi
});
}
-void EntityTreeElement::getEntities(EntityItemFilter& filter, QVector& foundEntities) {
+void EntityTreeElement::getEntities(EntityItemFilter& filter, QVector& foundEntities) {
forEachEntity([&](EntityItemPointer entity) {
if (filter(entity)) {
foundEntities.push_back(entity);
diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h
index f94da44138..dab56132c9 100644
--- a/libraries/entities/src/EntityTreeElement.h
+++ b/libraries/entities/src/EntityTreeElement.h
@@ -136,24 +136,24 @@ public:
static bool checkFilterSettings(const EntityItemPointer& entity, PickFilter searchFilter);
virtual bool canPickIntersect() const override { return hasEntities(); }
- virtual EntityItemID evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+ virtual EntityItemID evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard,
PickFilter searchFilter, QVariantMap& extraInfo);
virtual EntityItemID evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude,
const QVector& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const override;
virtual EntityItemID evalParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude,
const QVector& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
virtual EntityItemID evalDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& normal, const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude,
+ const glm::vec3& normal, const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude,
const QVector& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
template
diff --git a/libraries/entities/src/GizmoEntityItem.cpp b/libraries/entities/src/GizmoEntityItem.cpp
index 47c9afd168..694371d739 100644
--- a/libraries/entities/src/GizmoEntityItem.cpp
+++ b/libraries/entities/src/GizmoEntityItem.cpp
@@ -103,14 +103,15 @@ bool GizmoEntityItem::supportsDetailedIntersection() const {
}
bool GizmoEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const {
glm::vec3 dimensions = getScaledDimensions();
glm::vec2 xyDimensions(dimensions.x, dimensions.z);
glm::quat rotation = getWorldOrientation();
- rotation = glm::angleAxis(-(float)M_PI_2, rotation * Vectors::RIGHT) * rotation;
+ rotation *= glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
+ rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 hitPosition = origin + (distance * direction);
@@ -136,15 +137,16 @@ bool GizmoEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
}
bool GizmoEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
- OctreeElementPointer& element, float& parabolicDistance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const {
//// Scale the dimensions by the diameter
glm::vec3 dimensions = getScaledDimensions();
glm::vec2 xyDimensions(dimensions.x, dimensions.z);
glm::quat rotation = getWorldOrientation();
- rotation = glm::angleAxis(-(float)M_PI_2, rotation * Vectors::RIGHT) * rotation;
+ rotation *= glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
glm::vec3 position = getWorldPosition();
+ rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
glm::quat inverseRot = glm::inverse(rotation);
glm::vec3 localOrigin = inverseRot * (origin - position);
diff --git a/libraries/entities/src/GizmoEntityItem.h b/libraries/entities/src/GizmoEntityItem.h
index 37a802387d..a05c294523 100644
--- a/libraries/entities/src/GizmoEntityItem.h
+++ b/libraries/entities/src/GizmoEntityItem.h
@@ -45,13 +45,14 @@ public:
bool supportsDetailedIntersection() const override;
bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
+ bool getRotateForPicking() const override { return getBillboardMode() != BillboardMode::NONE; }
GizmoType getGizmoType() const;
void setGizmoType(GizmoType value);
diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp
index 6a8c457b0a..afa6d9ae69 100644
--- a/libraries/entities/src/ImageEntityItem.cpp
+++ b/libraries/entities/src/ImageEntityItem.cpp
@@ -35,7 +35,6 @@ EntityItemProperties ImageEntityItem::getProperties(const EntityPropertyFlags& d
withReadLock([&] {
_pulseProperties.getProperties(properties);
});
- COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getImageURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emissive, getEmissive);
@@ -55,7 +54,6 @@ bool ImageEntityItem::setSubClassProperties(const EntityItemProperties& properti
somethingChanged |= pulsePropertiesChanged;
_needsRenderUpdate |= pulsePropertiesChanged;
});
- SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setImageURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emissive, setEmissive);
@@ -82,7 +80,6 @@ int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesRead += bytesFromPulse;
dataAt += bytesFromPulse;
});
- READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setImageURL);
READ_ENTITY_PROPERTY(PROP_EMISSIVE, bool, setEmissive);
@@ -98,7 +95,6 @@ EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams&
requestedProperties += PROP_COLOR;
requestedProperties += PROP_ALPHA;
requestedProperties += _pulseProperties.getEntityProperties(params);
- requestedProperties += PROP_BILLBOARD_MODE;
requestedProperties += PROP_IMAGE_URL;
requestedProperties += PROP_EMISSIVE;
@@ -124,7 +120,6 @@ void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
});
- APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, getImageURL());
APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, getEmissive());
@@ -132,69 +127,6 @@ void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, getSubImage());
}
-glm::vec3 ImageEntityItem::getRaycastDimensions() const {
- glm::vec3 dimensions = getScaledDimensions();
- if (getBillboardMode() != BillboardMode::NONE) {
- float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
- const float SQRT_2 = 1.41421356237f;
- return glm::vec3(SQRT_2 * max);
- }
- return dimensions;
-}
-
-bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element,
- float& distance, BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const {
- glm::vec3 dimensions = getScaledDimensions();
- glm::vec2 xyDimensions(dimensions.x, dimensions.y);
- glm::quat rotation = getWorldOrientation();
- glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
- rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());
-
- if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
- glm::vec3 forward = rotation * Vectors::FRONT;
- if (glm::dot(forward, direction) > 0.0f) {
- face = MAX_Z_FACE;
- surfaceNormal = -forward;
- } else {
- face = MIN_Z_FACE;
- surfaceNormal = forward;
- }
- return true;
- }
- return false;
-}
-
-bool ImageEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
- OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const {
- glm::vec3 dimensions = getScaledDimensions();
- glm::vec2 xyDimensions(dimensions.x, dimensions.y);
- glm::quat rotation = getWorldOrientation();
- glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
-
- glm::quat inverseRot = glm::inverse(rotation);
- glm::vec3 localOrigin = inverseRot * (origin - position);
- glm::vec3 localVelocity = inverseRot * velocity;
- glm::vec3 localAcceleration = inverseRot * acceleration;
-
- if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) {
- float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
- glm::vec3 forward = rotation * Vectors::FRONT;
- if (localIntersectionVelocityZ > 0.0f) {
- face = MIN_Z_FACE;
- surfaceNormal = forward;
- } else {
- face = MAX_Z_FACE;
- surfaceNormal = -forward;
- }
- return true;
- }
- return false;
-}
-
QString ImageEntityItem::getImageURL() const {
QString result;
withReadLock([&] {
@@ -240,21 +172,6 @@ void ImageEntityItem::setKeepAspectRatio(bool keepAspectRatio) {
});
}
-BillboardMode ImageEntityItem::getBillboardMode() const {
- BillboardMode result;
- withReadLock([&] {
- result = _billboardMode;
- });
- return result;
-}
-
-void ImageEntityItem::setBillboardMode(BillboardMode value) {
- withWriteLock([&] {
- _needsRenderUpdate |= _billboardMode != value;
- _billboardMode = value;
- });
-}
-
QRect ImageEntityItem::getSubImage() const {
QRect result;
withReadLock([&] {
diff --git a/libraries/entities/src/ImageEntityItem.h b/libraries/entities/src/ImageEntityItem.h
index bca67dc738..4f7aac0c13 100644
--- a/libraries/entities/src/ImageEntityItem.h
+++ b/libraries/entities/src/ImageEntityItem.h
@@ -43,17 +43,6 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
- glm::vec3 getRaycastDimensions() const override;
- virtual bool supportsDetailedIntersection() const override { return true; }
- virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const override;
- virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const override;
-
void setImageURL(const QString& imageUrl);
QString getImageURL() const;
@@ -63,9 +52,6 @@ public:
void setKeepAspectRatio(bool keepAspectRatio);
bool getKeepAspectRatio() const;
- void setBillboardMode(BillboardMode value);
- BillboardMode getBillboardMode() const;
-
void setSubImage(const QRect& subImage);
QRect getSubImage() const;
@@ -81,7 +67,6 @@ protected:
glm::u8vec3 _color;
float _alpha;
PulsePropertyGroup _pulseProperties;
- BillboardMode _billboardMode;
QString _imageURL;
bool _emissive { false };
diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp
index 715b457bde..a3e00cddba 100644
--- a/libraries/entities/src/LightEntityItem.cpp
+++ b/libraries/entities/src/LightEntityItem.cpp
@@ -78,7 +78,14 @@ void LightEntityItem::setFalloffRadius(float value) {
}
void LightEntityItem::setIsSpotlight(bool value) {
- if (value == getIsSpotlight()) {
+ bool needsRenderUpdate;
+ withWriteLock([&] {
+ needsRenderUpdate = value != _isSpotlight;
+ _needsRenderUpdate |= needsRenderUpdate;
+ _isSpotlight = value;
+ });
+
+ if (!needsRenderUpdate) {
return;
}
@@ -92,25 +99,25 @@ void LightEntityItem::setIsSpotlight(bool value) {
newDimensions = glm::vec3(glm::compMax(dimensions));
}
- withWriteLock([&] {
- _needsRenderUpdate = true;
- _isSpotlight = value;
- });
setScaledDimensions(newDimensions);
}
void LightEntityItem::setCutoff(float value) {
value = glm::clamp(value, MIN_CUTOFF, MAX_CUTOFF);
- if (value == getCutoff()) {
+ bool needsRenderUpdate;
+ bool spotlight;
+ withWriteLock([&] {
+ needsRenderUpdate = value != _cutoff;
+ _needsRenderUpdate |= needsRenderUpdate;
+ _cutoff = value;
+ spotlight = _isSpotlight;
+ });
+
+ if (!needsRenderUpdate) {
return;
}
- withWriteLock([&] {
- _needsRenderUpdate = true;
- _cutoff = value;
- });
-
- if (getIsSpotlight()) {
+ if (spotlight) {
// If we are a spotlight, adjusting the cutoff will affect the area we encapsulate,
// so update the dimensions to reflect this.
const float length = getScaledDimensions().z;
@@ -247,7 +254,7 @@ float LightEntityItem::getCutoff() const {
}
bool LightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const {
@@ -260,8 +267,8 @@ bool LightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
}
bool LightEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const {
// TODO: consider if this is really what we want to do. We've made it so that "lights are pickable" is a global state
// this is probably reasonable since there's typically only one tree you'd be picking on at a time. Technically we could
diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h
index 5245770ec8..0f21c6acd9 100644
--- a/libraries/entities/src/LightEntityItem.h
+++ b/libraries/entities/src/LightEntityItem.h
@@ -74,12 +74,12 @@ public:
virtual bool supportsDetailedIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
private:
diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h
index 38e526204e..505291cdda 100644
--- a/libraries/entities/src/LineEntityItem.h
+++ b/libraries/entities/src/LineEntityItem.h
@@ -52,13 +52,13 @@ class LineEntityItem : public EntityItem {
// never have a ray intersection pick a LineEntityItem.
virtual bool supportsDetailedIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo,
bool precisionPicking) const override { return false; }
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo,
bool precisionPicking) const override { return false; }
diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp
index cd27c1cf36..61362896ee 100644
--- a/libraries/entities/src/ModelEntityItem.cpp
+++ b/libraries/entities/src/ModelEntityItem.cpp
@@ -73,6 +73,7 @@ EntityItemProperties ModelEntityItem::getProperties(const EntityPropertyFlags& d
COPY_ENTITY_PROPERTY_TO_PROPERTIES(relayParentJoints, getRelayParentJoints);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(groupCulled, getGroupCulled);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendshapeCoefficients, getBlendshapeCoefficients);
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(useOriginalPivot, getUseOriginalPivot);
withReadLock([&] {
_animationProperties.getProperties(properties);
});
@@ -96,6 +97,7 @@ bool ModelEntityItem::setSubClassProperties(const EntityItemProperties& properti
SET_ENTITY_PROPERTY_FROM_PROPERTIES(relayParentJoints, setRelayParentJoints);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(groupCulled, setGroupCulled);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendshapeCoefficients, setBlendshapeCoefficients);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(useOriginalPivot, setUseOriginalPivot);
withWriteLock([&] {
AnimationPropertyGroup animationProperties = _animationProperties;
@@ -130,6 +132,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints);
READ_ENTITY_PROPERTY(PROP_GROUP_CULLED, bool, setGroupCulled);
READ_ENTITY_PROPERTY(PROP_BLENDSHAPE_COEFFICIENTS, QString, setBlendshapeCoefficients);
+ READ_ENTITY_PROPERTY(PROP_USE_ORIGINAL_PIVOT, bool, setUseOriginalPivot);
// grab a local copy of _animationProperties to avoid multiple locks
int bytesFromAnimation;
@@ -169,6 +172,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams&
requestedProperties += PROP_RELAY_PARENT_JOINTS;
requestedProperties += PROP_GROUP_CULLED;
requestedProperties += PROP_BLENDSHAPE_COEFFICIENTS;
+ requestedProperties += PROP_USE_ORIGINAL_PIVOT;
requestedProperties += _animationProperties.getEntityProperties(params);
return requestedProperties;
@@ -198,6 +202,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, getRelayParentJoints());
APPEND_ENTITY_PROPERTY(PROP_GROUP_CULLED, getGroupCulled());
APPEND_ENTITY_PROPERTY(PROP_BLENDSHAPE_COEFFICIENTS, getBlendshapeCoefficients());
+ APPEND_ENTITY_PROPERTY(PROP_USE_ORIGINAL_PIVOT, getUseOriginalPivot());
withReadLock([&] {
_animationProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
@@ -251,29 +256,34 @@ void ModelEntityItem::debugDump() const {
qCDebug(entities) << " model URL:" << getModelURL();
qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL();
qCDebug(entities) << " blendshapeCoefficients:" << getBlendshapeCoefficients();
+ qCDebug(entities) << " useOrigialPivot:" << getUseOriginalPivot();
}
void ModelEntityItem::setShapeType(ShapeType type) {
+ bool changed = false;
+ uint32_t flags = 0;
withWriteLock([&] {
if (type != _shapeType) {
if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) {
// dynamic and STATIC_MESH are incompatible
// since the shape is being set here we clear the dynamic bit
_dynamic = false;
- _flags |= Simulation::DIRTY_MOTION_TYPE;
+ flags = Simulation::DIRTY_MOTION_TYPE;
}
_shapeType = type;
- _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+ flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+ changed = true;
}
});
+
+ if (changed) {
+ markDirtyFlags(flags);
+ locationChanged();
+ }
}
ShapeType ModelEntityItem::getShapeType() const {
- return computeTrueShapeType();
-}
-
-ShapeType ModelEntityItem::computeTrueShapeType() const {
- ShapeType type = _shapeType;
+ ShapeType type = resultWithReadLock([&] { return _shapeType; });
if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) {
// dynamic is incompatible with STATIC_MESH
// shouldn't fall in here but just in case --> fall back to COMPOUND
@@ -290,7 +300,6 @@ void ModelEntityItem::setModelURL(const QString& url) {
withWriteLock([&] {
if (_modelURL != url) {
_modelURL = url;
- _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
_needsRenderUpdate = true;
}
});
@@ -325,18 +334,10 @@ void ModelEntityItem::setCompoundShapeURL(const QString& url) {
withWriteLock([&] {
if (_compoundShapeURL.get() != url) {
_compoundShapeURL.set(url);
- _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
});
}
-void ModelEntityItem::setAnimationURL(const QString& url) {
- _flags |= Simulation::DIRTY_UPDATEABLE;
- withWriteLock([&] {
- _animationProperties.setURL(url);
- });
-}
-
void ModelEntityItem::setAnimationSettings(const QString& value) {
// NOTE: this method only called for old bitstream format
@@ -399,20 +400,6 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
});
}
-void ModelEntityItem::setAnimationIsPlaying(bool value) {
- _flags |= Simulation::DIRTY_UPDATEABLE;
- withWriteLock([&] {
- _animationProperties.setRunning(value);
- });
-}
-
-void ModelEntityItem::setAnimationFPS(float value) {
- _flags |= Simulation::DIRTY_UPDATEABLE;
- withWriteLock([&] {
- _animationProperties.setFPS(value);
- });
-}
-
void ModelEntityItem::resizeJointArrays(int newSize) {
if (newSize < 0) {
return;
@@ -588,10 +575,6 @@ QString ModelEntityItem::getCompoundShapeURL() const {
return _compoundShapeURL.get();
}
-QString ModelEntityItem::getCollisionShapeURL() const {
- return getShapeType() == SHAPE_TYPE_COMPOUND ? getCompoundShapeURL() : getModelURL();
-}
-
void ModelEntityItem::setColor(const glm::u8vec3& value) {
withWriteLock([&] {
_color = value;
@@ -629,61 +612,18 @@ void ModelEntityItem::setAnimationCurrentFrame(float value) {
});
}
-void ModelEntityItem::setAnimationAllowTranslation(bool value) {
- withWriteLock([&] {
- _animationProperties.setAllowTranslation(value);
- });
-}
-
bool ModelEntityItem::getAnimationAllowTranslation() const {
return resultWithReadLock([&] {
return _animationProperties.getAllowTranslation();
});
}
-void ModelEntityItem::setAnimationLoop(bool loop) {
- withWriteLock([&] {
- _animationProperties.setLoop(loop);
- });
-}
-
-bool ModelEntityItem::getAnimationLoop() const {
- return resultWithReadLock([&] {
- return _animationProperties.getLoop();
- });
-}
-
-
-void ModelEntityItem::setAnimationHold(bool hold) {
- withWriteLock([&] {
- _animationProperties.setHold(hold);
- });
-}
-
-bool ModelEntityItem::getAnimationHold() const {
- return resultWithReadLock([&] {
- return _animationProperties.getHold();
- });
-}
-
-bool ModelEntityItem::getAnimationIsPlaying() const {
- return resultWithReadLock([&] {
- return _animationProperties.getRunning();
- });
-}
-
float ModelEntityItem::getAnimationCurrentFrame() const {
return resultWithReadLock([&] {
return _animationProperties.getCurrentFrame();
});
}
-float ModelEntityItem::getAnimationFPS() const {
- return resultWithReadLock([&] {
- return _animationProperties.getFPS();
- });
-}
-
bool ModelEntityItem::isAnimatingSomething() const {
return resultWithReadLock([&] {
return _animationProperties.isValidAndRunning();
@@ -722,6 +662,7 @@ bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProp
bool somethingChanged = newProperties != _animationProperties;
if (somethingChanged) {
_animationProperties = newProperties;
+ _needsRenderUpdate = true;
_flags |= Simulation::DIRTY_UPDATEABLE;
}
return somethingChanged;
@@ -778,3 +719,25 @@ QVector ModelEntityItem::getBlendshapeCoefficientVector() {
return _blendshapeCoefficientsVector;
});
}
+
+void ModelEntityItem::setUseOriginalPivot(bool value) {
+ bool changed = false;
+ withWriteLock([&] {
+ if (_useOriginalPivot != value) {
+ _needsRenderUpdate = true;
+ _useOriginalPivot = value;
+ changed = true;
+ }
+ });
+
+ if (changed) {
+ markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+ locationChanged();
+ }
+}
+
+bool ModelEntityItem::getUseOriginalPivot() const {
+ return resultWithReadLock([&] {
+ return _useOriginalPivot;
+ });
+}
diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h
index 795630a72a..6e92b225a1 100644
--- a/libraries/entities/src/ModelEntityItem.h
+++ b/libraries/entities/src/ModelEntityItem.h
@@ -76,33 +76,18 @@ public:
static const QString DEFAULT_COMPOUND_SHAPE_URL;
QString getCompoundShapeURL() const;
- // Returns the URL used for the collision shape
- QString getCollisionShapeURL() const;
-
// model related properties
virtual void setModelURL(const QString& url);
virtual void setCompoundShapeURL(const QString& url);
// Animation related items...
AnimationPropertyGroup getAnimationProperties() const;
-
- // TODO: audit and remove unused Animation accessors
bool hasAnimation() const;
QString getAnimationURL() const;
- virtual void setAnimationURL(const QString& url);
-
void setAnimationCurrentFrame(float value);
- void setAnimationIsPlaying(bool value);
- void setAnimationFPS(float value);
-
- void setAnimationAllowTranslation(bool value);
+ float getAnimationCurrentFrame() const;
bool getAnimationAllowTranslation() const;
-
- void setAnimationLoop(bool loop);
- bool getAnimationLoop() const;
-
- void setAnimationHold(bool hold);
- bool getAnimationHold() const;
+ bool isAnimatingSomething() const;
void setRelayParentJoints(bool relayJoints);
bool getRelayParentJoints() const;
@@ -110,11 +95,6 @@ public:
void setGroupCulled(bool value);
bool getGroupCulled() const;
- bool getAnimationIsPlaying() const;
- float getAnimationCurrentFrame() const;
- float getAnimationFPS() const;
- bool isAnimatingSomething() const;
-
static const QString DEFAULT_TEXTURES;
const QString getTextures() const;
void setTextures(const QString& textures);
@@ -139,10 +119,12 @@ public:
bool blendshapesChanged() const { return _blendshapesChanged; }
QVector getBlendshapeCoefficientVector();
+ bool getUseOriginalPivot() const;
+ void setUseOriginalPivot(bool useOriginalPivot);
+
private:
void setAnimationSettings(const QString& value); // only called for old bitstream format
bool applyNewAnimationProperties(AnimationPropertyGroup newProperties);
- ShapeType computeTrueShapeType() const;
protected:
void resizeJointArrays(int newSize);
@@ -173,6 +155,7 @@ protected:
bool _relayParentJoints;
bool _groupCulled { false };
QVariantMap _blendshapeCoefficientsMap;
+ bool _useOriginalPivot { false };
ThreadSafeValueCache _compoundShapeURL;
diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp
index 909bc132fb..4aaf0ad521 100644
--- a/libraries/entities/src/PolyLineEntityItem.cpp
+++ b/libraries/entities/src/PolyLineEntityItem.cpp
@@ -266,21 +266,21 @@ glm::u8vec3 PolyLineEntityItem::getColor() const {
void PolyLineEntityItem::setIsUVModeStretch(bool isUVModeStretch) {
withWriteLock([&] {
- _needsRenderUpdate = _isUVModeStretch != isUVModeStretch;
+ _needsRenderUpdate |= _isUVModeStretch != isUVModeStretch;
_isUVModeStretch = isUVModeStretch;
});
}
void PolyLineEntityItem::setGlow(bool glow) {
withWriteLock([&] {
- _needsRenderUpdate = _glow != glow;
+ _needsRenderUpdate |= _glow != glow;
_glow = glow;
});
}
void PolyLineEntityItem::setFaceCamera(bool faceCamera) {
withWriteLock([&] {
- _needsRenderUpdate = _faceCamera != faceCamera;
+ _needsRenderUpdate |= _faceCamera != faceCamera;
_faceCamera = faceCamera;
});
}
diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h
index 8fb7831c6a..23f6e36e73 100644
--- a/libraries/entities/src/PolyLineEntityItem.h
+++ b/libraries/entities/src/PolyLineEntityItem.h
@@ -82,12 +82,12 @@ public:
// never have a ray intersection pick a PolyLineEntityItem.
virtual bool supportsDetailedIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
void computeTightLocalBoundingBox(AABox& box) const;
diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp
index dd55ca898b..5ed9f69b5a 100644
--- a/libraries/entities/src/PolyVoxEntityItem.cpp
+++ b/libraries/entities/src/PolyVoxEntityItem.cpp
@@ -377,15 +377,21 @@ glm::mat4 PolyVoxEntityItem::localToVoxelMatrix() const {
return localToModelMatrix;
}
-glm::mat4 PolyVoxEntityItem::voxelToWorldMatrix() const {
- glm::mat4 rotation = glm::mat4_cast(getWorldOrientation());
- glm::mat4 translation = glm::translate(getWorldPosition());
+glm::mat4 PolyVoxEntityItem::voxelToWorldMatrix(bool includeBillboard) const {
+ glm::quat orientation = getWorldOrientation();
+ glm::vec3 position = getWorldPosition();
+ glm::mat4 translation = glm::translate(position);
+ glm::mat4 rotation;
+ if (includeBillboard) {
+ rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition()));
+ } else {
+ rotation = glm::mat4_cast(orientation);
+ }
return translation * rotation * voxelToLocalMatrix();
}
-glm::mat4 PolyVoxEntityItem::worldToVoxelMatrix() const {
- glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix());
- return worldToModelMatrix;
+glm::mat4 PolyVoxEntityItem::worldToVoxelMatrix(bool includeBillboard) const {
+ return glm::inverse(voxelToWorldMatrix(includeBillboard));
}
glm::vec3 PolyVoxEntityItem::voxelCoordsToWorldCoords(const glm::vec3& voxelCoords) const {
diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h
index f994fcd37c..3e3fe0b18c 100644
--- a/libraries/entities/src/PolyVoxEntityItem.h
+++ b/libraries/entities/src/PolyVoxEntityItem.h
@@ -44,12 +44,12 @@ class PolyVoxEntityItem : public EntityItem {
// never have a ray intersection pick a PolyVoxEntityItem.
virtual bool supportsDetailedIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
virtual void debugDump() const override;
@@ -167,8 +167,8 @@ class PolyVoxEntityItem : public EntityItem {
bool isEdged() const;
- glm::mat4 voxelToWorldMatrix() const;
- glm::mat4 worldToVoxelMatrix() const;
+ glm::mat4 voxelToWorldMatrix(bool includeBillboard = false) const;
+ glm::mat4 worldToVoxelMatrix(bool includeBillboard = false) const;
glm::mat4 voxelToLocalMatrix() const;
glm::mat4 localToVoxelMatrix() const;
diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp
index 5e140665b3..7858e62f7d 100644
--- a/libraries/entities/src/ShapeEntityItem.cpp
+++ b/libraries/entities/src/ShapeEntityItem.cpp
@@ -257,7 +257,8 @@ float ShapeEntityItem::getAlpha() const {
void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) {
const float MAX_FLAT_DIMENSION = 0.0001f;
- if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
+ const auto shape = getShape();
+ if ((shape == entity::Shape::Circle || shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
// enforce flatness in Y
glm::vec3 newDimensions = value;
newDimensions.y = MAX_FLAT_DIMENSION;
@@ -268,15 +269,20 @@ void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) {
}
bool ShapeEntityItem::supportsDetailedIntersection() const {
- return _shape == entity::Sphere;
+ return getShape() == entity::Sphere;
}
bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element,
- float& distance, BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const {
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& distance, BoxFace& face, glm::vec3& surfaceNormal,
+ QVariantMap& extraInfo, bool precisionPicking) const {
+ glm::vec3 dimensions = getScaledDimensions();
+ glm::quat rotation = getWorldOrientation();
+ glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
+ rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
+
// determine the ray in the frame of the entity transformed from a unit sphere
- glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
+ glm::mat4 entityToWorldMatrix = glm::translate(position) * glm::mat4_cast(rotation) * glm::scale(dimensions);
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
@@ -299,11 +305,16 @@ bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
}
bool ShapeEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
- OctreeElementPointer& element, float& parabolicDistance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const {
+ glm::vec3 dimensions = getScaledDimensions();
+ glm::quat rotation = getWorldOrientation();
+ glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
+ rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
+
// determine the parabola in the frame of the entity transformed from a unit sphere
- glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
+ glm::mat4 entityToWorldMatrix = glm::translate(position) * glm::mat4_cast(rotation) * glm::scale(dimensions);
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
glm::vec3 entityFrameVelocity = glm::vec3(worldToEntityMatrix * glm::vec4(velocity, 0.0f));
@@ -324,6 +335,11 @@ bool ShapeEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin,
return false;
}
+bool ShapeEntityItem::getRotateForPicking() const {
+ auto shape = getShape();
+ return getBillboardMode() != BillboardMode::NONE && (_shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron);
+}
+
void ShapeEntityItem::debugDump() const {
quint64 now = usecTimestampNow();
qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------";
@@ -343,8 +359,9 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
// is set.
const glm::vec3 entityDimensions = getScaledDimensions();
+ const auto shape = getShape();
- switch (_shape){
+ switch (shape){
case entity::Shape::Quad:
// Quads collide like flat Cubes
case entity::Shape::Cube: {
@@ -442,4 +459,11 @@ PulsePropertyGroup ShapeEntityItem::getPulseProperties() const {
return resultWithReadLock([&] {
return _pulseProperties;
});
+}
+
+void ShapeEntityItem::setUserData(const QString& value) {
+ withWriteLock([&] {
+ _needsRenderUpdate |= _userData != value;
+ _userData = value;
+ });
}
\ No newline at end of file
diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h
index 7320867430..d5b934153a 100644
--- a/libraries/entities/src/ShapeEntityItem.h
+++ b/libraries/entities/src/ShapeEntityItem.h
@@ -86,13 +86,14 @@ public:
bool supportsDetailedIntersection() const override;
bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const override;
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& distance, BoxFace& face, glm::vec3& surfaceNormal,
+ QVariantMap& extraInfo, bool precisionPicking) const override;
bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
+ bool getRotateForPicking() const override;
void debugDump() const override;
@@ -101,6 +102,8 @@ public:
PulsePropertyGroup getPulseProperties() const;
+ void setUserData(const QString& value) override;
+
protected:
glm::u8vec3 _color;
float _alpha { 1.0f };
diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp
index a996319463..ebe536cae8 100644
--- a/libraries/entities/src/TextEntityItem.cpp
+++ b/libraries/entities/src/TextEntityItem.cpp
@@ -53,7 +53,6 @@ EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& de
withReadLock([&] {
_pulseProperties.getProperties(properties);
});
- COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(text, getText);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight);
@@ -81,7 +80,6 @@ bool TextEntityItem::setSubClassProperties(const EntityItemProperties& propertie
somethingChanged |= pulsePropertiesChanged;
_needsRenderUpdate |= pulsePropertiesChanged;
});
- SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(text, setText);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineHeight, setLineHeight);
@@ -117,7 +115,6 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesRead += bytesFromPulse;
dataAt += bytesFromPulse;
});
- READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY(PROP_TEXT, QString, setText);
READ_ENTITY_PROPERTY(PROP_LINE_HEIGHT, float, setLineHeight);
@@ -142,7 +139,6 @@ EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& p
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += _pulseProperties.getEntityProperties(params);
- requestedProperties += PROP_BILLBOARD_MODE;
requestedProperties += PROP_TEXT;
requestedProperties += PROP_LINE_HEIGHT;
@@ -177,7 +173,6 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
});
- APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_TEXT, getText());
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, getLineHeight());
@@ -196,69 +191,6 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT_THICKNESS, getTextEffectThickness());
}
-glm::vec3 TextEntityItem::getRaycastDimensions() const {
- glm::vec3 dimensions = getScaledDimensions();
- if (getBillboardMode() != BillboardMode::NONE) {
- float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
- const float SQRT_2 = 1.41421356237f;
- return glm::vec3(SQRT_2 * max);
- }
- return dimensions;
-}
-
-bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const {
- glm::vec3 dimensions = getScaledDimensions();
- glm::vec2 xyDimensions(dimensions.x, dimensions.y);
- glm::quat rotation = getWorldOrientation();
- glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
- rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());
-
- if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
- glm::vec3 forward = rotation * Vectors::FRONT;
- if (glm::dot(forward, direction) > 0.0f) {
- face = MAX_Z_FACE;
- surfaceNormal = -forward;
- } else {
- face = MIN_Z_FACE;
- surfaceNormal = forward;
- }
- return true;
- }
- return false;
-}
-
-bool TextEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
- OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const {
- glm::vec3 dimensions = getScaledDimensions();
- glm::vec2 xyDimensions(dimensions.x, dimensions.y);
- glm::quat rotation = getWorldOrientation();
- glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
-
- glm::quat inverseRot = glm::inverse(rotation);
- glm::vec3 localOrigin = inverseRot * (origin - position);
- glm::vec3 localVelocity = inverseRot * velocity;
- glm::vec3 localAcceleration = inverseRot * acceleration;
-
- if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) {
- float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
- glm::vec3 forward = rotation * Vectors::FRONT;
- if (localIntersectionVelocityZ > 0.0f) {
- face = MIN_Z_FACE;
- surfaceNormal = forward;
- } else {
- face = MAX_Z_FACE;
- surfaceNormal = -forward;
- }
- return true;
- }
- return false;
-}
-
void TextEntityItem::setText(const QString& value) {
withWriteLock([&] {
_needsRenderUpdate |= _text != value;
@@ -339,21 +271,6 @@ float TextEntityItem::getBackgroundAlpha() const {
});
}
-BillboardMode TextEntityItem::getBillboardMode() const {
- BillboardMode result;
- withReadLock([&] {
- result = _billboardMode;
- });
- return result;
-}
-
-void TextEntityItem::setBillboardMode(BillboardMode value) {
- withWriteLock([&] {
- _needsRenderUpdate |= _billboardMode != value;
- _billboardMode = value;
- });
-}
-
void TextEntityItem::setLeftMargin(float value) {
withWriteLock([&] {
_needsRenderUpdate |= _leftMargin != value;
diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h
index 91496708f6..3e58831a72 100644
--- a/libraries/entities/src/TextEntityItem.h
+++ b/libraries/entities/src/TextEntityItem.h
@@ -48,17 +48,6 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
- glm::vec3 getRaycastDimensions() const override;
- virtual bool supportsDetailedIntersection() const override { return true; }
- virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const override;
- virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const override;
-
static const QString DEFAULT_TEXT;
void setText(const QString& value);
QString getText() const;
@@ -82,9 +71,6 @@ public:
float getBackgroundAlpha() const;
void setBackgroundAlpha(float value);
- BillboardMode getBillboardMode() const;
- void setBillboardMode(BillboardMode value);
-
static const float DEFAULT_MARGIN;
float getLeftMargin() const;
void setLeftMargin(float value);
@@ -117,8 +103,6 @@ public:
PulsePropertyGroup getPulseProperties() const;
private:
- BillboardMode _billboardMode;
-
QString _text;
float _lineHeight;
glm::u8vec3 _textColor;
diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp
index 61a1ed18c5..2f8389fe2c 100644
--- a/libraries/entities/src/WebEntityItem.cpp
+++ b/libraries/entities/src/WebEntityItem.cpp
@@ -25,6 +25,7 @@
#include "EntityTreeElement.h"
const QString WebEntityItem::DEFAULT_SOURCE_URL = NetworkingConstants::WEB_ENTITY_DEFAULT_SOURCE_URL;
+const QString WebEntityItem::DEFAULT_USER_AGENT = NetworkingConstants::WEB_ENTITY_DEFAULT_USER_AGENT;
const uint8_t WebEntityItem::DEFAULT_MAX_FPS = 10;
EntityItemPointer WebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@@ -54,7 +55,6 @@ EntityItemProperties WebEntityItem::getProperties(const EntityPropertyFlags& des
withReadLock([&] {
_pulseProperties.getProperties(properties);
});
- COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(sourceUrl, getSourceUrl);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(dpi, getDPI);
@@ -63,6 +63,7 @@ EntityItemProperties WebEntityItem::getProperties(const EntityPropertyFlags& des
COPY_ENTITY_PROPERTY_TO_PROPERTIES(inputMode, getInputMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(showKeyboardFocusHighlight, getShowKeyboardFocusHighlight);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(useBackground, getUseBackground);
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(userAgent, getUserAgent);
return properties;
}
@@ -76,7 +77,6 @@ bool WebEntityItem::setSubClassProperties(const EntityItemProperties& properties
somethingChanged |= pulsePropertiesChanged;
_needsRenderUpdate |= pulsePropertiesChanged;
});
- SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(sourceUrl, setSourceUrl);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dpi, setDPI);
@@ -85,6 +85,7 @@ bool WebEntityItem::setSubClassProperties(const EntityItemProperties& properties
SET_ENTITY_PROPERTY_FROM_PROPERTIES(inputMode, setInputMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(showKeyboardFocusHighlight, setShowKeyboardFocusHighlight);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(useBackground, setUseBackground);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(userAgent, setUserAgent);
return somethingChanged;
}
@@ -106,7 +107,6 @@ int WebEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, i
bytesRead += bytesFromPulse;
dataAt += bytesFromPulse;
});
- READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
READ_ENTITY_PROPERTY(PROP_SOURCE_URL, QString, setSourceUrl);
READ_ENTITY_PROPERTY(PROP_DPI, uint16_t, setDPI);
@@ -115,6 +115,7 @@ int WebEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, i
READ_ENTITY_PROPERTY(PROP_INPUT_MODE, WebInputMode, setInputMode);
READ_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, bool, setShowKeyboardFocusHighlight);
READ_ENTITY_PROPERTY(PROP_WEB_USE_BACKGROUND, bool, setUseBackground);
+ READ_ENTITY_PROPERTY(PROP_USER_AGENT, QString, setUserAgent);
return bytesRead;
}
@@ -124,7 +125,6 @@ EntityPropertyFlags WebEntityItem::getEntityProperties(EncodeBitstreamParams& pa
requestedProperties += PROP_COLOR;
requestedProperties += PROP_ALPHA;
requestedProperties += _pulseProperties.getEntityProperties(params);
- requestedProperties += PROP_BILLBOARD_MODE;
requestedProperties += PROP_SOURCE_URL;
requestedProperties += PROP_DPI;
@@ -133,6 +133,7 @@ EntityPropertyFlags WebEntityItem::getEntityProperties(EncodeBitstreamParams& pa
requestedProperties += PROP_INPUT_MODE;
requestedProperties += PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT;
requestedProperties += PROP_WEB_USE_BACKGROUND;
+ requestedProperties += PROP_USER_AGENT;
return requestedProperties;
}
@@ -151,7 +152,6 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
});
- APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, getSourceUrl());
APPEND_ENTITY_PROPERTY(PROP_DPI, getDPI());
@@ -160,71 +160,7 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
APPEND_ENTITY_PROPERTY(PROP_INPUT_MODE, (uint32_t)getInputMode());
APPEND_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, getShowKeyboardFocusHighlight());
APPEND_ENTITY_PROPERTY(PROP_WEB_USE_BACKGROUND, getUseBackground());
-}
-
-glm::vec3 WebEntityItem::getRaycastDimensions() const {
- glm::vec3 dimensions = getScaledDimensions();
- if (getBillboardMode() != BillboardMode::NONE) {
- float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
- const float SQRT_2 = 1.41421356237f;
- return glm::vec3(SQRT_2 * max);
- }
- return dimensions;
-}
-
-bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const {
- glm::vec3 dimensions = getScaledDimensions();
- glm::vec2 xyDimensions(dimensions.x, dimensions.y);
- glm::quat rotation = getWorldOrientation();
- glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
- rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());
-
- if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
- glm::vec3 forward = rotation * Vectors::FRONT;
- if (glm::dot(forward, direction) > 0.0f) {
- face = MAX_Z_FACE;
- surfaceNormal = -forward;
- } else {
- face = MIN_Z_FACE;
- surfaceNormal = forward;
- }
- return true;
- } else {
- return false;
- }
-}
-
-bool WebEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
- OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const {
- glm::vec3 dimensions = getScaledDimensions();
- glm::vec2 xyDimensions(dimensions.x, dimensions.y);
- glm::quat rotation = getWorldOrientation();
- glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
-
- glm::quat inverseRot = glm::inverse(rotation);
- glm::vec3 localOrigin = inverseRot * (origin - position);
- glm::vec3 localVelocity = inverseRot * velocity;
- glm::vec3 localAcceleration = inverseRot * acceleration;
-
- if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) {
- float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
- glm::vec3 forward = rotation * Vectors::FRONT;
- if (localIntersectionVelocityZ > 0.0f) {
- face = MIN_Z_FACE;
- surfaceNormal = forward;
- } else {
- face = MAX_Z_FACE;
- surfaceNormal = -forward;
- }
- return true;
- } else {
- return false;
- }
+ APPEND_ENTITY_PROPERTY(PROP_USER_AGENT, getUserAgent());
}
void WebEntityItem::setColor(const glm::u8vec3& value) {
@@ -259,19 +195,6 @@ float WebEntityItem::getAlpha() const {
});
}
-BillboardMode WebEntityItem::getBillboardMode() const {
- return resultWithReadLock([&] {
- return _billboardMode;
- });
-}
-
-void WebEntityItem::setBillboardMode(BillboardMode value) {
- withWriteLock([&] {
- _needsRenderUpdate |= _billboardMode != value;
- _billboardMode = value;
- });
-}
-
void WebEntityItem::setSourceUrl(const QString& value) {
withWriteLock([&] {
_needsRenderUpdate |= _sourceUrl != value;
@@ -365,6 +288,17 @@ bool WebEntityItem::getUseBackground() const {
return resultWithReadLock([&] { return _useBackground; });
}
+void WebEntityItem::setUserAgent(const QString& value) {
+ withWriteLock([&] {
+ _needsRenderUpdate |= _userAgent != value;
+ _userAgent = value;
+ });
+}
+
+QString WebEntityItem::getUserAgent() const {
+ return resultWithReadLock([&] { return _userAgent; });
+}
+
PulsePropertyGroup WebEntityItem::getPulseProperties() const {
return resultWithReadLock([&] {
return _pulseProperties;
diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h
index 4b39261bfb..cc689c8998 100644
--- a/libraries/entities/src/WebEntityItem.h
+++ b/libraries/entities/src/WebEntityItem.h
@@ -45,26 +45,12 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
- glm::vec3 getRaycastDimensions() const override;
- virtual bool supportsDetailedIntersection() const override { return true; }
- virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const override;
- virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
- QVariantMap& extraInfo, bool precisionPicking) const override;
-
glm::u8vec3 getColor() const;
void setColor(const glm::u8vec3& value);
float getAlpha() const;
void setAlpha(float alpha);
- void setBillboardMode(BillboardMode value);
- BillboardMode getBillboardMode() const;
-
static const QString DEFAULT_SOURCE_URL;
void setSourceUrl(const QString& value);
QString getSourceUrl() const;
@@ -89,6 +75,10 @@ public:
bool getUseBackground() const;
void setUseBackground(bool value);
+
+ static const QString DEFAULT_USER_AGENT;
+ QString getUserAgent() const;
+ void setUserAgent(const QString& value);
PulsePropertyGroup getPulseProperties() const;
@@ -96,7 +86,6 @@ protected:
glm::u8vec3 _color;
float _alpha { 1.0f };
PulsePropertyGroup _pulseProperties;
- BillboardMode _billboardMode;
QString _sourceUrl;
uint16_t _dpi;
@@ -105,6 +94,7 @@ protected:
WebInputMode _inputMode;
bool _showKeyboardFocusHighlight;
bool _useBackground;
+ QString _userAgent;
bool _localSafeContext { false };
};
diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp
index 88466caff0..3eabfb4f1e 100644
--- a/libraries/entities/src/ZoneEntityItem.cpp
+++ b/libraries/entities/src/ZoneEntityItem.cpp
@@ -84,12 +84,12 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie
// Contains a QString property, must be synchronized
withWriteLock([&] {
- _keyLightPropertiesChanged = _keyLightProperties.setProperties(properties);
- _ambientLightPropertiesChanged = _ambientLightProperties.setProperties(properties);
- _skyboxPropertiesChanged = _skyboxProperties.setProperties(properties);
+ _keyLightPropertiesChanged |= _keyLightProperties.setProperties(properties);
+ _ambientLightPropertiesChanged |= _ambientLightProperties.setProperties(properties);
+ _skyboxPropertiesChanged |= _skyboxProperties.setProperties(properties);
});
- _hazePropertiesChanged = _hazeProperties.setProperties(properties);
- _bloomPropertiesChanged = _bloomProperties.setProperties(properties);
+ _hazePropertiesChanged |= _hazeProperties.setProperties(properties);
+ _bloomPropertiesChanged |= _bloomProperties.setProperties(properties);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
@@ -125,7 +125,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _keyLightPropertiesChanged);
});
- somethingChanged = somethingChanged || _keyLightPropertiesChanged;
+ somethingChanged |= _keyLightPropertiesChanged;
bytesRead += bytesFromKeylight;
dataAt += bytesFromKeylight;
}
@@ -136,7 +136,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged);
});
- somethingChanged = somethingChanged || _ambientLightPropertiesChanged;
+ somethingChanged |= _ambientLightPropertiesChanged;
bytesRead += bytesFromAmbientlight;
dataAt += bytesFromAmbientlight;
}
@@ -147,7 +147,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _skyboxPropertiesChanged);
});
- somethingChanged = somethingChanged || _skyboxPropertiesChanged;
+ somethingChanged |= _skyboxPropertiesChanged;
bytesRead += bytesFromSkybox;
dataAt += bytesFromSkybox;
}
@@ -155,7 +155,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
{
int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _hazePropertiesChanged);
- somethingChanged = somethingChanged || _hazePropertiesChanged;
+ somethingChanged |= _hazePropertiesChanged;
bytesRead += bytesFromHaze;
dataAt += bytesFromHaze;
}
@@ -163,7 +163,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
{
int bytesFromBloom = _bloomProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _bloomPropertiesChanged);
- somethingChanged = somethingChanged || _bloomPropertiesChanged;
+ somethingChanged |= _bloomPropertiesChanged;
bytesRead += bytesFromBloom;
dataAt += bytesFromBloom;
}
@@ -318,15 +318,15 @@ void ZoneEntityItem::setCompoundShapeURL(const QString& url) {
}
bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const {
return _zonesArePickable;
}
bool ZoneEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const {
return _zonesArePickable;
}
@@ -444,6 +444,13 @@ uint32_t ZoneEntityItem::getSkyboxMode() const {
return _skyboxMode;
}
+void ZoneEntityItem::setUserData(const QString& value) {
+ withWriteLock([&] {
+ _needsRenderUpdate |= _userData != value;
+ _userData = value;
+ });
+}
+
void ZoneEntityItem::fetchCollisionGeometryResource() {
QUrl hullURL(getCompoundShapeURL());
if (hullURL.isEmpty()) {
diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h
index dda03f9115..2b61bbd346 100644
--- a/libraries/entities/src/ZoneEntityItem.h
+++ b/libraries/entities/src/ZoneEntityItem.h
@@ -104,6 +104,8 @@ public:
uint32_t getScreenshare() const { return _screenshare; }
void setScreenshare(uint32_t value) { _screenshare = value; }
+ void setUserData(const QString& value) override;
+
bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; }
bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; }
bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; }
@@ -114,12 +116,12 @@ public:
virtual bool supportsDetailedIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
- OctreeElementPointer& element, float& distance,
+ const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
- const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
- BoxFace& face, glm::vec3& surfaceNormal,
+ const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
+ float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
bool contains(const glm::vec3& point) const override;
diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp
index 94702a9906..45c8e70659 100644
--- a/libraries/gl/src/gl/GLWidget.cpp
+++ b/libraries/gl/src/gl/GLWidget.cpp
@@ -35,11 +35,6 @@ class GLPaintEngine : public QPaintEngine {
};
GLWidget::GLWidget() {
-#ifdef Q_OS_LINUX
- // Cause GLWidget::eventFilter to be called.
- // It wouldn't hurt to do this on Mac and PC too; but apparently it's only needed on linux.
- qApp->installEventFilter(this);
-#endif
setAttribute(Qt::WA_AcceptTouchEvents);
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen);
@@ -118,39 +113,6 @@ bool GLWidget::event(QEvent* event) {
return QWidget::event(event);
}
-// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the
-// SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to
-// receive keyPress events for the Alt (and Meta) key in a reliable manner.
-//
-// This filter catches events before QMenuBar can steal the keyboard focus.
-// The idea was borrowed from
-// http://www.archivum.info/qt-interest@trolltech.com/2006-09/00053/Re-(Qt4)-Alt-key-focus-QMenuBar-(solved).html
-
-bool GLWidget::eventFilter(QObject*, QEvent* event) {
- switch (event->type()) {
- case QEvent::KeyPress:
- case QEvent::KeyRelease:
- case QEvent::ShortcutOverride:
- {
- QKeyEvent* keyEvent = static_cast(event);
- if (keyEvent->key() == Qt::Key_Alt || keyEvent->key() == Qt::Key_Meta) {
- if (event->type() == QEvent::KeyPress) {
- keyPressEvent(keyEvent);
- } else if (event->type() == QEvent::KeyRelease) {
- keyReleaseEvent(keyEvent);
- } else {
- QWidget::event(event);
- }
- return true;
- }
- }
- default:
- break;
- }
- return false;
-}
-
-
bool GLWidget::nativeEvent(const QByteArray &eventType, void *message, long *result) {
#ifdef Q_OS_WIN32
MSG* win32message = static_cast(message);
diff --git a/libraries/gl/src/gl/GLWidget.h b/libraries/gl/src/gl/GLWidget.h
index 777d43e8af..9d5c8800bb 100644
--- a/libraries/gl/src/gl/GLWidget.h
+++ b/libraries/gl/src/gl/GLWidget.h
@@ -42,9 +42,6 @@ protected:
virtual bool event(QEvent* event) override;
gl::Context* _context { nullptr };
-private slots:
- virtual bool eventFilter(QObject*, QEvent* event) override;
-
private:
QPaintEngine* _paintEngine { nullptr };
bool _vsyncSupported { false };
diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp
index 38aca093cd..8126988294 100644
--- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp
+++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp
@@ -153,7 +153,7 @@ void GLBackend::init() {
if (vendor.contains("NVIDIA") ) {
qCDebug(gpugllogging) << "NVIDIA card detected";
-#if !defined(Q_OS_ANDROID)
+#if !defined(Q_OS_ANDROID) && !defined(USE_GLES)
GL_GET_INTEGER(GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX);
GL_GET_INTEGER(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX);
GL_GET_INTEGER(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX);
@@ -170,7 +170,7 @@ void GLBackend::init() {
} else if (vendor.contains("ATI")) {
qCDebug(gpugllogging) << "ATI card detected";
-#if !defined(Q_OS_ANDROID)
+#if !defined(Q_OS_ANDROID) && !defined(USE_GLES)
GL_GET_INTEGER(TEXTURE_FREE_MEMORY_ATI);
#endif
@@ -225,12 +225,12 @@ size_t GLBackend::getAvailableMemory() {
switch( _videoCard ) {
case NVIDIA:
-#if !defined(Q_OS_ANDROID)
+#if !defined(Q_OS_ANDROID) && !defined(USE_GLES)
glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &mem[0]);
#endif
return mem[0] * BYTES_PER_KIB;
case ATI:
-#if !defined(Q_OS_ANDROID)
+#if !defined(Q_OS_ANDROID) && !defined(USE_GLES)
glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, &mem[0]);
#endif
return mem[0] * BYTES_PER_KIB;
diff --git a/libraries/hfm/src/hfm/HFM.cpp b/libraries/hfm/src/hfm/HFM.cpp
index 8fb0720c0d..dd13d6d4f3 100644
--- a/libraries/hfm/src/hfm/HFM.cpp
+++ b/libraries/hfm/src/hfm/HFM.cpp
@@ -104,7 +104,7 @@ bool HFMModel::convexHullContains(const glm::vec3& point) const {
auto checkEachPrimitive = [=](HFMMesh& mesh, QVector indices, int primitiveSize) -> bool {
// Check whether the point is "behind" all the primitives.
// But first must transform from model-frame into mesh-frame
- glm::vec3 transformedPoint = glm::vec3(glm::inverse(mesh.modelTransform) * glm::vec4(point, 1.0f));
+ glm::vec3 transformedPoint = glm::vec3(glm::inverse(offset * mesh.modelTransform) * glm::vec4(point, 1.0f));
int verticesSize = mesh.vertices.size();
for (int j = 0;
j < indices.size() - 2; // -2 in case the vertices aren't the right size -- we access j + 2 below
diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp
index d867b49b30..3da5b53dcb 100644
--- a/libraries/networking/src/LimitedNodeList.cpp
+++ b/libraries/networking/src/LimitedNodeList.cpp
@@ -1197,7 +1197,7 @@ void LimitedNodeList::stopInitialSTUNUpdate(bool success) {
}
// We now setup a timer here to fire every so often to check that our IP address has not changed.
- // Or, if we failed - if will check if we can eventually get a public socket
+ // Or, if we failed - it will check if we can eventually get a public socket
const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 10 * 1000;
QTimer* stunOccasionalTimer = new QTimer { this };
diff --git a/libraries/networking/src/NetworkingConstants.h b/libraries/networking/src/NetworkingConstants.h
index 58cefb35ad..ccdb9ea75c 100644
--- a/libraries/networking/src/NetworkingConstants.h
+++ b/libraries/networking/src/NetworkingConstants.h
@@ -25,6 +25,8 @@ namespace NetworkingConstants {
// You can avoid changing that and still effectively use a connected domain on staging
// if you manually generate a personal access token for the domains scope
// at https://staging.highfidelity.com/user/tokens/new?for_domain_server=true
+
+ const QString WEB_ENGINE_VERSION = "Chrome/69.0.3497.113";
// For now we only have one Metaverse server.
const QUrl METAVERSE_SERVER_URL_STABLE { "https://metaverse.vircadia.com/live" };
@@ -37,15 +39,16 @@ namespace NetworkingConstants {
// Use a custom User-Agent to avoid ModSecurity filtering, e.g. by hosting providers.
const QByteArray VIRCADIA_USER_AGENT = "Mozilla/5.0 (VircadiaInterface)";
- const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (VircadiaInterface)";
- const QString METAVERSE_USER_AGENT = "Chrome/48.0 (VircadiaInterface)";
- const QString MOBILE_USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
-
- const QUrl BUILDS_XML_URL("https://highfidelity.com/builds.xml");
- const QUrl MASTER_BUILDS_XML_URL("https://highfidelity.com/dev-builds.xml");
+ const QString WEB_ENGINE_USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) " + WEB_ENGINE_VERSION + " Mobile Safari/537.36";
+ const QString MOBILE_USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) " + WEB_ENGINE_VERSION + " Mobile Safari/537.36";
// WebEntity Defaults
const QString WEB_ENTITY_DEFAULT_SOURCE_URL = "https://vircadia.com/";
+ const QString WEB_ENTITY_DEFAULT_USER_AGENT = WEB_ENGINE_USER_AGENT;
+
+ // Builds URLs
+ const QUrl BUILDS_XML_URL("https://highfidelity.com/builds.xml");
+ const QUrl MASTER_BUILDS_XML_URL("https://highfidelity.com/dev-builds.xml");
const QString DEFAULT_AVATAR_COLLISION_SOUND_URL = "https://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/Body_Hits_Impact.wav";
@@ -72,7 +75,7 @@ namespace NetworkingConstants {
const QUrl HELP_FORUM_URL { "https://forums.vircadia.dev" };
const QUrl HELP_SCRIPTING_REFERENCE_URL{ "https://apidocs.vircadia.dev/" };
const QUrl HELP_RELEASE_NOTES_URL{ "https://docs.vircadia.dev/release-notes.html" };
- const QUrl HELP_BUG_REPORT_URL{ "https://github.com/kasenvr/project-athena/issues" };
+ const QUrl HELP_BUG_REPORT_URL{ "https://github.com/vircadia/vircadia/issues" };
const QString DEFAULT_VIRCADIA_ADDRESS = "file:///~/serverless/tutorial.json";
const QString DEFAULT_HOME_ADDRESS = "file:///~/serverless/tutorial.json";
diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h
index fc74f4459c..f54b004538 100644
--- a/libraries/networking/src/udt/PacketHeaders.h
+++ b/libraries/networking/src/udt/PacketHeaders.h
@@ -283,6 +283,9 @@ enum class EntityVersion : PacketVersion {
ZoneOcclusion,
ModelBlendshapes,
TransparentWeb,
+ UseOriginalPivot,
+ UserAgent,
+ AllBillboardMode,
// Add new versions above here
NUM_PACKET_TYPE,
diff --git a/libraries/oculusMobile/src/ovr/Helpers.h b/libraries/oculusMobile/src/ovr/Helpers.h
index 2bd0b7f603..10058dbac8 100644
--- a/libraries/oculusMobile/src/ovr/Helpers.h
+++ b/libraries/oculusMobile/src/ovr/Helpers.h
@@ -31,9 +31,9 @@ static inline void for_each_eye(const std::function& f) {
f(VRAPI_EYE_RIGHT);
}
-static inline void for_each_hand(const std::function& f) {
- f(VRAPI_HAND_LEFT);
- f(VRAPI_HAND_RIGHT);
+static inline void for_each_hand(const std::function& f) {
+ f(VRAPI_TRACKED_DEVICE_HAND_LEFT);
+ f(VRAPI_TRACKED_DEVICE_HAND_RIGHT);
}
static inline glm::mat4 toGlm(const ovrMatrix4f& om) {
diff --git a/libraries/oculusMobile/src/ovr/VrHandler.cpp b/libraries/oculusMobile/src/ovr/VrHandler.cpp
index aff1f256b5..1fe4d19401 100644
--- a/libraries/oculusMobile/src/ovr/VrHandler.cpp
+++ b/libraries/oculusMobile/src/ovr/VrHandler.cpp
@@ -324,7 +324,7 @@ struct VrSurface : public TaskQueue {
vrapi_SetTrackingSpace( session, VRAPI_TRACKING_SPACE_LOCAL);
vrapi_SetPerfThread(session, VRAPI_PERF_THREAD_TYPE_RENDERER, gettid());
vrapi_SetClockLevels(session, 2, 4);
- vrapi_SetExtraLatencyMode(session, VRAPI_EXTRA_LATENCY_MODE_DYNAMIC);
+ vrapi_SetExtraLatencyMode(session, VRAPI_EXTRA_LATENCY_MODE_ON);
// Generates a warning on the quest: "vrapi_SetDisplayRefreshRate: Dynamic Display Refresh Rate not supported"
// vrapi_SetDisplayRefreshRate(session, 72);
});
diff --git a/libraries/oculusMobilePlugin/src/OculusMobileControllerManager.cpp b/libraries/oculusMobilePlugin/src/OculusMobileControllerManager.cpp
index 705045b517..54a796954e 100644
--- a/libraries/oculusMobilePlugin/src/OculusMobileControllerManager.cpp
+++ b/libraries/oculusMobilePlugin/src/OculusMobileControllerManager.cpp
@@ -31,7 +31,7 @@ const quint64 LOST_TRACKING_DELAY = 3000000;
namespace ovr {
- controller::Pose toControllerPose(ovrHandedness hand, const ovrRigidBodyPosef& handPose) {
+ controller::Pose toControllerPose(ovrTrackedDeviceTypeId hand, const ovrRigidBodyPosef& handPose) {
// When the sensor-to-world rotation is identity the coordinate axes look like this:
//
// user
@@ -111,7 +111,7 @@ namespace ovr {
return pose;
}
- controller::Pose toControllerPose(ovrHandedness hand,
+ controller::Pose toControllerPose(ovrTrackedDeviceTypeId hand,
const ovrRigidBodyPosef& handPose,
const ovrRigidBodyPosef& lastHandPose) {
static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y);
@@ -165,9 +165,9 @@ public:
private:
void handlePose(float deltaTime, const controller::InputCalibrationData& inputCalibrationData,
- ovrHandedness hand, const ovrRigidBodyPosef& handPose);
+ ovrTrackedDeviceTypeId hand, const ovrRigidBodyPosef& handPose);
void handleRotationForUntrackedHand(const controller::InputCalibrationData& inputCalibrationData,
- ovrHandedness hand, const ovrRigidBodyPosef& handPose);
+ ovrTrackedDeviceTypeId hand, const ovrRigidBodyPosef& handPose);
void handleHeadPose(float deltaTime, const controller::InputCalibrationData& inputCalibrationData,
const ovrRigidBodyPosef& headPose);
@@ -379,9 +379,9 @@ void OculusMobileInputDevice::update(float deltaTime, const controller::InputCal
handleHeadPose(deltaTime, inputCalibrationData, _headTracking.HeadPose);
static const auto REQUIRED_HAND_STATUS = VRAPI_TRACKING_STATUS_ORIENTATION_TRACKED | VRAPI_TRACKING_STATUS_POSITION_TRACKED;
- ovr::for_each_hand([&](ovrHandedness hand) {
- size_t handIndex = (hand == VRAPI_HAND_LEFT) ? 0 : 1;
- int controller = (hand == VRAPI_HAND_LEFT) ? controller::LEFT_HAND : controller::RIGHT_HAND;
+ ovr::for_each_hand([&](ovrTrackedDeviceTypeId hand) {
+ size_t handIndex = (hand == VRAPI_TRACKED_DEVICE_HAND_LEFT) ? 0 : 1;
+ int controller = (hand == VRAPI_TRACKED_DEVICE_HAND_LEFT) ? controller::LEFT_HAND : controller::RIGHT_HAND;
auto& handData = _hands[handIndex];
const auto& tracking = handData.tracking;
++numTrackedControllers;
@@ -476,7 +476,7 @@ void OculusMobileInputDevice::focusOutEvent() {
void OculusMobileInputDevice::handlePose(float deltaTime,
const controller::InputCalibrationData& inputCalibrationData,
- ovrHandedness hand, const ovrRigidBodyPosef& handPose) {
+ ovrTrackedDeviceTypeId hand, const ovrRigidBodyPosef& handPose) {
auto poseId = (hand == VRAPI_HAND_LEFT) ? controller::LEFT_HAND : controller::RIGHT_HAND;
auto& pose = _poseStateMap[poseId];
pose = ovr::toControllerPose(hand, handPose);
@@ -507,7 +507,7 @@ void OculusMobileInputDevice::handleHeadPose(float deltaTime,
}
void OculusMobileInputDevice::handleRotationForUntrackedHand(const controller::InputCalibrationData& inputCalibrationData,
- ovrHandedness hand, const ovrRigidBodyPosef& handPose) {
+ ovrTrackedDeviceTypeId hand, const ovrRigidBodyPosef& handPose) {
auto poseId = (hand == VRAPI_HAND_LEFT ? controller::LEFT_HAND : controller::RIGHT_HAND);
auto& pose = _poseStateMap[poseId];
const auto& lastHandPose = (hand == VRAPI_HAND_LEFT) ? _hands[0].lastPose : _hands[1].lastPose;
diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp
index e222692aea..777a3d3f87 100755
--- a/libraries/physics/src/CharacterController.cpp
+++ b/libraries/physics/src/CharacterController.cpp
@@ -107,12 +107,12 @@ CharacterController::CharacterMotor::CharacterMotor(const glm::vec3& vel, const
static uint32_t _numCharacterControllers { 0 };
-CharacterController::CharacterController() {
+CharacterController::CharacterController(const FollowTimePerType& followTimeRemainingPerType) :
+ _followTimeRemainingPerType(followTimeRemainingPerType) {
_floorDistance = _scaleFactor * DEFAULT_AVATAR_FALL_HEIGHT;
_targetVelocity.setValue(0.0f, 0.0f, 0.0f);
_followDesiredBodyTransform.setIdentity();
- _followTimeRemaining = 0.0f;
_state = State::Hover;
_isPushingUp = false;
_rayHitStartTime = 0;
@@ -350,64 +350,103 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar
btVector3 velocity = _rigidBody->getLinearVelocity() - _parentVelocity;
computeNewVelocity(dt, velocity);
- const float MINIMUM_TIME_REMAINING = 0.005f;
- const float MAX_DISPLACEMENT = 0.5f * _radius;
- _followTimeRemaining -= dt;
- if (_followTimeRemaining >= MINIMUM_TIME_REMAINING) {
- btTransform bodyTransform = _rigidBody->getWorldTransform();
+ constexpr float MINIMUM_TIME_REMAINING = 0.005f;
+ static_assert(FOLLOW_TIME_IMMEDIATE_SNAP > MINIMUM_TIME_REMAINING, "The code below assumes this condition is true.");
+ bool hasFollowTimeRemaining = false;
+ for (float followTime : _followTimeRemainingPerType) {
+ if (followTime > MINIMUM_TIME_REMAINING) {
+ hasFollowTimeRemaining = true;
+ break;
+ }
+ }
+
+ if (hasFollowTimeRemaining) {
+ const float MAX_DISPLACEMENT = 0.5f * _radius;
+
+ btTransform bodyTransform = _rigidBody->getWorldTransform();
btVector3 startPos = bodyTransform.getOrigin();
btVector3 deltaPos = _followDesiredBodyTransform.getOrigin() - startPos;
- btVector3 vel = deltaPos / _followTimeRemaining;
- btVector3 linearDisplacement = clampLength(vel * dt, MAX_DISPLACEMENT); // clamp displacement to prevent tunneling.
+
+ btVector3 linearDisplacement(0.0f, 0.0f, 0.0f);
+ {
+ float horizontalTime = _followTimeRemainingPerType[static_cast(FollowType::Horizontal)];
+ float verticalTime = _followTimeRemainingPerType[static_cast(FollowType::Vertical)];
+
+ if (horizontalTime == FOLLOW_TIME_IMMEDIATE_SNAP) {
+ linearDisplacement.setX(deltaPos.x());
+ linearDisplacement.setZ(deltaPos.z());
+ } else if (horizontalTime > MINIMUM_TIME_REMAINING) {
+ linearDisplacement.setX((deltaPos.x() * dt) / horizontalTime);
+ linearDisplacement.setZ((deltaPos.z() * dt) / horizontalTime);
+ }
+
+ if (verticalTime == FOLLOW_TIME_IMMEDIATE_SNAP) {
+ linearDisplacement.setY(deltaPos.y());
+ } else if (verticalTime > MINIMUM_TIME_REMAINING) {
+ linearDisplacement.setY((deltaPos.y() * dt) / verticalTime);
+ }
+
+ linearDisplacement = clampLength(linearDisplacement, MAX_DISPLACEMENT); // clamp displacement to prevent tunneling.
+ }
+
btVector3 endPos = startPos + linearDisplacement;
// resolve the simple linearDisplacement
_followLinearDisplacement += linearDisplacement;
// now for the rotational part...
+
btQuaternion startRot = bodyTransform.getRotation();
- btQuaternion desiredRot = _followDesiredBodyTransform.getRotation();
// startRot as default rotation
btQuaternion endRot = startRot;
- // the dot product between two quaternions is equal to +/- cos(angle/2)
- // where 'angle' is that of the rotation between them
- float qDot = desiredRot.dot(startRot);
+ float rotationTime = _followTimeRemainingPerType[static_cast(FollowType::Rotation)];
+ if (rotationTime > MINIMUM_TIME_REMAINING) {
+ btQuaternion desiredRot = _followDesiredBodyTransform.getRotation();
- // when the abs() value of the dot product is approximately 1.0
- // then the two rotations are effectively adjacent
- const float MIN_DOT_PRODUCT_OF_ADJACENT_QUATERNIONS = 0.99999f; // corresponds to approx 0.5 degrees
- if (fabsf(qDot) < MIN_DOT_PRODUCT_OF_ADJACENT_QUATERNIONS) {
- if (qDot < 0.0f) {
- // the quaternions are actually on opposite hyperhemispheres
- // so we move one to agree with the other and negate qDot
- desiredRot = -desiredRot;
- qDot = -qDot;
+ // the dot product between two quaternions is equal to +/- cos(angle/2)
+ // where 'angle' is that of the rotation between them
+ float qDot = desiredRot.dot(startRot);
+
+ // when the abs() value of the dot product is approximately 1.0
+ // then the two rotations are effectively adjacent
+ const float MIN_DOT_PRODUCT_OF_ADJACENT_QUATERNIONS = 0.99999f; // corresponds to approx 0.5 degrees
+ if (fabsf(qDot) < MIN_DOT_PRODUCT_OF_ADJACENT_QUATERNIONS) {
+ if (qDot < 0.0f) {
+ // the quaternions are actually on opposite hyperhemispheres
+ // so we move one to agree with the other and negate qDot
+ desiredRot = -desiredRot;
+ qDot = -qDot;
+ }
+ btQuaternion deltaRot = desiredRot * startRot.inverse();
+
+ // the axis is the imaginary part, but scaled by sin(angle/2)
+ btVector3 axis(deltaRot.getX(), deltaRot.getY(), deltaRot.getZ());
+ axis /= sqrtf(1.0f - qDot * qDot);
+
+ // compute the angle we will resolve for this dt, but don't overshoot
+ float angle = 2.0f * acosf(qDot);
+
+ if (rotationTime != FOLLOW_TIME_IMMEDIATE_SNAP) {
+ if (dt < rotationTime) {
+ angle *= dt / rotationTime;
+ }
+ }
+
+ // accumulate rotation
+ deltaRot = btQuaternion(axis, angle);
+ _followAngularDisplacement = (deltaRot * _followAngularDisplacement).normalize();
+
+ // in order to accumulate displacement of avatar position, we need to take _shapeLocalOffset into account.
+ btVector3 shapeLocalOffset = glmToBullet(_shapeLocalOffset);
+
+ endRot = deltaRot * startRot;
+ btVector3 swingDisplacement =
+ rotateVector(endRot, -shapeLocalOffset) - rotateVector(startRot, -shapeLocalOffset);
+ _followLinearDisplacement += swingDisplacement;
}
- btQuaternion deltaRot = desiredRot * startRot.inverse();
-
- // the axis is the imaginary part, but scaled by sin(angle/2)
- btVector3 axis(deltaRot.getX(), deltaRot.getY(), deltaRot.getZ());
- axis /= sqrtf(1.0f - qDot * qDot);
-
- // compute the angle we will resolve for this dt, but don't overshoot
- float angle = 2.0f * acosf(qDot);
- if (dt < _followTimeRemaining) {
- angle *= dt / _followTimeRemaining;
- }
-
- // accumulate rotation
- deltaRot = btQuaternion(axis, angle);
- _followAngularDisplacement = (deltaRot * _followAngularDisplacement).normalize();
-
- // in order to accumulate displacement of avatar position, we need to take _shapeLocalOffset into account.
- btVector3 shapeLocalOffset = glmToBullet(_shapeLocalOffset);
-
- endRot = deltaRot * startRot;
- btVector3 swingDisplacement = rotateVector(endRot, -shapeLocalOffset) - rotateVector(startRot, -shapeLocalOffset);
- _followLinearDisplacement += swingDisplacement;
}
_rigidBody->setWorldTransform(btTransform(endRot, endPos));
}
@@ -606,8 +645,7 @@ void CharacterController::setParentVelocity(const glm::vec3& velocity) {
_parentVelocity = glmToBullet(velocity);
}
-void CharacterController::setFollowParameters(const glm::mat4& desiredWorldBodyMatrix, float timeRemaining) {
- _followTimeRemaining = timeRemaining;
+void CharacterController::setFollowParameters(const glm::mat4& desiredWorldBodyMatrix) {
_followDesiredBodyTransform = glmToBullet(desiredWorldBodyMatrix) * btTransform(btQuaternion::getIdentity(), glmToBullet(_shapeLocalOffset));
}
diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h
index e7ad3ddfa8..8242ae4b97 100755
--- a/libraries/physics/src/CharacterController.h
+++ b/libraries/physics/src/CharacterController.h
@@ -53,7 +53,20 @@ const btScalar MIN_CHARACTER_MOTOR_TIMESCALE = 0.05f;
class CharacterController : public btCharacterControllerInterface {
public:
- CharacterController();
+ enum class FollowType : uint8_t {
+ Rotation,
+ Horizontal,
+ Vertical,
+ Count
+ };
+
+ // Remaining follow time for each FollowType
+ typedef std::array(FollowType::Count)> FollowTimePerType;
+
+ // Follow time value meaning that we should snap immediately to the target.
+ static constexpr float FOLLOW_TIME_IMMEDIATE_SNAP = FLT_MAX;
+
+ CharacterController(const FollowTimePerType& followTimeRemainingPerType);
virtual ~CharacterController();
bool needsRemoval() const;
bool needsAddition() const;
@@ -99,7 +112,8 @@ public:
void getPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const;
void setParentVelocity(const glm::vec3& parentVelocity);
- void setFollowParameters(const glm::mat4& desiredWorldMatrix, float timeRemaining);
+
+ void setFollowParameters(const glm::mat4& desiredWorldMatrix);
float getFollowTime() const { return _followTime; }
glm::vec3 getFollowLinearDisplacement() const;
glm::quat getFollowAngularDisplacement() const;
@@ -144,7 +158,7 @@ public:
void setPendingFlagsUpdateCollisionMask(){ _pendingFlags |= PENDING_FLAG_UPDATE_COLLISION_MASK; }
void setSeated(bool isSeated) { _isSeated = isSeated; }
- bool getSeated() { return _isSeated; }
+ bool getSeated() const { return _isSeated; }
void resetStuckCounter() { _numStuckSubsteps = 0; }
@@ -178,7 +192,7 @@ protected:
btVector3 _preSimulationVelocity;
btVector3 _velocityChange;
btTransform _followDesiredBodyTransform;
- btScalar _followTimeRemaining;
+ const FollowTimePerType& _followTimeRemainingPerType;
btTransform _characterBodyTransform;
btVector3 _position;
btQuaternion _rotation;
diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp
index 4a2ee9184f..d0d900e14d 100644
--- a/libraries/physics/src/PhysicalEntitySimulation.cpp
+++ b/libraries/physics/src/PhysicalEntitySimulation.cpp
@@ -425,12 +425,12 @@ void PhysicalEntitySimulation::buildPhysicsTransaction(PhysicsEngine::Transactio
continue;
}
- bool needsNewShape = object->needsNewShape();
+ bool needsNewShape = object->needsNewShape() && object->_entity->isReadyToComputeShape();
if (needsNewShape) {
ShapeType shapeType = object->getShapeType();
if (shapeType == SHAPE_TYPE_STATIC_MESH) {
ShapeRequest shapeRequest(object->_entity);
- ShapeRequests::iterator requestItr = _shapeRequests.find(shapeRequest);
+ ShapeRequests::iterator requestItr = _shapeRequests.find(shapeRequest);
if (requestItr == _shapeRequests.end()) {
ShapeInfo shapeInfo;
object->_entity->computeShapeInfo(shapeInfo);
diff --git a/libraries/procedural/CMakeLists.txt b/libraries/procedural/CMakeLists.txt
index d737d34e95..a7394a3670 100644
--- a/libraries/procedural/CMakeLists.txt
+++ b/libraries/procedural/CMakeLists.txt
@@ -1,4 +1,4 @@
set(TARGET_NAME procedural)
setup_hifi_library()
-link_hifi_libraries(shared gpu shaders networking graphics material-networking ktx image hfm)
+link_hifi_libraries(shared gpu shaders networking render graphics material-networking ktx image hfm)
diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp
index 88c111f8fd..66dde1ca56 100644
--- a/libraries/procedural/src/procedural/Procedural.cpp
+++ b/libraries/procedural/src/procedural/Procedural.cpp
@@ -125,7 +125,7 @@ Procedural::Procedural() {
opaqueStencil(_opaqueState);
_transparentState->setCullMode(gpu::State::CULL_NONE);
- _transparentState->setDepthTest(true, true, gpu::LESS_EQUAL);
+ _transparentState->setDepthTest(true, false, gpu::LESS_EQUAL);
_transparentState->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h
index 9b3d0a9bd4..7d655b5ef4 100644
--- a/libraries/procedural/src/procedural/Procedural.h
+++ b/libraries/procedural/src/procedural/Procedural.h
@@ -16,6 +16,7 @@
#include
#include
+#include
#include
#include
#include
@@ -113,9 +114,9 @@ public:
void setDoesFade(bool doesFade) { _doesFade = doesFade; }
bool hasVertexShader() const;
- void setBoundOperator(const std::function& boundOperator) { _boundOperator = boundOperator; }
+ void setBoundOperator(const std::function& boundOperator) { _boundOperator = boundOperator; }
bool hasBoundOperator() const { return (bool)_boundOperator; }
- AABox getBound() { return _boundOperator(); }
+ AABox getBound(RenderArgs* args) { return _boundOperator(args); }
gpu::Shader::Source _vertexSource;
gpu::Shader::Source _vertexSourceSkinned;
@@ -199,7 +200,7 @@ private:
bool _doesFade { true };
ProceduralProgramKey _prevKey;
- std::function _boundOperator { nullptr };
+ std::function _boundOperator { nullptr };
mutable std::mutex _mutex;
};
@@ -232,9 +233,9 @@ public:
void initializeProcedural();
- void setBoundOperator(const std::function