Merge branch 'master' into domainlist-recv-logging

This commit is contained in:
Simon Walton 2019-05-29 15:54:31 -07:00 committed by GitHub
commit 8a280e71e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
225 changed files with 15020 additions and 1576 deletions
BUILD.mdBUILD_ANDROID.mdBUILD_LINUX.mdBUILD_OSX.mdBUILD_QUEST.mdBUILD_WIN.mdCMakeLists.txt
assignment-client/src/avatars
cmake
debian
domain-server/src
hifi_vcpkg.py
interface
libraries
audio-client/src
audio/src
avatars-renderer/src/avatars-renderer
avatars/src
display-plugins/src/display-plugins
entities-renderer/src
entities/src
gpu-gl/src/gpu/gl45
gpu/src/gpu
graphics/src/graphics
image/src/image
ktx/src
model-baker/src/model-baker

View file

@ -6,26 +6,25 @@
* [BUILD_ANDROID.md](BUILD_ANDROID.md) - additional instructions for Android
### Dependencies
- [git](https://git-scm.com/downloads): >= 1.6
- [cmake](https://cmake.org/download/): 3.9
- [Qt](https://www.qt.io/download-open-source): 5.10.1
- [Python](https://www.python.org/downloads/): 3.6 or higher
### CMake External Project Dependencies
These dependencies need not be installed manually. They are automatically downloaded on the platforms where they are required.
- [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases): 2.83
- [glm](https://glm.g-truc.net/0.9.8/index.html): 0.9.8
- [Oculus SDK](https://developer.oculus.com/downloads/): 1.11 (Win32) / 0.5 (Mac)
- [OpenVR](https://github.com/ValveSoftware/openvr): 1.0.6 (Win32 only)
- [Polyvox](http://www.volumesoffun.com/): 0.2.1
- [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/): 0.7.3
- [SDL2](https://www.libsdl.org/download-2.0.php): 2.0.3
- [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/): 4.3
- [vcpkg](https://github.com/highfidelity/vcpkg):
- [VHACD](https://github.com/virneo/v-hacd)
- [zlib](http://www.zlib.net/): 1.28 (Win32 only)
- [nvtt](https://github.com/highfidelity/nvidia-texture-tools): 2.1.1 (customized)
- [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases): 2.83
- [glm](https://glm.g-truc.net/0.9.8/index.html): 0.9.8
- [Oculus SDK](https://developer.oculus.com/downloads/): 1.11 (Win32) / 0.5 (Mac)
- [OpenVR](https://github.com/ValveSoftware/openvr): 1.0.6 (Win32 only)
- [Polyvox](http://www.volumesoffun.com/): 0.2.1
- [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/): 0.7.3
- [SDL2](https://www.libsdl.org/download-2.0.php): 2.0.3
- [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/): 4.3
- [vcpkg](https://github.com/highfidelity/vcpkg):
- [VHACD](https://github.com/virneo/v-hacd)
- [zlib](http://www.zlib.net/): 1.28 (Win32 only)
- [nvtt](https://github.com/highfidelity/nvidia-texture-tools): 2.1.1 (customized)
The above dependencies will be downloaded, built, linked and included automatically by CMake where we require them. The CMakeLists files that handle grabbing each of the following external dependencies can be found in the [cmake/externals folder](cmake/externals). The resulting downloads, source files and binaries will be placed in the `build/ext` folder in each of the subfolders for each external project.
@ -36,16 +35,14 @@ These are not placed in your normal build tree when doing an out of source build
Hifi uses CMake to generate build files and project files for your platform.
#### Qt
CMake will download Qt 5.12.3 using vcpkg.
In order for CMake to find the Qt5 find modules, you will need to set a QT_CMAKE_PREFIX_PATH environment variable pointing to your Qt installation.
To override this (i.e. use an installed Qt configuration - you will need to set a QT_CMAKE_PREFIX_PATH environment variable pointing to your Qt **lib/cmake** folder.
This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment). The path it needs to be set to will depend on where and how Qt5 was installed. e.g.
This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
The path it needs to be set to will depend on where and how Qt5 was installed. e.g.
export QT_CMAKE_PREFIX_PATH=/usr/local/Qt5.10.1/5.10.1/gcc_64/lib/cmake
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.10.1/clang_64/lib/cmake/
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.10.1/lib/cmake
export QT_CMAKE_PREFIX_PATH=/usr/local/Qt5.12.3/gcc_64/lib/cmake
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.12.3/clang_64/lib/cmake/
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.12.3/lib/cmake
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
#### Vcpkg
@ -68,15 +65,15 @@ Create a build directory in the root of your checkout and then run the CMake bui
cd build
cmake ..
If cmake gives you the same error message repeatedly after the build fails (e.g. you had a typo in the QT_CMAKE_PREFIX_PATH that you fixed but the `.cmake` files still cannot be found), try removing `CMakeCache.txt`.
If cmake gives you the same error message repeatedly after the build fails, try removing `CMakeCache.txt`.
#### Variables
Any variables that need to be set for CMake to find dependencies can be set as ENV variables in your shell profile, or passed directly to CMake with a `-D` flag appended to the `cmake ..` command.
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
For example, to pass the QT_CMAKE_PREFIX_PATH variable (if not using the vcpkg'ed version) during build file generation:
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.10.1/lib/cmake
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.12.3/lib/cmake
#### Finding Dependencies

View file

@ -1,64 +1,118 @@
Please read the [general build guide](BUILD.md) for information on building other platform. Only Android specific instructions are found in this file.
Please read the [general build guide](BUILD.md) for information on building other platforms. Only Android specific instructions are found in this file. **Note that these instructions apply to building for Oculus Quest.**
# Dependencies
Building is currently supported on OSX, Windows and Linux platforms, but developers intending to do work on the library dependencies are strongly urged to use 64 bit Linux as a build platform
Building is currently supported on Windows, OSX and Linux, but developers intending to do work on the library dependencies are strongly urged to use 64 bit Linux as a build platform.
You will need the following tools to build Android targets.
### OS specific dependencies
* [Android Studio](https://developer.android.com/studio/index.html)
Please install the dependencies for your OS using the [Windows](BUILD_WIN.md), [OSX](BUILD_OSX.md) or [Linux](BUILD_LINUX.md) build instructions before attempting to build for Android.
### Android Studio
Download the Android Studio installer and run it. Once installed, at the welcome screen, click configure in the lower right corner and select SDK manager
Download the [Android Studio](https://developer.android.com/studio/index.html) installer and run it. Once installed, at the welcome screen, click _Configure_ in the lower right corner and select _SDK Manager_.
From the SDK Platforms tab, select API levels 24 and 26.
From the _SDK Platforms_ tab, select API levels 26 and 28.
From the SDK Tools tab select the following
From the _SDK Tools_ tab, select the following
* Android SDK Build-Tools
* GPU Debugging Tools
* CMake (even if you have a separate CMake installation)
* LLDB
* Android SDK Platform-Tools
* Android SDK Tools
* NDK (even if you have the NDK installed separately)
Make sure the NDK installed version is 18 (or higher)
Still in the _SDK Tools_ tab, click _Show Package Details_. Select CMake 3.6.4. Do this even if you have a separate CMake installation.
# Environment
Also, make sure the NDK installed version is 18 (or higher).
Setting up the environment for android builds requires some additional steps
# Environment
#### Set up machine specific Gradle properties
### Create a keystore in Android Studio
Follow the directions [here](https://developer.android.com/studio/publish/app-signing#generate-key) to create a keystore file. You can save it anywhere (preferably not in the `hifi` folder).
Create a `gradle.properties` file in $HOME/.gradle. Edit the file to contain the following
### Set up machine specific Gradle properties
Create a `gradle.properties` file in the `.gradle` folder (`$HOME/.gradle` on Unix, `Users/<yourname>/.gradle` on Windows). Edit the file to contain the following
HIFI_ANDROID_PRECOMPILED=<your_home_directory>/Android/hifi_externals
HIFI_ANDROID_KEYSTORE=<key_store_directory>/<keystore_name>.jks
HIFI_ANDROID_KEYSTORE_PASSWORD=<password>
HIFI_ANDROID_KEY_ALIAS=<key_alias>
HIFI_ANDROID_KEY_PASSWORD=<key_passwords>
Note, do not use `$HOME` for the path. It must be a fully qualified path name.
Note, do not use $HOME for the path. It must be a fully qualified path name. Also, be sure to use forward slashes in your path.
### Setup the repository
#### If you are building for an Android phone
Clone the repository
Add these lines to `gradle.properties`
`git clone https://github.com/highfidelity/hifi.git`
SUPPRESS_QUEST_INTERFACE
SUPPRESS_QUEST_FRAME_PLAYER
Enter the repository `android` directory
#### If you are building for an Oculus Quest
`cd hifi/android`
Add these lines to `gradle.properties`
Execute two gradle pre-build steps. This steps should only need to be done once, unless you're working on the Android dependencies
SUPPRESS_INTERFACE
SUPPRESS_FRAME_PLAYER
`./gradlew extractDependencies`
The above code to suppress modules is not necessary, but will speed up the build process.
`./gradlew setupDependencies`
### Clone the repository
`git clone https://github.com/highfidelity/hifi.git `
# Building & Running
* Open Android Studio
* Choose _Open Existing Android Studio Project_
* Navigate to the `hifi` repository and choose the `android` folder and select _OK_
* From the _Build_ menu select _Make Project_
* Once the build completes, from the _Run_ menu select _Run App_
### Building Modules
* Open Android Studio
* Choose _Open an existing Android Studio project_
* Navigate to the `hifi` repository and choose the `android` folder and select _OK_
* Wait for Gradle to sync (this should take around 20 minutes the first time)
* From the _Build_ menu select _Make Project_
### Running a Module
* In the toolbar at the top of Android Studio, next to the green hammer icon, you should see a dropdown menu.
* You may already see a configuration for the module you are trying to build. If so, select it.
* Otherwise, select _Edit Configurations_.
Your configuration should be as follows
* Type: Android App
* Module: <your module> (you probably want `interface` or `questInterface`)
For the interface modules, you also need to select the activity to launch.
#### For the Android phone interface
* From the _Launch_ drop down menu, select _Specified Activity_
* In the _Activity_ field directly below, put `io.highfidelity.hifiinterface.PermissionChecker`
#### For the Oculus Quest interface
* From the _Launch_ drop down menu, select _Specified Activity_
* In the _Activity_ field directly below, put `io.highfidelity.questInterface.PermissionsChecker`
Note the 's' in Permission**s**Checker for the Quest.
Now you are able to run your module! Click the green play button in the top toolbar of Android Studio
r
# Troubleshooting
To view a more complete debug log,
* Click the icon with the two overlapping squares in the upper left corner of the tab where the sync is running (hover text says _Toggle view_)
* To change verbosity, click _File > Settings_. Under _Build, Execution, Deployment > Compiler_ you can add command-line flags, as per Gradle documentation
Some things you can try if you want to do a clean build
* Delete the `build` and `.externalNativeBuild` folders from the folder for each module you're building (for example, `hifi/android/apps/interface`)
* If you have set your `HIFI_VCPKG_ROOT` environment variable, delete the contents of that directory; otherwise, delete `AppData/Local/Temp/hifi`
* 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

View file

@ -2,56 +2,72 @@
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.
## Qt5 Dependencies
Should you choose not to install Qt5 via a package manager that handles dependencies for you, you may be missing some Qt5 dependencies. On Ubuntu, for example, the following additional packages are required:
libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev zlib1g-dev
## Ubuntu 16.04/18.04 specific build guide
### Ubuntu 18.04 only
### Ubuntu 16.04 only
Add the following line to *.bash_profile*
`export QT_QPA_FONTDIR=/usr/share/fonts/truetype/dejavu/`
### Ubuntu 18.04 server only
Add the universe repository:
_(This is not enabled by default on the server edition)_
```bash
sudo add-apt-repository universe
sudo apt-get update
```
### Prepare environment
Install Qt 5.10.1:
#### Install build tools:
1. First update the repositiories:
```bash
wget http://debian.highfidelity.com/pool/h/hi/hifiqt5.10.1_5.10.1_amd64.deb
sudo dpkg -i hifiqt5.10.1_5.10.1_amd64.deb
sudo apt-get update -y
sudo apt-get upgrade -y
```
Install build dependencies:
1. git
```bash
sudo apt-get install libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev zlib1g-dev
sudo apt-get install git -y
```
To compile interface in a server you must install:
Verify by git --version
1. g++
```bash
sudo apt-get install g++ -y
```
Verify by g++ --version
1. *Ubuntu 18.04* cmake
```bash
sudo apt-get install cmake -y
```
Verify by git --version
1. *Ubuntu 16.04* cmake
```bash
wget https://cmake.org/files/v3.14/cmake-3.14.2-Linux-x86_64.sh
sudo sh cmake-3.14.2-Linux-x86_64.sh --prefix=/usr/local --exclude-subdir
```
#### Install build dependencies:
1. OpenSSL
```bash
sudo apt-get install libssl-dev
```
Verify with `openssl version`
1. OpenGL
Verify (first install mesa-utils - `sudo apt install mesa-utils -y`) by `glxinfo | grep "OpenGL version"`
```bash
sudo apt-get install libgl1-mesa-dev -y
sudo ln -s /usr/lib/x86_64-linux-gnu/libGL.so.346.35 /usr/lib/x86_64-linux-gnu/libGL.so.1.2.0
```
#### To compile interface in a server you must install:
```bash
sudo apt-get -y install libpulse0 libnss3 libnspr4 libfontconfig1 libxcursor1 libxcomposite1 libxtst6 libxslt1.1
```
Install build tools:
1. Misc dependencies
```bash
# For Ubuntu 18.04
sudo apt-get install cmake
sudo apt-get install libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev zlib1g-dev
```
1. To compile interface in a server you must install:
```bash
# For Ubuntu 16.04
wget https://cmake.org/files/v3.9/cmake-3.9.5-Linux-x86_64.sh
sudo sh cmake-3.9.5-Linux-x86_64.sh --prefix=/usr/local --exclude-subdir
sudo apt-get -y install libpulse0 libnss3 libnspr4 libfontconfig1 libxcursor1 libxcomposite1 libxtst6 libxslt1.1
```
Install Python 3:
1. Install Python 3:
```bash
sudo apt-get install python3.6
```
Install node, required to build the jsdoc documentation
1. Install node, required to build the jsdoc documentation
```bash
sudo apt-get install nodejs
```
@ -84,9 +100,11 @@ cd hifi/build
Prepare makefiles:
```bash
cmake -DQT_CMAKE_PREFIX_PATH=/usr/local/Qt5.10.1/5.10.1/gcc_64/lib/cmake ..
cmake ..
```
* If cmake fails with a vcpkg error - delete /tmp/hifi/vcpkg.
Start compilation of the server and get a cup of coffee:
```bash
make domain-server assignment-client
@ -128,46 +146,34 @@ Go to localhost in the running interface.
In Ubuntu 18.04 there is a problem related with NVidia driver library version.
It can be workarounded following these steps:
It can be worked around following these steps:
Uninstall incompatible nvtt libraries:
```bash
sudo apt-get remove libnvtt2 libnvtt-dev
```
1. Uninstall incompatible nvtt libraries:
`sudo apt-get remove libnvtt2 libnvtt-dev`
Install libssl1.0-dev:
```bash
sudo apt-get -y install libssl1.0-dev
```
1. Install libssl1.0-dev:
`sudo apt-get -y install libssl1.0-dev`
Clone castano nvidia-texture-tools:
```
git clone https://github.com/castano/nvidia-texture-tools
cd nvidia-texture-tools/
```
1. Clone castano nvidia-texture-tools:
`git clone https://github.com/castano/nvidia-texture-tools`
`cd nvidia-texture-tools/`
Make these changes in repo:
* In file **VERSION** set `2.2.1`
* In file **configure**:
* set `build="release"`
* set `-DNVTT_SHARED=1`
1. Make these changes in repo:
* In file **VERSION** set `2.2.1`
* In file **configure**:
* set `build="release"`
* set `-DNVTT_SHARED=1`
Configure, build and install:
```
./configure
make
sudo make install
```
1. Configure, build and install:
`./configure`
`make`
`sudo make install`
Link compiled files:
```
sudo ln -s /usr/local/lib/libnvcore.so /usr/lib/libnvcore.so
sudo ln -s /usr/local/lib/libnvimage.so /usr/lib/libnvimage.so
sudo ln -s /usr/local/lib/libnvmath.so /usr/lib/libnvmath.so
sudo ln -s /usr/local/lib/libnvtt.so /usr/lib/libnvtt.so
```
1.. Link compiled files:
`sudo ln -s /usr/local/lib/libnvcore.so /usr/lib/libnvcore.so`
`sudo ln -s /usr/local/lib/libnvimage.so /usr/lib/libnvimage.so`
`sudo ln -s /usr/local/lib/libnvmath.so /usr/lib/libnvmath.so`
`sudo ln -s /usr/local/lib/libnvtt.so /usr/lib/libnvtt.so`
After running this steps you can run interface:
```
interface/interface
```
1. After running this steps you can run interface:
`interface/interface`

View file

@ -4,30 +4,21 @@ Please read the [general build guide](BUILD.md) for information on dependencies
[Homebrew](https://brew.sh/) is an excellent package manager for macOS. It makes install of some High Fidelity dependencies very simple.
brew install cmake openssl qt
brew install cmake openssl
### Python 3
Download an install Python 3.6.6 or higher from [here](https://www.python.org/downloads/). Execute the `Update Shell Profile.command` script that is provided with the installer.
Download an install Python 3.6.6 or higher from [here](https://www.python.org/downloads/).
Execute the `Update Shell Profile.command` script that is provided with the installer.
### OpenSSL
Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations.
Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations.
For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR:
export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2l
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
### Qt
Assuming you've installed Qt using the homebrew instructions above, you'll need to set QT_CMAKE_PREFIX_PATH so CMake can find your installations.
For Qt installed via homebrew, set QT_CMAKE_PREFIX_PATH:
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt/5.10.1/lib/cmake
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
### Xcode
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.

View file

@ -1,65 +0,0 @@
Please read the [general build guide](BUILD.md) for information on building other platform. Only Quest specific instructions are found in this file.
# Dependencies
Building is currently supported on OSX, Windows and Linux platforms, but developers intending to do work on the library dependencies are strongly urged to use 64 bit Linux as a build platform
You will need the following tools to build Android targets.
* [Android Studio](https://developer.android.com/studio/index.html)
### Android Studio
Download the Android Studio installer and run it. Once installed, at the welcome screen, click configure in the lower right corner and select SDK manager
From the SDK Platforms tab, select API levels 24 and 26.
From the SDK Tools tab select the following
* Android SDK Build-Tools
* GPU Debugging Tools
* CMake (even if you have a separate CMake installation)
* LLDB
* Android SDK Platform-Tools
* Android SDK Tools
* NDK (even if you have the NDK installed separately)
Make sure the NDK installed version is 18 (or higher)
# Environment
Setting up the environment for android builds requires some additional steps
#### Set up machine specific Gradle properties
Create a `gradle.properties` file in $HOME/.gradle. Edit the file to contain the following
HIFI_ANDROID_PRECOMPILED=<your_home_directory>/Android/hifi_externals
HIFI_ANDROID_KEYSTORE=<key_store_directory>/<keystore_name>.jks
HIFI_ANDROID_KEYSTORE_PASSWORD=<password>
HIFI_ANDROID_KEY_ALIAS=<key_alias>
HIFI_ANDROID_KEY_PASSWORD=<key_password>
Note, do not use `$HOME` for the path. It must be a fully qualified path name.
### Setup the repository
Clone the repository
`git clone https://github.com/highfidelity/hifi.git`
Enter the repository `android` directory
`cd hifi/android`
# Building & Running
* Open Android Studio
* Choose _Open Existing Android Studio Project_
* Navigate to the `hifi` repository and choose the `android` folder and select _OK_
* Open Gradle.settings and comment out any projects not necessary
* From _File_ menu select _Sync with File System_ to resync Gradle settings
* From the _Build_ menu select _Make Project_
* From
* Once the build completes, from the _Run_ menu select _Run App_

View file

@ -1,17 +1,29 @@
This is a stand-alone guide for creating your first High Fidelity build for Windows 64-bit.
This is a stand-alone guide for creating your first High Fidelity build for Windows 64-bit.
## Building High Fidelity
Note: We are now using Visual Studio 2017 and Qt 5.10.1. If you are upgrading from Visual Studio 2013 and Qt 5.6.2, do a clean uninstall of those versions before going through this guide.
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.
### Step 1. Visual Studio 2017 & Python
### Step 1. Visual Studio & Python
If you dont have Community or Professional edition of Visual Studio 2017, download [Visual Studio Community 2017](https://www.visualstudio.com/downloads/).
If you dont 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++". Also on the right on the Summary toolbar, check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)". If you do not already have a python development environment installed, also check "Python Development" in this screen.
When selecting components, check "Desktop development with C++". On the right on the Summary toolbar, select the following components.
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.
#### 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,
* 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 development environment installed, also check "Python Development" in this screen.
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
@ -22,28 +34,18 @@ If you do not wish to use the Python installation bundled with Visual Studio, yo
Download and install the latest version of CMake 3.9.
Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.9 Version page](https://cmake.org/files/v3.9/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted.
### Step 3. Installing Qt
Download and install the [Qt Open Source Online Installer](https://www.qt.io/download-open-source/?hsCtaTracking=f977210e-de67-475f-a32b-65cec207fd03%7Cd62710cd-e1db-46aa-8d4d-2f1c1ffdacea). While installing, you only need to have the following components checked under Qt 5.10.1: "msvc2017 64-bit", "Qt WebEngine", and "Qt Script (Deprecated)".
Note: Installing the Sources is optional but recommended if you have room for them (~2GB).
### Step 4. Setting Qt Environment Variable
Go to `Control Panel > System > Advanced System Settings > Environment Variables > New...` (or search “Environment Variables” in Start Search).
* Set "Variable name": `QT_CMAKE_PREFIX_PATH`
* Set "Variable value": `C:\Qt\5.10.1\msvc2017_64\lib\cmake`
### Step 5. Running CMake to Generate Build Files
Run Command Prompt from Start and run the following commands:
```
cd "%HIFI_DIR%"
mkdir build
cd build
cmake .. -G "Visual Studio 15 Win64"
```
Run Command Prompt from Start and run the following commands:
`cd "%HIFI_DIR%"`
`mkdir build`
`cd build`
#### If you're using Visual Studio 2017,
Run `cmake .. -G "Visual Studio 15 Win64"`.
#### If you're using Visual Studio 2019,
Run `cmake .. -G "Visual Studio 16 2019" -A x64`.
Where `%HIFI_DIR%` is the directory for the highfidelity repository.
@ -73,11 +75,11 @@ Note: You can also run Interface by launching it from command line or File Explo
## Troubleshooting
For any problems after Step #7, first try this:
* Delete your locally cloned copy of the highfidelity repository
* Restart your computer
* Redownload the [repository](https://github.com/highfidelity/hifi)
* Restart directions from Step #7
For any problems after Step #7, first try this:
* Delete your locally cloned copy of the highfidelity repository
* Restart your computer
* Redownload the [repository](https://github.com/highfidelity/hifi)
* Restart directions from Step #7
#### CMake gives you the same error message repeatedly after the build fails
@ -85,8 +87,4 @@ Remove `CMakeCache.txt` found in the `%HIFI_DIR%\build` directory.
#### CMake can't find OpenSSL
Remove `CMakeCache.txt` found in the `%HIFI_DIR%\build` directory. Verify that your VCPKG_ROOT environment variable is set and pointing to the correct location. Verify that the file `${VCPKG_ROOT}/installed/x64-windows/include/openssl/ssl.h` exists.
#### Qt is throwing an error
Make sure you have the correct version (5.10.1) installed and `QT_CMAKE_PREFIX_PATH` environment variable is set correctly.
Remove `CMakeCache.txt` found in the `%HIFI_DIR%\build` directory. Verify that your HIFI_VCPKG_BASE environment variable is set and pointing to the correct location. Verify that the file `${HIFI_VCPKG_BASE}/installed/x64-windows/include/openssl/ssl.h` exists.

View file

@ -17,14 +17,19 @@ if (APPLE)
set(ENV{MACOSX_DEPLOYMENT_TARGET} 10.9)
endif()
set(RELEASE_TYPE "$ENV{RELEASE_TYPE}")
if ((NOT "${RELEASE_TYPE}" STREQUAL "PRODUCTION") AND (NOT "${RELEASE_TYPE}" STREQUAL "PR"))
set(RELEASE_TYPE "DEV")
endif()
if (HIFI_ANDROID)
execute_process(
COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_CURRENT_SOURCE_DIR}/prebuild.py --android ${HIFI_ANDROID_APP} --build-root ${CMAKE_BINARY_DIR}
COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_CURRENT_SOURCE_DIR}/prebuild.py --release-type ${RELEASE_TYPE} --android ${HIFI_ANDROID_APP} --build-root ${CMAKE_BINARY_DIR}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
else()
execute_process(
COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_CURRENT_SOURCE_DIR}/prebuild.py --build-root ${CMAKE_BINARY_DIR}
COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_CURRENT_SOURCE_DIR}/prebuild.py --release-type ${RELEASE_TYPE} --build-root ${CMAKE_BINARY_DIR}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
# squelch the Policy CMP0074 warning without requiring an update to cmake 3.12.
@ -36,8 +41,8 @@ endif()
if(NOT EXISTS "${CMAKE_BINARY_DIR}/vcpkg.cmake")
message(FATAL_ERROR "vcpkg configuration missing.")
endif()
include("${CMAKE_BINARY_DIR}/vcpkg.cmake")
project(hifi)
include("cmake/init.cmake")
include("cmake/compiler.cmake")
@ -93,9 +98,9 @@ if (ANDROID)
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
add_definitions(-DHIFI_ANDROID_APP=\"${HIFI_ANDROID_APP}\")
if (
(${HIFI_ANDROID_APP} STREQUAL "questInterface") OR
(${HIFI_ANDROID_APP} STREQUAL "questInterface") OR
(${HIFI_ANDROID_APP} STREQUAL "questFramePlayer") OR
(${HIFI_ANDROID_APP} STREQUAL "framePlayer")
(${HIFI_ANDROID_APP} STREQUAL "framePlayer")
)
# We know the quest hardware has this extension, so we can force the use of instanced stereo
add_definitions(-DHAVE_EXT_clip_cull_distance)
@ -105,18 +110,18 @@ if (ANDROID)
# We can also use our own foveated textures
add_definitions(-DHAVE_QCOM_texture_foveated)
# if set, the application itself or some library it depends on MUST implement
# if set, the application itself or some library it depends on MUST implement
# `DisplayPluginList getDisplayPlugins()` and `InputPluginList getInputPlugins()`
add_definitions(-DCUSTOM_INPUT_PLUGINS)
add_definitions(-DCUSTOM_DISPLAY_PLUGINS)
add_definitions(-DCUSTOM_INPUT_PLUGINS)
add_definitions(-DCUSTOM_DISPLAY_PLUGINS)
set(PLATFORM_PLUGIN_LIBRARIES oculusMobile oculusMobilePlugin)
endif()
# Allow client code to use preprocessor macros to distinguish between quest and non-quest builds
if (${HIFI_ANDROID_APP} STREQUAL "questInterface")
add_definitions(-DANDROID_APP_QUEST_INTERFACE)
add_definitions(-DANDROID_APP_QUEST_INTERFACE)
elseif(${HIFI_ANDROID_APP} STREQUAL "interface")
add_definitions(-DANDROID_APP_INTERFACE)
add_definitions(-DANDROID_APP_INTERFACE)
endif()
else ()
set(PLATFORM_QT_COMPONENTS WebEngine Xml)
@ -194,6 +199,8 @@ GroupSources("scripts")
GroupSources("unpublishedScripts")
unset(JS_SRC)
set_packaging_parameters()
# Locate the required Qt build on the filesystem
setup_qt()
list(APPEND CMAKE_PREFIX_PATH "${QT_CMAKE_PREFIX_PATH}")
@ -203,6 +210,12 @@ find_package( Threads )
add_definitions(-DGLM_FORCE_RADIANS)
add_definitions(-DGLM_ENABLE_EXPERIMENTAL)
add_definitions(-DGLM_FORCE_CTOR_INIT)
if (WIN32)
# Deal with fakakta Visual Studo 2017 bug
add_definitions(-DQT_NO_FLOAT16_OPERATORS)
endif()
if (HIFI_USE_OPTIMIZED_IK)
MESSAGE(STATUS "SET THE USE IK DEFINITION ")
add_definitions(-DHIFI_USE_OPTIMIZED_IK)
@ -215,8 +228,6 @@ setup_externals_binary_dir()
option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
set_packaging_parameters()
# FIXME hack to work on the proper Android toolchain
if (ANDROID)
add_subdirectory(android/apps/${HIFI_ANDROID_APP})
@ -250,11 +261,11 @@ add_subdirectory(tools)
if (BUILD_TESTS)
# Turn on testing so that add_test works
# MUST be in the root cmake file for ctest to work
# MUST be in the root cmake file for ctest to work
include(CTest)
enable_testing()
add_subdirectory(tests)
if (BUILD_MANUAL_TESTS)
if (BUILD_MANUAL_TESTS)
add_subdirectory(tests-manual)
endif()
endif()

View file

@ -204,7 +204,10 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
if (traitType == AvatarTraits::SkeletonModelURL) {
// special handling for skeleton model URL, since we need to make sure it is in the whitelist
checkSkeletonURLAgainstWhitelist(slaveSharedData, sendingNode, packetTraitVersion);
#ifdef AVATAR_POP_CHECK
// Deferred for UX work. With no PoP check, no need to get the .fst.
_avatar->fetchAvatarFST();
#endif
}
anyTraitsChanged = true;

View file

@ -138,7 +138,7 @@ public:
/// Returns the index of the joint with the specified name, or -1 if not found/unknown.
Q_INVOKABLE virtual int getJointIndex(const QString& name) const override;
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
Q_INVOKABLE virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
/**jsdoc
* @comment Uses the base class's JSDoc.

View file

@ -10,28 +10,32 @@
#
macro(fixup_interface)
if (APPLE)
if (APPLE)
string(REPLACE " " "\\ " ESCAPED_BUNDLE_NAME ${INTERFACE_BUNDLE_NAME})
string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${INTERFACE_INSTALL_DIR})
set(_INTERFACE_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app")
string(REPLACE " " "\\ " ESCAPED_BUNDLE_NAME ${INTERFACE_BUNDLE_NAME})
string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${INTERFACE_INSTALL_DIR})
set(_INTERFACE_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app")
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH)
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH)
if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD))
message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin.\
It is required to produce an relocatable interface application.\
Check that the variable QT_DIR points to your Qt installation.\
")
endif ()
if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD))
message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin.\
It is required to produce an relocatable interface application.\
Check that the environment variable QT_DIR points to your Qt installation.\
")
if (RELEASE_TYPE STREQUAL "DEV")
install(CODE "
execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\
\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/\
-verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\
)"
COMPONENT ${CLIENT_COMPONENT}
)
else ()
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${MACDEPLOYQT_COMMAND} "$<TARGET_FILE_DIR:${TARGET_NAME}>/../.." -verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/
)
endif()
endif ()
install(CODE "
execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\
\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/\
-verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\
)"
COMPONENT ${CLIENT_COMPONENT}
)
endif ()
endmacro()

View file

@ -10,27 +10,32 @@
#
macro(fixup_nitpick)
if (APPLE)
string(REPLACE " " "\\ " ESCAPED_BUNDLE_NAME ${NITPICK_BUNDLE_NAME})
string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${NITPICK_INSTALL_DIR})
set(_NITPICK_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app")
if (APPLE)
string(REPLACE " " "\\ " ESCAPED_BUNDLE_NAME ${NITPICK_BUNDLE_NAME})
string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${NITPICK_INSTALL_DIR})
set(_NITPICK_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app")
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH)
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH)
if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD))
message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin.\
It is required to produce a relocatable nitpick application.\
Check that the environment variable QT_DIR points to your Qt installation.\
")
if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD))
message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin.\
It is required to produce a relocatable nitpick application.\
Check that the variable QT_DIR points to your Qt installation.\
")
endif ()
if (RELEASE_TYPE STREQUAL "DEV")
install(CODE "
execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\
\${CMAKE_INSTALL_PREFIX}/${_NITPICK_INSTALL_PATH}/\
-verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\
)"
COMPONENT ${CLIENT_COMPONENT}
)
else ()
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${MACDEPLOYQT_COMMAND} "$<TARGET_FILE_DIR:${TARGET_NAME}>/../.." -verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/
)
endif()
endif ()
install(CODE "
execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\
\${CMAKE_INSTALL_PREFIX}/${_NITPICK_INSTALL_PATH}/\
-verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\
)"
COMPONENT ${CLIENT_COMPONENT}
)
endif ()
endmacro()

View file

@ -39,7 +39,7 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT)
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND}\
COMMAND CMD /C "SET PATH=${QT_DIR}/bin;%PATH% && ${WINDEPLOYQT_COMMAND}\
${EXTRA_DEPLOY_OPTIONS} $<$<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>:--release>\
--no-compiler-runtime --no-opengl-sw --no-angle -no-system-d3d-compiler \"$<TARGET_FILE:${TARGET_NAME}>\""
)

View file

@ -1,4 +1,3 @@
#
# Created by Bradley Austin Davis on 2017/09/02
# Copyright 2013-2017 High Fidelity, Inc.
#
@ -6,67 +5,91 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
# Construct a default QT location from a root path, a version and an architecture
function(calculate_default_qt_dir _QT_VERSION _RESULT_NAME)
if (ANDROID)
set(QT_DEFAULT_ARCH "android_armv7")
elseif(UWP)
set(QT_DEFAULT_ARCH "winrt_x64_msvc2017")
elseif(APPLE)
set(QT_DEFAULT_ARCH "clang_64")
elseif(WIN32)
set(QT_DEFAULT_ARCH "msvc2017_64")
else()
set(QT_DEFAULT_ARCH "gcc_64")
function(get_sub_directories result curdir)
file(GLOB children RELATIVE ${curdir} ${curdir}/*)
set(dirlist "")
foreach(child ${children})
if(IS_DIRECTORY ${curdir}/${child})
LIST(APPEND dirlist ${child})
endif()
endforeach()
set(${result} ${dirlist} PARENT_SCOPE)
endfunction()
if (WIN32 OR (ANDROID AND ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")))
set(QT_DEFAULT_ROOT "c:/Qt")
else()
set(QT_DEFAULT_ROOT "$ENV{HOME}/Qt")
function(calculate_qt5_version result _QT_DIR)
# All Qt5 packages have little "private" include directories named with the actual Qt version such as:
# .../include/QtCore/5.12.3/QtCore/private
# Sometimes we need to include these private headers for debug hackery.
# Hence we find one of these directories and pick apart its path to determine the actual QT_VERSION.
if (APPLE)
set(_QT_CORE_DIR "${_QT_DIR}/lib/QtCore.framework/Versions/5/Headers")
else()
set(_QT_CORE_DIR "${_QT_DIR}/include/QtCore")
endif()
if(NOT EXISTS "${_QT_CORE_DIR}")
message(FATAL_ERROR "Could not find 'include/QtCore' in '${_QT_DIR}'")
endif()
set(subdirs "")
get_sub_directories(subdirs ${_QT_CORE_DIR})
foreach(subdir ${subdirs})
string(REGEX MATCH "5.[0-9]+.[0-9]+$" _QT_VERSION ${subdir})
if (NOT "${_QT_VERSION}" STREQUAL "")
# found it!
set(${result} "${_QT_VERSION}" PARENT_SCOPE)
break()
endif()
set_from_env(QT_ROOT QT_ROOT ${QT_DEFAULT_ROOT})
set_from_env(QT_ARCH QT_ARCH ${QT_DEFAULT_ARCH})
set(${_RESULT_NAME} "${QT_ROOT}/${_QT_VERSION}/${QT_ARCH}" PARENT_SCOPE)
endforeach()
endfunction()
# Sets the QT_CMAKE_PREFIX_PATH and QT_DIR variables
# Also enables CMAKE_AUTOMOC and CMAKE_AUTORCC
macro(setup_qt)
set_from_env(QT_VERSION QT_VERSION "5.10.1")
# if QT_CMAKE_PREFIX_PATH was not specified before hand,
# try to use the environment variable
if (NOT QT_CMAKE_PREFIX_PATH)
set(QT_CMAKE_PREFIX_PATH "$ENV{QT_CMAKE_PREFIX_PATH}")
# if we are in a development build and QT_CMAKE_PREFIX_PATH is specified
# then use it,
# otherwise, use the vcpkg'ed version
if(NOT DEFINED VCPKG_QT_CMAKE_PREFIX_PATH)
message(FATAL_ERROR "VCPKG_QT_CMAKE_PREFIX_PATH should have been set by hifi_vcpkg.py")
endif()
if (("QT_CMAKE_PREFIX_PATH" STREQUAL "") OR (NOT EXISTS "${QT_CMAKE_PREFIX_PATH}"))
calculate_default_qt_dir(${QT_VERSION} QT_DIR)
set(QT_CMAKE_PREFIX_PATH "${QT_DIR}/lib/cmake")
if (NOT DEV_BUILD)
if (APPLE)
# HACK: manually set the QT_CMAKE_PREFIX_PATH so that hard-coded paths find new QT libs where we'll put them
set(QT_CMAKE_PREFIX_PATH "/var/tmp/qt5-install/lib/cmake")
elseif (UNIX AND DEFINED ENV{QT_CMAKE_PREFIX_PATH})
# HACK: obey QT_CMAKE_PREFIX_PATH to allow UNIX to use older QT libs
set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH})
else()
set(QT_CMAKE_PREFIX_PATH ${VCPKG_QT_CMAKE_PREFIX_PATH})
endif()
else()
# figure out where the qt dir is
get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE)
# DEV_BUILD
if (DEFINED ENV{QT_CMAKE_PREFIX_PATH})
set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH})
else()
set(QT_CMAKE_PREFIX_PATH ${VCPKG_QT_CMAKE_PREFIX_PATH})
endif()
endif()
if (WIN32)
# figure out where the qt dir is
get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE)
set(QT_VERSION "unknown")
calculate_qt5_version(QT_VERSION "${QT_DIR}")
if (QT_VERSION STREQUAL "unknown")
message(FATAL_ERROR "Could not determine QT_VERSION")
endif()
if(WIN32)
# windows shell does not like backslashes expanded on the command line,
# so convert all backslashes in the QT path to forward slashes
string(REPLACE \\ / QT_CMAKE_PREFIX_PATH ${QT_CMAKE_PREFIX_PATH})
string(REPLACE \\ / QT_DIR ${QT_DIR})
endif()
# This check doesn't work on Mac
#if (NOT EXISTS "${QT_DIR}/include/QtCore/QtGlobal")
# message(FATAL_ERROR "Unable to locate Qt includes in ${QT_DIR}")
#endif()
if (NOT EXISTS "${QT_CMAKE_PREFIX_PATH}/Qt5Core/Qt5CoreConfig.cmake")
message(FATAL_ERROR "Unable to locate Qt cmake config in ${QT_CMAKE_PREFIX_PATH}")
if(NOT EXISTS "${QT_CMAKE_PREFIX_PATH}/Qt5Core/Qt5CoreConfig.cmake")
message(FATAL_ERROR "Unable to locate Qt5CoreConfig.cmake in '${QT_CMAKE_PREFIX_PATH}'")
endif()
message(STATUS "The Qt build in use is: \"${QT_DIR}\"")
message(STATUS "Using Qt build in : '${QT_DIR}' with version ${QT_VERSION}")
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)

View file

@ -25,14 +25,13 @@ vcpkg_from_github(
HEAD_REF master
)
vcpkg_configure_cmake(
SOURCE_PATH ${SOURCE_PATH}
OPTIONS
-DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=ON
-DUSE_MSVC_RUNTIME_LIBRARY_DLL=ON
-DUSE_GLUT=0
-DUSE_DX11=0
-DUSE_GLUT=0
-DUSE_DX11=0
-DBUILD_DEMOS=OFF
-DBUILD_OPENGL3_DEMOS=OFF
-DBUILD_BULLET3=OFF

5
debian/changelog vendored Normal file
View file

@ -0,0 +1,5 @@
hifi-interface (84-1) unstable; urgency=medium
* Initial release
-- Seth Alves <seth.alves@gmail.com> Tue, 14 May 2019 19:45:31 -0700

1
debian/compat vendored Normal file
View file

@ -0,0 +1 @@
11

15
debian/control vendored Normal file
View file

@ -0,0 +1,15 @@
Source: hifi-interface
Section: comm
Priority: optional
Maintainer: Seth Alves <seth.alves@gmail.com>
Build-Depends: debhelper (>= 11), cmake
Standards-Version: 4.1.3
Homepage: https://www.highfidelity.com/
Vcs-Browser: https://github.com/highfidelity/hifi
Vcs-Git: https://github.com/highfidelity/hifi.git
Package: hifi-interface
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libqt5quick5, libqt5quickcontrols2-5, libqt5quickwidgets5, qml-module-qtquick-controls, qml-module-qtquick-controls2, qml-module-qtquick-dialogs, libqt5webchannel5, qml-module-qtwebchannel, qml-module-qtwebengine, qml-module-qt-labs-folderlistmodel, qml-module-qt-labs-settings
Description: High Fidelity allows creation and sharing of VR experiences.
The High Fidelity metaverse provides built-in social features, including avatar interactions, spatialized audio and interactive physics. Additionally, you have the ability to import any 3D object into your virtual environment.

23
debian/copyright vendored Normal file
View file

@ -0,0 +1,23 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: hifi-interface
Source: https://github.com/highfidelity/hifi
Files: *
Copyright: 2013-2019, High Fidelity, Inc.
License: Apache-2.0
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
https://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian systems, the complete text of the Apache version 2.0 license
can be found in "/usr/share/common-licenses/Apache-2.0".

2
debian/hifi-interface-docs.docs vendored Normal file
View file

@ -0,0 +1,2 @@
README.Debian
README.source

1
debian/hifi-interface.dirs vendored Normal file
View file

@ -0,0 +1 @@
opt/hifi/interface/

76
debian/patches/hifi_use_system_qt.diff vendored Normal file
View file

@ -0,0 +1,76 @@
Index: hifi-interface-84/cmake/macros/SetupQt.cmake
===================================================================
--- hifi-interface-84.orig/cmake/macros/SetupQt.cmake
+++ hifi-interface-84/cmake/macros/SetupQt.cmake
@@ -18,19 +18,19 @@ function(calculate_default_qt_dir _QT_VE
elseif(WIN32)
set(QT_DEFAULT_ARCH "msvc2017_64")
else()
- set(QT_DEFAULT_ARCH "gcc_64")
+ set(QT_DEFAULT_ARCH "x86_64-linux-gnu")
endif()
if (WIN32 OR (ANDROID AND ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")))
set(QT_DEFAULT_ROOT "c:/Qt")
else()
- set(QT_DEFAULT_ROOT "$ENV{HOME}/Qt")
+ set(QT_DEFAULT_ROOT "/usr/lib")
endif()
set_from_env(QT_ROOT QT_ROOT ${QT_DEFAULT_ROOT})
set_from_env(QT_ARCH QT_ARCH ${QT_DEFAULT_ARCH})
- set(${_RESULT_NAME} "${QT_ROOT}/${_QT_VERSION}/${QT_ARCH}" PARENT_SCOPE)
+ set(${_RESULT_NAME} "${QT_ROOT}/${QT_ARCH}" PARENT_SCOPE)
endfunction()
# Sets the QT_CMAKE_PREFIX_PATH and QT_DIR variables
@@ -44,7 +44,7 @@ macro(setup_qt)
endif()
if (("QT_CMAKE_PREFIX_PATH" STREQUAL "") OR (NOT EXISTS "${QT_CMAKE_PREFIX_PATH}"))
calculate_default_qt_dir(${QT_VERSION} QT_DIR)
- set(QT_CMAKE_PREFIX_PATH "${QT_DIR}/lib/cmake")
+ set(QT_CMAKE_PREFIX_PATH "${QT_DIR}/cmake")
else()
# figure out where the qt dir is
get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE)
Index: hifi-interface-84/interface/CMakeLists.txt
===================================================================
--- hifi-interface-84.orig/interface/CMakeLists.txt
+++ hifi-interface-84/interface/CMakeLists.txt
@@ -35,7 +35,7 @@ else ()
add_custom_command(
OUTPUT ${RESOURCES_RCC}
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
- COMMAND "${QT_DIR}/bin/rcc"
+ COMMAND "rcc"
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC}
)
endif()
@@ -399,6 +399,13 @@ else()
optional_win_executable_signing()
endif()
+
+ install(
+ DIRECTORY "$<TARGET_FILE_DIR:${TARGET_NAME}>/"
+ DESTINATION ${INTERFACE_INSTALL_DIR}
+ COMPONENT ${CLIENT_COMPONENT}
+ )
+
endif()
if (SCRIPTS_INSTALL_DIR)
Index: hifi-interface-84/tools/nitpick/CMakeLists.txt
===================================================================
--- hifi-interface-84.orig/tools/nitpick/CMakeLists.txt
+++ hifi-interface-84/tools/nitpick/CMakeLists.txt
@@ -12,7 +12,7 @@ generate_qrc(OUTPUT ${RESOURCES_QRC} PAT
add_custom_command(
OUTPUT ${RESOURCES_RCC}
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
- COMMAND "${QT_DIR}/bin/rcc"
+ COMMAND "rcc"
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC}
)

1
debian/patches/series vendored Normal file
View file

@ -0,0 +1 @@
hifi_use_system_qt.diff

24
debian/rules vendored Executable file
View file

@ -0,0 +1,24 @@
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_configure:
mkdir obj-$(DEB_TARGET_MULTIARCH)
(cd obj-$(DEB_TARGET_MULTIARCH) && cmake .. -DCMAKE_INSTALL_PREFIX=/opt/hifi -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_EXPORT_NO_PACKAGE_REGISTRY=ON "-GUnix Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCLIENT_ONLY=ON -DDOWNLOAD_SERVERLESS_CONTENT=ON -DCMAKE_CXX_COMPILER=/usr/lib/llvm-7/bin/clang\+\+ -DOpenGL_GL_PREFERENCE=GLVND)
override_dh_auto_build:
(cd obj-$(DEB_TARGET_MULTIARCH) && make -j4)
S=obj-$(DEB_TARGET_MULTIARCH)
I=debian/hifi-interface/opt/hifi/interface
override_dh_auto_install:
cp $(S)/interface/interface $(I)
cp $(S)/ext/makefiles/steamworks/project/src/steamworks/redistributable_bin/linux64/libsteam_api.so $(I)
cp $(S)/ext/makefiles/quazip/project/build/libquazip5.so.1 $(I)
cp $(S)/ext/makefiles/polyvox/project/build/library/PolyVoxCore/libPolyVoxCore.so.0 $(I)
cp $(S)/interface/resources.rcc $(I)
cp -r $(S)/interface/scripts $(I)/scripts
cp -r $(S)/interface/plugins $(I)/plugins

1
debian/source/format vendored Normal file
View file

@ -0,0 +1 @@
3.0 (quilt)

6
debian/source/include-binaries vendored Normal file
View file

@ -0,0 +1,6 @@
interface/compiledResources/resources.rcc
tools/nitpick/compiledResources/resources.rcc
__pycache__/hifi_android.cpython-37.pyc
__pycache__/hifi_singleton.cpython-37.pyc
__pycache__/hifi_utils.cpython-37.pyc
__pycache__/hifi_vcpkg.cpython-37.pyc

View file

@ -128,7 +128,7 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
// signal that we just connected a node so the DomainServer can get it a list
// and broadcast its presence right away
emit connectedNode(node);
emit connectedNode(node, message->getFirstPacketReceiveTime());
} else {
qDebug() << "Refusing connection from node at" << message->getSenderSockAddr()
<< "with hardware address" << nodeConnection.hardwareAddress
@ -358,7 +358,8 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
nodeData->setNodeVersion(it->second.getNodeVersion());
nodeData->setHardwareAddress(nodeConnection.hardwareAddress);
nodeData->setMachineFingerprint(nodeConnection.machineFingerprint);
// client-side send time of last connect/domain list request
nodeData->setLastDomainCheckinTimestamp(nodeConnection.lastPingTimestamp);
nodeData->setWasAssigned(true);
// cleanup the PendingAssignedNodeData for this assignment now that it's connecting
@ -499,6 +500,9 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
// set the machine fingerprint passed in the connect request
nodeData->setMachineFingerprint(nodeConnection.machineFingerprint);
// set client-side send time of last connect/domain list request
nodeData->setLastDomainCheckinTimestamp(nodeConnection.lastPingTimestamp);
// also add an interpolation to DomainServerNodeData so that servers can get username in stats
nodeData->addOverrideForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY,
uuidStringWithoutCurlyBraces(newNode->getUUID()), username);

View file

@ -64,7 +64,7 @@ public slots:
signals:
void killNode(SharedNodePointer node);
void connectedNode(SharedNodePointer node);
void connectedNode(SharedNodePointer node, quint64 requestReceiveTime);
public slots:
void updateNodePermissions();

View file

@ -14,6 +14,7 @@
#include <memory>
#include <random>
#include <iostream>
#include <chrono>
#include <QDir>
#include <QJsonDocument>
@ -57,6 +58,8 @@
#include <OctreeDataUtils.h>
using namespace std::chrono;
Q_LOGGING_CATEGORY(domain_server, "hifi.domain_server")
Q_LOGGING_CATEGORY(domain_server_ice, "hifi.domain_server.ice")
@ -1068,7 +1071,10 @@ void DomainServer::processListRequestPacket(QSharedPointer<ReceivedMessage> mess
// update the connecting hostname in case it has changed
nodeData->setPlaceName(nodeRequestData.placeName);
sendDomainListToNode(sendingNode, message->getSenderSockAddr());
// client-side send time of last connect/domain list request
nodeData->setLastDomainCheckinTimestamp(nodeRequestData.lastPingTimestamp);
sendDomainListToNode(sendingNode, message->getFirstPacketReceiveTime(), message->getSenderSockAddr());
}
bool DomainServer::isInInterestSet(const SharedNodePointer& nodeA, const SharedNodePointer& nodeB) {
@ -1130,11 +1136,11 @@ QUrl DomainServer::oauthAuthorizationURL(const QUuid& stateUUID) {
return authorizationURL;
}
void DomainServer::handleConnectedNode(SharedNodePointer newNode) {
void DomainServer::handleConnectedNode(SharedNodePointer newNode, quint64 requestReceiveTime) {
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(newNode->getLinkedData());
// reply back to the user with a PacketType::DomainList
sendDomainListToNode(newNode, nodeData->getSendingSockAddr());
sendDomainListToNode(newNode, requestReceiveTime, nodeData->getSendingSockAddr());
// if this node is a user (unassigned Agent), signal
if (newNode->getType() == NodeType::Agent && !nodeData->wasAssigned()) {
@ -1150,7 +1156,7 @@ void DomainServer::handleConnectedNode(SharedNodePointer newNode) {
broadcastNewNode(newNode);
}
void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr &senderSockAddr) {
void DomainServer::sendDomainListToNode(const SharedNodePointer& node, quint64 requestPacketReceiveTime, const HifiSockAddr &senderSockAddr) {
const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + NLPacket::NUM_BYTES_LOCALID +
NUM_BYTES_RFC4122_UUID + NLPacket::NUM_BYTES_LOCALID + 4;
@ -1158,7 +1164,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
// this data is at the beginning of each of the domain list packets
QByteArray extendedHeader(NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES, 0);
QDataStream extendedHeaderStream(&extendedHeader, QIODevice::WriteOnly);
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
extendedHeaderStream << limitedNodeList->getSessionUUID();
@ -1167,13 +1173,14 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
extendedHeaderStream << node->getLocalID();
extendedHeaderStream << node->getPermissions();
extendedHeaderStream << limitedNodeList->getAuthenticatePackets();
extendedHeaderStream << nodeData->getLastDomainCheckinTimestamp();
extendedHeaderStream << requestPacketReceiveTime;
extendedHeaderStream << quint64(duration_cast<microseconds>(p_high_resolution_clock::now().time_since_epoch()).count());
auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader);
// always send the node their own UUID back
QDataStream domainListStream(domainListPackets.get());
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
// store the nodeInterestSet on this DomainServerNodeData, in case it has changed
auto& nodeInterestSet = nodeData->getNodeInterestSet();

View file

@ -111,7 +111,7 @@ private slots:
void sendHeartbeatToMetaverse() { sendHeartbeatToMetaverse(QString()); }
void sendHeartbeatToIceServer();
void handleConnectedNode(SharedNodePointer newNode);
void handleConnectedNode(SharedNodePointer newNode, quint64 requestReceiveTime);
void handleTempDomainSuccess(QNetworkReply* requestReply);
void handleTempDomainError(QNetworkReply* requestReply);
@ -172,7 +172,7 @@ private:
void handleKillNode(SharedNodePointer nodeToKill);
void broadcastNodeDisconnect(const SharedNodePointer& disconnnectedNode);
void sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr& senderSockAddr);
void sendDomainListToNode(const SharedNodePointer& node, quint64 requestPacketReceiveTime, const HifiSockAddr& senderSockAddr);
bool isInInterestSet(const SharedNodePointer& nodeA, const SharedNodePointer& nodeB);

View file

@ -61,6 +61,9 @@ public:
void setMachineFingerprint(const QUuid& machineFingerprint) { _machineFingerprint = machineFingerprint; }
const QUuid& getMachineFingerprint() { return _machineFingerprint; }
void setLastDomainCheckinTimestamp(quint64 lastDomainCheckinTimestamp) { _lastDomainCheckinTimestamp = lastDomainCheckinTimestamp; }
quint64 getLastDomainCheckinTimestamp() { return _lastDomainCheckinTimestamp; }
void addOverrideForKey(const QString& key, const QString& value, const QString& overrideValue);
void removeOverrideForKey(const QString& key, const QString& value);
@ -93,7 +96,7 @@ private:
QString _nodeVersion;
QString _hardwareAddress;
QUuid _machineFingerprint;
quint64 _lastDomainCheckinTimestamp;
QString _placeName;
bool _wasAssigned { false };

View file

@ -36,6 +36,8 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c
// now the machine fingerprint
dataStream >> newHeader.machineFingerprint;
}
dataStream >> newHeader.lastPingTimestamp;
dataStream >> newHeader.nodeType
>> newHeader.publicSockAddr >> newHeader.localSockAddr

View file

@ -22,6 +22,7 @@ public:
bool isConnectRequest = true);
QUuid connectUUID;
quint64 lastPingTimestamp{ 0 }; // client-side send time of last connect/domain list request
NodeType_t nodeType;
HifiSockAddr publicSockAddr;
HifiSockAddr localSockAddr;

View file

@ -15,10 +15,12 @@ print = functools.partial(print, flush=True)
# Encapsulates the vcpkg system
class VcpkgRepo:
CMAKE_TEMPLATE = """
# this file auto-generated by hifi_vcpkg.py
get_filename_component(CMAKE_TOOLCHAIN_FILE "{}" ABSOLUTE CACHE)
get_filename_component(CMAKE_TOOLCHAIN_FILE_UNCACHED "{}" ABSOLUTE)
set(VCPKG_INSTALL_ROOT "{}")
set(VCPKG_TOOLS_DIR "{}")
set(VCPKG_QT_CMAKE_PREFIX_PATH "{}")
"""
CMAKE_TEMPLATE_NON_ANDROID = """
@ -171,6 +173,11 @@ endif()
if not self.args.android:
print("Installing build dependencies")
self.run(['install', '--triplet', self.triplet, 'hifi-client-deps'])
# If not android, install our Qt build
if not self.args.android:
print("Installing Qt")
self.installQt()
def cleanBuilds(self):
# Remove temporary build artifacts
@ -206,22 +213,33 @@ endif()
with open(self.tagFile, 'w') as f:
f.write(self.tagContents)
def getQt5InstallPath(self):
qt5InstallPath = os.path.join(self.path, 'installed', 'qt5-install')
if platform.system() == "Darwin" and self.args.release_type != "DEV":
# HACK for MacOS Jenkins PRODUCTION and PR builds during Qt-5.12.3 transition
# we always supply /var/tmp/qt5-install for QT_CMAKE_PREFIX_PATH
qt5InstallPath = "/var/tmp/qt5-install"
elif self.args.android:
precompiled = os.path.realpath(self.androidPackagePath)
qt5InstallPath = os.path.realpath(os.path.join(precompiled, 'qt'))
return qt5InstallPath
def writeConfig(self):
print("Writing cmake config to {}".format(self.configFilePath))
# Write out the configuration for use by CMake
cmakeScript = os.path.join(self.path, 'scripts/buildsystems/vcpkg.cmake')
installPath = os.path.join(self.path, 'installed', self.triplet)
toolsPath = os.path.join(self.path, 'installed', self.hostTriplet, 'tools')
cmakeTemplate = VcpkgRepo.CMAKE_TEMPLATE
if not self.args.android:
cmakeTemplate += VcpkgRepo.CMAKE_TEMPLATE_NON_ANDROID
else:
precompiled = os.path.realpath(self.androidPackagePath)
qtCmakePrefix = os.path.realpath(os.path.join(precompiled, 'qt/lib/cmake'))
cmakeTemplate += 'set(HIFI_ANDROID_PRECOMPILED "{}")\n'.format(precompiled)
cmakeTemplate += 'set(QT_CMAKE_PREFIX_PATH "{}")\n'.format(qtCmakePrefix)
cmakeConfig = cmakeTemplate.format(cmakeScript, cmakeScript, installPath, toolsPath).replace('\\', '/')
cmakeTemplate = VcpkgRepo.CMAKE_TEMPLATE
if self.args.android:
precompiled = os.path.realpath(self.androidPackagePath)
cmakeTemplate += 'set(HIFI_ANDROID_PRECOMPILED "{}")\n'.format(precompiled)
else:
cmakeTemplate += VcpkgRepo.CMAKE_TEMPLATE_NON_ANDROID
qtCmakePrefixPath = os.path.join(self.getQt5InstallPath(), "lib/cmake")
cmakeConfig = cmakeTemplate.format(cmakeScript, cmakeScript, installPath, toolsPath, qtCmakePrefixPath).replace('\\', '/')
with open(self.configFilePath, 'w') as f:
f.write(cmakeConfig)
@ -232,3 +250,28 @@ endif()
print("Not implemented")
def installQt(self):
qt5InstallPath = self.getQt5InstallPath()
if not os.path.isdir(qt5InstallPath):
print ('Downloading Qt from AWS')
dest, tail = os.path.split(qt5InstallPath)
url = 'NOT DEFINED'
if platform.system() == 'Windows':
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-windows2.tar.gz'
elif platform.system() == 'Darwin':
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-macos.tar.gz'
elif platform.system() == 'Linux':
if platform.linux_distribution()[1][:3] == '16.':
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-ubuntu-16.04.tar.gz'
elif platform.linux_distribution()[1][:3] == '18.':
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-ubuntu-18.04.tar.gz'
else:
print('UNKNOWN LINUX VERSION!!!')
else:
print('UNKNOWN OPERATING SYSTEM!!!')
print('Extracting ' + url + ' to ' + dest)
hifi_utils.downloadAndExtract(url, dest)
else:
print ('Qt has already been downloaded')

View file

@ -334,11 +334,11 @@ if (APPLE)
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${PROJECT_SOURCE_DIR}/resources/fonts"
"${RESOURCES_DEV_DIR}/fonts"
#copy serverless for android
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${PROJECT_SOURCE_DIR}/resources/serverless"
"${RESOURCES_DEV_DIR}/serverless"
# add redirect json to macOS builds.
#copy serverless for android
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${PROJECT_SOURCE_DIR}/resources/serverless"
"${RESOURCES_DEV_DIR}/serverless"
# add redirect json to macOS builds.
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
@ -401,6 +401,20 @@ else()
endif()
endif()
if (DEV_BUILD AND (APPLE OR UNIX))
# create a qt.conf file to override hard-coded search paths in Qt libs
set(QT_LIB_PATH "${QT_CMAKE_PREFIX_PATH}/../..")
if (APPLE)
set(QT_CONF_FILE "${RESOURCES_DEV_DIR}/../Resources/qt.conf")
else ()
set(QT_CONF_FILE "${INTERFACE_EXEC_DIR}/qt.conf")
endif ()
file(GENERATE
OUTPUT "${QT_CONF_FILE}"
CONTENT "[Paths]\nPrefix=${QT_LIB_PATH}\n"
)
endif()
if (SCRIPTS_INSTALL_DIR)
# setup install of scripts beside interface executable
install(

Binary file not shown.

After

(image error) Size: 548 KiB

View file

@ -0,0 +1,9 @@
{
"compressed": {
"COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT": "Default-Sky-9-cubemap-ambient_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT.ktx",
"COMPRESSED_SRGB8_ETC2": "Default-Sky-9-cubemap-ambient_COMPRESSED_SRGB8_ETC2.ktx"
},
"original": "Default-Sky-9-cubemap-ambient.jpg",
"uncompressed": "Default-Sky-9-cubemap-ambient.ktx",
"version": 1
}

View file

@ -4,5 +4,6 @@
"COMPRESSED_SRGB8_ETC2": "Default-Sky-9-cubemap_COMPRESSED_SRGB8_ETC2.ktx"
},
"original": "Default-Sky-9-cubemap.jpg",
"uncompressed": "Default-Sky-9-cubemap.ktx"
"uncompressed": "Default-Sky-9-cubemap.ktx",
"version": 1
}

View file

@ -58,7 +58,8 @@ Rectangle {
if (isLoggedIn) {
Commerce.getWalletStatus();
} else {
// Show some error to the user
errorText.text = "There was a problem while retrieving your inventory. " +
"Please try closing and re-opening the Avatar app.\n\nLogin status result: " + isLoggedIn;
}
}
@ -66,11 +67,19 @@ Rectangle {
if (walletStatus === 5) {
getInventory();
} else {
// Show some error to the user
errorText.text = "There was a problem while retrieving your inventory. " +
"Please try closing and re-opening the Avatar app.\n\nWallet status result: " + walletStatus;
}
}
onInventoryResult: {
if (result.status !== "success") {
errorText.text = "There was a problem while retrieving your inventory. " +
"Please try closing and re-opening the Avatar app.\n\nInventory status: " + result.status + "\nMessage: " + result.message;
} else if (result.data && result.data.assets && result.data.assets.length === 0 && avatarAppInventoryModel.count === 0) {
errorText.text = "You have not created any avatars yet! Create an avatar with the Avatar Creator, then close and re-open the Avatar App."
}
avatarAppInventoryModel.handlePage(result.status !== "success" && result.message, result);
root.updatePreviewUrl();
}
@ -172,7 +181,7 @@ Rectangle {
anchors.bottom: parent.bottom
AnimatedImage {
visible: !inventoryContentsList.visible
visible: !inventoryContentsList.visible && !errorText.visible
anchors.centerIn: parent
width: 72
height: width
@ -181,7 +190,7 @@ Rectangle {
ListView {
id: inventoryContentsList
visible: avatarAppInventoryModel.count !== 0
visible: avatarAppInventoryModel.count !== 0 && !errorText.visible
interactive: contentItem.height > height
clip: true
model: avatarAppInventoryModel
@ -196,6 +205,18 @@ Rectangle {
standaloneIncompatible: model.standalone_incompatible
}
}
HifiStylesUit.GraphikRegular {
id: errorText
text: ""
visible: text !== ""
anchors.fill: parent
size: 22
color: simplifiedUI.colors.text.white
wrapMode: Text.Wrap
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}

View file

@ -19,8 +19,8 @@ Flickable {
id: root
contentWidth: parent.width
contentHeight: audioColumnLayout.height
topMargin: 16
bottomMargin: 16
topMargin: 24
bottomMargin: 24
clip: true
function changePeakValuesEnabled(enabled) {
@ -60,7 +60,7 @@ Flickable {
HifiStylesUit.GraphikRegular {
id: volumeControlsTitle
text: "Volume Controls"
Layout.maximumWidth: parent.width
Layout.preferredWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
@ -68,57 +68,82 @@ Flickable {
SimplifiedControls.Slider {
id: peopleVolume
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.preferredHeight: 30
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
height: 30
labelText: "People Volume"
from: -60
to: 10
from: simplifiedUI.numericConstants.mutedValue
to: 20.0
defaultValue: 0.0
value: AudioScriptingInterface.getAvatarGain()
stepSize: 5.0
value: AudioScriptingInterface.avatarGain
live: true
function updatePeopleGain(sliderValue) {
if (AudioScriptingInterface.avatarGain !== sliderValue) {
AudioScriptingInterface.avatarGain = sliderValue;
}
}
onValueChanged: {
if (AudioScriptingInterface.getAvatarGain() != peopleVolume.value) {
AudioScriptingInterface.setAvatarGain(peopleVolume.value);
updatePeopleGain(value);
}
onPressedChanged: {
if (!pressed) {
updatePeopleGain(value);
}
}
}
SimplifiedControls.Slider {
id: environmentVolume
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.preferredHeight: 30
Layout.topMargin: 2
height: 30
labelText: "Environment Volume"
from: -60
to: 10
from: simplifiedUI.numericConstants.mutedValue
to: 20.0
defaultValue: 0.0
value: AudioScriptingInterface.getInjectorGain()
stepSize: 5.0
value: AudioScriptingInterface.serverInjectorGain
live: true
function updateEnvironmentGain(sliderValue) {
if (AudioScriptingInterface.serverInjectorGain !== sliderValue) {
AudioScriptingInterface.serverInjectorGain = sliderValue;
AudioScriptingInterface.localInjectorGain = sliderValue;
}
}
onValueChanged: {
if (AudioScriptingInterface.getInjectorGain() != environmentVolume.value) {
AudioScriptingInterface.setInjectorGain(environmentVolume.value);
updateEnvironmentGain(value);
}
onPressedChanged: {
if (!pressed) {
updateEnvironmentGain(value);
}
}
}
SimplifiedControls.Slider {
id: systemSoundVolume
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.preferredHeight: 30
Layout.topMargin: 2
height: 30
labelText: "System Sound Volume"
from: -60
to: 10
from: simplifiedUI.numericConstants.mutedValue
to: 20.0
defaultValue: 0.0
value: AudioScriptingInterface.getSystemInjectorGain()
stepSize: 5.0
value: AudioScriptingInterface.systemInjectorGain
live: true
function updateSystemGain(sliderValue) {
if (AudioScriptingInterface.systemInjectorGain !== sliderValue) {
AudioScriptingInterface.systemInjectorGain = sliderValue;
}
}
onValueChanged: {
if (AudioScriptingInterface.getSystemInjectorGain() != systemSoundVolume.value) {
AudioScriptingInterface.setSystemInjectorGain(systemSoundVolume.value);
updateSystemGain(value);
}
onPressedChanged: {
if (!pressed) {
updateSystemGain(value);
}
}
}
@ -144,8 +169,8 @@ Flickable {
SimplifiedControls.Switch {
id: muteMicrophoneSwitch
width: parent.width
height: 18
Layout.preferredHeight: 18
Layout.preferredWidth: parent.width
labelTextOn: "Mute Microphone"
checked: AudioScriptingInterface.mutedDesktop
onClicked: {
@ -155,8 +180,8 @@ Flickable {
SimplifiedControls.Switch {
id: pushToTalkSwitch
width: parent.width
height: 18
Layout.preferredHeight: 18
Layout.preferredWidth: parent.width
labelTextOn: "Push to Talk - Press and Hold \"T\" to Talk"
checked: AudioScriptingInterface.pushToTalkDesktop
onClicked: {
@ -184,12 +209,11 @@ Flickable {
ListView {
id: inputDeviceListView
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.preferredHeight: contentItem.height
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false
height: contentItem.height
spacing: 4
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
clip: true
model: AudioScriptingInterface.devices.input
delegate: Item {
@ -200,6 +224,8 @@ Flickable {
id: inputDeviceCheckbox
anchors.left: parent.left
width: parent.width - inputLevel.width
height: 16
wrapLabel: false
checked: selectedDesktop
text: model.devicename
ButtonGroup.group: inputDeviceButtonGroup
@ -221,6 +247,7 @@ Flickable {
}
SimplifiedControls.Button {
id: audioLoopbackButton
property bool audioLoopedBack: AudioScriptingInterface.getLocalEcho()
function startAudioLoopback() {
@ -236,29 +263,23 @@ Flickable {
}
}
Timer {
id: loopbackTimer
interval: 8000
running: false
repeat: false
onTriggered: {
Component.onDestruction: stopAudioLoopback();
onVisibleChanged: {
if (!visible) {
stopAudioLoopback();
}
}
id: testYourMicButton
enabled: !HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32
text: audioLoopedBack ? "STOP TESTING" : "TEST YOUR MIC"
onClicked: {
if (audioLoopedBack) {
loopbackTimer.stop();
stopAudioLoopback();
} else {
loopbackTimer.restart();
startAudioLoopback();
}
}
@ -283,12 +304,11 @@ Flickable {
ListView {
id: outputDeviceListView
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.preferredHeight: contentItem.height
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false
height: contentItem.height
spacing: 4
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
clip: true
model: AudioScriptingInterface.devices.output
delegate: Item {
@ -299,8 +319,10 @@ Flickable {
id: outputDeviceCheckbox
anchors.left: parent.left
width: parent.width
height: 16
checked: selectedDesktop
text: model.devicename
wrapLabel: false
ButtonGroup.group: outputDeviceButtonGroup
onClicked: {
AudioScriptingInterface.setOutputDevice(model.info, false); // `false` argument for Desktop mode setting
@ -349,7 +371,6 @@ Flickable {
id: testYourSoundButton
enabled: !HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32

View file

@ -20,8 +20,8 @@ Flickable {
id: root
contentWidth: parent.width
contentHeight: generalColumnLayout.height
topMargin: 16
bottomMargin: 16
topMargin: 24
bottomMargin: 24
clip: true
onAvatarNametagModeChanged: {
@ -63,6 +63,7 @@ Flickable {
ColumnLayout {
id: avatarNameTagsRadioButtonGroup
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
SimplifiedControls.RadioButton {
id: avatarNameTagsOff
@ -110,6 +111,7 @@ Flickable {
ColumnLayout {
id: performanceRadioButtonGroup
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
SimplifiedControls.RadioButton {
id: performanceLow
@ -157,6 +159,7 @@ Flickable {
ColumnLayout {
id: cameraRadioButtonGroup
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
SimplifiedControls.RadioButton {
id: firstPerson

View file

@ -19,8 +19,8 @@ Flickable {
id: root
contentWidth: parent.width
contentHeight: vrColumnLayout.height
topMargin: 16
bottomMargin: 16
topMargin: 24
bottomMargin: 24
clip: true
function changePeakValuesEnabled(enabled) {
@ -70,6 +70,7 @@ Flickable {
id: controlsRadioButtonGroup
width: parent.width
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
ButtonGroup { id: controlsButtonGroup }
@ -197,12 +198,11 @@ Flickable {
ListView {
id: inputDeviceListView
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.preferredHeight: contentItem.height
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false
height: contentItem.height
spacing: 4
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
clip: true
model: AudioScriptingInterface.devices.input
delegate: Item {
@ -213,8 +213,10 @@ Flickable {
id: inputDeviceCheckbox
anchors.left: parent.left
width: parent.width - inputLevel.width
height: 16
checked: selectedHMD
text: model.devicename
wrapLabel: false
ButtonGroup.group: inputDeviceButtonGroup
onClicked: {
AudioScriptingInterface.setStereoInput(false); // the next selected audio device might not support stereo
@ -234,6 +236,7 @@ Flickable {
}
SimplifiedControls.Button {
id: audioLoopbackButton
property bool audioLoopedBack: AudioScriptingInterface.getLocalEcho()
function startAudioLoopback() {
@ -249,29 +252,23 @@ Flickable {
}
}
Timer {
id: loopbackTimer
interval: 8000
running: false
repeat: false
onTriggered: {
Component.onDestruction: stopAudioLoopback();
onVisibleChanged: {
if (!visible) {
stopAudioLoopback();
}
}
id: testYourMicButton
enabled: HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32
text: audioLoopedBack ? "STOP TESTING" : "TEST YOUR MIC"
onClicked: {
if (audioLoopedBack) {
loopbackTimer.stop();
stopAudioLoopback();
} else {
loopbackTimer.restart();
startAudioLoopback();
}
}
@ -296,12 +293,11 @@ Flickable {
ListView {
id: outputDeviceListView
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.preferredHeight: contentItem.height
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false
height: contentItem.height
spacing: 4
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
clip: true
model: AudioScriptingInterface.devices.output
delegate: Item {
@ -312,11 +308,13 @@ Flickable {
id: outputDeviceCheckbox
anchors.left: parent.left
width: parent.width
checked: selectedDesktop
height: 16
checked: selectedHMD
text: model.devicename
wrapLabel: false
ButtonGroup.group: outputDeviceButtonGroup
onClicked: {
AudioScriptingInterface.setOutputDevice(model.info, true); // `false` argument for Desktop mode setting
AudioScriptingInterface.setOutputDevice(model.info, true); // `true` argument for VR mode setting
}
}
}
@ -362,7 +360,6 @@ Flickable {
id: testYourSoundButton
enabled: HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32

View file

@ -147,7 +147,7 @@ QtObject {
}
readonly property color darkSeparator: "#595959"
readonly property color darkBackground: "#1A1A1A"
readonly property color darkBackground: "#000000"
readonly property color darkBackgroundHighlight: "#575757"
readonly property color highlightOnDark: Qt.rgba(1, 1, 1, 0.2)
readonly property color white: "#FFFFFF"
@ -182,9 +182,10 @@ QtObject {
}
readonly property QtObject settings: QtObject {
property real subtitleTopMargin: 2
property real settingsGroupTopMargin: 10
property real spacingBetweenSettings: 48
property int subtitleTopMargin: 2
property int settingsGroupTopMargin: 24
property int spacingBetweenSettings: 48
property int spacingBetweenRadiobuttons: 14
}
}
@ -220,4 +221,8 @@ QtObject {
}
}
}
readonly property QtObject numericConstants: QtObject {
readonly property real mutedValue: -60.0
}
}

View file

@ -87,7 +87,6 @@ RadioButton {
contentItem: Text {
id: radioButtonLabel
height: root.radioButtonRadius
font.pixelSize: 14
font.family: "Graphik"
font.weight: Font.Normal
@ -99,5 +98,6 @@ RadioButton {
enabled: root.enabled
verticalAlignment: Text.AlignVCenter
leftPadding: radioButtonIndicator.width + root.labelLeftMargin
topPadding: -3 // For perfect alignment when using Graphik
}
}

View file

@ -30,6 +30,7 @@ Item {
property alias live: sliderControl.live
property alias stepSize: sliderControl.stepSize
property alias snapMode: sliderControl.snapMode
property alias pressed: sliderControl.pressed
property real defaultValue: 0.0
HifiStylesUit.GraphikRegular {

View file

@ -70,8 +70,6 @@ Item {
}
onCheckedChanged: {
root.checkedChanged();
Tablet.playSound(TabletEnums.ButtonClick);
originalSwitch.changeColor();
}

View file

@ -203,7 +203,10 @@ Rectangle {
Image {
id: outputDeviceButton
property bool outputMuted: false
property bool outputMuted: AudioScriptingInterface.avatarGain === simplifiedUI.numericConstants.mutedValue &&
AudioScriptingInterface.serverInjectorGain === simplifiedUI.numericConstants.mutedValue &&
AudioScriptingInterface.localInjectorGain === simplifiedUI.numericConstants.mutedValue &&
AudioScriptingInterface.systemInjectorGain === simplifiedUI.numericConstants.mutedValue
source: outputDeviceButton.outputMuted ? "./images/outputDeviceMuted.svg" : "./images/outputDeviceLoud.svg"
anchors.centerIn: parent
width: 20
@ -228,13 +231,16 @@ Rectangle {
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
outputDeviceButton.outputMuted = !outputDeviceButton.outputMuted;
if (!outputDeviceButton.outputMuted && !AudioScriptingInterface.muted) {
AudioScriptingInterface.muted = true;
}
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "setOutputMuted",
"data": {
"outputMuted": outputDeviceButton.outputMuted
"outputMuted": !outputDeviceButton.outputMuted
}
});
}
@ -242,6 +248,69 @@ Rectangle {
}
Item {
id: statusButtonContainer
anchors.verticalCenter: parent.verticalCenter
anchors.left: outputDeviceButtonContainer.right
anchors.leftMargin: 8
width: 36
height: width
Rectangle {
id: statusButton
property string currentStatus
anchors.centerIn: parent
anchors.horizontalCenterOffset: 1
anchors.verticalCenterOffset: 2
width: 13
height: width
radius: width/2
visible: false
}
ColorOverlay {
anchors.fill: statusButton
opacity: statusButton.currentStatus ? 1 : 0
source: statusButton
color: if (statusButton.currentStatus === "busy") {
"#ff001a"
} else if (statusButton.currentStatus === "available") {
"#009036"
} else if (statusButton.currentStatus) {
"#ffed00"
}
}
Image {
id: focusIcon
source: "./images/focus.svg"
opacity: statusButtonMouseArea.containsMouse ? 1.0 : (statusButton.currentStatus === "busy" ? 0.7 : 0.3)
anchors.centerIn: parent
width: 36
height: 20
fillMode: Image.PreserveAspectFit
}
MouseArea {
id: statusButtonMouseArea
anchors.fill: parent
enabled: statusButton.currentStatus
hoverEnabled: true
onEntered: {
Tablet.playSound(TabletEnums.ButtonHover);
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "toggleStatus"
});
}
}
}
Item {
id: hmdButtonContainer
@ -250,6 +319,7 @@ Rectangle {
anchors.rightMargin: 14
width: 32
height: width
visible: false
Image {
id: displayModeImage
@ -279,11 +349,6 @@ Rectangle {
Tablet.playSound(TabletEnums.ButtonClick);
var displayPluginCount = Window.getDisplayPluginCount();
if (HMD.active) {
// This next line seems backwards and shouldn't be necessary - the NOTIFY handler should
// result in `displayModeImage.source` changing automatically - but that's not working.
// This is working. So, I'm keeping it.
displayModeImage.source = "./images/vrMode.svg";
// Switch to desktop mode - selects first VR display plugin
for (var i = 0; i < displayPluginCount; i++) {
if (!Window.isDisplayPluginHmd(i)) {
@ -292,11 +357,6 @@ Rectangle {
}
}
} else {
// This next line seems backwards and shouldn't be necessary - the NOTIFY handler should
// result in `displayModeImage.source` changing automatically - but that's not working.
// This is working. So, I'm keeping it.
displayModeImage.source = "./images/desktopMode.svg";
// Switch to VR mode - selects first HMD display plugin
for (var i = 0; i < displayPluginCount; i++) {
if (Window.isDisplayPluginHmd(i)) {
@ -306,6 +366,17 @@ Rectangle {
}
}
}
Component.onCompleted: {
// Don't show VR button unless they have a VR headset.
var displayPluginCount = Window.getDisplayPluginCount();
for (var i = 0; i < displayPluginCount; i++) {
if (Window.isDisplayPluginHmd(i)) {
hmdButtonContainer.visible = true;
return;
}
}
}
}
}
@ -385,8 +456,8 @@ Rectangle {
}
break;
case "updateOutputMuted":
outputDeviceButton.outputMuted = message.data.outputMuted;
case "updateStatusButton":
statusButton.currentStatus = message.data.currentStatus;
break;
default:

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="32" height="19.001" fill="none" version="1.1" viewBox="0 0 32 19.001" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<path d="m7 19h-3.542c-0.46115 0.0089-0.91905-0.0192-1.3443-0.2001-0.42525-0.1808-0.80846-0.4496-1.125-0.7892-0.3234-0.3355-0.57737-0.7329-0.74698-1.1691-0.16962-0.4362-0.25146-0.9023-0.24076-1.3709v-5.47c-0.0066251-0.46326 0.078429-0.92318 0.25019-1.3526 0.17176-0.42944 0.42674-0.81971 0.74988-1.1478 0.32313-0.32808 0.70786-0.58732 1.1316-0.76244 0.42368-0.17511 0.87772-0.26255 1.3353-0.25716h1.4718c0.03732-0.87492 0.24704-1.7335 0.61682-2.5251s0.89216-1.5005 1.5364-2.0849c1.2696-1.2214 3.1558-1.8924 4.9071-1.87l8 2.2471e-5c1.7402-0.025877 3.6023 0.64637 4.8546 1.87 1.2793 1.2015 2.0626 2.8482 2.1927 4.61h1.3178c0.946-0.01712 1.8609 0.3419 2.5484 1 0.3479 0.31321 0.625 0.69864 0.8125 1.13 0.1875 0.43142 0.2809 0.89867 0.274 1.37v5.47c0.0037 0.4767-0.091 0.9488-0.2781 1.3863-0.1871 0.4374-0.376 0.8397-0.7219 1.163-0.3346 0.3376-0.5167 0.5951-0.9542 0.7753-0.4376 0.1803-1.2083 0.2298-1.6807 0.2247h-3.3624v-12.049c0.0051-0.65734-0.1179-1.3092-0.362-1.9184-0.2441-0.60915-0.6044-1.1636-1.0603-1.6316-0.4213-0.48067-0.9384-0.86553-1.5173-1.1292-0.5788-0.26371-1.4283-0.27101-2.0631-0.27147h-8c-0.6475-0.00706-1.4451-0.00352-2.0378 0.26031-0.59274 0.26384-1.1231 0.65262-1.5556 1.1404-0.45594 0.46802-0.81626 1.0225-1.0603 1.6316-0.24406 0.60916-0.35129 1.261-0.34623 1.9184zm-3.4717-2h1.4717v-8.4793h-1.4717c-0.92847 0-1.5283 0.49-1.5283 1.48v5.47c0.01975 0.99 0.59981 1.5293 1.5283 1.5293zm26.472-6.9993c8e-3 -0.84434-0.6554-1.4883-1.5049-1.48h-1.4478v8.4793h1.4478c0.8319 0.0109 1.5175-0.722 1.5049-1.5293z" fill="#fff"/>
</svg>

After

(image error) Size: 2 KiB

File diff suppressed because one or more lines are too long

After

(image error) Size: 5.2 KiB

View file

@ -1190,13 +1190,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// setup a timer for domain-server check ins
QTimer* domainCheckInTimer = new QTimer(this);
QWeakPointer<NodeList> nodeListWeak = nodeList;
connect(domainCheckInTimer, &QTimer::timeout, [this, nodeListWeak] {
auto nodeList = nodeListWeak.lock();
if (!isServerlessMode() && nodeList) {
nodeList->sendDomainServerCheckIn();
}
});
connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);
domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);
connect(this, &QCoreApplication::aboutToQuit, [domainCheckInTimer] {
domainCheckInTimer->stop();
@ -3328,6 +3322,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
surfaceContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
surfaceContext->setContextProperty("Scene", DependencyManager::get<SceneScriptingInterface>().data());
surfaceContext->setContextProperty("Render", RenderScriptingInterface::getInstance());
surfaceContext->setContextProperty("PlatformInfo", PlatformInfoScriptingInterface::getInstance());
surfaceContext->setContextProperty("Workload", _gameWorkload._engine->getConfiguration().get());
surfaceContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
surfaceContext->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
@ -3451,6 +3446,7 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona
surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance());
surfaceContext->setContextProperty("WalletScriptingInterface", DependencyManager::get<WalletScriptingInterface>().data());
surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
surfaceContext->setContextProperty("PlatformInfo", PlatformInfoScriptingInterface::getInstance());
}
}
@ -3806,10 +3802,14 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
// If this is a first run we short-circuit the address passed in
if (_firstRun.get()) {
DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
_firstRun.set(false);
if (!_overrideEntry) {
DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
} else {
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
sentTo = SENT_TO_PREVIOUS_LOCATION;
}
_firstRun.set(false);
} else {
QString goingTo = "";
if (addressLookupString.isEmpty()) {
@ -3825,7 +3825,7 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
sentTo = SENT_TO_PREVIOUS_LOCATION;
}
UserActivityLogger::getInstance().logAction("startup_sent_to", {
{ "sent_to", sentTo },
{ "sandbox_is_running", sandboxIsRunning },
@ -3886,6 +3886,7 @@ void Application::setIsInterstitialMode(bool interstitialMode) {
}
void Application::setIsServerlessMode(bool serverlessDomain) {
DependencyManager::get<NodeList>()->setSendDomainServerCheckInEnabled(!serverlessDomain);
auto tree = getEntities()->getTree();
if (tree) {
tree->setIsServerlessMode(serverlessDomain);
@ -5439,9 +5440,7 @@ void Application::init() {
qCDebug(interfaceapp) << "Loaded settings";
// fire off an immediate domain-server check in now that settings are loaded
if (!isServerlessMode()) {
DependencyManager::get<NodeList>()->sendDomainServerCheckIn();
}
QMetaObject::invokeMethod(DependencyManager::get<NodeList>().data(), "sendDomainServerCheckIn");
// This allows collision to be set up properly for shape entities supported by GeometryCache.
// This is before entity setup to ensure that it's ready for whenever instance collision is initialized.
@ -6404,6 +6403,7 @@ void Application::update(float deltaTime) {
PerformanceTimer perfTimer("simulation");
getEntities()->preUpdate();
_entitySimulation->removeDeadEntities();
auto t0 = std::chrono::high_resolution_clock::now();
auto t1 = t0;
@ -9361,6 +9361,19 @@ void Application::showUrlHandler(const QUrl& url) {
}
});
}
void Application::overrideEntry(){
_overrideEntry = true;
}
void Application::forceDisplayName(const QString& displayName) {
getMyAvatar()->setDisplayName(displayName);
}
void Application::forceLoginWithTokens(const QString& tokens) {
DependencyManager::get<AccountManager>()->setAccessTokens(tokens);
Setting::Handle<bool>(KEEP_ME_LOGGED_IN_SETTING_NAME, true).set(true);
}
void Application::setConfigFileURL(const QString& fileUrl) {
DependencyManager::get<AccountManager>()->setConfigFileURL(fileUrl);
}
#if defined(Q_OS_ANDROID)
void Application::beforeEnterBackground() {

View file

@ -356,6 +356,11 @@ public:
void openDirectory(const QString& path);
void overrideEntry();
void forceDisplayName(const QString& displayName);
void forceLoginWithTokens(const QString& tokens);
void setConfigFileURL(const QString& fileUrl);
signals:
void svoImportRequested(const QString& url);
@ -828,5 +833,6 @@ private:
bool _resumeAfterLoginDialogActionTaken_WasPostponed { false };
bool _resumeAfterLoginDialogActionTaken_SafeToRun { false };
bool _startUpFinished { false };
bool _overrideEntry { false };
};
#endif // hifi_Application_h

View file

@ -49,16 +49,13 @@
#include "DeferredLightingEffect.h"
#include "PickManager.h"
#include "LightingModel.h"
#include "AmbientOcclusionEffect.h"
#include "RenderShadowTask.h"
#include "AntialiasingEffect.h"
#include "scripting/SettingsScriptingInterface.h"
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
#include "SpeechRecognizer.h"
#endif
#include "scripting/RenderScriptingInterface.h"
extern bool DEV_DECIMATE_TEXTURES;
Menu* Menu::getInstance() {
@ -367,45 +364,14 @@ Menu::Menu() {
// Developer > Render >>>
MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render");
action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AntiAliasing, 0, true);
connect(action, &QAction::triggered, [action] {
auto renderConfig = qApp->getRenderEngine()->getConfiguration();
if (renderConfig) {
auto mainViewJitterCamConfig = renderConfig->getConfig<JitterSample>("RenderMainView.JitterCam");
auto mainViewAntialiasingConfig = renderConfig->getConfig<Antialiasing>("RenderMainView.Antialiasing");
if (mainViewJitterCamConfig && mainViewAntialiasingConfig) {
if (action->isChecked()) {
mainViewJitterCamConfig->play();
mainViewAntialiasingConfig->setDebugFXAA(false);
} else {
mainViewJitterCamConfig->none();
mainViewAntialiasingConfig->setDebugFXAA(true);
}
}
}
});
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AntiAliasing, 0, RenderScriptingInterface::getInstance()->getAntialiasingEnabled(),
RenderScriptingInterface::getInstance(), SLOT(setAntialiasingEnabled(bool)));
action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, true);
connect(action, &QAction::triggered, [action] {
auto renderConfig = qApp->getRenderEngine()->getConfiguration();
if (renderConfig) {
auto lightingModelConfig = renderConfig->getConfig<MakeLightingModel>("RenderMainView.LightingModel");
if (lightingModelConfig) {
lightingModelConfig->setShadow(action->isChecked());
}
}
});
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, RenderScriptingInterface::getInstance()->getShadowsEnabled(),
RenderScriptingInterface::getInstance(), SLOT(setShadowsEnabled(bool)));
action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion, 0, false);
connect(action, &QAction::triggered, [action] {
auto renderConfig = qApp->getRenderEngine()->getConfiguration();
if (renderConfig) {
auto lightingModelConfig = renderConfig->getConfig<MakeLightingModel>("RenderMainView.LightingModel");
if (lightingModelConfig) {
lightingModelConfig->setAmbientOcclusion(action->isChecked());
}
}
});
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion, 0, RenderScriptingInterface::getInstance()->getAmbientOcclusionEnabled(),
RenderScriptingInterface::getInstance(), SLOT(setAmbientOcclusionEnabled(bool)));
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DefaultSkybox, 0, true);
@ -522,6 +488,12 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ComputeBlendshapes, 0, true,
DependencyManager::get<ModelBlender>().data(), SLOT(setComputeBlendshapes(bool)));
{
auto drawStatusConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<render::DrawStatus>("RenderMainView.DrawStatus");
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::HighlightTransitions, 0, false,
drawStatusConfig, SLOT(setShowFade(bool)));
}
// Developer > Assets >>>
// Menu item is not currently needed but code should be kept in case it proves useful again at some stage.
//#define WANT_ASSET_MIGRATION

View file

@ -228,6 +228,7 @@ namespace MenuOption {
const QString NotificationSoundsTablet = "play_notification_sounds_tablet";
const QString ForceCoarsePicking = "Force Coarse Picking";
const QString ComputeBlendshapes = "Compute Blendshapes";
const QString HighlightTransitions = "Highlight Transitions";
}
#endif // hifi_Menu_h

View file

@ -412,7 +412,7 @@ AvatarSharedPointer AvatarManager::newSharedAvatar(const QUuid& sessionUUID) {
auto otherAvatar = new OtherAvatar(qApp->thread());
otherAvatar->setSessionUUID(sessionUUID);
auto nodeList = DependencyManager::get<NodeList>();
if (!nodeList || !nodeList->isIgnoringNode(sessionUUID)) {
if (nodeList && !nodeList->isIgnoringNode(sessionUUID)) {
otherAvatar->createOrb();
}
return AvatarSharedPointer(otherAvatar, [](OtherAvatar* ptr) { ptr->deleteLater(); });
@ -521,6 +521,7 @@ void AvatarManager::buildPhysicsTransaction(PhysicsEngine::Transaction& transact
}
}
}
_otherAvatarsToChangeInPhysics.clear();
}
void AvatarManager::handleProcessedPhysicsTransaction(PhysicsEngine::Transaction& transaction) {
@ -645,7 +646,7 @@ void AvatarManager::clearOtherAvatars() {
}
void AvatarManager::deleteAllAvatars() {
assert(_otherAvatarsToChangeInPhysics.empty());
_otherAvatarsToChangeInPhysics.clear();
QReadLocker locker(&_hashLock);
AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) {

View file

@ -2367,6 +2367,11 @@ void MyAvatar::clearJointsData() {
}
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setSkeletonModelURL", Q_ARG(const QUrl&, skeletonModelURL));
return;
}
_skeletonModelChangeCount++;
int skeletonModelChangeCount = _skeletonModelChangeCount;

View file

@ -2409,7 +2409,7 @@ private:
void updateEyeContactTarget(float deltaTime);
// These are made private for MyAvatar so that you will use the "use" methods instead
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
Q_INVOKABLE virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
virtual void updatePalms() override {}
void lateUpdatePalms();

View file

@ -62,7 +62,7 @@ void OtherAvatar::removeOrb() {
}
void OtherAvatar::updateOrbPosition() {
if (_otherAvatarOrbMeshPlaceholderID.isNull()) {
if (!_otherAvatarOrbMeshPlaceholderID.isNull()) {
EntityItemProperties properties;
properties.setPosition(getHead()->getPosition());
DependencyManager::get<EntityScriptingInterface>()->editEntity(_otherAvatarOrbMeshPlaceholderID, properties);

View file

@ -654,7 +654,7 @@ QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
EC_KEY* ecPrivateKey = NULL;
if ((ecPrivateKey = readPrivateKey(keyFilePath()))) {
unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)];
const auto sig = std::make_unique<unsigned char[]>(ECDSA_size(ecPrivateKey));
unsigned int signatureBytes = 0;
@ -663,10 +663,10 @@ QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256);
int retrn = ECDSA_sign(0, reinterpret_cast<const unsigned char*>(hashedPlaintext.constData()), hashedPlaintext.size(),
sig, &signatureBytes, ecPrivateKey);
sig.get(), &signatureBytes, ecPrivateKey);
EC_KEY_free(ecPrivateKey);
QByteArray signature(reinterpret_cast<const char*>(sig), signatureBytes);
QByteArray signature(reinterpret_cast<const char*>(sig.get()), signatureBytes);
if (retrn != -1) {
return signature.toBase64();
}

View file

@ -75,6 +75,7 @@ int main(int argc, const char* argv[]) {
QCommandLineOption helpOption = parser.addHelpOption();
QCommandLineOption urlOption("url", "", "value");
QCommandLineOption noLauncherOption("no-launcher", "Do not execute the launcher");
QCommandLineOption noUpdaterOption("no-updater", "Do not show auto-updater");
QCommandLineOption checkMinSpecOption("checkMinSpec", "Check if machine meets minimum specifications");
QCommandLineOption runServerOption("runServer", "Whether to run the server");
@ -82,8 +83,11 @@ int main(int argc, const char* argv[]) {
QCommandLineOption allowMultipleInstancesOption("allowMultipleInstances", "Allow multiple instances to run");
QCommandLineOption overrideAppLocalDataPathOption("cache", "set test cache <dir>", "dir");
QCommandLineOption overrideScriptsPathOption(SCRIPTS_SWITCH, "set scripts <path>", "path");
QCommandLineOption responseTokensOption("tokens", "set response tokens <json>", "json");
QCommandLineOption displayNameOption("displayName", "set user display name <string>", "string");
parser.addOption(urlOption);
parser.addOption(noLauncherOption);
parser.addOption(noUpdaterOption);
parser.addOption(checkMinSpecOption);
parser.addOption(runServerOption);
@ -91,6 +95,8 @@ int main(int argc, const char* argv[]) {
parser.addOption(overrideAppLocalDataPathOption);
parser.addOption(overrideScriptsPathOption);
parser.addOption(allowMultipleInstancesOption);
parser.addOption(responseTokensOption);
parser.addOption(displayNameOption);
if (!parser.parse(arguments)) {
std::cout << parser.errorText().toStdString() << std::endl; // Avoid Qt log spam
@ -106,6 +112,52 @@ int main(int argc, const char* argv[]) {
Q_UNREACHABLE();
}
QString applicationPath;
{
// A temporary application instance is needed to get the location of the running executable
// Tests using high_resolution_clock show that this takes about 30-50 microseconds (on my machine, YMMV)
// If we wanted to avoid the QCoreApplication, we would need to write our own
// cross-platform implementation.
QCoreApplication tempApp(argc, const_cast<char**>(argv));
applicationPath = QCoreApplication::applicationDirPath();
}
static const QString APPLICATION_CONFIG_FILENAME = "config.json";
QDir applicationDir(applicationPath);
QString configFileName = applicationDir.filePath(APPLICATION_CONFIG_FILENAME);
QFile configFile(configFileName);
QString launcherPath;
if (configFile.exists()) {
if (!configFile.open(QIODevice::ReadOnly)) {
qWarning() << "Found application config, but could not open it";
} else {
auto contents = configFile.readAll();
QJsonParseError error;
auto doc = QJsonDocument::fromJson(contents, &error);
if (error.error) {
qWarning() << "Found application config, but could not parse it: " << error.errorString();
} else {
static const QString LAUNCHER_PATH_KEY = "launcherPath";
launcherPath = doc.object()[LAUNCHER_PATH_KEY].toString();
if (!launcherPath.isEmpty()) {
if (!parser.isSet(noLauncherOption)) {
qDebug() << "Found a launcherPath in application config. Starting launcher.";
QProcess launcher;
launcher.setProgram(launcherPath);
launcher.startDetached();
return 0;
} else {
qDebug() << "Found a launcherPath in application config, but the launcher"
" has been suppressed. Continuing normal execution.";
}
configFile.close();
}
}
}
}
// Early check for --traceFile argument
auto tracer = DependencyManager::set<tracing::Tracer>();
const char * traceFile = nullptr;
@ -353,6 +405,24 @@ int main(int argc, const char* argv[]) {
printSystemInformation();
auto appPointer = dynamic_cast<Application*>(&app);
if (appPointer) {
if (parser.isSet(urlOption)) {
appPointer->overrideEntry();
}
if (parser.isSet(displayNameOption)) {
QString displayName = QString(parser.value(displayNameOption));
appPointer->forceDisplayName(displayName);
}
if (!launcherPath.isEmpty()) {
appPointer->setConfigFileURL(configFileName);
}
if (parser.isSet(responseTokensOption)) {
QString tokens = QString(parser.value(responseTokensOption));
appPointer->forceLoginWithTokens(tokens);
}
}
QTranslator translator;
translator.load("i18n/interface_en");
app.installTranslator(&translator);

View file

@ -10,7 +10,6 @@
//
#include "SafeLanding.h"
#include <SharedUtil.h>
#include "EntityTreeRenderer.h"
@ -35,24 +34,26 @@ bool SafeLanding::SequenceLessThan::operator()(const int& a, const int& b) const
}
void SafeLanding::startEntitySequence(QSharedPointer<EntityTreeRenderer> entityTreeRenderer) {
auto entityTree = entityTreeRenderer->getTree();
if (entityTree) {
Locker lock(_lock);
_entityTree = entityTree;
_trackedEntities.clear();
_trackingEntities = true;
_maxTrackedEntityCount = 0;
connect(std::const_pointer_cast<EntityTree>(_entityTree).get(),
&EntityTree::addingEntity, this, &SafeLanding::addTrackedEntity);
connect(std::const_pointer_cast<EntityTree>(_entityTree).get(),
&EntityTree::deletingEntity, this, &SafeLanding::deleteTrackedEntity);
if (!entityTreeRenderer.isNull()) {
auto entityTree = entityTreeRenderer->getTree();
if (entityTree) {
Locker lock(_lock);
_entityTreeRenderer = entityTreeRenderer;
_trackedEntities.clear();
_trackingEntities = true;
_maxTrackedEntityCount = 0;
connect(std::const_pointer_cast<EntityTree>(entityTree).get(),
&EntityTree::addingEntity, this, &SafeLanding::addTrackedEntity, Qt::DirectConnection);
connect(std::const_pointer_cast<EntityTree>(entityTree).get(),
&EntityTree::deletingEntity, this, &SafeLanding::deleteTrackedEntity);
_sequenceNumbers.clear();
_initialStart = INVALID_SEQUENCE;
_initialEnd = INVALID_SEQUENCE;
_startTime = usecTimestampNow();
EntityTreeRenderer::setEntityLoadingPriorityFunction(&ElevatedPriority);
_sequenceNumbers.clear();
_initialStart = INVALID_SEQUENCE;
_initialEnd = INVALID_SEQUENCE;
_startTime = usecTimestampNow();
EntityTreeRenderer::setEntityLoadingPriorityFunction(&ElevatedPriority);
}
}
}
@ -70,7 +71,12 @@ void SafeLanding::stopEntitySequence() {
void SafeLanding::addTrackedEntity(const EntityItemID& entityID) {
if (_trackingEntities) {
Locker lock(_lock);
EntityItemPointer entity = _entityTree->findEntityByID(entityID);
if (_entityTreeRenderer.isNull() || _entityTreeRenderer->getTree() == nullptr) {
return;
}
EntityItemPointer entity = _entityTreeRenderer->getTree()->findEntityByID(entityID);
if (entity && !entity->isLocalEntity() && entity->getCreated() < _startTime) {
@ -111,7 +117,7 @@ bool SafeLanding::isLoadSequenceComplete() {
Locker lock(_lock);
_initialStart = INVALID_SEQUENCE;
_initialEnd = INVALID_SEQUENCE;
_entityTree = nullptr;
_entityTreeRenderer.clear();
_trackingEntities = false; // Don't track anything else that comes in.
EntityTreeRenderer::setEntityLoadingPriorityFunction(StandardPriority);
}
@ -158,7 +164,7 @@ bool SafeLanding::isSequenceNumbersComplete() {
return false;
}
bool isEntityPhysicsReady(const EntityItemPointer& entity) {
bool SafeLanding::isEntityPhysicsReady(const EntityItemPointer& entity) {
if (entity && !entity->getCollisionless()) {
const auto& entityType = entity->getType();
if (entityType == EntityTypes::Model) {
@ -168,7 +174,10 @@ bool isEntityPhysicsReady(const EntityItemPointer& entity) {
bool hasAABox;
entity->getAABox(hasAABox);
if (hasAABox && downloadedCollisionTypes.count(modelEntity->getShapeType()) != 0) {
return (!entity->shouldBePhysical() || entity->isInPhysicsSimulation() || modelEntity->computeShapeFailedToLoad());
auto space = _entityTreeRenderer->getWorkloadSpace();
uint8_t region = space ? space->getRegion(entity->getSpaceIndex()) : (uint8_t)workload::Region::INVALID;
bool shouldBePhysical = region < workload::Region::R3 && entity->shouldBePhysical();
return (!shouldBePhysical || entity->isInPhysicsSimulation() || modelEntity->computeShapeFailedToLoad());
}
}
}

View file

@ -38,13 +38,14 @@ private slots:
private:
bool isSequenceNumbersComplete();
bool isEntityPhysicsReady(const EntityItemPointer& entity);
void debugDumpSequenceIDs() const;
bool isEntityLoadingComplete();
std::mutex _lock;
using Locker = std::lock_guard<std::mutex>;
bool _trackingEntities { false };
EntityTreePointer _entityTree;
QSharedPointer<EntityTreeRenderer> _entityTreeRenderer;
using EntityMap = std::map<EntityItemID, EntityItemPointer>;
EntityMap _trackedEntities;

View file

@ -400,10 +400,19 @@ void Audio::setReverbOptions(const AudioEffectOptions* options) {
}
void Audio::setAvatarGain(float gain) {
bool changed = false;
if (getAvatarGain() != gain) {
changed = true;
}
withWriteLock([&] {
// ask the NodeList to set the master avatar gain
DependencyManager::get<NodeList>()->setAvatarGain(QUuid(), gain);
});
if (changed) {
emit avatarGainChanged(gain);
}
}
float Audio::getAvatarGain() {
@ -413,10 +422,19 @@ float Audio::getAvatarGain() {
}
void Audio::setInjectorGain(float gain) {
bool changed = false;
if (getInjectorGain() != gain) {
changed = true;
}
withWriteLock([&] {
// ask the NodeList to set the audio injector gain
DependencyManager::get<NodeList>()->setInjectorGain(gain);
});
if (changed) {
emit serverInjectorGainChanged(gain);
}
}
float Audio::getInjectorGain() {
@ -426,6 +444,11 @@ float Audio::getInjectorGain() {
}
void Audio::setLocalInjectorGain(float gain) {
bool changed = false;
if (getLocalInjectorGain() != gain) {
changed = true;
}
withWriteLock([&] {
if (_localInjectorGain != gain) {
_localInjectorGain = gain;
@ -436,6 +459,11 @@ void Audio::setLocalInjectorGain(float gain) {
DependencyManager::get<AudioClient>()->setLocalInjectorGain(gain);
}
});
if (changed) {
emit localInjectorGainChanged(gain);
}
}
float Audio::getLocalInjectorGain() {
@ -445,6 +473,11 @@ float Audio::getLocalInjectorGain() {
}
void Audio::setSystemInjectorGain(float gain) {
bool changed = false;
if (getSystemInjectorGain() != gain) {
changed = true;
}
withWriteLock([&] {
if (_systemInjectorGain != gain) {
_systemInjectorGain = gain;
@ -455,6 +488,10 @@ void Audio::setSystemInjectorGain(float gain) {
DependencyManager::get<AudioClient>()->setSystemInjectorGain(gain);
}
});
if (changed) {
emit systemInjectorGainChanged(gain);
}
}
float Audio::getSystemInjectorGain() {

View file

@ -66,6 +66,10 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
* @property {boolean} pushToTalkHMD - <code>true</code> if HMD push-to-talk is enabled, otherwise <code>false</code>.
* @property {boolean} pushingToTalk - <code>true</code> if the user is currently pushing-to-talk, otherwise
* <code>false</code>.
* @property {float} avatarGain - The gain (relative volume) that avatars' voices are played at. This gain is used at the server.
* @property {float} localInjectorGain - The gain (relative volume) that local injectors (local environment sounds) are played at.
* @property {float} serverInjectorGain - The gain (relative volume) that server injectors (server environment sounds) are played at. This gain is used at the server.
* @property {float} systemInjectorGain - The gain (relative volume) that system sounds are played at.
*
* @comment The following properties are from AudioScriptingInterface.h.
* @property {boolean} isStereoInput - <code>true</code> if the input audio is being used in stereo, otherwise
@ -90,6 +94,10 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
Q_PROPERTY(bool pushToTalkDesktop READ getPTTDesktop WRITE setPTTDesktop NOTIFY pushToTalkDesktopChanged)
Q_PROPERTY(bool pushToTalkHMD READ getPTTHMD WRITE setPTTHMD NOTIFY pushToTalkHMDChanged)
Q_PROPERTY(bool pushingToTalk READ getPushingToTalk WRITE setPushingToTalk NOTIFY pushingToTalkChanged)
Q_PROPERTY(float avatarGain READ getAvatarGain WRITE setAvatarGain NOTIFY avatarGainChanged)
Q_PROPERTY(float localInjectorGain READ getLocalInjectorGain WRITE setLocalInjectorGain NOTIFY localInjectorGainChanged)
Q_PROPERTY(float serverInjectorGain READ getInjectorGain WRITE setInjectorGain NOTIFY serverInjectorGainChanged)
Q_PROPERTY(float systemInjectorGain READ getSystemInjectorGain WRITE setSystemInjectorGain NOTIFY systemInjectorGainChanged)
public:
static QString AUDIO;
@ -412,6 +420,38 @@ signals:
*/
void pushingToTalkChanged(bool talking);
/**jsdoc
* Triggered when the avatar gain changes.
* @function Audio.avatarGainChanged
* @param {float} gain - The new avatar gain value.
* @returns {Signal}
*/
void avatarGainChanged(float gain);
/**jsdoc
* Triggered when the local injector gain changes.
* @function Audio.localInjectorGainChanged
* @param {float} gain - The new local injector gain value.
* @returns {Signal}
*/
void localInjectorGainChanged(float gain);
/**jsdoc
* Triggered when the server injector gain changes.
* @function Audio.serverInjectorGainChanged
* @param {float} gain - The new server injector gain value.
* @returns {Signal}
*/
void serverInjectorGainChanged(float gain);
/**jsdoc
* Triggered when the system injector gain changes.
* @function Audio.systemInjectorGainChanged
* @param {float} gain - The new system injector gain value.
* @returns {Signal}
*/
void systemInjectorGainChanged(float gain);
public slots:
/**jsdoc

View file

@ -10,6 +10,9 @@
#include <shared/GlobalAppProperties.h>
#include <thread>
#include <platform/Platform.h>
#include <platform/Profiler.h>
#ifdef Q_OS_WIN
#include <Windows.h>
#elif defined Q_OS_MAC
@ -21,6 +24,17 @@ PlatformInfoScriptingInterface* PlatformInfoScriptingInterface::getInstance() {
return &sharedInstance;
}
PlatformInfoScriptingInterface::PlatformInfoScriptingInterface() {
platform::create();
if (!platform::enumeratePlatform()) {
}
}
PlatformInfoScriptingInterface::~PlatformInfoScriptingInterface() {
platform::destroy();
}
QString PlatformInfoScriptingInterface::getOperatingSystemType() {
#ifdef Q_OS_WIN
return "WINDOWS";
@ -149,3 +163,52 @@ bool PlatformInfoScriptingInterface::isStandalone() {
return qApp->property(hifi::properties::STANDALONE).toBool();
#endif
}
int PlatformInfoScriptingInterface::getNumCPUs() {
return platform::getNumCPUs();
}
QString PlatformInfoScriptingInterface::getCPU(int index) {
auto desc = platform::getCPU(index);
return QString(desc.dump().c_str());
}
int PlatformInfoScriptingInterface::getNumGPUs() {
return platform::getNumGPUs();
}
QString PlatformInfoScriptingInterface::getGPU(int index) {
auto desc = platform::getGPU(index);
return QString(desc.dump().c_str());
}
int PlatformInfoScriptingInterface::getNumDisplays() {
return platform::getNumDisplays();
}
QString PlatformInfoScriptingInterface::getDisplay(int index) {
auto desc = platform::getDisplay(index);
return QString(desc.dump().c_str());
}
QString PlatformInfoScriptingInterface::getMemory() {
auto desc = platform::getMemory(0);
return QString(desc.dump().c_str());
}
QString PlatformInfoScriptingInterface::getComputer() {
auto desc = platform::getComputer();
return QString(desc.dump().c_str());
}
PlatformInfoScriptingInterface::PlatformTier PlatformInfoScriptingInterface::getTierProfiled() {
return (PlatformInfoScriptingInterface::PlatformTier) platform::Profiler::profilePlatform();
}
QStringList PlatformInfoScriptingInterface::getPlatformTierNames() {
static const QStringList platformTierNames = { "UNKNWON", "LOW", "MID", "HIGH" };
return platformTierNames;
}

View file

@ -9,6 +9,7 @@
#ifndef hifi_PlatformInfoScriptingInterface_h
#define hifi_PlatformInfoScriptingInterface_h
#include <platform/Profiler.h>
#include <QtCore/QObject>
class QScriptValue;
@ -25,6 +26,20 @@ class QScriptValue;
class PlatformInfoScriptingInterface : public QObject {
Q_OBJECT
public:
PlatformInfoScriptingInterface();
virtual ~PlatformInfoScriptingInterface();
// Platform tier enum type
enum PlatformTier {
UNKNOWN = platform::Profiler::Tier::UNKNOWN,
LOW = platform::Profiler::Tier::LOW,
MID = platform::Profiler::Tier::MID,
HIGH = platform::Profiler::Tier::HIGH,
};
Q_ENUM(PlatformTier);
public slots:
/**jsdoc
* @function PlatformInfo.getInstance
@ -98,6 +113,96 @@ public slots:
* @returns {boolean} <code>true</code> if Interface is running on a stand-alone device, <code>false</code> if it isn't.
*/
bool isStandalone();
/**jsdoc
* Get the number of CPUs.
* @function PlatformInfo.getNumCPUs
* @returns {number} The number of CPUs detected on the hardware platform.
*/
int getNumCPUs();
/**jsdoc
* Get the description of the CPU at the index parameter
* expected fields are:
* - cpuVendor...
* @param index The index of the CPU of the platform
* @function PlatformInfo.getCPU
* @returns {string} The CPU description json field
*/
QString getCPU(int index);
/**jsdoc
* Get the number of GPUs.
* @function PlatformInfo.getNumGPUs
* @returns {number} The number of GPUs detected on the hardware platform.
*/
int getNumGPUs();
/**jsdoc
* Get the description of the GPU at the index parameter
* expected fields are:
* - gpuVendor...
* @param index The index of the GPU of the platform
* @function PlatformInfo.getGPU
* @returns {string} The GPU description json field
*/
QString getGPU(int index);
/**jsdoc
* Get the number of Displays.
* @function PlatformInfo.getNumDisplays
* @returns {number} The number of Displays detected on the hardware platform.
*/
int getNumDisplays();
/**jsdoc
* Get the description of the Display at the index parameter
* expected fields are:
* - DisplayVendor...
* @param index The index of the Display of the platform
* @function PlatformInfo.getDisplay
* @returns {string} The Display description json field
*/
QString getDisplay(int index);
/**jsdoc
* Get the description of the Memory
* expected fields are:
* - MemoryVendor...
* @function PlatformInfo.getMemory
* @returns {string} The Memory description json field
*/
QString getMemory();
/**jsdoc
* Get the description of the Computer
* expected fields are:
* - ComputerVendor...
* @function PlatformInfo.getComputer
* @returns {string} The Computer description json field
*/
QString getComputer();
/**jsdoc
* Get the Platform TIer profiled on startup of the Computer
* Platform Tier is an ineger/enum value:
* LOW = 0, MID = 1, HIGH = 2
* @function PlatformInfo.getTierProfiled
* @returns {number} The Platform Tier profiled on startup.
*/
PlatformTier getTierProfiled();
/**jsdoc
* Get the Platform Tier possible Names as an array of strings
* Platform Tier is an ineger/enum value:
* LOW = 0, MID = 1, HIGH = 2
* @function PlatformInfo.getPlatformTierNames
* @returns {string} The array of names matching the number returned from PlatformInfo.getTierProfiled
*/
QStringList getPlatformTierNames();
};
#endif // hifi_PlatformInfoScriptingInterface_h

View file

@ -7,6 +7,9 @@
//
#include "RenderScriptingInterface.h"
#include "LightingModel.h"
#include "AntialiasingEffect.h"
const QString DEFERRED = "deferred";
const QString FORWARD = "forward";
@ -17,6 +20,9 @@ RenderScriptingInterface* RenderScriptingInterface::getInstance() {
RenderScriptingInterface::RenderScriptingInterface() {
setRenderMethod((render::Args::RenderMethod)_renderMethodSetting.get() == render::Args::RenderMethod::DEFERRED ? DEFERRED : FORWARD);
setShadowsEnabled(_shadowsEnabledSetting.get());
setAmbientOcclusionEnabled(_ambientOcclusionEnabledSetting.get());
setAntialiasingEnabled(_antialiasingEnabledSetting.get());
}
QString RenderScriptingInterface::getRenderMethod() {
@ -24,6 +30,11 @@ QString RenderScriptingInterface::getRenderMethod() {
}
void RenderScriptingInterface::setRenderMethod(const QString& renderMethod) {
render::Args::RenderMethod newMethod = renderMethod == FORWARD ? render::Args::RenderMethod::FORWARD : render::Args::RenderMethod::DEFERRED;
if (_renderMethodSetting.get() == newMethod) {
return;
}
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setRenderMethod", Q_ARG(const QString&, renderMethod));
return;
@ -31,14 +42,81 @@ void RenderScriptingInterface::setRenderMethod(const QString& renderMethod) {
auto config = dynamic_cast<task::SwitchConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.DeferredForwardSwitch"));
if (config) {
if (renderMethod == DEFERRED) {
_renderMethodSetting.set(render::Args::RenderMethod::DEFERRED);
config->setBranch(render::Args::RenderMethod::DEFERRED);
emit config->dirtyEnabled();
} else if (renderMethod == FORWARD) {
_renderMethodSetting.set(render::Args::RenderMethod::FORWARD);
config->setBranch(render::Args::RenderMethod::FORWARD);
emit config->dirtyEnabled();
_renderMethodSetting.set(newMethod);
config->setBranch(newMethod);
emit config->dirtyEnabled();
}
}
bool RenderScriptingInterface::getShadowsEnabled() {
return _shadowsEnabledSetting.get();
}
void RenderScriptingInterface::setShadowsEnabled(bool enabled) {
if (_shadowsEnabledSetting.get() == enabled) {
return;
}
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setShadowsEnabled", Q_ARG(bool, enabled));
return;
}
auto lightingModelConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<MakeLightingModel>("RenderMainView.LightingModel");
if (lightingModelConfig) {
Menu::getInstance()->setIsOptionChecked(MenuOption::Shadows, enabled);
_shadowsEnabledSetting.set(enabled);
lightingModelConfig->setShadow(enabled);
}
}
bool RenderScriptingInterface::getAmbientOcclusionEnabled() {
return _ambientOcclusionEnabledSetting.get();
}
void RenderScriptingInterface::setAmbientOcclusionEnabled(bool enabled) {
if (_ambientOcclusionEnabledSetting.get() == enabled) {
return;
}
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setAmbientOcclusionEnabled", Q_ARG(bool, enabled));
return;
}
auto lightingModelConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<MakeLightingModel>("RenderMainView.LightingModel");
if (lightingModelConfig) {
Menu::getInstance()->setIsOptionChecked(MenuOption::AmbientOcclusion, enabled);
_ambientOcclusionEnabledSetting.set(enabled);
lightingModelConfig->setAmbientOcclusion(enabled);
}
}
bool RenderScriptingInterface::getAntialiasingEnabled() {
return _antialiasingEnabledSetting.get();
}
void RenderScriptingInterface::setAntialiasingEnabled(bool enabled) {
if (_antialiasingEnabledSetting.get() == enabled) {
return;
}
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setAntialiasingEnabled", Q_ARG(bool, enabled));
return;
}
auto mainViewJitterCamConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<JitterSample>("RenderMainView.JitterCam");
auto mainViewAntialiasingConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<Antialiasing>("RenderMainView.Antialiasing");
if (mainViewJitterCamConfig && mainViewAntialiasingConfig) {
Menu::getInstance()->setIsOptionChecked(MenuOption::AntiAliasing, enabled);
_antialiasingEnabledSetting.set(enabled);
if (enabled) {
mainViewJitterCamConfig->play();
mainViewAntialiasingConfig->setDebugFXAA(false);
} else {
mainViewJitterCamConfig->none();
mainViewAntialiasingConfig->setDebugFXAA(true);
}
}
}

View file

@ -26,6 +26,9 @@
class RenderScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(QString renderMethod READ getRenderMethod WRITE setRenderMethod)
Q_PROPERTY(bool shadowsEnabled READ getShadowsEnabled WRITE setShadowsEnabled)
Q_PROPERTY(bool ambientOcclusionEnabled READ getAmbientOcclusionEnabled WRITE setAmbientOcclusionEnabled)
Q_PROPERTY(bool antialiasingEnabled READ getAntialiasingEnabled WRITE setAntialiasingEnabled)
public:
RenderScriptingInterface();
@ -37,8 +40,8 @@ public slots:
* Get a config for a job by name
* @function Render.getConfig
* @param {string} name - Can be:
* - <job_name>. Search for the first job named job_name traversing the the sub graph of task and jobs (from this task as root)
* - <parent_name>.[<sub_parent_names>.]<job_name>. Allows you to first look for the parent_name job (from this task as root) and then search from there for the
* - <job_name>: Search for the first job named job_name traversing the the sub graph of task and jobs (from this task as root)
* - <parent_name>.[<sub_parent_names>.]<job_name>: Allows you to first look for the parent_name job (from this task as root) and then search from there for the
* optional sub_parent_names and finally from there looking for the job_name (assuming every job in the path is found)
* @returns {object} The sub job config.
*/
@ -58,8 +61,53 @@ public slots:
*/
void setRenderMethod(const QString& renderMethod);
/**jsdoc
* Whether or not shadows are enabled
* @function Render.getShadowsEnabled
* @returns {bool} <code>true</code> if shadows are enabled, otherwise <code>false</code>
*/
bool getShadowsEnabled();
/**jsdoc
* Enables or disables shadows
* @function Render.setShadowsEnabled
* @param {bool} enabled - <code>true</code> to enable shadows, <code>false</code> to disable them
*/
void setShadowsEnabled(bool enabled);
/**jsdoc
* Whether or not ambient occlusion is enabled
* @function Render.getAmbientOcclusionEnabled
* @returns {bool} <code>true</code> if ambient occlusion is enabled, otherwise <code>false</code>
*/
bool getAmbientOcclusionEnabled();
/**jsdoc
* Enables or disables ambient occlusion
* @function Render.setAmbientOcclusionEnabled
* @param {bool} enabled - <code>true</code> to enable ambient occlusion, <code>false</code> to disable it
*/
void setAmbientOcclusionEnabled(bool enabled);
/**jsdoc
* Whether or not anti-aliasing is enabled
* @function Render.getAntialiasingEnabled
* @returns {bool} <code>true</code> if anti-aliasing is enabled, otherwise <code>false</code>
*/
bool getAntialiasingEnabled();
/**jsdoc
* Enables or disables anti-aliasing
* @function Render.setAntialiasingEnabled
* @param {bool} enabled - <code>true</code> to enable anti-aliasing, <code>false</code> to disable it
*/
void setAntialiasingEnabled(bool enabled);
private:
Setting::Handle<int> _renderMethodSetting { "renderMethod", RENDER_FORWARD ? render::Args::RenderMethod::FORWARD : render::Args::RenderMethod::DEFERRED };
Setting::Handle<bool> _shadowsEnabledSetting { "shadowsEnabled", true };
Setting::Handle<bool> _ambientOcclusionEnabledSetting { "ambientOcclusionEnabled", false };
Setting::Handle<bool> _antialiasingEnabledSetting { "antialiasingEnabled", true };
};
#endif // hifi_RenderScriptingInterface_h

View file

@ -44,13 +44,14 @@ SelectionScriptingInterface::SelectionScriptingInterface() {
}
/**jsdoc
* The type of a specific item in a selection list.
* <table>
* <thead>
* <tr><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"avatar"</code></td><td></td></tr>
* <tr><td><code>"entity"</code></td><td></td></tr>
* <tr><td><code>"avatar"</code></td><td>The item is an avatar.</td></tr>
* <tr><td><code>"entity"</code></td><td>The item is an entity.</td></tr>
* </tbody>
* </table>
* @typedef {string} Selection.ItemType
@ -245,9 +246,10 @@ void SelectionScriptingInterface::printList(const QString& listName) {
}
/**jsdoc
* A selection list.
* @typedef {object} Selection.SelectedItemsList
* @property {Uuid[]} avatars - The IDs of the avatars in the selection.
* @property {Uuid[]} entities - The IDs of the entities in the selection.
* @property {Uuid[]} avatars - The IDs of the avatars in the selection list.
* @property {Uuid[]} entities - The IDs of the entities in the selection list.
*/
QVariantMap SelectionScriptingInterface::getSelectedItemsList(const QString& listName) const {
QReadLocker lock(&_selectionListsLock);
@ -438,18 +440,19 @@ bool SelectionHighlightStyle::fromVariantMap(const QVariantMap& properties) {
}
/**jsdoc
* The highlighting style of a selection list.
* @typedef {object} Selection.HighlightStyle
* @property {Color} outlineUnoccludedColor - Color of the specified highlight region.
* @property {Color} outlineOccludedColor - ""
* @property {Color} fillUnoccludedColor- ""
* @property {Color} fillOccludedColor- ""
* @property {number} outlineUnoccludedAlpha - Alpha value ranging from <code>0.0</code> (not visible) to <code>1.0</code>
* (fully opaque) for the specified highlight region.
* @property {number} outlineOccludedAlpha - ""
* @property {number} fillUnoccludedAlpha - ""
* @property {number} fillOccludedAlpha - ""
* @property {number} outlineWidth - Width of the outline, in pixels.
* @property {boolean} isOutlineSmooth - <code>true</code> to enable outline smooth fall-off.
* @property {Color} outlineUnoccludedColor=255,178,51 - Unoccluded outline color.
* @property {Color} outlineOccludedColor=255,178,51 - Occluded outline color.
* @property {Color} fillUnoccludedColor=51,178,255 - Unoccluded fill color.
* @property {Color} fillOccludedColor=51,178,255 - Occluded fill color.
* @property {number} outlineUnoccludedAlpha=0.9 - Unoccluded outline alpha, range <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} outlineOccludedAlpha=0.9 - Occluded outline alpha, range <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} fillUnoccludedAlpha=0.0 - Unoccluded fill alpha, range <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} fillOccludedAlpha=0.0 - Occluded fill alpha, range <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} outlineWidth=2 - Width of the outline, in pixels.
* @property {boolean} isOutlineSmooth=false - <code>true</code> to fade the outside edge of the outline, <code>false</code>
* to have a sharp edge.
*/
QVariantMap SelectionHighlightStyle::toVariantMap() const {
QVariantMap properties;

View file

@ -77,47 +77,45 @@ protected:
};
/**jsdoc
* The <code>Selection</code> API provides a means of grouping together avatars and entities in named lists.
* The <code>Selection</code> API provides a means of grouping together and highlighting avatars and entities in named lists.
*
* @namespace Selection
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @example <caption>Outline an entity when it is grabbed by a controller.</caption>
* // Create a box and copy the following text into the entity's "Script URL" field.
* @example <caption>Outline an entity when it is grabbed by the mouse or a controller.</caption>
* // Create an entity and copy the following script into the entity's "Script URL" field.
* // Move the entity behind another entity to see the occluded outline.
* (function () {
* print("Starting highlight script...............");
* var _this = this;
* var prevID = 0;
* var listName = "contextOverlayHighlightList";
* var listType = "entity";
*
* _this.startNearGrab = function(entityID){
* if (prevID !== entityID) {
* Selection.addToSelectedItemsList(listName, listType, entityID);
* prevID = entityID;
* }
* var LIST_NAME = "SelectionExample",
* ITEM_TYPE = "entity",
* HIGHLIGHT_STYLE = {
* outlineUnoccludedColor: { red: 0, green: 180, blue: 239 },
* outlineUnoccludedAlpha: 0.5,
* outlineOccludedColor: { red: 239, green: 180, blue: 0 },
* outlineOccludedAlpha: 0.5,
* outlineWidth: 4
* };
*
* Selection.enableListHighlight(LIST_NAME, HIGHLIGHT_STYLE);
*
* this.startNearGrab = function (entityID) {
* Selection.addToSelectedItemsList(LIST_NAME, ITEM_TYPE, entityID);
* };
*
* _this.releaseGrab = function(entityID){
* if (prevID !== 0) {
* Selection.removeFromSelectedItemsList("contextOverlayHighlightList", listType, prevID);
* prevID = 0;
* }
*
* this.startDistanceGrab = function (entityID) {
* Selection.addToSelectedItemsList(LIST_NAME, ITEM_TYPE, entityID);
* };
*
* var cleanup = function(){
* Entities.findEntities(MyAvatar.position, 1000).forEach(function(entity) {
* try {
* Selection.removeListFromMap(listName);
* } catch (e) {
* print("Error cleaning up.");
* }
* });
*
* this.releaseGrab = function (entityID) {
* Selection.removeFromSelectedItemsList(LIST_NAME, ITEM_TYPE, entityID);
* };
*
* Script.scriptEnding.connect(cleanup);
*
* Script.scriptEnding.connect(function () {
* Selection.removeListFromMap(LIST_NAME);
* });
* });
*/
class SelectionScriptingInterface : public QObject, public Dependency {
@ -127,121 +125,119 @@ public:
SelectionScriptingInterface();
/**jsdoc
* Get the names of all the selection lists.
* @function Selection.getListNames
* @returns {list[]} An array of names of all the selection lists.
*/
* Gets the names of all current selection lists.
* @function Selection.getListNames
* @returns {string[]} The names of all current selection lists.
* @example <caption>List all the current selection lists.</caption>
* print("Selection lists: " + Selection.getListNames());
*/
Q_INVOKABLE QStringList getListNames() const;
/**jsdoc
* Delete a named selection list.
* @function Selection.removeListFromMap
* @param {string} listName - The name of the selection list.
* @returns {boolean} <code>true</code> if the selection existed and was successfully removed, otherwise <code>false</code>.
*/
* Deletes a selection list.
* @function Selection.removeListFromMap
* @param {string} listName - The name of the selection list to delete.
* @returns {boolean} <code>true</code> if the selection existed and was successfully removed, otherwise <code>false</code>.
*/
Q_INVOKABLE bool removeListFromMap(const QString& listName);
/**jsdoc
* Add an item to a selection list.
* @function Selection.addToSelectedItemsList
* @param {string} listName - The name of the selection list to add the item to.
* @param {Selection.ItemType} itemType - The type of the item being added.
* @param {Uuid} id - The ID of the item to add to the selection.
* @returns {boolean} <code>true</code> if the item was successfully added, otherwise <code>false</code>.
*/
* Adds an item to a selection list. The list is created if it doesn't exist.
* @function Selection.addToSelectedItemsList
* @param {string} listName - The name of the selection list to add the item to.
* @param {Selection.ItemType} itemType - The type of item being added.
* @param {Uuid} itemID - The ID of the item to add.
* @returns {boolean} <code>true</code> if the item was successfully added or already existed in the list, otherwise
* <code>false</code>.
*/
Q_INVOKABLE bool addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id);
/**jsdoc
* Remove an item from a selection list.
* @function Selection.removeFromSelectedItemsList
* @param {string} listName - The name of the selection list to remove the item from.
* @param {Selection.ItemType} itemType - The type of the item being removed.
* @param {Uuid} id - The ID of the item to remove.
* @returns {boolean} <code>true</code> if the item was successfully removed, otherwise <code>false</code>.
* <codefalse</code> is returned if the list doesn't contain any data.
*/
* Removes an item from a selection list.
* @function Selection.removeFromSelectedItemsList
* @param {string} listName - The name of the selection list to remove the item from.
* @param {Selection.ItemType} itemType - The type of item being removed.
* @param {Uuid} itemID - The ID of the item to remove.
* @returns {boolean} <code>true</code> if the item was successfully removed or was not in the list, otherwise
* <code>false</code>.
*/
Q_INVOKABLE bool removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id);
/**jsdoc
* Remove all items from a selection.
* @function Selection.clearSelectedItemsList
* @param {string} listName - The name of the selection list.
* @returns {boolean} <code>true</code> if the item was successfully cleared, otherwise <code>false</code>.
*/
* Removes all items from a selection list.
* @function Selection.clearSelectedItemsList
* @param {string} listName - The name of the selection list.
* @returns {boolean} <code>true</code> always.
*/
Q_INVOKABLE bool clearSelectedItemsList(const QString& listName);
/**jsdoc
* Print out the list of avatars and entities in a selection to the <em>debug log</em> (not the script log).
* @function Selection.printList
* @param {string} listName - The name of the selection list.
*/
* Prints the list of avatars and entities in a selection to the program log (but not the Script Log window).
* @function Selection.printList
* @param {string} listName - The name of the selection list.
*/
Q_INVOKABLE void printList(const QString& listName);
/**jsdoc
* Get the list of avatars and entities stored in a selection list.
* @function Selection.getSelectedItemsList
* @param {string} listName - The name of the selection list.
* @returns {Selection.SelectedItemsList} The content of a selection list. If the list name doesn't exist, the function
* returns an empty object with no properties.
*/
* Gets the list of avatars and entities in a selection list.
* @function Selection.getSelectedItemsList
* @param {string} listName - The name of the selection list.
* @returns {Selection.SelectedItemsList} The content of the selection list if the list exists, otherwise an empty object.
*/
Q_INVOKABLE QVariantMap getSelectedItemsList(const QString& listName) const;
/**jsdoc
* Get the names of the highlighted selection lists.
* @function Selection.getHighlightedListNames
* @returns {string[]} An array of names of the selection list currently highlight enabled.
*/
* Gets the names of all current selection lists that have highlighting enabled.
* @function Selection.getHighlightedListNames
* @returns {string[]} The names of the selection lists that currently have highlighting enabled.
*/
Q_INVOKABLE QStringList getHighlightedListNames() const;
/**jsdoc
* Enable highlighting for a selection list.
* If the selection list doesn't exist, it will be created.
* All objects in the list will be displayed with the highlight effect specified.
* The function can be called several times with different values in the style to modify it.<br />
* Note: This function implicitly calls {@link Selection.enableListToScene}.
* @function Selection.enableListHighlight
* @param {string} listName - The name of the selection list.
* @param {Selection.HighlightStyle} highlightStyle - The highlight style.
* @returns {boolean} true if the selection was successfully enabled for highlight.
*/
* Enables highlighting for a selection list. All items in or subsequently added to the list are displayed with the
* highlight effect specified. The method can be called multiple times with different values in the style to modify the
* highlighting.
* <p>Note: This function implicitly calls {@link Selection.enableListToScene|enableListToScene}.</p>
* @function Selection.enableListHighlight
* @param {string} listName - The name of the selection list.
* @param {Selection.HighlightStyle} highlightStyle - The highlight style.
* @returns {boolean} <code>true</code> always.
*/
Q_INVOKABLE bool enableListHighlight(const QString& listName, const QVariantMap& highlightStyle);
/**jsdoc
* Disable highlighting for the selection list.
* If the selection list doesn't exist or wasn't enabled for highlighting then nothing happens and <code>false</code> is
* returned.<br />
* Note: This function implicitly calls {@link Selection.disableListToScene}.
* @function Selection.disableListHighlight
* @param {string} listName - The name of the selection list.
* @returns {boolean} <code>true</code> if the selection was successfully disabled for highlight, otherwise
* <code>false</code>.
*/
* Disables highlighting for a selection list.
* <p>Note: This function implicitly calls {@link Selection.disableListToScene|disableListToScene}.</p>
* @function Selection.disableListHighlight
* @param {string} listName - The name of the selection list.
* @returns {boolean} <code>true</code> always.
*/
Q_INVOKABLE bool disableListHighlight(const QString& listName);
/**jsdoc
* Enable scene selection for the selection list.
* If the Selection doesn't exist, it will be created.
* All objects in the list will be sent to a scene selection.
* @function Selection.enableListToScene
* @param {string} listName - The name of the selection list.
* @returns {boolean} <code>true</code> if the selection was successfully enabled on the scene, otherwise <code>false</code>.
*/
* Enables scene selection for a selection list. All items in or subsequently added to the list are sent to a scene
* selection in the rendering engine for debugging purposes.
* @function Selection.enableListToScene
* @param {string} listName - The name of the selection list.
* @returns {boolean} <code>true</code> always.
*/
Q_INVOKABLE bool enableListToScene(const QString& listName);
/**jsdoc
* Disable scene selection for the named selection.
* If the selection list doesn't exist or wasn't enabled on the scene then nothing happens and <code>false</code> is
* returned.
* @function Selection.disableListToScene
* @param {string} listName - The name of the selection list.
* @returns {boolean} true if the selection was successfully disabled on the scene, false otherwise.
*/
* Disables scene selection for a selection list.
* @function Selection.disableListToScene
* @param {string} listName - The name of the selection list.
* @returns {boolean} <code>true</code> always.
*/
Q_INVOKABLE bool disableListToScene(const QString& listName);
/**jsdoc
* Get the highlight style values for the a selection list.
* If the selection doesn't exist or hasn't been highlight enabled yet, an empty object is returned.
* @function Selection.getListHighlightStyle
* @param {string} listName - The name of the selection list.
* @returns {Selection.HighlightStyle} highlight style
*/
* Gets the current highlighting style for a selection list.
* @function Selection.getListHighlightStyle
* @param {string} listName - The name of the selection list.
* @returns {Selection.HighlightStyle} The highlight style of the selection list if the list exists and highlighting is
* enabled, otherwise an empty object.
*/
Q_INVOKABLE QVariantMap getListHighlightStyle(const QString& listName) const;
@ -253,7 +249,7 @@ public:
signals:
/**jsdoc
* Triggered when a list's content changes.
* Triggered when a selection list's content changes or the list is deleted.
* @function Selection.selectedItemsListChanged
* @param {string} listName - The name of the selection list that changed.
* @returns {Signal}
@ -276,7 +272,6 @@ private:
void setupHandler(const QString& selectionName);
void removeHandler(const QString& selectionName);
};
#endif // hifi_SelectionScriptingInterface_h

View file

@ -16,7 +16,8 @@
#include <QString>
/**jsdoc
* The Settings API provides a facility to store and retrieve values that persist between Interface runs.
* The <code>Settings</code> API provides a facility to store and retrieve values that persist between Interface runs.
*
* @namespace Settings
*
* @hifi-interface
@ -33,7 +34,7 @@ public:
public slots:
/**jsdoc
* Retrieve the value from a named setting.
* Retrieves the value from a named setting.
* @function Settings.getValue
* @param {string} key - The name of the setting.
* @param {string|number|boolean|object} [defaultValue=""] - The value to return if the setting doesn't exist.
@ -50,8 +51,8 @@ public slots:
QVariant getValue(const QString& setting, const QVariant& defaultValue);
/**jsdoc
* Store a value in a named setting. If the setting already exists its value is overwritten, otherwise a new setting is
* created. If the value is set to <code>null</code> or <code>undefined</code>, the setting is deleted.
* Stores a value in a named setting. If the setting already exists, its value is overwritten. If the value is
* <code>null</code> or <code>undefined</code>, the setting is deleted.
* @function Settings.setValue
* @param {string} key - The name of the setting. Be sure to use a unique name if creating a new setting.
* @param {string|number|boolean|object|undefined} value - The value to store in the setting. If <code>null</code> or

View file

@ -313,8 +313,9 @@ public slots:
* Takes a snapshot of the current Interface view from the primary camera. When a still image only is captured,
* {@link Window.stillSnapshotTaken|stillSnapshotTaken} is emitted; when a still image plus moving images are captured,
* {@link Window.processingGifStarted|processingGifStarted} and {@link Window.processingGifCompleted|processingGifCompleted}
* are emitted. The path to store the snapshots and the length of the animated GIF to capture are specified in Settings >
* General > Snapshots.
* are emitted.
* <p>Snapshots are saved to the path specified in Settings &gt; General &gt; Snapshots, which can be accessed via the
* {@link Snapshot} API.</p>
*
* @function Window.takeSnapshot
* @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
@ -351,13 +352,15 @@ public slots:
* var notify = true;
* var animated = true;
* var aspect = 1920 / 1080;
* var filename = "";
* var filename = "example-snapshot";
* Window.takeSnapshot(notify, animated, aspect, filename);
*/
void takeSnapshot(bool notify = true, bool includeAnimated = false, float aspectRatio = 0.0f, const QString& filename = QString());
/**jsdoc
* Takes a still snapshot of the current view from the secondary camera that can be set up through the {@link Render} API.
* <p>Snapshots are saved to the path specified in Settings &gt; General &gt; Snapshots, which can be accessed via the
* {@link Snapshot} API.</p>
* @function Window.takeSecondaryCameraSnapshot
* @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken}
* signal.
@ -372,6 +375,8 @@ public slots:
/**jsdoc
* Takes a 360&deg; snapshot at a given position for the secondary camera. The secondary camera does not need to have been
* set up.
* <p>Snapshots are saved to the path specified in Settings &gt; General &gt; Snapshots, which can be accessed via the
* {@link Snapshot} API.</p>
* @function Window.takeSecondaryCamera360Snapshot
* @param {Vec3} cameraPosition - The position of the camera for the snapshot.
* @param {boolean} [cubemapOutputFormat=false] - If <code>true</code> then the snapshot is saved as a cube map image,

View file

@ -109,7 +109,11 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
auto mainWindow = qApp->getWindow();
_dockWidget = std::shared_ptr<DockWidget>(new DockWidget(title, mainWindow), dockWidgetDeleter);
auto quickView = _dockWidget->getQuickView();
Application::setupQmlSurface(quickView->rootContext(), true);
Application::setupQmlSurface(quickView->rootContext() , true);
//add any whitelisted callbacks
OffscreenUi::applyWhiteList(sourceUrl, quickView->rootContext());
/**jsdoc
* Configures how a <code>NATIVE</code> window is displayed.
@ -150,6 +154,8 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
}
});
_dockWidget->setSource(QUrl(sourceUrl));
mainWindow->addDockWidget(dockArea, _dockWidget.get());
} else {
auto offscreenUi = DependencyManager::get<OffscreenUi>();

View file

@ -180,11 +180,7 @@ private:
mutable ReadWriteLockable _preferMalletsOverLasersSettingLock;
mutable ReadWriteLockable _ignoreItemsLock;
#ifdef Q_OS_ANDROID
Setting::Handle<bool> _use3DKeyboard { "use3DKeyboard", false };
#else
Setting::Handle<bool> _use3DKeyboard { "use3DKeyboard", true };
#endif
QString _typedCharacters;
TextDisplay _textDisplay;

View file

@ -38,6 +38,10 @@ private:
/**jsdoc
* The <code>Snapshot</code> API provides access to the path that snapshots are saved to. This path is that provided in
* Settings &gt; General &gt; Snapshots. Snapshots may be taken using <code>Window</code> API functions such as
* {@link Window.takeSnapshot}.
*
* @namespace Snapshot
*
* @hifi-interface
@ -64,23 +68,31 @@ public:
signals:
/**jsdoc
* Triggered when the path that snapshots are saved to is changed.
* @function Snapshot.snapshotLocationSet
* @param {string} location
* @param {string} location - The new snapshots location.
* @returns {Signal}
* @example <caption>Report when the snapshots location is changed.</caption>
* // Run this script then change the snapshots location in Settings > General > Snapshots.
* Snapshot.snapshotLocationSet.connect(function (path) {
* print("New snapshot location: " + path);
* });
*/
void snapshotLocationSet(const QString& value);
public slots:
/**jsdoc
* Gets the path that snapshots are saved to.
* @function Snapshot.getSnapshotsLocation
* @returns {string}
* @returns {string} The path to save snapshots to.
*/
Q_INVOKABLE QString getSnapshotsLocation();
/**jsdoc
* Sets the path that snapshots are saved to.
* @function Snapshot.setSnapshotsLocation
* @param {String} location
* @param {String} location - The path to save snapshots to.
*/
Q_INVOKABLE void setSnapshotsLocation(const QString& location);

View file

@ -314,10 +314,11 @@ class Stats : public QQuickItem {
STATS_PROPERTY(QVector3D, parabolaPicksUpdated, QVector3D(0, 0, 0))
STATS_PROPERTY(QVector3D, collisionPicksUpdated, QVector3D(0, 0, 0))
#ifdef DEBUG_EVENT_QUEUE
STATS_PROPERTY(bool, eventQueueDebuggingOn, true)
STATS_PROPERTY(int, mainThreadQueueDepth, -1);
STATS_PROPERTY(int, nodeListThreadQueueDepth, -1);
#ifdef DEBUG_EVENT_QUEUE
STATS_PROPERTY(bool, eventQueueDebuggingOn, true)
#else
STATS_PROPERTY(bool, eventQueueDebuggingOn, false)
#endif // DEBUG_EVENT_QUEUE

View file

@ -1869,6 +1869,7 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
if (_audioOutput) {
_audioOutputIODevice.close();
_audioOutput->stop();
_audioOutputInitialized = false;
//must be deleted in next eventloop cycle when its called from notify()
_audioOutput->deleteLater();
@ -1939,52 +1940,50 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
int requestedSize = _sessionOutputBufferSizeFrames * frameSize * AudioConstants::SAMPLE_SIZE;
_audioOutput->setBufferSize(requestedSize);
// initialize mix buffers on the _audioOutput thread to avoid races
connect(_audioOutput, &QAudioOutput::stateChanged, [&, frameSize, requestedSize](QAudio::State state) {
if (state == QAudio::ActiveState) {
// restrict device callback to _outputPeriod samples
_outputPeriod = _audioOutput->periodSize() / AudioConstants::SAMPLE_SIZE;
// device callback may exceed reported period, so double it to avoid stutter
_outputPeriod *= 2;
_outputMixBuffer = new float[_outputPeriod];
_outputScratchBuffer = new int16_t[_outputPeriod];
// size local output mix buffer based on resampled network frame size
int networkPeriod = _localToOutputResampler ? _localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO) : AudioConstants::NETWORK_FRAME_SAMPLES_STEREO;
_localOutputMixBuffer = new float[networkPeriod];
// local period should be at least twice the output period,
// in case two device reads happen before more data can be read (worst case)
int localPeriod = _outputPeriod * 2;
// round up to an exact multiple of networkPeriod
localPeriod = ((localPeriod + networkPeriod - 1) / networkPeriod) * networkPeriod;
// this ensures lowest latency without stutter from underrun
_localInjectorsStream.resizeForFrameSize(localPeriod);
int bufferSize = _audioOutput->bufferSize();
int bufferSamples = bufferSize / AudioConstants::SAMPLE_SIZE;
int bufferFrames = bufferSamples / (float)frameSize;
qCDebug(audioclient) << "frame (samples):" << frameSize;
qCDebug(audioclient) << "buffer (frames):" << bufferFrames;
qCDebug(audioclient) << "buffer (samples):" << bufferSamples;
qCDebug(audioclient) << "buffer (bytes):" << bufferSize;
qCDebug(audioclient) << "requested (bytes):" << requestedSize;
qCDebug(audioclient) << "period (samples):" << _outputPeriod;
qCDebug(audioclient) << "local buffer (samples):" << localPeriod;
disconnect(_audioOutput, &QAudioOutput::stateChanged, 0, 0);
// unlock to avoid a deadlock with the device callback (which always succeeds this initialization)
localAudioLock.unlock();
}
});
connect(_audioOutput, &QAudioOutput::notify, this, &AudioClient::outputNotify);
// start the output device
_audioOutputIODevice.start();
_audioOutput->start(&_audioOutputIODevice);
// initialize mix buffers
// restrict device callback to _outputPeriod samples
_outputPeriod = _audioOutput->periodSize() / AudioConstants::SAMPLE_SIZE;
// device callback may exceed reported period, so double it to avoid stutter
_outputPeriod *= 2;
_outputMixBuffer = new float[_outputPeriod];
_outputScratchBuffer = new int16_t[_outputPeriod];
// size local output mix buffer based on resampled network frame size
int networkPeriod = _localToOutputResampler ? _localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO) : AudioConstants::NETWORK_FRAME_SAMPLES_STEREO;
_localOutputMixBuffer = new float[networkPeriod];
// local period should be at least twice the output period,
// in case two device reads happen before more data can be read (worst case)
int localPeriod = _outputPeriod * 2;
// round up to an exact multiple of networkPeriod
localPeriod = ((localPeriod + networkPeriod - 1) / networkPeriod) * networkPeriod;
// this ensures lowest latency without stutter from underrun
_localInjectorsStream.resizeForFrameSize(localPeriod);
_audioOutputInitialized = true;
int bufferSize = _audioOutput->bufferSize();
int bufferSamples = bufferSize / AudioConstants::SAMPLE_SIZE;
int bufferFrames = bufferSamples / (float)frameSize;
qCDebug(audioclient) << "frame (samples):" << frameSize;
qCDebug(audioclient) << "buffer (frames):" << bufferFrames;
qCDebug(audioclient) << "buffer (samples):" << bufferSamples;
qCDebug(audioclient) << "buffer (bytes):" << bufferSize;
qCDebug(audioclient) << "requested (bytes):" << requestedSize;
qCDebug(audioclient) << "period (samples):" << _outputPeriod;
qCDebug(audioclient) << "local buffer (samples):" << localPeriod;
// unlock to avoid a deadlock with the device callback (which always succeeds this initialization)
localAudioLock.unlock();
// setup a loopback audio output device
_loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
@ -2082,6 +2081,12 @@ float AudioClient::gainForSource(float distance, float volume) {
qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
// lock-free wait for initialization to avoid races
if (!_audio->_audioOutputInitialized.load(std::memory_order_acquire)) {
memset(data, 0, maxSize);
return maxSize;
}
// samples requested from OUTPUT_CHANNEL_COUNT
int deviceChannelCount = _audio->_outputFormat.channelCount();
int samplesRequested = (int)(maxSize / AudioConstants::SAMPLE_SIZE) * OUTPUT_CHANNEL_COUNT / deviceChannelCount;
@ -2162,6 +2167,8 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
}
bytesWritten = framesPopped * AudioConstants::SAMPLE_SIZE * deviceChannelCount;
assert(bytesWritten <= maxSize);
} else {
// nothing on network, don't grab anything from injectors, and just return 0s
memset(data, 0, maxSize);
@ -2174,7 +2181,6 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
_audio->_audioFileWav.addRawAudioChunk(reinterpret_cast<char*>(scratchBuffer), bytesWritten);
}
int bytesAudioOutputUnplayed = _audio->_audioOutput->bufferSize() - _audio->_audioOutput->bytesFree();
float msecsAudioOutputUnplayed = bytesAudioOutputUnplayed / (float)_audio->_outputFormat.bytesForDuration(USECS_PER_MSEC);
_audio->_stats.updateOutputMsUnplayed(msecsAudioOutputUnplayed);

View file

@ -340,6 +340,7 @@ private:
QIODevice* _inputDevice;
int _numInputCallbackBytes;
QAudioOutput* _audioOutput;
std::atomic<bool> _audioOutputInitialized { false };
QAudioFormat _desiredOutputFormat;
QAudioFormat _outputFormat;
int _outputFrameSize;

View file

@ -364,10 +364,19 @@ int InboundAudioStream::popSamples(int maxSamples, bool allOrNothing) {
// buffer calculations.
setToStarved();
_consecutiveNotMixedCount++;
//Kick PLC to generate a filler frame, reducing 'click'
lostAudioData(allOrNothing ? (maxSamples - samplesAvailable) / _ringBuffer.getNumFrameSamples() : 1);
samplesPopped = _ringBuffer.samplesAvailable();
if (samplesPopped) {
// use PLC to generate extrapolated audio data, to reduce clicking
if (allOrNothing) {
int samplesNeeded = maxSamples - samplesAvailable;
int packetsNeeded = (samplesNeeded + _ringBuffer.getNumFrameSamples() - 1) / _ringBuffer.getNumFrameSamples();
lostAudioData(packetsNeeded);
} else {
lostAudioData(1);
}
samplesAvailable = _ringBuffer.samplesAvailable();
if (samplesAvailable > 0) {
samplesPopped = std::min(samplesAvailable, maxSamples);
popSamplesNoCheck(samplesPopped);
} else {
// No samples available means a packet is currently being

View file

@ -1519,18 +1519,19 @@ void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const {
}
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
AvatarData::setSkeletonModelURL(skeletonModelURL);
if (QThread::currentThread() == thread()) {
if (!isMyAvatar() && !DependencyManager::get<NodeList>()->isIgnoringNode(getSessionUUID())) {
createOrb();
}
_skeletonModel->setURL(_skeletonModelURL);
indicateLoadingStatus(LoadingStatus::LoadModel);
} else {
QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", Qt::QueuedConnection, Q_ARG(QUrl, _skeletonModelURL));
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setSkeletonModelURL", Q_ARG(const QUrl&, skeletonModelURL));
return;
}
AvatarData::setSkeletonModelURL(skeletonModelURL);
if (!isMyAvatar() && !DependencyManager::get<NodeList>()->isIgnoringNode(getSessionUUID())) {
createOrb();
}
indicateLoadingStatus(LoadingStatus::LoadModel);
_skeletonModel->setURL(_skeletonModelURL);
}
void Avatar::setModelURLFinished(bool success) {

View file

@ -339,7 +339,7 @@ public:
*/
Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const;
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
Q_INVOKABLE virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
void updateDisplayNameAlpha(bool showDisplayName);

View file

@ -1211,7 +1211,7 @@ public:
const QString& getDisplayName() const { return _displayName; }
const QString& getSessionDisplayName() const { return _sessionDisplayName; }
bool getLookAtSnappingEnabled() const { return _lookAtSnappingEnabled; }
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
Q_INVOKABLE virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
virtual void setDisplayName(const QString& displayName);
virtual void setSessionDisplayName(const QString& sessionDisplayName) {

View file

@ -15,7 +15,7 @@
// These properties have JSDoc documentation in HMDScriptingInterface.h.
class AbstractHMDScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(bool active READ isHMDMode NOTIFY mountedChanged)
Q_PROPERTY(bool active READ isHMDMode NOTIFY displayModeChanged)
Q_PROPERTY(float ipd READ getIPD)
Q_PROPERTY(float eyeHeight READ getEyeHeight)
Q_PROPERTY(float playerHeight READ getPlayerHeight)

View file

@ -32,19 +32,6 @@
using namespace render;
using namespace render::entities;
// These or the icon "name" used by the render item status value, they correspond to the atlas texture used by the DrawItemStatus
// job in the current rendering pipeline defined as of now (11/2015) in render-utils/RenderDeferredTask.cpp.
enum class RenderItemStatusIcon {
ACTIVE_IN_BULLET = 0,
PACKET_SENT = 1,
PACKET_RECEIVED = 2,
SIMULATION_OWNER = 3,
HAS_ACTIONS = 4,
OTHER_SIMULATION_OWNER = 5,
ENTITY_HOST_TYPE = 6,
NONE = 255
};
void EntityRenderer::initEntityRenderers() {
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(PolyVox, RenderablePolyVoxEntityItem::factory)
@ -67,7 +54,7 @@ void EntityRenderer::makeStatusGetters(const EntityItemPointer& entity, Item::St
return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ?
render::Item::Status::Value::GREEN :
render::Item::Status::Value::RED),
(unsigned char)RenderItemStatusIcon::PACKET_RECEIVED);
(unsigned char)render::Item::Status::Icon::PACKET_RECEIVED);
});
statusGetters.push_back([entity] () -> render::Item::Status::Value {
@ -79,17 +66,17 @@ void EntityRenderer::makeStatusGetters(const EntityItemPointer& entity, Item::St
return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ?
render::Item::Status::Value::MAGENTA :
render::Item::Status::Value::CYAN),
(unsigned char)RenderItemStatusIcon::PACKET_SENT);
(unsigned char)render::Item::Status::Icon::PACKET_SENT);
});
statusGetters.push_back([entity] () -> render::Item::Status::Value {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(entity->getPhysicsInfo());
if (motionState && motionState->isActive()) {
return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE,
(unsigned char)RenderItemStatusIcon::ACTIVE_IN_BULLET);
(unsigned char)render::Item::Status::Icon::ACTIVE_IN_BULLET);
}
return render::Item::Status::Value(0.0f, render::Item::Status::Value::BLUE,
(unsigned char)RenderItemStatusIcon::ACTIVE_IN_BULLET);
(unsigned char)render::Item::Status::Icon::ACTIVE_IN_BULLET);
});
statusGetters.push_back([entity, myNodeID] () -> render::Item::Status::Value {
@ -98,39 +85,39 @@ void EntityRenderer::makeStatusGetters(const EntityItemPointer& entity, Item::St
if (weOwnSimulation) {
return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE,
(unsigned char)RenderItemStatusIcon::SIMULATION_OWNER);
(unsigned char)render::Item::Status::Icon::SIMULATION_OWNER);
} else if (otherOwnSimulation) {
return render::Item::Status::Value(1.0f, render::Item::Status::Value::RED,
(unsigned char)RenderItemStatusIcon::OTHER_SIMULATION_OWNER);
(unsigned char)render::Item::Status::Icon::OTHER_SIMULATION_OWNER);
}
return render::Item::Status::Value(0.0f, render::Item::Status::Value::BLUE,
(unsigned char)RenderItemStatusIcon::SIMULATION_OWNER);
(unsigned char)render::Item::Status::Icon::SIMULATION_OWNER);
});
statusGetters.push_back([entity] () -> render::Item::Status::Value {
if (entity->hasActions()) {
return render::Item::Status::Value(1.0f, render::Item::Status::Value::GREEN,
(unsigned char)RenderItemStatusIcon::HAS_ACTIONS);
(unsigned char)render::Item::Status::Icon::HAS_ACTIONS);
}
return render::Item::Status::Value(0.0f, render::Item::Status::Value::GREEN,
(unsigned char)RenderItemStatusIcon::HAS_ACTIONS);
(unsigned char)render::Item::Status::Icon::HAS_ACTIONS);
});
statusGetters.push_back([entity, myNodeID] () -> render::Item::Status::Value {
if (entity->isAvatarEntity()) {
if (entity->getOwningAvatarID() == myNodeID) {
return render::Item::Status::Value(1.0f, render::Item::Status::Value::GREEN,
(unsigned char)RenderItemStatusIcon::ENTITY_HOST_TYPE);
(unsigned char)render::Item::Status::Icon::ENTITY_HOST_TYPE);
} else {
return render::Item::Status::Value(1.0f, render::Item::Status::Value::RED,
(unsigned char)RenderItemStatusIcon::ENTITY_HOST_TYPE);
(unsigned char)render::Item::Status::Icon::ENTITY_HOST_TYPE);
}
} else if (entity->isLocalEntity()) {
return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE,
(unsigned char)RenderItemStatusIcon::ENTITY_HOST_TYPE);
(unsigned char)render::Item::Status::Icon::ENTITY_HOST_TYPE);
}
return render::Item::Status::Value(0.0f, render::Item::Status::Value::GREEN,
(unsigned char)RenderItemStatusIcon::ENTITY_HOST_TYPE);
(unsigned char)render::Item::Status::Icon::ENTITY_HOST_TYPE);
});
}

View file

@ -363,7 +363,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
ShapeType type = getShapeType();
auto model = getModel();
if (!model) {
if (!model || !model->isLoaded()) {
type = SHAPE_TYPE_NONE;
}

View file

@ -1770,6 +1770,7 @@ signals:
/**jsdoc
* Triggered on the client that is the physics simulation owner during the collision of two entities. Note: Isn't triggered
* for a collision with an avatar.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.collisionWithEntity
* @param {Uuid} idA - The ID of one entity in the collision. For an entity script, this is the ID of the entity containing
* the script.
@ -1882,6 +1883,7 @@ signals:
/**jsdoc
* Triggered when a mouse button is clicked while the mouse cursor is on an entity, or a controller trigger is fully
* pressed while its laser is on an entity.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.mousePressOnEntity
* @param {Uuid} entityID - The ID of the entity that was pressed.
* @param {PointerEvent} event - Details of the event.
@ -1906,6 +1908,7 @@ signals:
/**jsdoc
* Repeatedly triggered while the mouse cursor or controller laser moves on an entity.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.mouseMoveOnEntity
* @param {Uuid} entityID - The ID of the entity that was moved on.
* @param {PointerEvent} event - Details of the event.
@ -1916,6 +1919,7 @@ signals:
/**jsdoc
* Triggered when a mouse button is released after clicking on an entity or the controller trigger is partly or fully
* released after pressing on an entity, even if the mouse pointer or controller laser has moved off the entity.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.mouseReleaseOnEntity
* @param {Uuid} entityID - The ID of the entity that was originally pressed.
* @param {PointerEvent} event - Details of the event.
@ -1942,6 +1946,7 @@ signals:
/**jsdoc
* Triggered when a mouse button is clicked while the mouse cursor is on an entity. Note: Not triggered by controller.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.clickDownOnEntity
* @param {Uuid} entityID - The ID of the entity that was clicked.
* @param {PointerEvent} event - Details of the event.
@ -1952,6 +1957,7 @@ signals:
/**jsdoc
* Repeatedly triggered while a mouse button continues to be held after clicking an entity, even if the mouse cursor has
* moved off the entity. Note: Not triggered by controller.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.holdingClickOnEntity
* @param {Uuid} entityID - The ID of the entity that was originally clicked.
* @param {PointerEvent} event - Details of the event.
@ -1962,6 +1968,7 @@ signals:
/**jsdoc
* Triggered when a mouse button is released after clicking on an entity, even if the mouse cursor has moved off the
* entity. Note: Not triggered by controller.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.clickReleaseOnEntity
* @param {Uuid} entityID - The ID of the entity that was originally clicked.
* @param {PointerEvent} event - Details of the event.
@ -1971,6 +1978,7 @@ signals:
/**jsdoc
* Triggered when the mouse cursor or controller laser starts hovering on an entity.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.hoverEnterEntity
* @param {Uuid} entityID - The ID of the entity that is being hovered.
* @param {PointerEvent} event - Details of the event.
@ -1980,6 +1988,7 @@ signals:
/**jsdoc
* Repeatedly triggered when the mouse cursor or controller laser moves while hovering over an entity.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.hoverOverEntity
* @param {Uuid} entityID - The ID of the entity that is being hovered.
* @param {PointerEvent} event - Details of the event.
@ -1989,6 +1998,7 @@ signals:
/**jsdoc
* Triggered when the mouse cursor or controller laser stops hovering over an entity.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.hoverLeaveEntity
* @param {Uuid} entityID - The ID of the entity that was being hovered.
* @param {PointerEvent} event - Details of the event.
@ -1999,6 +2009,7 @@ signals:
/**jsdoc
* Triggered when an avatar enters an entity.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.enterEntity
* @param {Uuid} entityID - The ID of the entity that the avatar entered.
* @returns {Signal}
@ -2032,6 +2043,7 @@ signals:
/**jsdoc
* Triggered when an avatar leaves an entity.
* <p>See also, {@link Script.addEventHandler}.</p>
* @function Entities.leaveEntity
* @param {Uuid} entityID - The ID of the entity that the avatar left.
* @returns {Signal}

View file

@ -220,6 +220,10 @@ void GL45Texture::generateMips() const {
(void)CHECK_GL_ERROR();
}
// (NOTE: it seems to work now, but for posterity:) DSA ARB does not work on AMD, so use EXT
// unless EXT is not available on the driver
#define AMD_CUBE_MAP_EXT_WORKAROUND 0
Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const {
Size amountCopied = sourceSize;
if (GL_TEXTURE_2D == _target) {
@ -267,22 +271,26 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
#if AMD_CUBE_MAP_EXT_WORKAROUND
if (glCompressedTextureSubImage2DEXT) {
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
glCompressedTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, internalFormat,
static_cast<GLsizei>(sourceSize), sourcePointer);
} else {
} else
#endif
{
glCompressedTextureSubImage3D(_id, mip, 0, yOffset, face, size.x, size.y, 1, internalFormat,
static_cast<GLsizei>(sourceSize), sourcePointer);
}
break;
default:
// DSA ARB does not work on AMD, so use EXT
// unless EXT is not available on the driver
#if AMD_CUBE_MAP_EXT_WORKAROUND
if (glTextureSubImage2DEXT) {
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
glTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
} else {
} else
#endif
{
glTextureSubImage3D(_id, mip, 0, yOffset, face, size.x, size.y, 1, format, type, sourcePointer);
}
break;

View file

@ -26,8 +26,8 @@ const Element Element::COLOR_COMPRESSED_BCX_SRGB { TILE4x4, COMPRESSED, COMPRESS
const Element Element::COLOR_COMPRESSED_BCX_SRGBA_MASK { TILE4x4, COMPRESSED, COMPRESSED_BC1_SRGBA };
const Element Element::COLOR_COMPRESSED_BCX_SRGBA { TILE4x4, COMPRESSED, COMPRESSED_BC3_SRGBA };
const Element Element::COLOR_COMPRESSED_BCX_XY { TILE4x4, COMPRESSED, COMPRESSED_BC5_XY };
const Element Element::COLOR_COMPRESSED_BCX_SRGBA_HIGH { TILE4x4, COMPRESSED, COMPRESSED_BC7_SRGBA };
const Element Element::COLOR_COMPRESSED_BCX_HDR_RGB { TILE4x4, COMPRESSED, COMPRESSED_BC6_RGB };
const Element Element::COLOR_COMPRESSED_BCX_SRGBA_HIGH { TILE4x4, COMPRESSED, COMPRESSED_BC7_SRGBA };
const Element Element::COLOR_COMPRESSED_ETC2_RGB { TILE4x4, COMPRESSED, COMPRESSED_ETC2_RGB };
const Element Element::COLOR_COMPRESSED_ETC2_SRGB { TILE4x4, COMPRESSED, COMPRESSED_ETC2_SRGB };

View file

@ -18,7 +18,6 @@
#include "Batch.h"
#include "TextureTable.h"
#include "FrameIOKeys.h"
namespace gpu {
@ -324,6 +323,13 @@ TexturePointer Deserializer::readTexture(const json& node, uint32_t external) {
readOptional(ktxFile, node, keys::ktxFile);
Element ktxTexelFormat, ktxMipFormat;
if (!ktxFile.empty()) {
// If we get a texture that starts with ":" we need to re-route it to the resources directory
if (ktxFile.at(0) == ':') {
QString frameReaderPath = __FILE__;
frameReaderPath.replace("\\", "/");
frameReaderPath.replace("libraries/gpu/src/gpu/framereader.cpp", "interface/resources", Qt::CaseInsensitive);
ktxFile.replace(0, 1, frameReaderPath.toStdString());
}
if (QFileInfo(ktxFile.c_str()).isRelative()) {
ktxFile = basedir + ktxFile;
}

View file

@ -26,13 +26,14 @@ layout(location=0) in vec3 _normal;
layout(location=0) out vec4 _fragColor;
void main(void) {
vec3 coord = normalize(_normal);
vec3 color = skybox.color.rgb;
// FIXME: For legacy reasons, when skybox.color.a is 0.5, this is equivalent to:
// skyboxColor * skyboxTexel
// It should actually be:
// mix(skyboxColor, skyboxTexel, skybox.color.a)
// and the blend factor should be user controlled
// blend is only set if there is a cubemap
float check = float(skybox.color.a > 0.0);
color = mix(color, texture(cubeMap, coord).rgb, check);
color *= mix(vec3(1.0), skybox.color.rgb, check * float(skybox.color.a < 1.0));
_fragColor = vec4(color, 0.0);
vec3 skyboxTexel = texture(cubeMap, normalize(_normal)).rgb;
vec3 skyboxColor = skybox.color.rgb;
_fragColor = vec4(mix(vec3(1.0), skyboxTexel, float(skybox.color.a > 0.0)) *
mix(vec3(1.0), skyboxColor, float(skybox.color.a < 1.0)), 1.0);
}

View file

@ -690,6 +690,8 @@ void convertImageToLDRTexture(gpu::Texture* texture, Image&& image, BackendTarge
compressionOptions.setFormat(nvtt::Format_BC4);
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_XY) {
compressionOptions.setFormat(nvtt::Format_BC5);
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB) {
compressionOptions.setFormat(nvtt::Format_BC6);
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_HIGH) {
alphaMode = nvtt::AlphaMode_Transparency;
compressionOptions.setFormat(nvtt::Format_BC7);

View file

@ -57,6 +57,7 @@ namespace TextureUsage {
* @typedef {number} TextureCache.TextureType
*/
enum Type {
// NOTE: add new texture types at the bottom here
DEFAULT_TEXTURE,
STRICT_TEXTURE,
ALBEDO_TEXTURE,

View file

@ -16,6 +16,7 @@
#include <QJsonObject>
const QString TEXTURE_META_EXTENSION = ".texmeta.json";
const uint16_t KTX_VERSION = 1;
bool TextureMeta::deserialize(const QByteArray& data, TextureMeta* meta) {
QJsonParseError error;
@ -46,6 +47,9 @@ bool TextureMeta::deserialize(const QByteArray& data, TextureMeta* meta) {
}
}
}
if (root.contains("version")) {
meta->version = root["version"].toInt();
}
return true;
}
@ -62,6 +66,7 @@ QByteArray TextureMeta::serialize() {
root["original"] = original.toString();
root["uncompressed"] = uncompressed.toString();
root["compressed"] = compressed;
root["version"] = KTX_VERSION;
doc.setObject(root);
return doc.toJson();

View file

@ -19,6 +19,7 @@
#include "khronos/KHR.h"
extern const QString TEXTURE_META_EXTENSION;
extern const uint16_t KTX_VERSION;
namespace std {
template<> struct hash<khronos::gl::texture::InternalFormat> {
@ -37,6 +38,7 @@ struct TextureMeta {
QUrl original;
QUrl uncompressed;
std::unordered_map<khronos::gl::texture::InternalFormat, QUrl> availableTextureTypes;
uint16_t version { 0 };
};

View file

@ -27,7 +27,7 @@ namespace baker {
class GetModelPartsTask {
public:
using Input = hfm::Model::Pointer;
using Output = VaryingSet6<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, QHash<QString, hfm::Material>, std::vector<hfm::Joint>>;
using Output = VaryingSet5<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, std::vector<hfm::Joint>>;
using JobModel = Job::ModelIO<GetModelPartsTask, Input, Output>;
void run(const BakeContextPointer& context, const Input& input, Output& output) {
@ -40,8 +40,7 @@ namespace baker {
for (int i = 0; i < hfmModelIn->meshes.size(); i++) {
blendshapesPerMesh.push_back(hfmModelIn->meshes[i].blendshapes.toStdVector());
}
output.edit4() = hfmModelIn->materials;
output.edit5() = hfmModelIn->joints.toStdVector();
output.edit4() = hfmModelIn->joints.toStdVector();
}
};
@ -134,17 +133,16 @@ namespace baker {
const auto url = modelPartsIn.getN<GetModelPartsTask::Output>(1);
const auto meshIndicesToModelNames = modelPartsIn.getN<GetModelPartsTask::Output>(2);
const auto blendshapesPerMeshIn = modelPartsIn.getN<GetModelPartsTask::Output>(3);
const auto materials = modelPartsIn.getN<GetModelPartsTask::Output>(4);
const auto jointsIn = modelPartsIn.getN<GetModelPartsTask::Output>(5);
const auto jointsIn = modelPartsIn.getN<GetModelPartsTask::Output>(4);
// Calculate normals and tangents for meshes and blendshapes if they do not exist
// Note: Normals are never calculated here for OBJ models. OBJ files optionally define normals on a per-face basis, so for consistency normals are calculated beforehand in OBJSerializer.
const auto normalsPerMesh = model.addJob<CalculateMeshNormalsTask>("CalculateMeshNormals", meshesIn);
const auto calculateMeshTangentsInputs = CalculateMeshTangentsTask::Input(normalsPerMesh, meshesIn, materials).asVarying();
const auto calculateMeshTangentsInputs = CalculateMeshTangentsTask::Input(normalsPerMesh, meshesIn).asVarying();
const auto tangentsPerMesh = model.addJob<CalculateMeshTangentsTask>("CalculateMeshTangents", calculateMeshTangentsInputs);
const auto calculateBlendshapeNormalsInputs = CalculateBlendshapeNormalsTask::Input(blendshapesPerMeshIn, meshesIn).asVarying();
const auto normalsPerBlendshapePerMesh = model.addJob<CalculateBlendshapeNormalsTask>("CalculateBlendshapeNormals", calculateBlendshapeNormalsInputs);
const auto calculateBlendshapeTangentsInputs = CalculateBlendshapeTangentsTask::Input(normalsPerBlendshapePerMesh, blendshapesPerMeshIn, meshesIn, materials).asVarying();
const auto calculateBlendshapeTangentsInputs = CalculateBlendshapeTangentsTask::Input(normalsPerBlendshapePerMesh, blendshapesPerMeshIn, meshesIn).asVarying();
const auto tangentsPerBlendshapePerMesh = model.addJob<CalculateBlendshapeTangentsTask>("CalculateBlendshapeTangents", calculateBlendshapeTangentsInputs);
// Build the graphics::MeshPointer for each hfm::Mesh

View file

@ -19,7 +19,6 @@ void CalculateBlendshapeTangentsTask::run(const baker::BakeContextPointer& conte
const auto& normalsPerBlendshapePerMesh = input.get0();
const auto& blendshapesPerMesh = input.get1();
const auto& meshes = input.get2();
const auto& materials = input.get3();
auto& tangentsPerBlendshapePerMeshOut = output;
tangentsPerBlendshapePerMeshOut.reserve(normalsPerBlendshapePerMesh.size());
@ -30,16 +29,6 @@ void CalculateBlendshapeTangentsTask::run(const baker::BakeContextPointer& conte
tangentsPerBlendshapePerMeshOut.emplace_back();
auto& tangentsPerBlendshapeOut = tangentsPerBlendshapePerMeshOut[tangentsPerBlendshapePerMeshOut.size()-1];
// Check if we actually need to calculate the tangents, or just append empty arrays
bool needTangents = false;
for (const auto& meshPart : mesh.parts) {
auto materialIt = materials.find(meshPart.materialID);
if (materialIt != materials.end() && (*materialIt).needTangentSpace()) {
needTangents = true;
break;
}
}
for (size_t j = 0; j < blendshapes.size(); j++) {
const auto& blendshape = blendshapes[j];
const auto& tangentsIn = blendshape.tangents;
@ -53,8 +42,8 @@ void CalculateBlendshapeTangentsTask::run(const baker::BakeContextPointer& conte
continue;
}
// Check if we can and should calculate tangents (we need normals to calculate the tangents)
if (normals.empty() || !needTangents) {
// Check if we can calculate tangents (we need normals and texcoords to calculate the tangents)
if (normals.empty() || normals.size() != (size_t)mesh.texCoords.size()) {
continue;
}
tangentsOut.resize(normals.size());

Some files were not shown because too many files have changed in this diff Show more