mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 03:33:25 +02:00
Merging from upstream
This commit is contained in:
commit
d838b78df9
308 changed files with 4475 additions and 28452 deletions
38
BUILD.md
38
BUILD.md
|
@ -4,19 +4,28 @@
|
|||
* [Qt](http://qt-project.org/downloads) ~> 5.3.2
|
||||
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g
|
||||
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
|
||||
* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
|
||||
* [Soxr](http://sourceforge.net/projects/soxr/) ~> 0.1.1
|
||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||
|
||||
####CMake External Project Dependencies
|
||||
|
||||
* [Bullet Physics Engine](https://code.google.com/p/bullet/downloads/list) ~> 2.82
|
||||
* [Gverb](https://github.com/highfidelity/gverb/archive/master.zip) (direct download to latest version)
|
||||
|
||||
#### CMake External Project Dependencies
|
||||
|
||||
The following 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` directory in each of the subfolders for each external project. These are not placed in your normal build tree when doing an out of source build so that they do not need to be re-downloaded and re-compiled every time the CMake build folder is cleared.
|
||||
|
||||
* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
|
||||
* [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4
|
||||
* [gverb](https://github.com/highfidelity/gverb)
|
||||
* [Soxr](http://sourceforge.net/projects/soxr/) ~> 0.1.1
|
||||
|
||||
### OS Specific Build Guides
|
||||
The following external projects are optional dependencies. You can indicate to CMake that you would like to include them by passing -DGET_$NAME=1 when running a clean CMake build. For example, to get CMake to download and compile SDL2 you would pass -DGET_SDL2=1.
|
||||
|
||||
* [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3
|
||||
* Enables game controller support in Interface
|
||||
|
||||
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` directory in each of the subfolders for each external project.
|
||||
|
||||
These are not placed in your normal build tree when doing an out of source build so that they do not need to be re-downloaded and re-compiled every time the CMake build folder is cleared. Should you want to force a re-download and re-compile of a specific external, you can simply remove that directory from the appropriate subfolder in `build-ext`. Should you want to force a re-download and re-compile of all externals, just remove the `build-ext` folder.
|
||||
|
||||
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DGET_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
|
||||
|
||||
###OS Specific Build Guides
|
||||
* [BUILD_OSX.md](BUILD_OSX.md) - additional instructions for OS X.
|
||||
* [BUILD_LINUX.md](BUILD_LINUX.md) - additional instructions for Linux.
|
||||
* [BUILD_WIN.md](BUILD_WIN.md) - additional instructions for Windows.
|
||||
|
@ -51,6 +60,9 @@ For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generat
|
|||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.3.2/lib/cmake
|
||||
|
||||
####Finding Dependencies
|
||||
|
||||
The following applies for dependencies we do not grab via CMake ExternalProject (OpenSSL is an example), or for dependencies you have opted not to grab as a CMake ExternalProject (via -DGET_$NAME=0). The list of dependencies we grab by default as external projects can be found in [the CMake External Project Dependencies section](#cmake-external-project-dependencies).
|
||||
|
||||
You can point our [Cmake find modules](cmake/modules/) to the correct version of dependencies by setting one of the three following variables to the location of the correct version of the dependency.
|
||||
|
||||
In the examples below the variable $NAME would be replaced by the name of the dependency in uppercase, and $name would be replaced by the name of the dependency in lowercase (ex: OPENSSL_ROOT_DIR, openssl).
|
||||
|
@ -61,13 +73,7 @@ In the examples below the variable $NAME would be replaced by the name of the de
|
|||
|
||||
###Optional Components
|
||||
|
||||
####QXmpp
|
||||
|
||||
You can [find QXmpp here](https://github.com/qxmpp-project/qxmpp), 0.7.6 is the version you want. The inclusion of the QXmpp enables text chat in the Interface client.
|
||||
|
||||
OS X users who tap our [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) can install QXmpp via homebrew - `brew install highfidelity/formulas/qxmpp`.
|
||||
|
||||
####Devices
|
||||
|
||||
You can support external input/output devices such as Oculus Rift, Leap Motion, Faceshift, PrioVR, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
You can support external input/output devices such as Oculus Rift, Leap Motion, Faceshift, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
|
||||
|
|
|
@ -72,38 +72,6 @@ This should generate libcrypto and libssl in the root of the OpenSSL directory.
|
|||
|
||||
If you have been building other components it is possible that the OpenSSL compile will fail based on the values other cross-compilations (tbb, bullet) have set. Ensure that you are in a new terminal window to avoid compilation errors from previously set environment variables.
|
||||
|
||||
####Intel Threading Building Blocks
|
||||
|
||||
Download the [Intel Threading Building Blocks source](https://www.threadingbuildingblocks.org/download) and extract the tarball inside your `ANDROID_LIB_DIR`. Rename the extracted folder to `tbb`.
|
||||
|
||||
NOTE: BEFORE YOU ATTEMPT TO CROSS-COMPILE TBB, DISCONNECT ANY DEVICES ADB WOULD DETECT. The tbb build process asks adb for a couple of strings, and if a device is plugged in extra characters get added that will cause ndk-build to fail with an error.
|
||||
|
||||
From the tbb directory, execute the following commands. First, we build TBB using `ndk-build`. Then, the compiled libs are copied to a lib folder in the root of tbb directory.
|
||||
|
||||
```
|
||||
cd jni
|
||||
ndk-build target=android tbb tbbmalloc arch=arm
|
||||
cd ../
|
||||
mkdir lib
|
||||
cp `find . -name "*.so"` lib/
|
||||
```
|
||||
|
||||
####Soxr
|
||||
|
||||
Download the [Soxr source](http://sourceforge.net/projects/soxr/) and extract the tarball inside your `ANDROID_LIB_DIR`. Rename the extracted folder to `soxr`.
|
||||
|
||||
From the soxr directory, use cmake, along with the `android.toolchain.cmake` file (included in this repository under cmake/android) to cross-compile soxr for Android. Note that you will need ANDROID_NDK set in your environment before using the toolchain file.
|
||||
|
||||
The full set of commands to build soxr for Android is shown below. It is a long command, make sure you copy the entire command (up to `-DBUILD_TESTS=0`).
|
||||
|
||||
```
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=$FULL_PATH_TO_TOOLCHAIN -DCMAKE_INSTALL_PREFIX=. -DHAVE_WORDS_BIGENDIAN_EXITCODE=1 -DBUILD_TESTS=0
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
This will create the `lib` and `include` folders inside `ANDROID_LIB_DIR/soxr` that FindSoxr will look for.
|
||||
|
||||
####Oculus Mobile SDK
|
||||
|
||||
The Oculus Mobile SDK is optional, for Gear VR support. It is not required to compile gvr-interface.
|
||||
|
@ -127,7 +95,6 @@ To put the Gear VR Service into developer mode you need an application with an O
|
|||
|
||||
Once the application is on your device, go to `Settings->Application Manager->Gear VR Service->Manage Storage`. Tap on `VR Service Version` six times. It will scan your device to verify that you have an osig file in an application on your device, and then it will let you enable Developer mode.
|
||||
|
||||
|
||||
###CMake
|
||||
|
||||
We use CMake to generate the makefiles that compile and deploy the Android APKs to your device. In order to create Makefiles for the Android targets, CMake requires that some environment variables are set, and that other variables are passed to it when it is run.
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
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.
|
||||
|
||||
###Linux Specific Dependencies
|
||||
* [freeglut](http://freeglut.sourceforge.net/) ~> 2.8.0
|
||||
* [zLib](http://www.zlib.net/) ~> 1.2.8
|
||||
|
||||
In general, as long as external dependencies are placed in OS standard locations, CMake will successfully find them during its run. When possible, you may choose to install depencies from your package manager of choice, or from source.
|
||||
|
||||
###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:
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ Please read the [general build guide](BUILD.md) for information on dependencies
|
|||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all hifi dependencies very simple.
|
||||
|
||||
brew tap highfidelity/homebrew-formulas
|
||||
brew install cmake openssl tbb libsoxr
|
||||
brew install cmake openssl
|
||||
brew install highfidelity/formulas/qt5
|
||||
brew link qt5 --force
|
||||
|
||||
|
|
135
BUILD_WIN.md
135
BUILD_WIN.md
|
@ -1,12 +1,6 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Windows specific instructions are found in this file.
|
||||
|
||||
###Windows Specific Dependencies
|
||||
* [GLEW](http://glew.sourceforge.net/) ~> 1.10.0
|
||||
* [freeglut MSVC](http://www.transmissionzero.co.uk/software/freeglut-devel/) ~> 2.8.1
|
||||
* [zLib](http://www.zlib.net/) ~> 1.2.8
|
||||
* (remember that you need all other dependencies listed in [BUILD.md](BUILD.md))
|
||||
|
||||
####Visual Studio 2013
|
||||
###Visual Studio 2013
|
||||
|
||||
You can use the Community or Professional editions of Visual Studio 2013.
|
||||
|
||||
|
@ -16,10 +10,18 @@ Or you can start a regular command prompt and then run:
|
|||
|
||||
"%VS120COMNTOOLS%\vsvars32.bat"
|
||||
|
||||
#####Windows SDK 8.1
|
||||
####Windows SDK 8.1
|
||||
|
||||
If using Visual Studio 2013 and building as a Visual Studio 2013 project you need the Windows 8 SDK which you should already have as part of installing Visual Studio 2013. You should be able to see it at `C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86`.
|
||||
|
||||
####nmake
|
||||
|
||||
Some of the external projects may require nmake to compile and install. If it is not installed at the location listed below, please ensure that it is in your PATH so CMake can find it when required.
|
||||
|
||||
We expect nmake.exe to be located at the following path.
|
||||
|
||||
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin
|
||||
|
||||
###Qt
|
||||
You can use the online installer or the offline installer. If you use the offline installer, be sure to select the "OpenGL" version.
|
||||
|
||||
|
@ -32,9 +34,8 @@ NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit
|
|||
* [Download the offline installer](http://download.qt-project.org/official_releases/qt/5.3/5.3.2/qt-opensource-windows-x86-msvc2013_opengl-5.3.2.exe)
|
||||
|
||||
Once Qt is installed, you need to manually configure the following:
|
||||
* Make sure the Qt runtime DLLs are loadable. You must do this before you attempt to build because some tools for the build depend on Qt. E.g., add to the PATH: `Qt\5.3.2\msvc2013_opengl\bin\`.
|
||||
* Go to Control Panel > System > Advanced System Settings > Environment Variables > New ...
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.3.2\msvc2013_opengl` directory.
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.3.2\msvc2013_opengl\lib\cmake` directory.
|
||||
* You can set an environment variable from Control Panel > System > Advanced System Settings > Environment Variables > New
|
||||
|
||||
###External Libraries
|
||||
|
||||
|
@ -42,37 +43,19 @@ As it stands, Hifi/Interface is a 32-bit application, so all libraries should al
|
|||
|
||||
CMake will need to know where the headers and libraries for required external dependencies are.
|
||||
|
||||
We use CMake's `fixup_bundle` to find the DLLs all of our exectuable targets require, and then copy them beside the executable in a post-build step. If `fixup_bundle` is having problems finding a DLL, you can fix it manually on your end by adding the folder containing that DLL to your path. Let us know which DLL CMake had trouble finding, as it is possible a tweak to our CMake files is required.
|
||||
|
||||
The recommended route for CMake to find the external dependencies is to place all of the dependencies in one folder and set one ENV variable - HIFI_LIB_DIR. That ENV variable should point to a directory with the following structure:
|
||||
|
||||
root_lib_dir
|
||||
-> bullet
|
||||
-> include
|
||||
-> lib
|
||||
-> freeglut
|
||||
-> bin
|
||||
-> include
|
||||
-> lib
|
||||
-> glew
|
||||
-> bin
|
||||
-> include
|
||||
-> lib
|
||||
-> openssl
|
||||
-> bin
|
||||
-> include
|
||||
-> lib
|
||||
-> tbb
|
||||
-> include
|
||||
-> lib
|
||||
-> zlib
|
||||
-> include
|
||||
-> lib
|
||||
-> test
|
||||
|
||||
For many of the external libraries where precompiled binaries are readily available you should be able to simply copy the extracted folder that you get from the download links provided at the top of the guide. Otherwise you may need to build from source and install the built product to this directory. The `root_lib_dir` in the above example can be wherever you choose on your system - as long as the environment variable HIFI_LIB_DIR is set to it. From here on, whenever you see %HIFI_LIB_DIR% you should substitute the directory that you chose.
|
||||
|
||||
As with the Qt libraries, you will need to make sure that directories containing DLL'S are in your path. Where possible, you can use static builds of the external dependencies to avoid this requirement.
|
||||
|
||||
###OpenSSL
|
||||
####OpenSSL
|
||||
|
||||
Qt will use OpenSSL if it's available, but it doesn't install it, so you must install it separately.
|
||||
|
||||
|
@ -92,89 +75,25 @@ To prevent these problems, install OpenSSL yourself. Download the following bina
|
|||
|
||||
Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
|
||||
|
||||
###Intel Threading Building Blocks (TBB)
|
||||
###vhacd
|
||||
Download it directly from https://github.com/virneo/v-hacd
|
||||
|
||||
Download the zip from the [TBB website](https://www.threadingbuildingblocks.org/).
|
||||
To build it run the following commands
|
||||
1. cd src\
|
||||
2. mkdir build
|
||||
3. cd build
|
||||
4. cmake ..
|
||||
|
||||
Build using visual studio 2013. Build ALL_BUILD and INSTALL targets both in Release and Debug.
|
||||
|
||||
We recommend you extract it to %HIFI_LIB_DIR%\tbb. This will help our FindTBB cmake module find what it needs. You can place it wherever you like on your machine if you specify TBB_ROOT_DIR as an environment variable or a variable passed when cmake is run.
|
||||
This will create an output folder with include and lib directory inside it.
|
||||
|
||||
###Zlib
|
||||
|
||||
Download the compiled DLL from the [zlib website](http://www.zlib.net/). Extract to %HIFI_LIB_DIR%\zlib.
|
||||
|
||||
Add the following environment variables (remember to substitute your own directory for %HIFI_LIB_DIR%):
|
||||
|
||||
ZLIB_LIBRARY=%HIFI_LIB_DIR%\zlib\lib\zdll.lib
|
||||
ZLIB_INCLUDE_DIR=%HIFI_LIB_DIR%\zlib\include
|
||||
|
||||
Add to the PATH: `%HIFI_LIB_DIR%\zlib`
|
||||
|
||||
(The PATH environment variable is where Windows looks for its DLL's and executables. There's a great tool for editing these variables with ease, [Rapid Environment Editor](http://www.rapidee.com/en/download))
|
||||
|
||||
Important! This should be added at the beginning of the path, not the end (your
|
||||
system likely has many copies of zlib1.dll, and you want High Fidelity to use the correct version). If High Fidelity picks up the wrong zlib1.dll then it might be unable to use it, and that would cause it to fail to start, showing only the cryptic error "The application was unable to start correctly: 0xc0000022".
|
||||
|
||||
###freeglut
|
||||
|
||||
Download the binary package: `freeglut-MSVC-2.8.1-1.mp.zip`. Extract to %HIFI_LIB_DIR%\freeglut.
|
||||
|
||||
Add to the PATH: `%HIFI_LIB_DIR%\freeglut\bin`
|
||||
|
||||
###GLEW
|
||||
|
||||
Download the binary package: `glew-1.10.0-win32.zip`. Extract to %HIFI_LIB_DIR%\glew (you'll need to rename the default directory name).
|
||||
|
||||
Add to the PATH: `%HIFI_LIB_DIR%\glew\bin\Release\Win32`
|
||||
|
||||
###Bullet
|
||||
|
||||
Bullet 2.82 source can be [downloaded here](https://code.google.com/p/bullet/downloads/detail?name=bullet-2.82-r2704.zip). Bullet does not come with prebuilt libraries, you need to make those yourself.
|
||||
|
||||
* Download the zip file and extract into a temporary folder
|
||||
* Create a directory named cmakebuild. Bullet comes with a build\ directory by default, however, that directory is intended for use with premake, and considering premake doesn't support VS2013, we prefer to run the cmake build on its own directory.
|
||||
* Make the following modifications to Bullet's source:
|
||||
1. In file: Extras\HACD\hacdICHull.cpp --- in line: 17 --- insert: #include <algorithm>
|
||||
2. In file: src\MiniCL\cl_MiniCL_Defs.h --- comment lines 364 to 372
|
||||
3. In file: CMakeLists.txt set to ON the option USE_MSVC_RUNTIME_LIBRARY_DLL in line 27
|
||||
|
||||
Then create the Visual Studio solution and build the libraries - run the following commands from a Visual Studio 2013 command prompt, from within the cmakebuild directory created before:
|
||||
|
||||
```shell
|
||||
cmake .. -G "Visual Studio 12"
|
||||
msbuild BULLET_PHYSICS.sln /p:Configuration=Debug
|
||||
```
|
||||
|
||||
This will create Debug libraries in cmakebuild\lib\Debug. You can replace Debug with Release in the msbuild command and that will generate Release libraries in cmakebuild\lib\Release.
|
||||
|
||||
You now have Bullet libraries compiled, now you need to put them in the right place for hifi to find them:
|
||||
|
||||
* Create a directory named bullet\ inside your %HIFI_LIB_DIR%
|
||||
* Create two directores named lib\ and include\ inside bullet\
|
||||
* Copy all the contents inside src\ from the bullet unzip path into %HIFI_LIB_DIR%\bullet\include\
|
||||
* Copy all the contents inside cmakebuild\lib\ into %HIFI_LIB_DIR\bullet\lib
|
||||
|
||||
_Note that the INSTALL target should handle the copying of files into an install directory automatically, however, without modifications to Cmake, the install target didn't work right for me, please update this instructions if you get that working right - Leo <leo@highfidelity.io>_
|
||||
|
||||
###Soxr
|
||||
|
||||
Download the zip from the [soxr sourceforge page](http://sourceforge.net/projects/soxr/).
|
||||
|
||||
We recommend you install it to %HIFI_LIB_DIR%\soxr. This will help our FindSoxr cmake module find what it needs. You can place it wherever you like on your machine if you specify SOXR_ROOT_DIR as an environment variable or a variable passed when cmake is run.
|
||||
|
||||
Extract the soxr archive wherever you like. Then, inside the extracted folder, create a directory called `build`. From that build directory, the following commands will build and then install soxr to `%HIFI_LIB_DIR%`.
|
||||
|
||||
(Make sure to run the following inside Visual Studio)
|
||||
|
||||
```
|
||||
cmake .. -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=%HIFI_LIB_DIR%/soxr
|
||||
nmake
|
||||
nmake install
|
||||
```
|
||||
Either copy the contents of output folder to ENV %HIFI_LIB_DIR%/vhacd or create an environment variable VHACD_ROOT_DIR to this output directory.
|
||||
|
||||
###Build High Fidelity using Visual Studio
|
||||
Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.
|
||||
|
||||
cmake .. -DZLIB_LIBRARY=%ZLIB_LIBRARY% -DZLIB_INCLUDE_DIR=%ZLIB_INCLUDE_DIR% -G "Visual Studio 12"
|
||||
cmake .. -G "Visual Studio 12"
|
||||
|
||||
Open %HIFI_DIR%\build\hifi.sln and compile.
|
||||
|
||||
|
|
|
@ -86,10 +86,33 @@ else ()
|
|||
endif ()
|
||||
endif ()
|
||||
|
||||
# figure out where the qt dir is
|
||||
get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE)
|
||||
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT_CMAKE_PREFIX_PATH})
|
||||
|
||||
# set our OS X deployment target to
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.8)
|
||||
if (APPLE)
|
||||
# set our OS X deployment target
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.8)
|
||||
|
||||
# find the 10.9 SDK path
|
||||
find_path(
|
||||
_OSX_DESIRED_SDK_PATH
|
||||
NAME MacOSX10.9.sdk
|
||||
HINTS ${OSX_SDK_PATH}
|
||||
PATHS /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
|
||||
/Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
|
||||
)
|
||||
|
||||
if (NOT _OSX_DESIRED_SDK_PATH)
|
||||
message(FATAL_ERROR "Could not find OS X 10.9 SDK. Please pass OSX_SDK_PATH to CMake to point us to your SDKs directory.")
|
||||
else ()
|
||||
message(STATUS "Found OS X 10.9 SDK at ${_OSX_DESIRED_SDK_PATH}/MacOSX10.9.sdk")
|
||||
endif ()
|
||||
|
||||
# set that as the SDK to use
|
||||
set(CMAKE_OSX_SYSROOT ${_OSX_DESIRED_SDK_PATH}/MacOSX10.9.sdk)
|
||||
endif ()
|
||||
|
||||
# Find includes in corresponding build directories
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
@ -103,8 +126,15 @@ set(HIFI_LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries")
|
|||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
|
||||
|
||||
set(MACRO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros")
|
||||
set(EXTERNAL_PROJECT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/externals")
|
||||
if (CMAKE_BUILD_TYPE)
|
||||
string(TOUPPER ${CMAKE_BUILD_TYPE} UPPER_CMAKE_BUILD_TYPE)
|
||||
else ()
|
||||
set(UPPER_CMAKE_BUILD_TYPE DEBUG)
|
||||
endif ()
|
||||
|
||||
set(HIFI_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
set(MACRO_DIR "${HIFI_CMAKE_DIR}/macros")
|
||||
set(EXTERNAL_PROJECT_DIR "${HIFI_CMAKE_DIR}/externals")
|
||||
|
||||
file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake")
|
||||
foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS})
|
||||
|
@ -118,6 +148,27 @@ if (ANDROID)
|
|||
endforeach()
|
||||
endif ()
|
||||
|
||||
set(EXTERNAL_PROJECT_PREFIX "project")
|
||||
set_property(DIRECTORY PROPERTY EP_PREFIX ${EXTERNAL_PROJECT_PREFIX})
|
||||
setup_externals_binary_dir()
|
||||
|
||||
# setup options to grab external project dependencies
|
||||
option(GET_BULLET "Get Bullet library automatically as external project" 1)
|
||||
option(GET_GLM "Get GLM library automatically as external project" 1)
|
||||
option(GET_GVERB "Get Gverb library automatically as external project" 1)
|
||||
option(GET_SOXR "Get Soxr library automatically as external project" 1)
|
||||
option(GET_TBB "Get Threading Building Blocks library automatically as external project" 1)
|
||||
|
||||
if (WIN32)
|
||||
option(GET_GLEW "Get GLEW library automatically as external project" 1)
|
||||
endif ()
|
||||
|
||||
option(GET_SDL2 "Get SDL2 library automatically as external project" 0)
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs("${QT_DIR}/bin")
|
||||
endif ()
|
||||
|
||||
# add subdirectories for all targets
|
||||
if (NOT ANDROID)
|
||||
add_subdirectory(assignment-client)
|
||||
|
|
|
@ -2,13 +2,13 @@ set(TARGET_NAME assignment-client)
|
|||
|
||||
setup_hifi_project(Core Gui Network Script Widgets)
|
||||
|
||||
add_dependency_external_project(glm)
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${GLM_INCLUDE_DIRS})
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
audio avatars octree environment gpu model fbx entities metavoxels
|
||||
audio avatars octree environment gpu model fbx entities
|
||||
networking animation shared script-engine embedded-webserver
|
||||
physics
|
||||
)
|
||||
|
@ -17,4 +17,4 @@ if (UNIX)
|
|||
target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})
|
||||
endif (UNIX)
|
||||
|
||||
include_dependency_includes()
|
||||
copy_dlls_beside_windows_executable()
|
|
@ -44,7 +44,7 @@ Agent::Agent(const QByteArray& packet) :
|
|||
// be the parent of the script engine so it gets moved when we do
|
||||
_scriptEngine.setParent(this);
|
||||
|
||||
_scriptEngine.getEntityScriptingInterface()->setPacketSender(&_entityEditSender);
|
||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||
|
||||
DependencyManager::set<ResouceCacheSharedItems>();
|
||||
DependencyManager::set<SoundCache>();
|
||||
|
@ -68,8 +68,8 @@ void Agent::readPendingDatagrams() {
|
|||
// PacketType_JURISDICTION, first byte is the node type...
|
||||
switch (receivedPacket[headerBytes]) {
|
||||
case NodeType::EntityServer:
|
||||
_scriptEngine.getEntityScriptingInterface()->getJurisdictionListener()->
|
||||
queueReceivedPacket(matchedNode, receivedPacket);
|
||||
DependencyManager::get<EntityScriptingInterface>()->getJurisdictionListener()->
|
||||
queueReceivedPacket(matchedNode, receivedPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -211,10 +211,12 @@ void Agent::run() {
|
|||
|
||||
_scriptEngine.registerGlobalObject("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
||||
_scriptEngine.registerGlobalObject("EntityViewer", &_entityViewer);
|
||||
_entityViewer.setJurisdictionListener(_scriptEngine.getEntityScriptingInterface()->getJurisdictionListener());
|
||||
_entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener());
|
||||
_entityViewer.init();
|
||||
_scriptEngine.getEntityScriptingInterface()->setEntityTree(_entityViewer.getTree());
|
||||
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
|
||||
|
||||
_scriptEngine.setScriptContents(scriptContents);
|
||||
_scriptEngine.run();
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <Assignment.h>
|
||||
#include <AvatarHashMap.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <EntityScriptingInterface.h>
|
||||
#include <LogHandler.h>
|
||||
#include <LogUtils.h>
|
||||
#include <LimitedNodeList.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
|
@ -40,79 +40,44 @@ SharedAssignmentPointer AssignmentClient::_currentAssignment;
|
|||
|
||||
int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
||||
|
||||
AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||
QCoreApplication(argc, argv),
|
||||
AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, QUuid walletUUID,
|
||||
QString assignmentServerHostname, quint16 assignmentServerPort) :
|
||||
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
||||
_localASPortSharedMem(NULL)
|
||||
_localASPortSharedMem(NULL),
|
||||
_localACMPortSharedMem(NULL)
|
||||
{
|
||||
LogUtils::init();
|
||||
|
||||
setOrganizationName("High Fidelity");
|
||||
setOrganizationDomain("highfidelity.io");
|
||||
setApplicationName("assignment-client");
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
|
||||
// create a NodeList as an unassigned client
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<NodeList>(NodeType::Unassigned);
|
||||
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
#ifdef _WIN32
|
||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||
#else
|
||||
ShutdownEventListener::getInstance();
|
||||
#endif
|
||||
auto entityScriptingInterface = DependencyManager::set<EntityScriptingInterface>();
|
||||
|
||||
// make up a uuid for this child so the parent can tell us apart. This id will be changed
|
||||
// when the domain server hands over an assignment.
|
||||
QUuid nodeUUID = QUuid::createUuid();
|
||||
nodeList->setSessionUUID(nodeUUID);
|
||||
|
||||
// set the logging target to the the CHILD_TARGET_NAME
|
||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
||||
|
||||
const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||
|
||||
const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t";
|
||||
const QString ASSIGNMENT_POOL_OPTION = "pool";
|
||||
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p";
|
||||
|
||||
Assignment::Type requestAssignmentType = Assignment::AllTypes;
|
||||
|
||||
// check for an assignment type passed on the command line or in the config
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) {
|
||||
requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt();
|
||||
}
|
||||
|
||||
QString assignmentPool;
|
||||
|
||||
// check for an assignment pool passed on the command line or in the config
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_POOL_OPTION)) {
|
||||
assignmentPool = argumentVariantMap.value(ASSIGNMENT_POOL_OPTION).toString();
|
||||
}
|
||||
|
||||
// setup our _requestAssignment member variable from the passed arguments
|
||||
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
|
||||
|
||||
// check for a wallet UUID on the command line or in the config
|
||||
// this would represent where the user running AC wants funds sent to
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
QUuid walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString();
|
||||
if (!walletUUID.isNull()) {
|
||||
qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID);
|
||||
_requestAssignment.setWalletUUID(walletUUID);
|
||||
}
|
||||
|
||||
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
|
||||
// check for an overriden assignment server hostname
|
||||
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) {
|
||||
if (assignmentServerHostname != "") {
|
||||
// change the hostname for our assignment server
|
||||
_assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
|
||||
}
|
||||
|
||||
// check for an overriden assignment server port
|
||||
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) {
|
||||
assignmentServerPort =
|
||||
argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
|
||||
_assignmentServerHostname = assignmentServerHostname;
|
||||
}
|
||||
|
||||
_assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
|
||||
|
@ -123,9 +88,12 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
|
||||
qDebug() << "Waiting for assignment -" << _requestAssignment;
|
||||
|
||||
QTimer* timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
|
||||
timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
|
||||
if (_assignmentServerHostname != "localhost") {
|
||||
qDebug () << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort();
|
||||
}
|
||||
|
||||
connect(&_requestTimer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
|
||||
_requestTimer.start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
|
||||
|
||||
// connect our readPendingDatagrams method to the readyRead() signal of the socket
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
||||
|
@ -136,6 +104,45 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
|
||||
// Create Singleton objects on main thread
|
||||
NetworkAccessManager::getInstance();
|
||||
|
||||
// Hook up a timer to send this child's status to the Monitor once per second
|
||||
setUpStatsToMonitor();
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClient::stopAssignmentClient() {
|
||||
qDebug() << "Exiting.";
|
||||
_requestTimer.stop();
|
||||
_statsTimerACM.stop();
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClient::setUpStatsToMonitor() {
|
||||
// Figure out the address to send out stats to
|
||||
quint16 localMonitorServerPort = DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT;
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
nodeList->getLocalServerPortFromSharedMemory(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY,
|
||||
_localACMPortSharedMem, localMonitorServerPort);
|
||||
_assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, localMonitorServerPort, true);
|
||||
|
||||
// send a stats packet every 1 seconds
|
||||
connect(&_statsTimerACM, &QTimer::timeout, this, &AssignmentClient::sendStatsPacketToACM);
|
||||
_statsTimerACM.start(1000);
|
||||
}
|
||||
|
||||
void AssignmentClient::sendStatsPacketToACM() {
|
||||
// tell the assignment client monitor what this assignment client is doing (if anything)
|
||||
QJsonObject statsObject;
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (_currentAssignment) {
|
||||
statsObject["assignment_type"] = _currentAssignment->getTypeName();
|
||||
} else {
|
||||
statsObject["assignment_type"] = "none";
|
||||
}
|
||||
nodeList->sendStats(statsObject, _assignmentClientMonitorSocket);
|
||||
}
|
||||
|
||||
void AssignmentClient::sendAssignmentRequest() {
|
||||
|
@ -145,23 +152,9 @@ void AssignmentClient::sendAssignmentRequest() {
|
|||
|
||||
if (_assignmentServerHostname == "localhost") {
|
||||
// we want to check again for the local domain-server port in case the DS has restarted
|
||||
if (!_localASPortSharedMem) {
|
||||
_localASPortSharedMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
|
||||
|
||||
if (!_localASPortSharedMem->attach(QSharedMemory::ReadOnly)) {
|
||||
qWarning() << "Could not attach to shared memory at key" << DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY
|
||||
<< "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort();
|
||||
}
|
||||
}
|
||||
|
||||
if (_localASPortSharedMem->isAttached()) {
|
||||
_localASPortSharedMem->lock();
|
||||
|
||||
quint16 localAssignmentServerPort;
|
||||
memcpy(&localAssignmentServerPort, _localASPortSharedMem->data(), sizeof(localAssignmentServerPort));
|
||||
|
||||
_localASPortSharedMem->unlock();
|
||||
|
||||
quint16 localAssignmentServerPort;
|
||||
if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, _localASPortSharedMem,
|
||||
localAssignmentServerPort)) {
|
||||
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
|
||||
qDebug() << "Port for local assignment server read from shared memory is"
|
||||
<< localAssignmentServerPort;
|
||||
|
@ -170,7 +163,6 @@ void AssignmentClient::sendAssignmentRequest() {
|
|||
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nodeList->sendAssignment(_requestAssignment);
|
||||
|
@ -227,6 +219,14 @@ void AssignmentClient::readPendingDatagrams() {
|
|||
} else {
|
||||
qDebug() << "Received an assignment that could not be unpacked. Re-requesting.";
|
||||
}
|
||||
} else if (packetTypeForPacket(receivedPacket) == PacketTypeStopNode) {
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
qDebug() << "Network told me to exit.";
|
||||
emit stopAssignmentClient();
|
||||
} else {
|
||||
qDebug() << "Got a stop packet from other than localhost.";
|
||||
}
|
||||
} else {
|
||||
// have the NodeList attempt to handle it
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
|
||||
class QSharedMemory;
|
||||
|
||||
class AssignmentClient : public QCoreApplication {
|
||||
class AssignmentClient : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClient(int &argc, char **argv);
|
||||
|
||||
AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort);
|
||||
static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; }
|
||||
|
||||
private slots:
|
||||
|
@ -29,13 +31,22 @@ private slots:
|
|||
void readPendingDatagrams();
|
||||
void assignmentCompleted();
|
||||
void handleAuthenticationRequest();
|
||||
void sendStatsPacketToACM();
|
||||
void stopAssignmentClient();
|
||||
|
||||
private:
|
||||
void setUpStatsToMonitor();
|
||||
Assignment _requestAssignment;
|
||||
static SharedAssignmentPointer _currentAssignment;
|
||||
QString _assignmentServerHostname;
|
||||
HifiSockAddr _assignmentServerSocket;
|
||||
QSharedMemory* _localASPortSharedMem;
|
||||
QSharedMemory* _localASPortSharedMem; // memory shared with domain server
|
||||
QSharedMemory* _localACMPortSharedMem; // memory shared with assignment client monitor
|
||||
QTimer _requestTimer; // timer for requesting and assignment
|
||||
QTimer _statsTimerACM; // timer for sending stats to assignment client monitor
|
||||
|
||||
protected:
|
||||
HifiSockAddr _assignmentClientMonitorSocket;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClient_h
|
||||
|
|
185
assignment-client/src/AssignmentClientApp.cpp
Normal file
185
assignment-client/src/AssignmentClientApp.cpp
Normal file
|
@ -0,0 +1,185 @@
|
|||
//
|
||||
// AssignmentClientapp.cpp
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Seth Alves on 2/19/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
|
||||
#include "Assignment.h"
|
||||
#include "AssignmentClient.h"
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
|
||||
|
||||
AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv)
|
||||
{
|
||||
# ifndef WIN32
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
# endif
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
# ifdef _WIN32
|
||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||
# else
|
||||
ShutdownEventListener::getInstance();
|
||||
# endif
|
||||
|
||||
setOrganizationName("High Fidelity");
|
||||
setOrganizationDomain("highfidelity.io");
|
||||
setApplicationName("assignment-client");
|
||||
|
||||
// use the verbose message handler in Logging
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
|
||||
// parse command-line
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("High Fidelity Assignment Client");
|
||||
parser.addHelpOption();
|
||||
|
||||
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||
|
||||
const QCommandLineOption clientTypeOption(ASSIGNMENT_TYPE_OVERRIDE_OPTION,
|
||||
"run single assignment client of given type", "type");
|
||||
parser.addOption(clientTypeOption);
|
||||
|
||||
const QCommandLineOption poolOption(ASSIGNMENT_POOL_OPTION, "set assignment pool", "pool-name");
|
||||
parser.addOption(poolOption);
|
||||
|
||||
const QCommandLineOption walletDestinationOption(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION,
|
||||
"set wallet destination", "wallet-uuid");
|
||||
parser.addOption(walletDestinationOption);
|
||||
|
||||
const QCommandLineOption assignmentServerHostnameOption(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION,
|
||||
"set assignment-server hostname", "hostname");
|
||||
parser.addOption(assignmentServerHostnameOption);
|
||||
|
||||
const QCommandLineOption assignmentServerPortOption(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION,
|
||||
"set assignment-server port", "port");
|
||||
parser.addOption(assignmentServerPortOption);
|
||||
|
||||
const QCommandLineOption numChildsOption(ASSIGNMENT_NUM_FORKS_OPTION, "number of children to fork", "child-count");
|
||||
parser.addOption(numChildsOption);
|
||||
|
||||
const QCommandLineOption minChildsOption(ASSIGNMENT_MIN_FORKS_OPTION, "minimum number of children", "child-count");
|
||||
parser.addOption(minChildsOption);
|
||||
|
||||
const QCommandLineOption maxChildsOption(ASSIGNMENT_MAX_FORKS_OPTION, "maximum number of children", "child-count");
|
||||
parser.addOption(maxChildsOption);
|
||||
|
||||
|
||||
if (!parser.parse(QCoreApplication::arguments())) {
|
||||
qCritical() << parser.errorText() << endl;
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (parser.isSet(helpOption)) {
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||
|
||||
|
||||
unsigned int numForks = 0;
|
||||
if (parser.isSet(numChildsOption)) {
|
||||
numForks = parser.value(numChildsOption).toInt();
|
||||
}
|
||||
|
||||
unsigned int minForks = 0;
|
||||
if (parser.isSet(minChildsOption)) {
|
||||
minForks = parser.value(minChildsOption).toInt();
|
||||
}
|
||||
|
||||
unsigned int maxForks = 0;
|
||||
if (parser.isSet(maxChildsOption)) {
|
||||
maxForks = parser.value(maxChildsOption).toInt();
|
||||
}
|
||||
|
||||
if (!numForks && minForks) {
|
||||
// if the user specified --min but not -n, set -n to --min
|
||||
numForks = minForks;
|
||||
}
|
||||
|
||||
Assignment::Type requestAssignmentType = Assignment::AllTypes;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) {
|
||||
requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt();
|
||||
}
|
||||
if (parser.isSet(clientTypeOption)) {
|
||||
requestAssignmentType = (Assignment::Type) parser.value(clientTypeOption).toInt();
|
||||
}
|
||||
|
||||
QString assignmentPool;
|
||||
// check for an assignment pool passed on the command line or in the config
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_POOL_OPTION)) {
|
||||
assignmentPool = argumentVariantMap.value(ASSIGNMENT_POOL_OPTION).toString();
|
||||
}
|
||||
if (parser.isSet(poolOption)) {
|
||||
assignmentPool = parser.value(poolOption);
|
||||
}
|
||||
|
||||
|
||||
QUuid walletUUID;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString();
|
||||
}
|
||||
if (parser.isSet(walletDestinationOption)) {
|
||||
walletUUID = parser.value(walletDestinationOption);
|
||||
}
|
||||
|
||||
QString assignmentServerHostname;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
|
||||
}
|
||||
if (parser.isSet(assignmentServerHostnameOption)) {
|
||||
assignmentServerHostname = parser.value(assignmentServerHostnameOption);
|
||||
}
|
||||
|
||||
// check for an overriden assignment server port
|
||||
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||
assignmentServerPort = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
|
||||
}
|
||||
if (parser.isSet(assignmentServerPortOption)) {
|
||||
assignmentServerPort = parser.value(assignmentServerPortOption).toInt();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (parser.isSet(numChildsOption)) {
|
||||
if (minForks && minForks > numForks) {
|
||||
qCritical() << "--min can't be more than -n";
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
if (maxForks && maxForks < numForks) {
|
||||
qCritical() << "--max can't be less than -n";
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (numForks || minForks || maxForks) {
|
||||
AssignmentClientMonitor monitor(numForks, minForks, maxForks, assignmentPool,
|
||||
walletUUID, assignmentServerHostname, assignmentServerPort);
|
||||
exec();
|
||||
} else {
|
||||
AssignmentClient client(requestAssignmentType, assignmentPool,
|
||||
walletUUID, assignmentServerHostname, assignmentServerPort);
|
||||
exec();
|
||||
}
|
||||
}
|
34
assignment-client/src/AssignmentClientApp.h
Normal file
34
assignment-client/src/AssignmentClientApp.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// AssignmentClientapp.h
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Seth Alves on 2/19/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AssignmentClientApp_h
|
||||
#define hifi_AssignmentClientApp_h
|
||||
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t";
|
||||
const QString ASSIGNMENT_POOL_OPTION = "pool";
|
||||
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a";
|
||||
const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p";
|
||||
const QString ASSIGNMENT_NUM_FORKS_OPTION = "n";
|
||||
const QString ASSIGNMENT_MIN_FORKS_OPTION = "min";
|
||||
const QString ASSIGNMENT_MAX_FORKS_OPTION = "max";
|
||||
|
||||
|
||||
class AssignmentClientApp : public QCoreApplication {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClientApp(int argc, char* argv[]);
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientApp_h
|
8
assignment-client/src/AssignmentClientChildData.cpp
Normal file
8
assignment-client/src/AssignmentClientChildData.cpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
#include "AssignmentClientChildData.h"
|
||||
|
||||
|
||||
AssignmentClientChildData::AssignmentClientChildData(QString childType) :
|
||||
_childType(childType)
|
||||
{
|
||||
}
|
32
assignment-client/src/AssignmentClientChildData.h
Normal file
32
assignment-client/src/AssignmentClientChildData.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// AssignmentClientChildData.h
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Seth Alves on 2/23/2015.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AssignmentClientChildData_h
|
||||
#define hifi_AssignmentClientChildData_h
|
||||
|
||||
#include <Assignment.h>
|
||||
|
||||
|
||||
class AssignmentClientChildData : public NodeData {
|
||||
public:
|
||||
AssignmentClientChildData(QString childType);
|
||||
|
||||
QString getChildType() { return _childType; }
|
||||
void setChildType(QString childType) { _childType = childType; }
|
||||
|
||||
// implement parseData to return 0 so we can be a subclass of NodeData
|
||||
int parseData(const QByteArray& packet) { return 0; }
|
||||
|
||||
private:
|
||||
QString _childType;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientChildData_h
|
|
@ -12,40 +12,52 @@
|
|||
#include <signal.h>
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
#include <AddressManager.h>
|
||||
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
#include "AssignmentClientChildData.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
const char* NUM_FORKS_PARAMETER = "-n";
|
||||
|
||||
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
|
||||
|
||||
AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks) :
|
||||
QCoreApplication(argc, argv)
|
||||
AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks,
|
||||
const unsigned int minAssignmentClientForks,
|
||||
const unsigned int maxAssignmentClientForks,
|
||||
QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname,
|
||||
quint16 assignmentServerPort) :
|
||||
_numAssignmentClientForks(numAssignmentClientForks),
|
||||
_minAssignmentClientForks(minAssignmentClientForks),
|
||||
_maxAssignmentClientForks(maxAssignmentClientForks),
|
||||
_assignmentPool(assignmentPool),
|
||||
_walletUUID(walletUUID),
|
||||
_assignmentServerHostname(assignmentServerHostname),
|
||||
_assignmentServerPort(assignmentServerPort)
|
||||
{
|
||||
// start the Logging class with the parent's target name
|
||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
#ifdef _WIN32
|
||||
installNativeEventFilter(&ShutdownEventListener::getInstance());
|
||||
#else
|
||||
ShutdownEventListener::getInstance();
|
||||
#endif
|
||||
|
||||
_childArguments = arguments();
|
||||
|
||||
// remove the parameter for the number of forks so it isn't passed to the child forked processes
|
||||
int forksParameterIndex = _childArguments.indexOf(NUM_FORKS_PARAMETER);
|
||||
|
||||
// this removes both the "-n" parameter and the number of forks passed
|
||||
_childArguments.removeAt(forksParameterIndex);
|
||||
_childArguments.removeAt(forksParameterIndex);
|
||||
|
||||
// create a NodeList so we can receive stats from children
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<LimitedNodeList>(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT);
|
||||
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClientMonitor::readPendingDatagrams);
|
||||
|
||||
nodeList->putLocalPortIntoSharedMemory(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY, this,
|
||||
nodeList->getNodeSocket().localPort());
|
||||
|
||||
// use QProcess to fork off a process for each of the child assignment clients
|
||||
for (int i = 0; i < numAssignmentClientForks; i++) {
|
||||
for (unsigned int i = 0; i < _numAssignmentClientForks; i++) {
|
||||
spawnChildClient();
|
||||
}
|
||||
|
||||
connect(&_checkSparesTimer, &QTimer::timeout, this, &AssignmentClientMonitor::checkSpares);
|
||||
|
||||
_checkSparesTimer.start(NODE_SILENCE_THRESHOLD_MSECS * 3);
|
||||
}
|
||||
|
||||
AssignmentClientMonitor::~AssignmentClientMonitor() {
|
||||
|
@ -53,46 +65,145 @@ AssignmentClientMonitor::~AssignmentClientMonitor() {
|
|||
}
|
||||
|
||||
void AssignmentClientMonitor::stopChildProcesses() {
|
||||
|
||||
QList<QPointer<QProcess> >::Iterator it = _childProcesses.begin();
|
||||
while (it != _childProcesses.end()) {
|
||||
if (!it->isNull()) {
|
||||
qDebug() << "Monitor is terminating child process" << it->data();
|
||||
|
||||
// don't re-spawn this child when it goes down
|
||||
disconnect(it->data(), 0, this, 0);
|
||||
|
||||
it->data()->terminate();
|
||||
it->data()->waitForFinished();
|
||||
}
|
||||
|
||||
it = _childProcesses.erase(it);
|
||||
}
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
qDebug() << "asking child" << node->getUUID() << "to exit.";
|
||||
node->activateLocalSocket();
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket());
|
||||
});
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::spawnChildClient() {
|
||||
QProcess *assignmentClient = new QProcess(this);
|
||||
|
||||
_childProcesses.append(QPointer<QProcess>(assignmentClient));
|
||||
|
||||
|
||||
// unparse the parts of the command-line that the child cares about
|
||||
QStringList _childArguments;
|
||||
if (_assignmentPool != "") {
|
||||
_childArguments.append("--" + ASSIGNMENT_POOL_OPTION);
|
||||
_childArguments.append(_assignmentPool);
|
||||
}
|
||||
if (!_walletUUID.isNull()) {
|
||||
_childArguments.append("--" + ASSIGNMENT_WALLET_DESTINATION_ID_OPTION);
|
||||
_childArguments.append(_walletUUID.toString());
|
||||
}
|
||||
if (_assignmentServerHostname != "") {
|
||||
_childArguments.append("--" + CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION);
|
||||
_childArguments.append(_assignmentServerHostname);
|
||||
}
|
||||
if (_assignmentServerPort != DEFAULT_DOMAIN_SERVER_PORT) {
|
||||
_childArguments.append("--" + CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION);
|
||||
_childArguments.append(QString::number(_assignmentServerPort));
|
||||
}
|
||||
|
||||
// make sure that the output from the child process appears in our output
|
||||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
|
||||
assignmentClient->start(applicationFilePath(), _childArguments);
|
||||
|
||||
// link the child processes' finished slot to our childProcessFinished slot
|
||||
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this,
|
||||
SLOT(childProcessFinished(int, QProcess::ExitStatus)));
|
||||
|
||||
assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments);
|
||||
|
||||
qDebug() << "Spawned a child client with PID" << assignmentClient->pid();
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qDebug("Replacing dead child assignment client with a new one");
|
||||
|
||||
// remove the old process from our list of child processes
|
||||
qDebug() << "need to remove" << QPointer<QProcess>(qobject_cast<QProcess*>(sender()));
|
||||
_childProcesses.removeOne(QPointer<QProcess>(qobject_cast<QProcess*>(sender())));
|
||||
|
||||
spawnChildClient();
|
||||
|
||||
|
||||
void AssignmentClientMonitor::checkSpares() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QUuid aSpareId = "";
|
||||
unsigned int spareCount = 0;
|
||||
unsigned int totalCount = 0;
|
||||
|
||||
nodeList->removeSilentNodes();
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
AssignmentClientChildData *childData = static_cast<AssignmentClientChildData*>(node->getLinkedData());
|
||||
totalCount ++;
|
||||
if (childData->getChildType() == "none") {
|
||||
spareCount ++;
|
||||
aSpareId = node->getUUID();
|
||||
}
|
||||
});
|
||||
|
||||
// Spawn or kill children, as needed. If --min or --max weren't specified, allow the child count
|
||||
// to drift up or down as far as needed.
|
||||
if (spareCount < 1 || totalCount < _minAssignmentClientForks) {
|
||||
if (!_maxAssignmentClientForks || totalCount < _maxAssignmentClientForks) {
|
||||
spawnChildClient();
|
||||
}
|
||||
}
|
||||
|
||||
if (spareCount > 1) {
|
||||
if (!_minAssignmentClientForks || totalCount > _minAssignmentClientForks) {
|
||||
// kill aSpareId
|
||||
qDebug() << "asking child" << aSpareId << "to exit.";
|
||||
SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId);
|
||||
childNode->activateLocalSocket();
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClientMonitor::readPendingDatagrams() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (packetTypeForPacket(receivedPacket) == PacketTypeNodeJsonStats) {
|
||||
QUuid packetUUID = uuidFromPacketHeader(receivedPacket);
|
||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (!matchingNode) {
|
||||
// The parent only expects to be talking with prorams running on this same machine.
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
if (!packetUUID.isNull()) {
|
||||
matchingNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode
|
||||
(packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false);
|
||||
AssignmentClientChildData *childData = new AssignmentClientChildData("unknown");
|
||||
matchingNode->setLinkedData(childData);
|
||||
} else {
|
||||
// tell unknown assignment-client child to exit.
|
||||
qDebug() << "asking unknown child to exit.";
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, senderSockAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingNode) {
|
||||
// update our records about how to reach this child
|
||||
matchingNode->setLocalSocket(senderSockAddr);
|
||||
|
||||
// push past the packet header
|
||||
QDataStream packetStream(receivedPacket);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
|
||||
// decode json
|
||||
QVariantMap unpackedVariantMap;
|
||||
packetStream >> unpackedVariantMap;
|
||||
QJsonObject unpackedStatsJSON = QJsonObject::fromVariantMap(unpackedVariantMap);
|
||||
|
||||
// get child's assignment type out of the decoded json
|
||||
QString childType = unpackedStatsJSON["assignment_type"].toString();
|
||||
AssignmentClientChildData *childData =
|
||||
static_cast<AssignmentClientChildData*>(matchingNode->getLinkedData());
|
||||
childData->setChildType(childType);
|
||||
// note when this child talked
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
} else {
|
||||
// have the NodeList attempt to handle it
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,25 +15,40 @@
|
|||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QDateTime>
|
||||
|
||||
#include <Assignment.h>
|
||||
|
||||
#include "AssignmentClientChildData.h"
|
||||
|
||||
extern const char* NUM_FORKS_PARAMETER;
|
||||
|
||||
class AssignmentClientMonitor : public QCoreApplication {
|
||||
|
||||
class AssignmentClientMonitor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks);
|
||||
AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks,
|
||||
const unsigned int maxAssignmentClientForks, QString assignmentPool, QUuid walletUUID,
|
||||
QString assignmentServerHostname, quint16 assignmentServerPort);
|
||||
~AssignmentClientMonitor();
|
||||
|
||||
void stopChildProcesses();
|
||||
private slots:
|
||||
void childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void readPendingDatagrams();
|
||||
void checkSpares();
|
||||
|
||||
private:
|
||||
void spawnChildClient();
|
||||
QList<QPointer<QProcess> > _childProcesses;
|
||||
|
||||
QStringList _childArguments;
|
||||
QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children
|
||||
|
||||
const unsigned int _numAssignmentClientForks;
|
||||
const unsigned int _minAssignmentClientForks;
|
||||
const unsigned int _maxAssignmentClientForks;
|
||||
|
||||
QString _assignmentPool;
|
||||
QUuid _walletUUID;
|
||||
QString _assignmentServerHostname;
|
||||
quint16 _assignmentServerPort;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientMonitor_h
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "AssignmentFactory.h"
|
||||
#include "audio/AudioMixer.h"
|
||||
#include "avatars/AvatarMixer.h"
|
||||
#include "metavoxels/MetavoxelServer.h"
|
||||
#include "entities/EntityServer.h"
|
||||
|
||||
ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet) {
|
||||
|
@ -34,8 +33,6 @@ ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet
|
|||
return new AvatarMixer(packet);
|
||||
case Assignment::AgentType:
|
||||
return new Agent(packet);
|
||||
case Assignment::MetavoxelServerType:
|
||||
return new MetavoxelServer(packet);
|
||||
case Assignment::EntityServerType:
|
||||
return new EntityServer(packet);
|
||||
default:
|
||||
|
|
|
@ -9,34 +9,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Assignment.h"
|
||||
#include "AssignmentClient.h"
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifndef WIN32
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
#endif
|
||||
|
||||
// use the verbose message handler in Logging
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
|
||||
const char* numForksString = getCmdOption(argc, (const char**)argv, NUM_FORKS_PARAMETER);
|
||||
|
||||
int numForks = 0;
|
||||
|
||||
if (numForksString) {
|
||||
numForks = atoi(numForksString);
|
||||
}
|
||||
|
||||
if (numForks) {
|
||||
AssignmentClientMonitor monitor(argc, argv, numForks);
|
||||
return monitor.exec();
|
||||
} else {
|
||||
AssignmentClient client(argc, argv);
|
||||
return client.exec();
|
||||
}
|
||||
AssignmentClientApp app(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,367 +0,0 @@
|
|||
//
|
||||
// MetavoxelServer.cpp
|
||||
// assignment-client/src/metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/18/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QSaveFile>
|
||||
#include <QThread>
|
||||
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
#include <MetavoxelMessages.h>
|
||||
#include <MetavoxelUtil.h>
|
||||
|
||||
#include "MetavoxelServer.h"
|
||||
|
||||
MetavoxelServer::MetavoxelServer(const QByteArray& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_nextSender(0),
|
||||
_savedDataInitialized(false) {
|
||||
}
|
||||
|
||||
void MetavoxelServer::applyEdit(const MetavoxelEditMessage& edit) {
|
||||
MetavoxelData data = _data;
|
||||
edit.apply(data, SharedObject::getWeakHash());
|
||||
setData(data);
|
||||
}
|
||||
|
||||
void MetavoxelServer::setData(const MetavoxelData& data, bool loaded) {
|
||||
if (_data == data) {
|
||||
return;
|
||||
}
|
||||
emit dataChanged(_data = data);
|
||||
|
||||
if (loaded) {
|
||||
_savedData = data;
|
||||
|
||||
} else if (!_savedDataInitialized) {
|
||||
_savedDataInitialized = true;
|
||||
|
||||
// start the save timer
|
||||
QTimer* saveTimer = new QTimer(this);
|
||||
connect(saveTimer, &QTimer::timeout, this, &MetavoxelServer::maybeSaveData);
|
||||
const int SAVE_INTERVAL = 1000 * 30;
|
||||
saveTimer->start(SAVE_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
const QString METAVOXEL_SERVER_LOGGING_NAME = "metavoxel-server";
|
||||
|
||||
void MetavoxelServer::run() {
|
||||
commonInit(METAVOXEL_SERVER_LOGGING_NAME, NodeType::MetavoxelServer);
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||
|
||||
connect(nodeList.data(), &NodeList::nodeAdded, this, &MetavoxelServer::maybeAttachSession);
|
||||
connect(nodeList.data(), &NodeList::nodeKilled, this, &MetavoxelServer::maybeDeleteSession);
|
||||
|
||||
// initialize Bitstream before using it in multiple threads
|
||||
Bitstream::preThreadingInit();
|
||||
|
||||
// create the senders, each with its own thread
|
||||
int threadCount = QThread::idealThreadCount();
|
||||
if (threadCount == -1) {
|
||||
const int DEFAULT_THREAD_COUNT = 4;
|
||||
threadCount = DEFAULT_THREAD_COUNT;
|
||||
}
|
||||
qDebug() << "Creating" << threadCount << "sender threads";
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
QThread* thread = new QThread(this);
|
||||
MetavoxelSender* sender = new MetavoxelSender(this);
|
||||
sender->moveToThread(thread);
|
||||
connect(thread, &QThread::finished, sender, &QObject::deleteLater);
|
||||
thread->start();
|
||||
QMetaObject::invokeMethod(sender, "start");
|
||||
_senders.append(sender);
|
||||
}
|
||||
|
||||
// create the persister and start it in its own thread
|
||||
_persister = new MetavoxelPersister(this);
|
||||
QThread* persistenceThread = new QThread(this);
|
||||
_persister->moveToThread(persistenceThread);
|
||||
connect(persistenceThread, &QThread::finished, _persister, &QObject::deleteLater);
|
||||
persistenceThread->start();
|
||||
|
||||
// queue up the load
|
||||
QMetaObject::invokeMethod(_persister, "load");
|
||||
}
|
||||
|
||||
void MetavoxelServer::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
switch (packetTypeForPacket(receivedPacket)) {
|
||||
case PacketTypeMetavoxelData:
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
|
||||
break;
|
||||
|
||||
default:
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelServer::aboutToFinish() {
|
||||
QMetaObject::invokeMethod(_persister, "save", Q_ARG(const MetavoxelData&, _data));
|
||||
|
||||
foreach (MetavoxelSender* sender, _senders) {
|
||||
sender->thread()->quit();
|
||||
sender->thread()->wait();
|
||||
}
|
||||
_persister->thread()->quit();
|
||||
_persister->thread()->wait();
|
||||
}
|
||||
|
||||
void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) {
|
||||
if (node->getType() == NodeType::Agent) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelSender* sender = _senders.at(_nextSender);
|
||||
_nextSender = (_nextSender + 1) % _senders.size();
|
||||
MetavoxelSession* session = new MetavoxelSession(node, sender);
|
||||
session->moveToThread(sender->thread());
|
||||
QMetaObject::invokeMethod(sender, "addSession", Q_ARG(QObject*, session));
|
||||
node->setLinkedData(session);
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelServer::maybeDeleteSession(const SharedNodePointer& node) {
|
||||
if (node->getType() == NodeType::Agent) {
|
||||
// we assume the node is already locked
|
||||
MetavoxelSession* session = static_cast<MetavoxelSession*>(node->getLinkedData());
|
||||
if (session) {
|
||||
node->setLinkedData(NULL);
|
||||
session->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelServer::maybeSaveData() {
|
||||
if (_savedData != _data) {
|
||||
QMetaObject::invokeMethod(_persister, "save", Q_ARG(const MetavoxelData&, _savedData = _data));
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelSender::MetavoxelSender(MetavoxelServer* server) :
|
||||
_server(server),
|
||||
_sendTimer(this) {
|
||||
|
||||
_sendTimer.setSingleShot(true);
|
||||
connect(&_sendTimer, &QTimer::timeout, this, &MetavoxelSender::sendDeltas);
|
||||
|
||||
connect(_server, &MetavoxelServer::dataChanged, this, &MetavoxelSender::setData);
|
||||
}
|
||||
|
||||
const int SEND_INTERVAL = 50;
|
||||
|
||||
void MetavoxelSender::start() {
|
||||
_lastSend = QDateTime::currentMSecsSinceEpoch();
|
||||
_sendTimer.start(SEND_INTERVAL);
|
||||
}
|
||||
|
||||
void MetavoxelSender::addSession(QObject* session) {
|
||||
_sessions.insert(static_cast<MetavoxelSession*>(session));
|
||||
connect(session, &QObject::destroyed, this, &MetavoxelSender::removeSession);
|
||||
}
|
||||
|
||||
void MetavoxelSender::sendDeltas() {
|
||||
// send deltas for all sessions associated with our thread
|
||||
foreach (MetavoxelSession* session, _sessions) {
|
||||
session->update();
|
||||
}
|
||||
|
||||
// restart the send timer
|
||||
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
int elapsed = now - _lastSend;
|
||||
_lastSend = now;
|
||||
|
||||
_sendTimer.start(qMax(0, 2 * SEND_INTERVAL - qMax(elapsed, SEND_INTERVAL)));
|
||||
}
|
||||
|
||||
void MetavoxelSender::removeSession(QObject* session) {
|
||||
_sessions.remove(static_cast<MetavoxelSession*>(session));
|
||||
}
|
||||
|
||||
MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender) :
|
||||
Endpoint(node, new PacketRecord(), NULL),
|
||||
_sender(sender),
|
||||
_reliableDeltaChannel(NULL),
|
||||
_reliableDeltaID(0) {
|
||||
|
||||
connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleMessage(const QVariant&)));
|
||||
connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(checkReliableDeltaReceived()));
|
||||
connect(_sequencer.getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&, Bitstream&)),
|
||||
SLOT(handleMessage(const QVariant&, Bitstream&)));
|
||||
}
|
||||
|
||||
void MetavoxelSession::update() {
|
||||
// wait until we have a valid lod before sending
|
||||
if (!_lod.isValid()) {
|
||||
return;
|
||||
}
|
||||
// if we're sending a reliable delta, wait until it's acknowledged
|
||||
if (_reliableDeltaChannel) {
|
||||
sendPacketGroup();
|
||||
return;
|
||||
}
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
int start = _sequencer.getOutputStream().getUnderlying().device()->pos();
|
||||
out << QVariant::fromValue(MetavoxelDeltaMessage());
|
||||
PacketRecord* sendRecord = getLastAcknowledgedSendRecord();
|
||||
_sender->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod);
|
||||
out.flush();
|
||||
int end = _sequencer.getOutputStream().getUnderlying().device()->pos();
|
||||
if (end > _sequencer.getMaxPacketSize()) {
|
||||
// we need to send the delta on the reliable channel
|
||||
_reliableDeltaChannel = _sequencer.getReliableOutputChannel(RELIABLE_DELTA_CHANNEL_INDEX);
|
||||
_reliableDeltaChannel->startMessage();
|
||||
_reliableDeltaChannel->getBuffer().write(_sequencer.getOutgoingPacketData().constData() + start, end - start);
|
||||
_reliableDeltaChannel->endMessage();
|
||||
|
||||
_reliableDeltaWriteMappings = out.getAndResetWriteMappings();
|
||||
_reliableDeltaReceivedOffset = _reliableDeltaChannel->getBytesWritten();
|
||||
_reliableDeltaData = _sender->getData();
|
||||
_reliableDeltaLOD = _lod;
|
||||
|
||||
// go back to the beginning with the current packet and note that there's a delta pending
|
||||
_sequencer.getOutputStream().getUnderlying().device()->seek(start);
|
||||
MetavoxelDeltaPendingMessage msg = { ++_reliableDeltaID, sendRecord->getPacketNumber(), _lodPacketNumber };
|
||||
out << (_reliableDeltaMessage = QVariant::fromValue(msg));
|
||||
_sequencer.endPacket();
|
||||
|
||||
} else {
|
||||
_sequencer.endPacket();
|
||||
}
|
||||
|
||||
// perhaps send additional packets to fill out the group
|
||||
sendPacketGroup(1);
|
||||
}
|
||||
|
||||
void MetavoxelSession::handleMessage(const QVariant& message, Bitstream& in) {
|
||||
handleMessage(message);
|
||||
}
|
||||
|
||||
PacketRecord* MetavoxelSession::maybeCreateSendRecord() const {
|
||||
return _reliableDeltaChannel ? new PacketRecord(_sequencer.getOutgoingPacketNumber(),
|
||||
_reliableDeltaLOD, _reliableDeltaData) : new PacketRecord(_sequencer.getOutgoingPacketNumber(),
|
||||
_lod, _sender->getData());
|
||||
}
|
||||
|
||||
void MetavoxelSession::handleMessage(const QVariant& message) {
|
||||
int userType = message.userType();
|
||||
if (userType == ClientStateMessage::Type) {
|
||||
ClientStateMessage state = message.value<ClientStateMessage>();
|
||||
_lod = state.lod;
|
||||
_lodPacketNumber = _sequencer.getIncomingPacketNumber();
|
||||
|
||||
} else if (userType == MetavoxelEditMessage::Type) {
|
||||
if (_node->getCanAdjustLocks()) {
|
||||
QMetaObject::invokeMethod(_sender->getServer(), "applyEdit",
|
||||
Q_ARG(const MetavoxelEditMessage&, message.value<MetavoxelEditMessage>()));
|
||||
}
|
||||
} else if (userType == QMetaType::QVariantList) {
|
||||
foreach (const QVariant& element, message.toList()) {
|
||||
handleMessage(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelSession::checkReliableDeltaReceived() {
|
||||
if (!_reliableDeltaChannel || _reliableDeltaChannel->getOffset() < _reliableDeltaReceivedOffset) {
|
||||
return;
|
||||
}
|
||||
_sequencer.getOutputStream().persistWriteMappings(_reliableDeltaWriteMappings);
|
||||
_reliableDeltaWriteMappings = Bitstream::WriteMappings();
|
||||
_reliableDeltaData = MetavoxelData();
|
||||
_reliableDeltaChannel = NULL;
|
||||
}
|
||||
|
||||
void MetavoxelSession::sendPacketGroup(int alreadySent) {
|
||||
int additionalPackets = _sequencer.notePacketGroup() - alreadySent;
|
||||
for (int i = 0; i < additionalPackets; i++) {
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
if (_reliableDeltaChannel) {
|
||||
out << _reliableDeltaMessage;
|
||||
} else {
|
||||
out << QVariant();
|
||||
}
|
||||
_sequencer.endPacket();
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelPersister::MetavoxelPersister(MetavoxelServer* server) :
|
||||
_server(server) {
|
||||
}
|
||||
|
||||
const char* SAVE_FILE = "/resources/metavoxels.dat";
|
||||
|
||||
const int FILE_MAGIC = 0xDADAFACE;
|
||||
const int FILE_VERSION = 4;
|
||||
|
||||
void MetavoxelPersister::load() {
|
||||
QString path = QCoreApplication::applicationDirPath() + SAVE_FILE;
|
||||
QFile file(path);
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
MetavoxelData data;
|
||||
{
|
||||
QDebug debug = qDebug() << "Reading from" << path << "...";
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QDataStream inStream(&file);
|
||||
Bitstream in(inStream);
|
||||
int magic, version;
|
||||
in >> magic;
|
||||
if (magic != FILE_MAGIC) {
|
||||
debug << "wrong file magic: " << magic;
|
||||
return;
|
||||
}
|
||||
in >> version;
|
||||
if (version != FILE_VERSION) {
|
||||
debug << "wrong file version: " << version;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
in >> data;
|
||||
} catch (const BitstreamException& e) {
|
||||
debug << "failed, " << e.getDescription();
|
||||
return;
|
||||
}
|
||||
QMetaObject::invokeMethod(_server, "setData", Q_ARG(const MetavoxelData&, data), Q_ARG(bool, true));
|
||||
debug << "done.";
|
||||
}
|
||||
data.dumpStats();
|
||||
}
|
||||
|
||||
void MetavoxelPersister::save(const MetavoxelData& data) {
|
||||
QString path = QCoreApplication::applicationDirPath() + SAVE_FILE;
|
||||
QDir directory = QFileInfo(path).dir();
|
||||
if (!directory.exists()) {
|
||||
directory.mkpath(".");
|
||||
}
|
||||
QDebug debug = qDebug() << "Writing to" << path << "...";
|
||||
QSaveFile file(path);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
QDataStream outStream(&file);
|
||||
Bitstream out(outStream);
|
||||
out << FILE_MAGIC << FILE_VERSION << data;
|
||||
out.flush();
|
||||
file.commit();
|
||||
debug << "done.";
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
//
|
||||
// MetavoxelServer.h
|
||||
// assignment-client/src/metavoxels
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/18/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_MetavoxelServer_h
|
||||
#define hifi_MetavoxelServer_h
|
||||
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
|
||||
#include <ThreadedAssignment.h>
|
||||
|
||||
#include <Endpoint.h>
|
||||
|
||||
class MetavoxelEditMessage;
|
||||
class MetavoxelPersister;
|
||||
class MetavoxelSender;
|
||||
class MetavoxelSession;
|
||||
|
||||
/// Maintains a shared metavoxel system, accepting change requests and broadcasting updates.
|
||||
class MetavoxelServer : public ThreadedAssignment {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelServer(const QByteArray& packet);
|
||||
|
||||
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit);
|
||||
|
||||
const MetavoxelData& getData() const { return _data; }
|
||||
|
||||
Q_INVOKABLE void setData(const MetavoxelData& data, bool loaded = false);
|
||||
|
||||
virtual void run();
|
||||
|
||||
virtual void readPendingDatagrams();
|
||||
|
||||
virtual void aboutToFinish();
|
||||
|
||||
signals:
|
||||
|
||||
void dataChanged(const MetavoxelData& data);
|
||||
|
||||
private slots:
|
||||
|
||||
void maybeAttachSession(const SharedNodePointer& node);
|
||||
void maybeDeleteSession(const SharedNodePointer& node);
|
||||
void maybeSaveData();
|
||||
|
||||
private:
|
||||
|
||||
QVector<MetavoxelSender*> _senders;
|
||||
int _nextSender;
|
||||
|
||||
MetavoxelPersister* _persister;
|
||||
|
||||
MetavoxelData _data;
|
||||
MetavoxelData _savedData;
|
||||
bool _savedDataInitialized;
|
||||
};
|
||||
|
||||
/// Handles update sending for one thread.
|
||||
class MetavoxelSender : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelSender(MetavoxelServer* server);
|
||||
|
||||
MetavoxelServer* getServer() const { return _server; }
|
||||
|
||||
const MetavoxelData& getData() const { return _data; }
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
Q_INVOKABLE void addSession(QObject* session);
|
||||
|
||||
private slots:
|
||||
|
||||
void setData(const MetavoxelData& data) { _data = data; }
|
||||
void sendDeltas();
|
||||
void removeSession(QObject* session);
|
||||
|
||||
private:
|
||||
|
||||
MetavoxelServer* _server;
|
||||
QSet<MetavoxelSession*> _sessions;
|
||||
|
||||
QTimer _sendTimer;
|
||||
qint64 _lastSend;
|
||||
|
||||
MetavoxelData _data;
|
||||
};
|
||||
|
||||
/// Contains the state of a single client session.
|
||||
class MetavoxelSession : public Endpoint {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender);
|
||||
|
||||
virtual void update();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
virtual PacketRecord* maybeCreateSendRecord() const;
|
||||
|
||||
private slots:
|
||||
|
||||
void handleMessage(const QVariant& message);
|
||||
void checkReliableDeltaReceived();
|
||||
|
||||
private:
|
||||
|
||||
void sendPacketGroup(int alreadySent = 0);
|
||||
|
||||
MetavoxelSender* _sender;
|
||||
|
||||
MetavoxelLOD _lod;
|
||||
int _lodPacketNumber;
|
||||
|
||||
ReliableChannel* _reliableDeltaChannel;
|
||||
int _reliableDeltaReceivedOffset;
|
||||
MetavoxelData _reliableDeltaData;
|
||||
MetavoxelLOD _reliableDeltaLOD;
|
||||
Bitstream::WriteMappings _reliableDeltaWriteMappings;
|
||||
int _reliableDeltaID;
|
||||
QVariant _reliableDeltaMessage;
|
||||
};
|
||||
|
||||
/// Handles persistence in a separate thread.
|
||||
class MetavoxelPersister : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelPersister(MetavoxelServer* server);
|
||||
|
||||
Q_INVOKABLE void load();
|
||||
Q_INVOKABLE void save(const MetavoxelData& data);
|
||||
|
||||
private:
|
||||
|
||||
MetavoxelServer* _server;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelServer_h
|
|
@ -26,7 +26,7 @@ macro(qt_create_apk)
|
|||
set(ANDROID_APK_THEME "")
|
||||
endif()
|
||||
|
||||
if (CMAKE_BUILD_TYPE MATCHES RELEASE)
|
||||
if (UPPER_CMAKE_BUILD_TYPE MATCHES RELEASE)
|
||||
set(ANDROID_APK_DEBUGGABLE "false")
|
||||
set(ANDROID_APK_RELEASE_LOCAL ${ANDROID_APK_RELEASE})
|
||||
else ()
|
||||
|
@ -39,9 +39,6 @@ macro(qt_create_apk)
|
|||
|
||||
# create "strings.xml"
|
||||
configure_file("${ANDROID_THIS_DIRECTORY}/strings.xml.in" "${ANDROID_APK_BUILD_DIR}/res/values/strings.xml")
|
||||
|
||||
# figure out where the qt dir is
|
||||
get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE)
|
||||
|
||||
# find androiddeployqt
|
||||
find_program(ANDROID_DEPLOY_QT androiddeployqt HINTS "${QT_DIR}/bin")
|
||||
|
|
78
cmake/externals/bullet/CMakeLists.txt
vendored
Normal file
78
cmake/externals/bullet/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
set(EXTERNAL_NAME bullet)
|
||||
|
||||
if (WIN32)
|
||||
set(PLATFORM_CMAKE_ARGS "-DUSE_MSVC_RUNTIME_LIBRARY_DLL=1")
|
||||
else ()
|
||||
set(PLATFORM_CMAKE_ARGS "-DBUILD_SHARED_LIBS=1")
|
||||
|
||||
if (ANDROID)
|
||||
list(APPEND PLATFORM_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
|
||||
elseif (APPLE)
|
||||
list(APPEND PLATFORM_CMAKE_ARGS "-DCMAKE_INSTALL_NAME_DIR=<INSTALL_DIR>/lib")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
if (WIN32)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://bullet.googlecode.com/files/bullet-2.82-r2704.zip
|
||||
URL_MD5 f5e8914fc9064ad32e0d62d19d33d977
|
||||
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DBUILD_EXTRAS=0 -DINSTALL_LIBS=1 -DBUILD_DEMOS=0 -DUSE_GLUT=0
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
)
|
||||
else ()
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://bullet.googlecode.com/files/bullet-2.82-r2704.tgz
|
||||
URL_MD5 70b3c8d202dee91a0854b4cbc88173e8
|
||||
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DBUILD_EXTRAS=0 -DINSTALL_LIBS=1 -DBUILD_DEMOS=0 -DUSE_GLUT=0
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
)
|
||||
endif ()
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
set(BULLET_LIB_DIR "${INSTALL_DIR}/lib")
|
||||
|
||||
if (APPLE OR UNIX OR ANDROID)
|
||||
if (APPLE)
|
||||
set(BULLET_LIB_EXT "dylib")
|
||||
else ()
|
||||
set(BULLET_LIB_EXT "so")
|
||||
endif ()
|
||||
|
||||
set(LIB_PREFIX "lib")
|
||||
elseif (WIN32)
|
||||
set(BULLET_LIB_EXT "lib")
|
||||
endif ()
|
||||
|
||||
if (DEFINED BULLET_LIB_EXT)
|
||||
set(_BULLET_LIB_PAIRS "DYNAMICS_LIBRARY\;BulletDynamics" "COLLISION_LIBRARY\;BulletCollision" "MATH_LIBRARY\;LinearMath" "SOFTBODY_LIBRARY\;BulletSoftBody")
|
||||
|
||||
foreach(_LIB_PAIR ${_BULLET_LIB_PAIRS})
|
||||
list(GET _LIB_PAIR 0 _LIB_VAR_NAME)
|
||||
list(GET _LIB_PAIR 1 _LIB_NAME)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_${_LIB_VAR_NAME}_RELEASE ${BULLET_LIB_DIR}/${LIB_PREFIX}${_LIB_NAME}.${BULLET_LIB_EXT} CACHE FILEPATH "${_LIB_NAME} release library location")
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_${_LIB_VAR_NAME}_DEBUG ${BULLET_LIB_DIR}/${LIB_PREFIX}${_LIB_NAME}_Debug.${BULLET_LIB_EXT} CACHE FILEPATH "${_LIB_NAME} debug library location")
|
||||
else ()
|
||||
set(${EXTERNAL_NAME_UPPER}_${_LIB_VAR_NAME}_DEBUG "" CACHE FILEPATH "${_LIB_NAME} debug library location")
|
||||
endif ()
|
||||
endforeach()
|
||||
endif ()
|
||||
|
||||
if (DEFINED ${EXTERNAL_NAME_UPPER}_DYNAMICS_LIBRARY_RELEASE)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include/bullet CACHE PATH "Path to bullet include directory")
|
||||
endif ()
|
26
cmake/externals/glew/CMakeLists.txt
vendored
Normal file
26
cmake/externals/glew/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
if (WIN32)
|
||||
set(EXTERNAL_NAME glew)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/glew-1.10.0-win32.zip
|
||||
URL_MD5 37514e4e595a3b3dc587eee8f7e8ec2f
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of glew include directories")
|
||||
|
||||
set(_LIB_DIR ${SOURCE_DIR}/lib/Release/Win32)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/glew32.lib CACHE FILEPATH "Location of GLEW release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Location of GLEW debug library")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/Win32 CACHE FILEPATH "Location of GLEW DLL")
|
||||
endif ()
|
9
cmake/externals/glm/CMakeLists.txt
vendored
9
cmake/externals/glm/CMakeLists.txt
vendored
|
@ -3,13 +3,16 @@ set(EXTERNAL_NAME glm)
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
PREFIX ${EXTERNAL_NAME}
|
||||
URL http://pkgs.fedoraproject.org/repo/pkgs/glm/glm-0.9.5.4.zip/fab76fc982b256b46208e5c750ed456a/glm-0.9.5.4.zip
|
||||
URL_MD5 fab76fc982b256b46208e5c750ed456a
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
LOG_DOWNLOAD ON
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE TYPE STRING)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of glm include directories")
|
13
cmake/externals/gverb/CMakeLists.txt
vendored
13
cmake/externals/gverb/CMakeLists.txt
vendored
|
@ -7,19 +7,22 @@ endif ()
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
PREFIX ${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/gverb-master.zip
|
||||
URL_MD5 8b16d586390a2102804e46b87820dfc6
|
||||
CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
LOG_DOWNLOAD ON
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE TYPE STRING)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to gverb include directory")
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/gverb.lib CACHE TYPE STRING)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/gverb.lib CACHE FILEPATH "List of gverb libraries")
|
||||
else ()
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libgverb.a CACHE TYPE STRING)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libgverb.a CACHE FILEPATH "List of gverb libraries")
|
||||
endif ()
|
74
cmake/externals/qxmpp/CMakeLists.txt
vendored
Normal file
74
cmake/externals/qxmpp/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
set(EXTERNAL_NAME qxmpp)
|
||||
|
||||
# we need to find qmake inside QT_DIR
|
||||
find_program(QMAKE_COMMAND NAME qmake PATHS ${QT_DIR}/bin $ENV{QTTOOLDIR} NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT QMAKE_COMMAND)
|
||||
message(FATAL_ERROR "Could not find qmake. Qxmpp cannot be compiled without qmake.")
|
||||
endif ()
|
||||
|
||||
if (ANDROID)
|
||||
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
find_program(PLATFORM_BUILD_COMMAND nmake PATHS "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin")
|
||||
|
||||
if (NOT PLATFORM_BUILD_COMMAND)
|
||||
message(FATAL_ERROR "You asked CMake to grap QXmpp and build it, but nmake was not found. Please make sure the folder containing nmake.exe is in your PATH.")
|
||||
endif ()
|
||||
else ()
|
||||
find_program(PLATFORM_BUILD_COMMAND make)
|
||||
endif ()
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://qxmpp.googlecode.com/files/qxmpp-0.7.6.tar.gz
|
||||
URL_MD5 ee45a97313306ded2ff0f6618a3ed1e1
|
||||
BUILD_IN_SOURCE 1
|
||||
PATCH_COMMAND patch -p2 -t -N --verbose < ${CMAKE_CURRENT_SOURCE_DIR}/qxmpp.patch
|
||||
CONFIGURE_COMMAND ${QMAKE_COMMAND} PREFIX=<INSTALL_DIR>
|
||||
BUILD_COMMAND ${PLATFORM_BUILD_COMMAND}
|
||||
INSTALL_COMMAND ${PLATFORM_BUILD_COMMAND} install
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
if (CMAKE_GENERATOR STREQUAL Xcode)
|
||||
find_program(DITTO_COMMAND ditto)
|
||||
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
copy-from-xcode-install
|
||||
COMMENT "Copying from /tmp/hifi.dst${INSTALL_DIR} to move install to proper location"
|
||||
COMMAND ${DITTO_COMMAND} /tmp/hifi.dst${INSTALL_DIR} ${INSTALL_DIR}
|
||||
DEPENDEES install
|
||||
LOG 1
|
||||
)
|
||||
endif ()
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to Qxmpp include directory")
|
||||
|
||||
set(_LIB_DIR ${INSTALL_DIR}/lib)
|
||||
|
||||
if (WIN32)
|
||||
set(_LIB_EXT "0.lib")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${_LIB_DIR} CACHE PATH "Location of QXmpp DLL")
|
||||
else ()
|
||||
if (APPLE)
|
||||
set(_LIB_EXT ".dylib")
|
||||
else ()
|
||||
set(_LIB_EXT ".so")
|
||||
endif ()
|
||||
|
||||
set(_LIB_PREFIX "lib")
|
||||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/${_LIB_PREFIX}qxmpp${_LIB_EXT} CACHE FILEPATH "Path to QXmpp release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Path to QXmpp debug library")
|
68
cmake/externals/sdl2/CMakeLists.txt
vendored
Normal file
68
cmake/externals/sdl2/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
set(EXTERNAL_NAME sdl2)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
if (WIN32)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip
|
||||
URL_MD5 30a333bcbe94bc5016e8799c73e86233
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
elseif (APPLE)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/SDL2-2.0.3-OSX.tar.gz
|
||||
URL_MD5 64f888886268bdf1656ef1b4b7d7756d
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
else ()
|
||||
if (ANDROID)
|
||||
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
|
||||
endif ()
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://www.libsdl.org/release/SDL2-2.0.3.tar.gz
|
||||
URL_MD5 fe6c61d2e9df9ef570e7e80c6e822537
|
||||
CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
endif ()
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (APPLE)
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${SOURCE_DIR}/SDL2.framework/Headers CACHE PATH "Location of SDL2 include directory")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${SOURCE_DIR}/SDL2.framework/SDL2 CACHE STRING "Path to SDL2 library")
|
||||
else ()
|
||||
if (WIN32)
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
set(_ROOT_DIR ${SOURCE_DIR})
|
||||
set(_INCLUDE_DIR ${_ROOT_DIR}/include)
|
||||
set(_LIB_DIR "${SOURCE_DIR}/lib/x86")
|
||||
set(_LIB_EXT "lib")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${_LIB_DIR} CACHE PATH "Location of SDL2 DLL")
|
||||
else ()
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
set(_ROOT_DIR ${INSTALL_DIR})
|
||||
set(_INCLUDE_DIR ${_ROOT_DIR}/include/SDL2)
|
||||
|
||||
set(_LIB_DIR ${INSTALL_DIR}/lib)
|
||||
set(_LIB_EXT "so")
|
||||
set(_LIB_PREFIX "lib")
|
||||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${_INCLUDE_DIR} CACHE PATH "Location of SDL2 include directory")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${_LIB_DIR}/${_LIB_PREFIX}SDL2.${_LIB_EXT} CACHE FILEPATH "Path to SDL2 library")
|
||||
endif ()
|
31
cmake/externals/soxr/CMakeLists.txt
vendored
Normal file
31
cmake/externals/soxr/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
set(EXTERNAL_NAME soxr)
|
||||
|
||||
if (ANDROID)
|
||||
set(PLATFORM_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19" "-DHAVE_WORDS_BIGENDIAN_EXITCODE=1")
|
||||
endif ()
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/soxr-0.1.1.zip
|
||||
URL_MD5 349b5b2f323a7380bc12186d98c77d1d
|
||||
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DBUILD_SHARED_LIBS=1 -DBUILD_TESTS=0 -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of soxr include directories")
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/soxr.lib CACHE FILEPATH "List of soxr libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${INSTALL_DIR}/bin CACHE PATH "Path to soxr dll")
|
||||
elseif (APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libsoxr.dylib CACHE FILEPATH "List of soxr libraries")
|
||||
else ()
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libsoxr.so CACHE FILEPATH "List of soxr libraries")
|
||||
endif ()
|
23
cmake/externals/tbb/AndroidTBBLibCopy.cmake
vendored
Normal file
23
cmake/externals/tbb/AndroidTBBLibCopy.cmake
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
# AndroidTBBLibCopy.cmake
|
||||
# cmake/externals/tbb
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 18, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
# first find the so files in the source dir
|
||||
file(GLOB_RECURSE _TBB_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/build/*.so")
|
||||
|
||||
# raise an error if we found none
|
||||
if (NOT _TBB_LIBRARIES)
|
||||
message(FATAL_ERROR "Did not find any compiled TBB libraries")
|
||||
endif ()
|
||||
|
||||
# make the libs directory and copy the resulting files there
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")
|
||||
message(STATUS "Copying TBB Android libs to ${CMAKE_CURRENT_SOURCE_DIR}/lib")
|
||||
file(COPY ${_TBB_LIBRARIES} DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/lib")
|
105
cmake/externals/tbb/CMakeLists.txt
vendored
Normal file
105
cmake/externals/tbb/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
set(EXTERNAL_NAME tbb)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
if (ANDROID)
|
||||
|
||||
find_program(NDK_BUILD_COMMAND NAMES ndk-build DOC "Path to the ndk-build command")
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150209oss_src.tgz
|
||||
URL_MD5 f09c9abe8ec74e6558c1f89cebbe2893
|
||||
BUILD_COMMAND ${NDK_BUILD_COMMAND} --directory=jni target=android tbb tbbmalloc arch=arm
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ""
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/AndroidTBBLibCopy.cmake
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
else ()
|
||||
if (APPLE)
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_osx.tgz)
|
||||
set(DOWNLOAD_MD5 3e683c19792582b61382e0d760ea5db2)
|
||||
elseif (WIN32)
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_win.zip)
|
||||
set(DOWNLOAD_MD5 e19c184f2bb0e944fc5f397f1e34ca84)
|
||||
else ()
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_lin.tgz)
|
||||
set(DOWNLOAD_MD5 d9c2a6f7807df364be44a8c3c05e8457)
|
||||
endif ()
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL ${DOWNLOAD_URL}
|
||||
BUILD_COMMAND ""
|
||||
CONFIGURE_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD ON
|
||||
)
|
||||
endif ()
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (APPLE)
|
||||
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/libc++")
|
||||
set(_LIB_PREFIX "lib")
|
||||
set(_LIB_EXT "dylib")
|
||||
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
change-install-name
|
||||
COMMENT "Calling install_name_tool on TBB libraries to fix install name for dylib linking"
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/OSXTBBInstallNameChange.cmake
|
||||
DEPENDEES install
|
||||
WORKING_DIRECTORY <SOURCE_DIR>
|
||||
LOG 1
|
||||
)
|
||||
|
||||
elseif (WIN32)
|
||||
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/ia32/vc12")
|
||||
set(_LIB_EXT "lib")
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/ia32/vc12" CACHE PATH "Path to TBB DLLs")
|
||||
elseif (ANDROID)
|
||||
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib")
|
||||
set(_LIB_PREFIX "lib")
|
||||
set(_LIB_EXT "so")
|
||||
elseif (UNIX)
|
||||
set(_LIB_PREFIX "lib")
|
||||
set(_LIB_EXT "so")
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_TBB_ARCH_DIR "intel64")
|
||||
else()
|
||||
set(_TBB_ARCH_DIR "ia32")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE GCC_VERSION
|
||||
)
|
||||
|
||||
if (GCC_VERSION VERSION_GREATER 4.4 OR GCC_VERSION VERSION_EQUAL 4.4)
|
||||
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/${_TBB_ARCH_DIR}/gcc4.4")
|
||||
elseif (GCC_VERSION VERSION_GREATER 4.1 OR GCC_VERSION VERSION_EQUAL 4.1)
|
||||
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/${_TBB_ARCH_DIR}/gcc4.1")
|
||||
else ()
|
||||
message(STATUS "Could not find a compatible version of Threading Building Blocks library for your compiler.")
|
||||
endif ()
|
||||
|
||||
|
||||
endif ()
|
||||
|
||||
if (DEFINED _TBB_LIB_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbb_debug.${_LIB_EXT} CACHE FILEPATH "TBB debug library location")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbb.${_LIB_EXT} CACHE FILEPATH "TBB release library location")
|
||||
set(${EXTERNAL_NAME_UPPER}_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbbmalloc_debug.${_LIB_EXT} CACHE FILEPATH "TBB malloc debug library location")
|
||||
set(${EXTERNAL_NAME_UPPER}_MALLOC_LIBRARY_RELEASE ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbbmalloc.${_LIB_EXT} CACHE FILEPATH "TBB malloc release library location")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE "List of tbb include directories")
|
||||
endif ()
|
59
cmake/externals/tbb/OSXTBBInstallNameChange.cmake
vendored
Normal file
59
cmake/externals/tbb/OSXTBBInstallNameChange.cmake
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
#
|
||||
# OSXTBBInstallNameChange.cmake
|
||||
# cmake/externals/tbb
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 20, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
# first find the so files in the source dir
|
||||
set(_TBB_LIBRARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/libc++)
|
||||
file(GLOB_RECURSE _TBB_LIBRARIES "${_TBB_LIBRARY_DIR}/*.dylib")
|
||||
|
||||
# raise an error if we found none
|
||||
if (NOT _TBB_LIBRARIES)
|
||||
message(FATAL_ERROR "Did not find any TBB libraries")
|
||||
endif ()
|
||||
|
||||
# find the install_name_tool command
|
||||
find_program(INSTALL_NAME_TOOL_COMMAND NAMES install_name_tool DOC "Path to the install_name_tool command")
|
||||
|
||||
# find the lipo command
|
||||
find_program(LIPO_COMMAND NAMES lipo DOC "Path to the lipo command")
|
||||
|
||||
# enumerate the libraries
|
||||
foreach(_TBB_LIBRARY ${_TBB_LIBRARIES})
|
||||
get_filename_component(_TBB_LIBRARY_FILENAME ${_TBB_LIBRARY} NAME)
|
||||
|
||||
set(_LIPO_ARGS -remove i386 ${_TBB_LIBRARY_FILENAME} -output ${_TBB_LIBRARY_FILENAME})
|
||||
message(STATUS "${LIPO_COMMAND} ${_LIPO_ARGS}")
|
||||
|
||||
# first we use lipo to remove i386 from each dylib
|
||||
execute_process(
|
||||
COMMAND ${LIPO_COMMAND} ${_LIPO_ARGS}
|
||||
WORKING_DIRECTORY ${_TBB_LIBRARY_DIR}
|
||||
ERROR_VARIABLE _LIPO_ERROR
|
||||
)
|
||||
|
||||
if (_LIPO_ERROR)
|
||||
message(FATAL_ERROR "There was an error removing i386 for ${_TBB_LIBRARY_FILENAME} - ${_LIPO_ERROR}")
|
||||
endif ()
|
||||
|
||||
set(_INSTALL_NAME_ARGS ${INSTALL_NAME_TOOL_COMMAND} -id ${_TBB_LIBRARY} ${_TBB_LIBRARY_FILENAME})
|
||||
|
||||
message(STATUS "${INSTALL_NAME_COMMAND} ${_INSTALL_NAME_ARGS}")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${INSTALL_NAME_COMMAND} ${_INSTALL_NAME_ARGS}
|
||||
WORKING_DIRECTORY ${_TBB_LIBRARY_DIR}
|
||||
ERROR_VARIABLE _INSTALL_NAME_ERROR
|
||||
)
|
||||
|
||||
if (_INSTALL_NAME_ERROR)
|
||||
message(FATAL_ERROR "There was an error changing install name for ${_TBB_LIBRARY_FILENAME} - ${_INSTALL_NAME_ERROR}")
|
||||
endif ()
|
||||
endforeach()
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#
|
||||
# SetupExternalProject.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 13, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(ADD_DEPENDENCY_EXTERNAL_PROJECT _PROJ_NAME)
|
||||
|
||||
string(TOUPPER ${_PROJ_NAME} _PROJ_NAME_UPPER)
|
||||
|
||||
if (NOT DEFINED GET_${_PROJ_NAME_UPPER} OR GET_${_PROJ_NAME_UPPER})
|
||||
if (NOT TARGET ${_PROJ_NAME})
|
||||
add_subdirectory(${EXTERNAL_PROJECT_DIR}/${_PROJ_NAME} ${CMAKE_BINARY_DIR}/externals/${_PROJ_NAME})
|
||||
endif ()
|
||||
|
||||
add_dependencies(${TARGET_NAME} ${_PROJ_NAME})
|
||||
|
||||
endif ()
|
||||
|
||||
endmacro()
|
46
cmake/macros/AddDependencyExternalProjects.cmake
Normal file
46
cmake/macros/AddDependencyExternalProjects.cmake
Normal file
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# AddDependencyExternalProjects.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 13, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(ADD_DEPENDENCY_EXTERNAL_PROJECTS)
|
||||
|
||||
foreach(_PROJ_NAME ${ARGN})
|
||||
|
||||
string(TOUPPER ${_PROJ_NAME} _PROJ_NAME_UPPER)
|
||||
|
||||
# has the user told us they specific don't want this as an external project?
|
||||
if (GET_${_PROJ_NAME_UPPER})
|
||||
# have we already detected we can't have this as external project on this OS?
|
||||
if (NOT DEFINED ${_PROJ_NAME_UPPER}_EXTERNAL_PROJECT OR ${_PROJ_NAME_UPPER}_EXTERNAL_PROJECT)
|
||||
# have we already setup the target?
|
||||
if (NOT TARGET ${_PROJ_NAME})
|
||||
add_subdirectory(${EXTERNAL_PROJECT_DIR}/${_PROJ_NAME} ${EXTERNALS_BINARY_DIR}/${_PROJ_NAME})
|
||||
|
||||
# did we end up adding an external project target?
|
||||
if (NOT TARGET ${_PROJ_NAME})
|
||||
set(${_PROJ_NAME_UPPER}_EXTERNAL_PROJECT FALSE CACHE BOOL "Presence of ${_PROJ_NAME} as external target")
|
||||
|
||||
message(STATUS "${_PROJ_NAME} was not added as an external project target for your OS."
|
||||
" Either your system should already have the external library or you will need to install it separately.")
|
||||
else ()
|
||||
set(${_PROJ_NAME_UPPER}_EXTERNAL_PROJECT TRUE CACHE BOOL "Presence of ${_PROJ_NAME} as external target")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (TARGET ${_PROJ_NAME})
|
||||
add_dependencies(${TARGET_NAME} ${_PROJ_NAME})
|
||||
endif ()
|
||||
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
endforeach()
|
||||
|
||||
endmacro()
|
22
cmake/macros/AddPathsToFixupLibs.cmake
Normal file
22
cmake/macros/AddPathsToFixupLibs.cmake
Normal file
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# AddPathsToFixupLibs.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 17, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(add_paths_to_fixup_libs)
|
||||
foreach(_PATH ${ARGN})
|
||||
set(_TEMP_LIB_PATHS ${FIXUP_LIBS})
|
||||
|
||||
list(APPEND _TEMP_LIB_PATHS ${_PATH})
|
||||
|
||||
list(REMOVE_DUPLICATES _TEMP_LIB_PATHS)
|
||||
|
||||
set(FIXUP_LIBS ${_TEMP_LIB_PATHS} CACHE STRING "Paths for external libraries passed to fixup_bundle" FORCE)
|
||||
endforeach()
|
||||
endmacro()
|
|
@ -15,12 +15,21 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
|
|||
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
|
||||
endforeach()
|
||||
|
||||
#Extract the unique include shader paths
|
||||
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
|
||||
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
|
||||
endforeach()
|
||||
|
||||
|
||||
#Extract the unique include shader paths
|
||||
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
|
||||
#message(Hifi for includes ${INCLUDES})
|
||||
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
|
||||
#message(ready for includes ${SHADER_INCLUDES_PATHS})
|
||||
|
||||
# make the scribe include arguments
|
||||
set(SCRIBE_INCLUDES)
|
||||
|
@ -64,6 +73,17 @@ endfunction()
|
|||
|
||||
|
||||
macro(AUTOSCRIBE_SHADER_LIB)
|
||||
|
||||
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
|
||||
foreach(HIFI_LIBRARY ${ARGN})
|
||||
#if (NOT TARGET ${HIFI_LIBRARY})
|
||||
# file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}/src/)
|
||||
#endif ()
|
||||
|
||||
#file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src/*.slh)
|
||||
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src)
|
||||
endforeach()
|
||||
#message(${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
|
||||
|
||||
file(GLOB_RECURSE SHADER_INCLUDE_FILES src/*.slh)
|
||||
file(GLOB_RECURSE SHADER_SOURCE_FILES src/*.slv src/*.slf)
|
||||
|
|
43
cmake/macros/CopyDllsBesideWindowsExecutable.cmake
Normal file
43
cmake/macros/CopyDllsBesideWindowsExecutable.cmake
Normal file
|
@ -0,0 +1,43 @@
|
|||
#
|
||||
# CopyDllsBesideWindowsExecutable.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 17, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(COPY_DLLS_BESIDE_WINDOWS_EXECUTABLE)
|
||||
|
||||
if (WIN32)
|
||||
configure_file(
|
||||
${HIFI_CMAKE_DIR}/templates/FixupBundlePostBuild.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/FixupBundlePostBuild.cmake
|
||||
@ONLY
|
||||
)
|
||||
|
||||
# add a post-build command to copy DLLs beside the executable
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DBUNDLE_EXECUTABLE=$<TARGET_FILE:${TARGET_NAME}>
|
||||
-P ${CMAKE_CURRENT_BINARY_DIR}/FixupBundlePostBuild.cmake
|
||||
)
|
||||
|
||||
find_program(WINDEPLOYQT_COMMAND windeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT WINDEPLOYQT_COMMAND)
|
||||
message(FATAL_ERROR "Could not find windeployqt at ${QT_DIR}/bin. windeployqt is required.")
|
||||
endif ()
|
||||
|
||||
# add a post-build command to call windeployqt to copy Qt plugins
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} --no-libraries $<TARGET_FILE:${TARGET_NAME}>"
|
||||
)
|
||||
endif ()
|
||||
endmacro()
|
|
@ -1,16 +0,0 @@
|
|||
#
|
||||
# IncludeBullet.cmake
|
||||
#
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(INCLUDE_BULLET)
|
||||
find_package(Bullet REQUIRED)
|
||||
include_directories("${BULLET_INCLUDE_DIRS}")
|
||||
if (APPLE OR UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${BULLET_INCLUDE_DIRS}")
|
||||
endif()
|
||||
endmacro(INCLUDE_BULLET)
|
|
@ -1,22 +0,0 @@
|
|||
#
|
||||
# IncludeDependencyIncludes.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on August 8, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(INCLUDE_DEPENDENCY_INCLUDES)
|
||||
if (${TARGET_NAME}_DEPENDENCY_INCLUDES)
|
||||
list(REMOVE_DUPLICATES ${TARGET_NAME}_DEPENDENCY_INCLUDES)
|
||||
|
||||
# include those in our own target
|
||||
include_directories(SYSTEM ${${TARGET_NAME}_DEPENDENCY_INCLUDES})
|
||||
|
||||
# set the property on this target so it can be retreived by targets linking to us
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_INCLUDES "${${TARGET_NAME}_DEPENDENCY_INCLUDES}")
|
||||
endif()
|
||||
endmacro(INCLUDE_DEPENDENCY_INCLUDES)
|
32
cmake/macros/SetupExternalsBinaryDir.cmake
Normal file
32
cmake/macros/SetupExternalsBinaryDir.cmake
Normal file
|
@ -0,0 +1,32 @@
|
|||
#
|
||||
# SetupExternalsBinaryDir.cmake
|
||||
# cmake/macros
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 19, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(SETUP_EXTERNALS_BINARY_DIR)
|
||||
|
||||
# get a short name for the generator to use in the path
|
||||
STRING(REGEX REPLACE " " "-" CMAKE_GENERATOR_FOLDER_NAME ${CMAKE_GENERATOR})
|
||||
|
||||
if (MSVC12)
|
||||
set(CMAKE_GENERATOR_FOLDER_NAME "vc12")
|
||||
else ()
|
||||
if (CMAKE_GENERATOR_FOLDER_NAME STREQUAL "Unix-Makefiles")
|
||||
set(CMAKE_GENERATOR_FOLDER_NAME "makefiles")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(EXTERNALS_BINARY_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build-ext")
|
||||
if (ANDROID)
|
||||
set(EXTERNALS_BINARY_DIR "${EXTERNALS_BINARY_ROOT_DIR}/android/${CMAKE_GENERATOR_FOLDER_NAME}")
|
||||
else ()
|
||||
set(EXTERNALS_BINARY_DIR "${EXTERNALS_BINARY_ROOT_DIR}/${CMAKE_GENERATOR_FOLDER_NAME}")
|
||||
endif ()
|
||||
|
||||
endmacro()
|
|
@ -85,9 +85,7 @@ set(BULLET_INCLUDE_DIRS ${BULLET_INCLUDE_DIR})
|
|||
set(BULLET_LIBRARIES ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY} ${BULLET_SOFTBODY_LIBRARY})
|
||||
|
||||
find_package_handle_standard_args(Bullet "Could NOT find Bullet, try to set the path to Bullet root folder in the system variable BULLET_ROOT_DIR"
|
||||
BULLET_DYNAMICS_LIBRARY BULLET_COLLISION_LIBRARY BULLET_MATH_LIBRARY
|
||||
BULLET_INCLUDE_DIRS
|
||||
BULLET_DYNAMICS_LIBRARY BULLET_COLLISION_LIBRARY BULLET_MATH_LIBRARY BULLET_SOFTBODY_LIBRARY
|
||||
BULLET_LIBRARIES
|
||||
)
|
||||
|
||||
|
||||
)
|
|
@ -24,16 +24,19 @@ if (WIN32)
|
|||
|
||||
find_path(GLEW_INCLUDE_DIRS GL/glew.h PATH_SUFFIXES include HINTS ${GLEW_SEARCH_DIRS})
|
||||
|
||||
find_library(GLEW_LIBRARY_RELEASE glew32s PATH_SUFFIXES "lib/Release/Win32" "lib" HINTS ${GLEW_SEARCH_DIRS})
|
||||
find_library(GLEW_LIBRARY_DEBUG glew32sd PATH_SUFFIXES "lib/Debug/Win32" "lib" HINTS ${GLEW_SEARCH_DIRS})
|
||||
find_library(GLEW_LIBRARY_RELEASE glew32 PATH_SUFFIXES "lib/Release/Win32" "lib" HINTS ${GLEW_SEARCH_DIRS})
|
||||
find_library(GLEW_LIBRARY_DEBUG glew32d PATH_SUFFIXES "lib/Debug/Win32" "lib" HINTS ${GLEW_SEARCH_DIRS})
|
||||
|
||||
find_path(GLEW_DLL_PATH glew32.dll PATH_SUFFIXES "bin/Release/Win32" HINTS ${GLEW_SEARCH_DIRS})
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(GLEW)
|
||||
|
||||
set(GLEW_LIBRARIES ${GLEW_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_INCLUDE_DIRS GLEW_LIBRARIES GLEW_DLL_PATH)
|
||||
|
||||
add_paths_to_fixup_libs(${GLEW_DLL_PATH})
|
||||
endif ()
|
||||
|
||||
set(GLEW_LIBRARIES ${GLEW_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
|
||||
|
||||
mark_as_advanced(GLEW_INCLUDE_DIRS GLEW_LIBRARIES GLEW_SEARCH_DIRS)
|
|
@ -22,4 +22,4 @@ find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_
|
|||
find_library(GVERB_LIBRARIES gverb PATH_SUFFIXES lib HINTS ${GVERB_SEARCH_DIRS})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GVERB DEFAULT_MSG GVERB_INCLUDE_DIRS GVERB_LIBRARIES)
|
||||
find_package_handle_standard_args(Gverb DEFAULT_MSG GVERB_INCLUDE_DIRS GVERB_LIBRARIES)
|
|
@ -20,6 +20,8 @@ find_path(LEAPMOTION_INCLUDE_DIRS Leap.h PATH_SUFFIXES include HINTS ${LEAPMOTIO
|
|||
if (WIN32)
|
||||
find_library(LEAPMOTION_LIBRARY_DEBUG Leapd PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS})
|
||||
find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS})
|
||||
|
||||
find_path(LEAPMOTION_DLL_PATH Leap.dll PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS})
|
||||
elseif (APPLE)
|
||||
find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES lib HINTS ${LEAPMOTION_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
@ -27,9 +29,18 @@ endif ()
|
|||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(LEAPMOTION)
|
||||
|
||||
set(LEAPMOTION_LIBRARIES "${LEAPMOTION_LIBRARY}")
|
||||
set(LEAPMOTION_LIBRARIES ${LEAPMOTION_LIBRARY})
|
||||
|
||||
set(LEAPMOTION_REQUIREMENTS LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES)
|
||||
if (WIN32)
|
||||
list(APPEND LEAPMOTION_REQUIREMENTS LEAPMOTION_DLL_PATH)
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LeapMotion DEFAULT_MSG LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES)
|
||||
find_package_handle_standard_args(LeapMotion DEFAULT_MSG ${LEAPMOTION_REQUIREMENTS})
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${LEAPMOTION_DLL_PATH})
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES LEAPMOTION_SEARCH_DIRS)
|
||||
|
|
|
@ -98,6 +98,9 @@ if (WIN32 AND NOT CYGWIN)
|
|||
select_library_configurations(SSL_EAY)
|
||||
|
||||
set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY})
|
||||
|
||||
find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS})
|
||||
|
||||
elseif (MINGW)
|
||||
# same player, for MinGW
|
||||
set(LIB_EAY_NAMES libeay32)
|
||||
|
@ -218,11 +221,15 @@ endif ()
|
|||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
set(OPENSSL_REQUIREMENTS OPENSSL_LIBRARIES OPENSSL_INCLUDE_DIR)
|
||||
if (WIN32)
|
||||
list(APPEND OPENSSL_REQUIREMENTS OPENSSL_DLL_PATH)
|
||||
endif ()
|
||||
|
||||
if (OPENSSL_VERSION)
|
||||
find_package_handle_standard_args(OpenSSL
|
||||
REQUIRED_VARS
|
||||
OPENSSL_LIBRARIES
|
||||
OPENSSL_INCLUDE_DIR
|
||||
${OPENSSL_REQUIREMENTS}
|
||||
VERSION_VAR
|
||||
OPENSSL_VERSION
|
||||
FAIL_MESSAGE
|
||||
|
@ -230,9 +237,12 @@ if (OPENSSL_VERSION)
|
|||
)
|
||||
else ()
|
||||
find_package_handle_standard_args(OpenSSL "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR"
|
||||
OPENSSL_LIBRARIES
|
||||
OPENSSL_INCLUDE_DIR
|
||||
${OPENSSL_REQUIREMENTS}
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${OPENSSL_DLL_PATH})
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES OPENSSL_SEARCH_DIRS)
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
# Try to find the PrioVR library
|
||||
#
|
||||
# You must provide a PRIOVR_ROOT_DIR which contains lib and include directories
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# PRIOVR_FOUND - system found PrioVR
|
||||
# PRIOVR_INCLUDE_DIRS - the PrioVR include directory
|
||||
# PRIOVR_LIBRARIES - Link this to use PrioVR
|
||||
#
|
||||
# Created on 5/12/2014 by Andrzej Kapolka
|
||||
# Copyright (c) 2014 High Fidelity
|
||||
#
|
||||
|
||||
find_path(PRIOVR_INCLUDE_DIRS yei_skeletal_api.h ${PRIOVR_ROOT_DIR}/include)
|
||||
|
||||
if (WIN32)
|
||||
find_library(PRIOVR_LIBRARIES Skeletal_API.lib ${PRIOVR_ROOT_DIR}/lib)
|
||||
endif (WIN32)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(PrioVR DEFAULT_MSG PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)
|
||||
|
||||
mark_as_advanced(PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES)
|
|
@ -1,39 +0,0 @@
|
|||
#
|
||||
# FindQxmpp.cmake
|
||||
#
|
||||
# Try to find the qxmpp library
|
||||
#
|
||||
# You can provide a QXMPP_ROOT_DIR which contains lib and include directories
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# QXMPP_FOUND - system found qxmpp
|
||||
# QXMPP_INCLUDE_DIRS - the qxmpp include directory
|
||||
# QXMPP_LIBRARIES - Link this to use qxmpp
|
||||
#
|
||||
# Created on 3/10/2014 by Stephen Birarda
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("qxmpp")
|
||||
|
||||
find_path(QXMPP_INCLUDE_DIRS QXmppClient.h PATH_SUFFIXES include/qxmpp HINTS ${QXMPP_SEARCH_DIRS})
|
||||
|
||||
find_library(QXMPP_LIBRARY_RELEASE NAMES qxmpp PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})
|
||||
find_library(QXMPP_LIBRARY_DEBUG NAMES qxmpp_d PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS})
|
||||
|
||||
find_package(Qt5 COMPONENTS Xml REQUIRED)
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(QXMPP)
|
||||
|
||||
set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}" Qt5::Xml)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(QXmpp DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_LIBRARY)
|
||||
|
||||
mark_as_advanced(QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_SEARCH_DIRS)
|
|
@ -138,6 +138,10 @@ IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|||
/opt/csw
|
||||
/opt
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
find_path(SDL2_DLL_PATH SDL2.dll PATH_SUFFIXES lib/x64 HINTS ${SDL2_SEARCH_DIRS})
|
||||
endif ()
|
||||
# On 32bit build find the 32bit libs
|
||||
ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
FIND_LIBRARY(SDL2_LIBRARY_TEMP SDL2
|
||||
|
@ -153,50 +157,12 @@ ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|||
/opt/csw
|
||||
/opt
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
find_path(SDL2_DLL_PATH SDL2.dll PATH_SUFFIXES lib/x86 HINTS ${SDL2_SEARCH_DIRS})
|
||||
endif ()
|
||||
ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
|
||||
IF(NOT SDL2_BUILDING_LIBRARY)
|
||||
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
|
||||
# Non-OS X framework versions expect you to also dynamically link to
|
||||
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
|
||||
# seem to provide SDL2main for compatibility even though they don't
|
||||
# necessarily need it.
|
||||
# Lookup the 64 bit libs on x64
|
||||
IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
FIND_LIBRARY(SDL2MAIN_LIBRARY
|
||||
NAMES SDL2main
|
||||
HINTS
|
||||
${SDL2_SEARCH_DIRS}
|
||||
$ENV{SDL2}
|
||||
PATH_SUFFIXES lib64 lib
|
||||
lib/x64
|
||||
x86_64-w64-mingw32/lib
|
||||
PATHS
|
||||
/sw
|
||||
/opt/local
|
||||
/opt/csw
|
||||
/opt
|
||||
)
|
||||
# On 32bit build find the 32bit libs
|
||||
ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
FIND_LIBRARY(SDL2MAIN_LIBRARY
|
||||
NAMES SDL2main
|
||||
HINTS
|
||||
${SDL2_SEARCH_DIRS}
|
||||
$ENV{SDL2}
|
||||
PATH_SUFFIXES lib
|
||||
lib/x86
|
||||
i686-w64-mingw32/lib
|
||||
PATHS
|
||||
/sw
|
||||
/opt/local
|
||||
/opt/csw
|
||||
/opt
|
||||
)
|
||||
ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
|
||||
ENDIF(NOT SDL2_BUILDING_LIBRARY)
|
||||
|
||||
# SDL2 may require threads on your system.
|
||||
# The Apple build may not need an explicit flag because one of the
|
||||
# frameworks may already provide it.
|
||||
|
@ -214,13 +180,6 @@ ENDIF(MINGW)
|
|||
|
||||
SET(SDL2_FOUND "NO")
|
||||
IF(SDL2_LIBRARY_TEMP)
|
||||
# For SDL2main
|
||||
IF(NOT SDL2_BUILDING_LIBRARY)
|
||||
IF(SDL2MAIN_LIBRARY)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
|
||||
ENDIF(SDL2MAIN_LIBRARY)
|
||||
ENDIF(NOT SDL2_BUILDING_LIBRARY)
|
||||
|
||||
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
|
||||
# CMake doesn't display the -framework Cocoa string in the UI even
|
||||
# though it actually is there if I modify a pre-used variable.
|
||||
|
@ -253,4 +212,13 @@ ENDIF(SDL2_LIBRARY_TEMP)
|
|||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
|
||||
set(SDL2_REQUIREMENTS SDL2_LIBRARY SDL2_INCLUDE_DIR)
|
||||
if (WIN32)
|
||||
list(APPEND SDL2_REQUIREMENTS SDL2_DLL_PATH)
|
||||
endif ()
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS ${SDL2_REQUIREMENTS})
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${SDL2_DLL_PATH})
|
||||
endif ()
|
||||
|
|
|
@ -32,14 +32,27 @@ elseif (UNIX)
|
|||
elseif (WIN32)
|
||||
find_library(SIXENSE_LIBRARY_RELEASE lib/win32/release_dll/sixense.lib HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
find_library(SIXENSE_LIBRARY_DEBUG lib/win32/debug_dll/sixensed.lib HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
|
||||
find_path(SIXENSE_DEBUG_DLL_PATH sixensed.dll PATH_SUFFIXES bin/win32/debug_dll HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
find_path(SIXENSE_RELEASE_DLL_PATH sixense.dll PATH_SUFFIXES bin/win32/release_dll HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/win32/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(SIXENSE)
|
||||
|
||||
set(SIXENSE_REQUIREMENTS SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
|
||||
if (WIN32)
|
||||
list(APPEND SIXENSE_REQUIREMENTS SIXENSE_DEBUG_DLL_PATH SIXENSE_RELEASE_DLL_PATH SIXENSE_DEVICE_DLL_PATH)
|
||||
endif ()
|
||||
|
||||
set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Sixense DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
|
||||
find_package_handle_standard_args(Sixense DEFAULT_MSG ${SIXENSE_REQUIREMENTS})
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${SIXENSE_DEBUG_DLL_PATH} ${SIXENSE_RELEASE_DLL_PATH} ${SIXENSE_DEVICE_DLL_PATH})
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS)
|
||||
|
|
|
@ -24,7 +24,20 @@ hifi_library_search_hints("soxr")
|
|||
find_path(SOXR_INCLUDE_DIRS soxr.h PATH_SUFFIXES include HINTS ${SOXR_SEARCH_DIRS})
|
||||
find_library(SOXR_LIBRARIES NAMES soxr PATH_SUFFIXES lib HINTS ${SOXR_SEARCH_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
find_path(SOXR_DLL_PATH soxr.dll PATH_SUFFIXES bin HINTS ${SOXR_SEARCH_DIRS})
|
||||
endif()
|
||||
|
||||
set(SOXR_REQUIREMENTS SOXR_INCLUDE_DIRS SOXR_LIBRARIES)
|
||||
if (WIN32)
|
||||
list(APPEND SOXR_REQUIREMENTS SOXR_DLL_PATH)
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(SOXR DEFAULT_MSG SOXR_INCLUDE_DIRS SOXR_LIBRARIES)
|
||||
find_package_handle_standard_args(Soxr DEFAULT_MSG ${SOXR_REQUIREMENTS})
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${SOXR_DLL_PATH})
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(SOXR_INCLUDE_DIRS SOXR_LIBRARIES SOXR_SEARCH_DIRS)
|
|
@ -56,6 +56,9 @@ elseif (WIN32)
|
|||
endif()
|
||||
|
||||
set(_TBB_LIB_DIR "lib/${_TBB_ARCH_DIR}/vc12")
|
||||
|
||||
find_path(TBB_DLL_PATH tbb_debug.dll PATH_SUFFIXES "bin/${_TBB_ARCH_DIR}/vc12" HINTS ${TBB_SEARCH_DIRS})
|
||||
|
||||
elseif (ANDROID)
|
||||
set(_TBB_DEFAULT_INSTALL_DIR "/tbb")
|
||||
set(_TBB_LIB_NAME "tbb")
|
||||
|
@ -77,6 +80,15 @@ include(FindPackageHandleStandardArgs)
|
|||
select_library_configurations(TBB)
|
||||
select_library_configurations(TBB_MALLOC)
|
||||
|
||||
find_package_handle_standard_args(TBB DEFAULT_MSG TBB_LIBRARY TBB_MALLOC_LIBRARY TBB_INCLUDE_DIRS)
|
||||
set(TBB_REQUIREMENTS TBB_LIBRARY TBB_MALLOC_LIBRARY TBB_INCLUDE_DIRS)
|
||||
if (WIN32)
|
||||
list(APPEND TBB_REQUIREMENTS TBB_DLL_PATH)
|
||||
endif ()
|
||||
|
||||
find_package_handle_standard_args(TBB DEFAULT_MSG ${TBB_REQUIREMENTS})
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${TBB_DLL_PATH})
|
||||
endif ()
|
||||
|
||||
set(TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY})
|
||||
|
|
59
cmake/modules/FindVHACD.cmake
Normal file
59
cmake/modules/FindVHACD.cmake
Normal file
|
@ -0,0 +1,59 @@
|
|||
#
|
||||
# FindVHACD.cmake
|
||||
#
|
||||
# Try to find the V-HACD library that decomposes a 3D surface into a set of "near" convex parts.
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# VHACD_FOUND - system found V-HACD
|
||||
# VHACD_INCLUDE_DIRS - the V-HACD include directory
|
||||
# VHACD_LIBRARIES - link to this to use V-HACD
|
||||
#
|
||||
# Created on 2/20/2015 by Virendra Singh
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("vhacd")
|
||||
|
||||
macro(_FIND_VHACD_LIBRARY _var)
|
||||
set(_${_var}_NAMES ${ARGN})
|
||||
find_library(${_var}_LIBRARY_RELEASE
|
||||
NAMES ${_${_var}_NAMES}
|
||||
HINTS
|
||||
${VHACD_SEARCH_DIRS}
|
||||
$ENV{VHACD_ROOT_DIR}
|
||||
PATH_SUFFIXES lib lib/Release
|
||||
)
|
||||
|
||||
find_library(${_var}_LIBRARY_DEBUG
|
||||
NAMES ${_${_var}_NAMES}
|
||||
HINTS
|
||||
${VHACD_SEARCH_DIRS}
|
||||
$ENV{VHACD_ROOT_DIR}
|
||||
PATH_SUFFIXES lib lib/Debug
|
||||
)
|
||||
|
||||
select_library_configurations(${_var})
|
||||
|
||||
mark_as_advanced(${_var}_LIBRARY)
|
||||
mark_as_advanced(${_var}_LIBRARY)
|
||||
endmacro()
|
||||
|
||||
|
||||
find_path(VHACD_INCLUDE_DIRS VHACD.h PATH_SUFFIXES include HINTS ${VHACD_SEARCH_DIRS} $ENV{VHACD_ROOT_DIR})
|
||||
if(NOT WIN32)
|
||||
_FIND_VHACD_LIBRARY(VHACD libVHACD.a)
|
||||
else()
|
||||
_FIND_VHACD_LIBRARY(VHACD VHACD_LIB)
|
||||
endif()
|
||||
set(VHACD_LIBRARIES ${VHACD_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(VHACD "Could NOT find VHACD, try to set the path to VHACD root folder in the system variable VHACD_ROOT_DIR or create a directory vhacd in HIFI_LIB_DIR and paste the necessary files there"
|
||||
VHACD_INCLUDE_DIRS VHACD_LIBRARIES)
|
||||
|
||||
mark_as_advanced(VHACD_INCLUDE_DIRS VHACD_LIBRARIES VHACD_SEARCH_DIRS)
|
14
cmake/templates/FixupBundlePostBuild.cmake.in
Normal file
14
cmake/templates/FixupBundlePostBuild.cmake.in
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# FixupBundlePostBuild.cmake.in
|
||||
# cmake/templates
|
||||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Stephen Birarda on February 13, 2014
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include(BundleUtilities)
|
||||
message(STATUS "FIXUP_LIBS for fixup_bundle called for bundle ${BUNDLE_EXECUTABLE} are @FIXUP_LIBS@")
|
||||
fixup_bundle("${BUNDLE_EXECUTABLE}" "" "@FIXUP_LIBS@")
|
|
@ -52,4 +52,4 @@ include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
|||
# append OpenSSL to our list of libraries to link
|
||||
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})
|
||||
|
||||
include_dependency_includes()
|
||||
copy_dlls_beside_windows_executable()
|
|
@ -32,6 +32,7 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <ShutdownEventListener.h>
|
||||
#include <UUID.h>
|
||||
#include <LogHandler.h>
|
||||
|
||||
#include "DomainServerNodeData.h"
|
||||
|
||||
|
@ -246,19 +247,14 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
auto nodeList = DependencyManager::set<LimitedNodeList>(domainServerPort, domainServerDTLSPort);
|
||||
|
||||
// no matter the local port, save it to shared mem so that local assignment clients can ask what it is
|
||||
QSharedMemory* sharedPortMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
|
||||
quint16 localPort = nodeList->getNodeSocket().localPort();
|
||||
|
||||
// attempt to create the shared memory segment
|
||||
if (sharedPortMem->create(sizeof(localPort)) || sharedPortMem->attach()) {
|
||||
sharedPortMem->lock();
|
||||
memcpy(sharedPortMem->data(), &localPort, sizeof(localPort));
|
||||
sharedPortMem->unlock();
|
||||
|
||||
qDebug() << "Wrote local listening port" << localPort << "to shared memory at key" << DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY;
|
||||
} else {
|
||||
qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children.";
|
||||
}
|
||||
nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this, nodeList->getNodeSocket().localPort());
|
||||
|
||||
// store our local http ports in shared memory
|
||||
quint16 localHttpPort = DOMAIN_SERVER_HTTP_PORT;
|
||||
nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_HTTP_PORT_SMEM_KEY, this, localHttpPort);
|
||||
quint16 localHttpsPort = DOMAIN_SERVER_HTTPS_PORT;
|
||||
nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_HTTPS_PORT_SMEM_KEY, this, localHttpsPort);
|
||||
|
||||
|
||||
// set our LimitedNodeList UUID to match the UUID from our config
|
||||
// nodes will currently use this to add resources to data-web that relate to our domain
|
||||
|
@ -570,8 +566,7 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
|||
}
|
||||
|
||||
const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
|
||||
<< NodeType::AvatarMixer << NodeType::EntityServer
|
||||
<< NodeType::MetavoxelServer;
|
||||
<< NodeType::AvatarMixer << NodeType::EntityServer;
|
||||
|
||||
void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSockAddr& senderSockAddr) {
|
||||
|
||||
|
@ -955,8 +950,10 @@ void DomainServer::readAvailableDatagrams() {
|
|||
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Received a request for assignment type [^ ]+ from [^ ]+");
|
||||
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessageTimer.restart();
|
||||
}
|
||||
|
||||
|
@ -986,6 +983,8 @@ void DomainServer::readAvailableDatagrams() {
|
|||
} else {
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Unable to fulfill assignment request of type [^ ]+ from [^ ]+");
|
||||
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessageTimer.restart();
|
||||
|
|
|
@ -29,15 +29,21 @@ var RIGHT_BUTTON_FWD = 11;
|
|||
var RIGHT_BUTTON_3 = 9;
|
||||
|
||||
var BALL_RADIUS = 0.08;
|
||||
var GRAVITY_STRENGTH = 1.0;
|
||||
var GRAVITY_STRENGTH = 3.0;
|
||||
|
||||
var HELD_COLOR = { red: 240, green: 0, blue: 0 };
|
||||
var THROWN_COLOR = { red: 128, green: 0, blue: 0 };
|
||||
|
||||
var averageLinearVelocity = [ { x: 0, y: 0, z : 0 }, { x: 0, y: 0, z : 0 } ];
|
||||
|
||||
var LIFETIME_SECONDS = 600;
|
||||
|
||||
var BALL_MODEL_URL = "https://hifi-public.s3.amazonaws.com/ryan/baseball4.fbx";
|
||||
|
||||
var leftBallAlreadyInHand = false;
|
||||
var rightBallAlreadyInHand = false;
|
||||
var leftHandEntity;
|
||||
var rightHandEntity;
|
||||
var leftHandEntity = false;
|
||||
var rightHandEntity = false;
|
||||
|
||||
var newSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw");
|
||||
var catchSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw");
|
||||
|
@ -67,28 +73,51 @@ function checkControllerSide(whichSide) {
|
|||
var BUTTON_3;
|
||||
var TRIGGER;
|
||||
var palmPosition;
|
||||
var palmRotation;
|
||||
var ballAlreadyInHand;
|
||||
var handMessage;
|
||||
var linearVelocity;
|
||||
var angularVelocity;
|
||||
var AVERAGE_FACTOR = 0.33;
|
||||
|
||||
if (whichSide == LEFT_PALM) {
|
||||
BUTTON_FWD = LEFT_BUTTON_FWD;
|
||||
BUTTON_3 = LEFT_BUTTON_3;
|
||||
TRIGGER = 0;
|
||||
palmPosition = Controller.getSpatialControlPosition(LEFT_PALM);
|
||||
palmRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(LEFT_PALM));
|
||||
ballAlreadyInHand = leftBallAlreadyInHand;
|
||||
handMessage = "LEFT";
|
||||
averageLinearVelocity[0] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, Controller.getSpatialControlVelocity(LEFT_TIP)),
|
||||
Vec3.multiply(1.0 - AVERAGE_FACTOR, averageLinearVelocity[0]));
|
||||
linearVelocity = averageLinearVelocity[0];
|
||||
angularVelocity = Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getSpatialControlRawAngularVelocity(LEFT_TIP));
|
||||
angularVelocity = Vec3.multiply(180.0 / Math.PI, angularVelocity);
|
||||
} else {
|
||||
BUTTON_FWD = RIGHT_BUTTON_FWD;
|
||||
BUTTON_3 = RIGHT_BUTTON_3;
|
||||
TRIGGER = 1;
|
||||
palmPosition = Controller.getSpatialControlPosition(RIGHT_PALM);
|
||||
palmRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(RIGHT_PALM));
|
||||
ballAlreadyInHand = rightBallAlreadyInHand;
|
||||
averageLinearVelocity[1] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, Controller.getSpatialControlVelocity(RIGHT_TIP)),
|
||||
Vec3.multiply(1.0 - AVERAGE_FACTOR, averageLinearVelocity[1]));
|
||||
linearVelocity = averageLinearVelocity[1];
|
||||
angularVelocity = Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getSpatialControlRawAngularVelocity(RIGHT_TIP));
|
||||
angularVelocity = Vec3.multiply(180.0 / Math.PI, angularVelocity);
|
||||
handMessage = "RIGHT";
|
||||
}
|
||||
|
||||
var grabButtonPressed = (Controller.isButtonPressed(BUTTON_FWD) || Controller.isButtonPressed(BUTTON_3) || (Controller.getTriggerValue(TRIGGER) > 0.5));
|
||||
|
||||
// If I don't currently have a ball in my hand, then try to catch closest one
|
||||
if (leftHandEntity && !leftHandEntity.isKnownID) {
|
||||
leftHandEntity = Entities.identifyEntity(leftHandEntity);
|
||||
}
|
||||
if (rightHandEntity && !rightHandEntity.isKnownID) {
|
||||
rightHandEntity = Entities.identifyEntity(rightHandEntity);
|
||||
}
|
||||
|
||||
if (!ballAlreadyInHand && grabButtonPressed) {
|
||||
var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius);
|
||||
|
||||
|
@ -107,13 +136,14 @@ function checkControllerSide(whichSide) {
|
|||
var properties = { position: { x: ballPosition.x,
|
||||
y: ballPosition.y,
|
||||
z: ballPosition.z },
|
||||
color: HELD_COLOR,
|
||||
rotation: palmRotation,
|
||||
color: HELD_COLOR,
|
||||
velocity : { x: 0, y: 0, z: 0},
|
||||
lifetime : 600,
|
||||
inHand: true };
|
||||
gravity: { x: 0, y: 0, z: 0}
|
||||
};
|
||||
Entities.editEntity(closestEntity, properties);
|
||||
|
||||
Audio.playSound(catchSound, { position: ballPosition });
|
||||
Audio.playSound(catchSound, { position: ballPosition });
|
||||
|
||||
return; // exit early
|
||||
}
|
||||
|
@ -129,18 +159,20 @@ function checkControllerSide(whichSide) {
|
|||
if (grabButtonPressed && !ballAlreadyInHand) {
|
||||
var ballPosition = getBallHoldPosition(whichSide);
|
||||
var properties = {
|
||||
type: "Sphere",
|
||||
type: "Model",
|
||||
modelURL: BALL_MODEL_URL,
|
||||
position: { x: ballPosition.x,
|
||||
y: ballPosition.y,
|
||||
z: ballPosition.z },
|
||||
z: ballPosition.z },
|
||||
rotation: palmRotation,
|
||||
velocity: { x: 0, y: 0, z: 0},
|
||||
gravity: { x: 0, y: 0, z: 0},
|
||||
inHand: true,
|
||||
dimensions: { x: BALL_RADIUS * 2, y: BALL_RADIUS * 2, z: BALL_RADIUS * 2 },
|
||||
damping: 0.00001,
|
||||
shapeType: "sphere",
|
||||
collisionsWillMove: false,
|
||||
color: HELD_COLOR,
|
||||
|
||||
lifetime: 600 // 10 seconds - same as default, not needed but here as an example
|
||||
lifetime: LIFETIME_SECONDS
|
||||
};
|
||||
|
||||
newEntity = Entities.addEntity(properties);
|
||||
|
@ -174,21 +206,20 @@ function checkControllerSide(whichSide) {
|
|||
var properties = { position: { x: ballPosition.x,
|
||||
y: ballPosition.y,
|
||||
z: ballPosition.z },
|
||||
rotation: palmRotation,
|
||||
velocity: { x: 0, y: 0, z: 0},
|
||||
gravity: { x: 0, y: 0, z: 0},
|
||||
};
|
||||
Entities.editEntity(handEntity, properties);
|
||||
} else {
|
||||
debugPrint(">>>>> " + handMessage + "-BALL IN HAND, not grabbing, THROW!!!");
|
||||
// If toy ball just released, add velocity to it!
|
||||
var tipVelocity = Controller.getSpatialControlVelocity(whichTip);
|
||||
var THROWN_VELOCITY_SCALING = 1.5;
|
||||
var properties = {
|
||||
velocity: { x: tipVelocity.x * THROWN_VELOCITY_SCALING,
|
||||
y: tipVelocity.y * THROWN_VELOCITY_SCALING,
|
||||
z: tipVelocity.z * THROWN_VELOCITY_SCALING } ,
|
||||
velocity: linearVelocity,
|
||||
rotation: palmRotation,
|
||||
angularVelocity: angularVelocity,
|
||||
collisionsWillMove: true,
|
||||
inHand: false,
|
||||
color: THROWN_COLOR,
|
||||
lifetime: 10,
|
||||
gravity: { x: 0, y: -GRAVITY_STRENGTH, z: 0},
|
||||
};
|
||||
|
||||
|
@ -216,7 +247,7 @@ function checkController(deltaTime) {
|
|||
|
||||
// this is expected for hydras
|
||||
if (!(numberOfButtons==12 && numberOfTriggers == 2 && controllersPerTrigger == 2)) {
|
||||
debugPrint("no hydra connected?");
|
||||
debugPrint("total buttons = " + numberOfButtons + ", Triggers = " + numberOfTriggers + ", controllers/trigger = " + controllersPerTrigger);
|
||||
return; // bail if no hydra
|
||||
}
|
||||
|
||||
|
|
|
@ -53,8 +53,10 @@ function shootDice(position, velocity) {
|
|||
position: position,
|
||||
velocity: velocity,
|
||||
rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360),
|
||||
angularVelocity: { x: Math.random() * 100, y: Math.random() * 100, z: Math.random() * 100 },
|
||||
lifetime: LIFETIME,
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
shapeType: "box",
|
||||
collisionsWillMove: true
|
||||
}));
|
||||
position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation()))));
|
||||
|
|
|
@ -81,6 +81,8 @@ var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled";
|
|||
var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
|
||||
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
|
||||
|
||||
var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain."
|
||||
|
||||
var modelURLs = [
|
||||
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx",
|
||||
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush1.fbx",
|
||||
|
@ -177,25 +179,29 @@ var toolBar = (function () {
|
|||
|
||||
that.setActive = function(active) {
|
||||
if (active != isActive) {
|
||||
isActive = active;
|
||||
if (!isActive) {
|
||||
entityListTool.setVisible(false);
|
||||
gridTool.setVisible(false);
|
||||
grid.setEnabled(false);
|
||||
propertiesTool.setVisible(false);
|
||||
selectionManager.clearSelections();
|
||||
cameraManager.disable();
|
||||
if (active && !Entities.canAdjustLocks()) {
|
||||
Window.alert(INSUFFICIENT_PERMISSIONS_ERROR_MSG);
|
||||
} else {
|
||||
hasShownPropertiesTool = false;
|
||||
cameraManager.enable();
|
||||
entityListTool.setVisible(true);
|
||||
gridTool.setVisible(true);
|
||||
grid.setEnabled(true);
|
||||
propertiesTool.setVisible(true);
|
||||
Window.setFocus();
|
||||
isActive = active;
|
||||
if (!isActive) {
|
||||
entityListTool.setVisible(false);
|
||||
gridTool.setVisible(false);
|
||||
grid.setEnabled(false);
|
||||
propertiesTool.setVisible(false);
|
||||
selectionManager.clearSelections();
|
||||
cameraManager.disable();
|
||||
} else {
|
||||
hasShownPropertiesTool = false;
|
||||
cameraManager.enable();
|
||||
entityListTool.setVisible(true);
|
||||
gridTool.setVisible(true);
|
||||
grid.setEnabled(true);
|
||||
propertiesTool.setVisible(true);
|
||||
Window.setFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
toolBar.selectTool(activeButton, active);
|
||||
toolBar.selectTool(activeButton, isActive);
|
||||
};
|
||||
|
||||
var RESIZE_INTERVAL = 50;
|
||||
|
@ -396,6 +402,16 @@ var toolBar = (function () {
|
|||
return handled;
|
||||
}
|
||||
|
||||
Window.domainChanged.connect(function() {
|
||||
that.setActive(false);
|
||||
});
|
||||
|
||||
Entities.canAdjustLocksChanged.connect(function(canAdjustLocks) {
|
||||
if (isActive && !canAdjustLocks) {
|
||||
that.setActive(false);
|
||||
}
|
||||
});
|
||||
|
||||
that.cleanup = function () {
|
||||
toolBar.cleanup();
|
||||
};
|
||||
|
@ -930,24 +946,37 @@ PropertiesTool = function(opts) {
|
|||
data = {
|
||||
type: 'update',
|
||||
};
|
||||
if (selectionManager.hasSelection()) {
|
||||
data.id = selectionManager.selections[0].id;
|
||||
data.properties = Entities.getEntityProperties(selectionManager.selections[0]);
|
||||
data.properties.rotation = Quat.safeEulerAngles(data.properties.rotation);
|
||||
var selections = [];
|
||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||
var entity = {};
|
||||
entity.id = selectionManager.selections[i].id;
|
||||
entity.properties = Entities.getEntityProperties(selectionManager.selections[i]);
|
||||
entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation);
|
||||
selections.push(entity);
|
||||
}
|
||||
data.selections = selections;
|
||||
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
|
||||
});
|
||||
|
||||
webView.eventBridge.webEventReceived.connect(function(data) {
|
||||
print(data);
|
||||
data = JSON.parse(data);
|
||||
if (data.type == "update") {
|
||||
selectionManager.saveProperties();
|
||||
if (data.properties.rotation !== undefined) {
|
||||
var rotation = data.properties.rotation;
|
||||
data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z);
|
||||
if (selectionManager.selections.length > 1) {
|
||||
properties = {
|
||||
locked: data.properties.locked,
|
||||
visible: data.properties.visible,
|
||||
};
|
||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||
Entities.editEntity(selectionManager.selections[i], properties);
|
||||
}
|
||||
} else {
|
||||
if (data.properties.rotation !== undefined) {
|
||||
var rotation = data.properties.rotation;
|
||||
data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z);
|
||||
}
|
||||
Entities.editEntity(selectionManager.selections[0], data.properties);
|
||||
}
|
||||
Entities.editEntity(selectionManager.selections[0], data.properties);
|
||||
pushCommandForSelections();
|
||||
selectionManager._update();
|
||||
} else if (data.type == "action") {
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
//
|
||||
// globalServicesExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Thijs Wenker on 9/12/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Example usage of the GlobalServices object. You could use it to make your own chatbox.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
function onConnected() {
|
||||
if (GlobalServices.onlineUsers.length > 0) {
|
||||
sendMessageForm()
|
||||
return;
|
||||
}
|
||||
Script.setTimeout(function() { sendMessageForm(); }, 5000);
|
||||
}
|
||||
|
||||
function onDisconnected(reason) {
|
||||
switch(reason) {
|
||||
case "logout":
|
||||
Window.alert("logged out!");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function onOnlineUsersChanged(users) {
|
||||
print(users);
|
||||
}
|
||||
|
||||
function onIncommingMessage(user, message) {
|
||||
print(user + ": " + message);
|
||||
if (message === "hello") {
|
||||
GlobalServices.chat("hello, @" + user + "!");
|
||||
}
|
||||
}
|
||||
|
||||
function sendMessageForm() {
|
||||
var form =
|
||||
[
|
||||
{ label: "To:", options: ["(noone)"].concat(GlobalServices.onlineUsers) },
|
||||
{ label: "Message:", value: "Enter message here" }
|
||||
];
|
||||
if (Window.form("Send message on public chat", form)) {
|
||||
GlobalServices.chat(form[0].value == "(noone)" ? form[1].value : "@" + form[0].value + ", " + form[1].value);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
GlobalServices.connected.connect(onConnected);
|
||||
GlobalServices.disconnected.connect(onDisconnected);
|
||||
GlobalServices.onlineUsersChanged.connect(onOnlineUsersChanged);
|
||||
GlobalServices.incomingMessage.connect(onIncommingMessage);
|
34
examples/example/misc/sunLightExample.js
Normal file
34
examples/example/misc/sunLightExample.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// SunLightExample.js
|
||||
// examples
|
||||
// Sam Gateau
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var intensity = 1.0;
|
||||
var day = 0.0;
|
||||
var hour = 12.0;
|
||||
var longitude = 115.0;
|
||||
var latitude = 31.0;
|
||||
var stageOrientation = Quat.fromPitchYawRollDegrees(0.0, 180.0, 0.0);
|
||||
|
||||
Scene.setStageDayTime(hour);
|
||||
Scene.setStageOrientation(stageOrientation);
|
||||
Scene.setStageLocation(longitude, latitude, 0.0);
|
||||
/*
|
||||
function ticktack() {
|
||||
hour += 0.1;
|
||||
//Scene.setSunIntensity(Math.cos(time));
|
||||
if (hour > 24.0) {
|
||||
hour = 0.0;
|
||||
day++;
|
||||
Scene.setStageYearTime(day);
|
||||
}
|
||||
Scene.setStageDayTime(hour);
|
||||
}
|
||||
|
||||
Script.setInterval(ticktack, 41);
|
||||
*/
|
|
@ -1,27 +0,0 @@
|
|||
//
|
||||
// loadScriptFromMessage.js
|
||||
// examples
|
||||
//
|
||||
// Created by Thijs Wenker on 9/15/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Filters script links out of incomming messages and prompts you to run the script.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
//Javascript link RegEX
|
||||
const JS_LINK_REGEX = /https?:\/\/[^ ]+\.js/i;
|
||||
|
||||
function onIncomingMessage(user, message) {
|
||||
var script_link = JS_LINK_REGEX.exec(message);
|
||||
if (script_link == null) {
|
||||
return;
|
||||
}
|
||||
if (Window.confirm("@" + user + " sent the following script:\n" + script_link + "\nwould you like to run it?")) {
|
||||
Script.load(script_link);
|
||||
}
|
||||
}
|
||||
|
||||
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
|
@ -20,6 +20,7 @@
|
|||
elRefresh = document.getElementById("refresh");
|
||||
elDelete = document.getElementById("delete");
|
||||
elTeleport = document.getElementById("teleport");
|
||||
elNoEntitiesMessage = document.getElementById("no-entities");
|
||||
|
||||
document.getElementById("entity-type").onclick = function() {
|
||||
setSortColumn('type');
|
||||
|
@ -155,11 +156,18 @@
|
|||
}
|
||||
} else if (data.type == "update") {
|
||||
var newEntities = data.entities;
|
||||
for (var i = 0; i < newEntities.length; i++) {
|
||||
var id = newEntities[i].id;
|
||||
addEntity(id, newEntities[i].type, newEntities[i].url);
|
||||
if (newEntities.length == 0) {
|
||||
elEntityTable.style.display = "none";
|
||||
elNoEntitiesMessage.style.display = "block";
|
||||
} else {
|
||||
elEntityTable.style.display = "table";
|
||||
elNoEntitiesMessage.style.display = "none";
|
||||
for (var i = 0; i < newEntities.length; i++) {
|
||||
var id = newEntities[i].id;
|
||||
addEntity(id, newEntities[i].type, newEntities[i].url);
|
||||
}
|
||||
updateSelectedEntities(data.selectedIDs);
|
||||
}
|
||||
updateSelectedEntities(data.selectedIDs);
|
||||
}
|
||||
});
|
||||
setTimeout(refreshEntities, 1000);
|
||||
|
@ -194,6 +202,8 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="no-entities">
|
||||
No entities found within 50 meter radius. Try moving to a different location and refreshing.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -128,21 +128,11 @@
|
|||
|
||||
var elLightSections = document.querySelectorAll(".light-section");
|
||||
var elLightSpotLight = document.getElementById("property-light-spot-light");
|
||||
var elLightDiffuseRed = document.getElementById("property-light-diffuse-red");
|
||||
var elLightDiffuseGreen = document.getElementById("property-light-diffuse-green");
|
||||
var elLightDiffuseBlue = document.getElementById("property-light-diffuse-blue");
|
||||
var elLightColorRed = document.getElementById("property-light-color-red");
|
||||
var elLightColorGreen = document.getElementById("property-light-color-green");
|
||||
var elLightColorBlue = document.getElementById("property-light-color-blue");
|
||||
|
||||
var elLightAmbientRed = document.getElementById("property-light-ambient-red");
|
||||
var elLightAmbientGreen = document.getElementById("property-light-ambient-green");
|
||||
var elLightAmbientBlue = document.getElementById("property-light-ambient-blue");
|
||||
|
||||
var elLightSpecularRed = document.getElementById("property-light-specular-red");
|
||||
var elLightSpecularGreen = document.getElementById("property-light-specular-green");
|
||||
var elLightSpecularBlue = document.getElementById("property-light-specular-blue");
|
||||
|
||||
var elLightConstantAttenuation = document.getElementById("property-light-constant-attenuation");
|
||||
var elLightLinearAttenuation = document.getElementById("property-light-linear-attenuation");
|
||||
var elLightQuadraticAttenuation = document.getElementById("property-light-quadratic-attenuation");
|
||||
var elLightIntensity = document.getElementById("property-light-intensity");
|
||||
var elLightExponent = document.getElementById("property-light-exponent");
|
||||
var elLightCutoff = document.getElementById("property-light-cutoff");
|
||||
|
||||
|
@ -171,12 +161,37 @@
|
|||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
if (data.type == "update") {
|
||||
if (data.properties === undefined) {
|
||||
disableChildren(document.getElementById("properties"), 'input');
|
||||
} else {
|
||||
var properties = data.properties;
|
||||
if (data.selections.length == 0) {
|
||||
elType.innerHTML = "<i>No Selection</i>";
|
||||
elID.innerHTML = "";
|
||||
disableChildren(document.getElementById("properties-list"), 'input');
|
||||
} else if (data.selections.length > 1) {
|
||||
var selections = data.selections;
|
||||
|
||||
elID.innerHTML = data.id;
|
||||
var ids = [];
|
||||
var types = {};
|
||||
|
||||
for (var i = 0; i < selections.length; i++) {
|
||||
ids.push(selections[i].id);
|
||||
var type = selections[i].properties.type;
|
||||
if (types[type] === undefined) {
|
||||
types[type] = 0;
|
||||
}
|
||||
types[type]++;
|
||||
}
|
||||
elID.innerHTML = ids.join("<br>");
|
||||
|
||||
var typeStrs = [];
|
||||
for (type in types) {
|
||||
typeStrs.push(type + " (" + types[type] + ")");
|
||||
}
|
||||
elType.innerHTML = typeStrs.join(", ");
|
||||
|
||||
disableChildren(document.getElementById("properties-list"), 'input');
|
||||
} else {
|
||||
var properties = data.selections[0].properties;
|
||||
|
||||
elID.innerHTML = properties.id;
|
||||
|
||||
elType.innerHTML = properties.type;
|
||||
|
||||
|
@ -290,21 +305,11 @@
|
|||
elLightSections[i].style.display = 'block';
|
||||
}
|
||||
|
||||
elLightDiffuseRed.value = properties.diffuseColor.red;
|
||||
elLightDiffuseGreen.value = properties.diffuseColor.green;
|
||||
elLightDiffuseBlue.value = properties.diffuseColor.blue;
|
||||
elLightColorRed.value = properties.color.red;
|
||||
elLightColorGreen.value = properties.color.green;
|
||||
elLightColorBlue.value = properties.color.blue;
|
||||
|
||||
elLightAmbientRed.value = properties.ambientColor.red;
|
||||
elLightAmbientGreen.value = properties.ambientColor.green;
|
||||
elLightAmbientBlue.value = properties.ambientColor.blue;
|
||||
|
||||
elLightSpecularRed.value = properties.specularColor.red;
|
||||
elLightSpecularGreen.value = properties.specularColor.green;
|
||||
elLightSpecularBlue.value = properties.specularColor.blue;
|
||||
|
||||
elLightConstantAttenuation.value = properties.constantAttenuation;
|
||||
elLightLinearAttenuation.value = properties.linearAttenuation;
|
||||
elLightQuadraticAttenuation.value = properties.quadraticAttenuation;
|
||||
elLightIntensity.value = properties.intensity;
|
||||
elLightExponent.value = properties.exponent;
|
||||
elLightCutoff.value = properties.cutoff;
|
||||
}
|
||||
|
@ -375,27 +380,13 @@
|
|||
|
||||
elLightSpotLight.addEventListener('change', createEmitCheckedPropertyUpdateFunction('isSpotlight'));
|
||||
|
||||
var lightDiffuseChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'diffuseColor', elLightDiffuseRed, elLightDiffuseGreen, elLightDiffuseBlue);
|
||||
elLightDiffuseRed.addEventListener('change', lightDiffuseChangeFunction);
|
||||
elLightDiffuseGreen.addEventListener('change', lightDiffuseChangeFunction);
|
||||
elLightDiffuseBlue.addEventListener('change', lightDiffuseChangeFunction);
|
||||
var lightColorChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'color', elLightColorRed, elLightColorGreen, elLightColorBlue);
|
||||
elLightColorRed.addEventListener('change', lightColorChangeFunction);
|
||||
elLightColorGreen.addEventListener('change', lightColorChangeFunction);
|
||||
elLightColorBlue.addEventListener('change', lightColorChangeFunction);
|
||||
|
||||
var lightAmbientChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'ambientColor', elLightAmbientRed, elLightAmbientGreen, elLightAmbientBlue);
|
||||
elLightAmbientRed.addEventListener('change', lightAmbientChangeFunction);
|
||||
elLightAmbientGreen.addEventListener('change', lightAmbientChangeFunction);
|
||||
elLightAmbientBlue.addEventListener('change', lightAmbientChangeFunction);
|
||||
|
||||
var lightSpecularChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'specularColor', elLightSpecularRed, elLightSpecularGreen, elLightSpecularBlue);
|
||||
elLightSpecularRed.addEventListener('change', lightSpecularChangeFunction);
|
||||
elLightSpecularGreen.addEventListener('change', lightSpecularChangeFunction);
|
||||
elLightSpecularBlue.addEventListener('change', lightSpecularChangeFunction);
|
||||
|
||||
elLightConstantAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('constantAttenuation'));
|
||||
elLightLinearAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('linearAttenuation'));
|
||||
elLightQuadraticAttenuation.addEventListener('change', createEmitNumberPropertyUpdateFunction('quadraticAttenuation'));
|
||||
elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity'));
|
||||
elLightExponent.addEventListener('change', createEmitNumberPropertyUpdateFunction('exponent'));
|
||||
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
|
||||
|
||||
|
@ -448,6 +439,13 @@
|
|||
percentage: parseInt(elRescaleDimensionsPct.value),
|
||||
}));
|
||||
});
|
||||
|
||||
window.onblur = function() {
|
||||
// Fake a change event
|
||||
var ev = document.createEvent("HTMLEvents");
|
||||
ev.initEvent("change", true, true);
|
||||
document.activeElement.dispatchEvent(ev);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
@ -715,55 +713,27 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Diffuse</div>
|
||||
<div class="label">Color</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-diffuse-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-diffuse-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-diffuse-blue"></input></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-color-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-color-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-color-blue"></input></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Ambient</div>
|
||||
<div class="label">Intensity</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-ambient-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-ambient-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-ambient-blue"></input></div>
|
||||
<input class="coord" type='number' id="property-light-intensity"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Specular</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-light-specular-red"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-light-specular-green"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-light-specular-blue"></input></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Constant Attenuation</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-constant-attenuation"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Linear Attenuation</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-linear-attenuation"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Quadratic Attenuation</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-quadratic-attenuation"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Exponent</div>
|
||||
<div class="label">Spot Light Exponent</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-exponent"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-section property">
|
||||
<div class="label">Cutoff (degrees)</div>
|
||||
<div class="label">Spot Light Cutoff (degrees)</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-light-cutoff"></input>
|
||||
</div>
|
||||
|
|
|
@ -189,6 +189,11 @@ input, textarea {
|
|||
font-size: 7.5pt;
|
||||
}
|
||||
|
||||
input:disabled, textarea:disabled {
|
||||
background-color: rgb(102, 102, 102);
|
||||
color: rgb(160, 160, 160);
|
||||
}
|
||||
|
||||
#properties-list input[type=button] {
|
||||
cursor: pointer;
|
||||
background-color: rgb(51, 102, 102);
|
||||
|
@ -199,6 +204,11 @@ input, textarea {
|
|||
color: rgb(204, 204, 204);
|
||||
}
|
||||
|
||||
#properties-list input[type=button]:disabled {
|
||||
background-color: rgb(41, 82, 82);
|
||||
color: rgb(160, 160, 160);
|
||||
}
|
||||
|
||||
#properties-list .property {
|
||||
padding: 6pt 6pt;
|
||||
border-top: 0.75pt solid rgb(63, 63, 63);
|
||||
|
@ -257,3 +267,11 @@ td {
|
|||
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#no-entities {
|
||||
display: none;
|
||||
font-size: 120%;
|
||||
padding: 10pt;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
|
|
|
@ -238,12 +238,12 @@ SelectionDisplay = (function () {
|
|||
|
||||
// These are multipliers for sizing the rotation degrees display while rotating an entity
|
||||
var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.2;
|
||||
var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.5;
|
||||
var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.6;
|
||||
var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.18;
|
||||
var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.17;
|
||||
var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.14;
|
||||
|
||||
var ROTATE_ARROW_WEST_NORTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-north.png";
|
||||
var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.png";
|
||||
var ROTATE_ARROW_WEST_NORTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-north.svg";
|
||||
var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.svg";
|
||||
|
||||
var showExtendedStretchHandles = false;
|
||||
|
||||
|
@ -280,11 +280,11 @@ SelectionDisplay = (function () {
|
|||
var originalRoll;
|
||||
|
||||
|
||||
var rotateHandleColor = { red: 0, green: 0, blue: 0 };
|
||||
var rotateHandleAlpha = 0.7;
|
||||
var handleColor = { red: 255, green: 255, blue: 255 };
|
||||
var handleAlpha = 0.7;
|
||||
|
||||
var highlightedHandleColor = { red: 255, green: 0, blue: 0 };
|
||||
var highlightedHandleAlpha = 0.7;
|
||||
var highlightedHandleColor = { red: 183, green: 64, blue: 44 };
|
||||
var highlightedHandleAlpha = 0.9;
|
||||
|
||||
var previousHandle = false;
|
||||
var previousHandleColor;
|
||||
|
@ -385,10 +385,10 @@ SelectionDisplay = (function () {
|
|||
});
|
||||
|
||||
var grabberMoveUp = Overlays.addOverlay("billboard", {
|
||||
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.png",
|
||||
url: HIFI_PUBLIC_BUCKET + "images/up-arrow.svg",
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: { red: 0, green: 0, blue: 0 },
|
||||
alpha: 1.0,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -533,7 +533,7 @@ SelectionDisplay = (function () {
|
|||
|
||||
var rotateOverlayTarget = Overlays.addOverlay("circle3d", {
|
||||
position: { x:0, y: 0, z: 0},
|
||||
size: rotateOverlayTargetSize,
|
||||
size: rotateOverlayTargetSize * 2,
|
||||
color: { red: 0, green: 0, blue: 0 },
|
||||
alpha: 0.0,
|
||||
solid: true,
|
||||
|
@ -595,8 +595,8 @@ SelectionDisplay = (function () {
|
|||
var yawHandle = Overlays.addOverlay("billboard", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -608,8 +608,8 @@ SelectionDisplay = (function () {
|
|||
var pitchHandle = Overlays.addOverlay("billboard", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -621,8 +621,8 @@ SelectionDisplay = (function () {
|
|||
var rollHandle = Overlays.addOverlay("billboard", {
|
||||
url: ROTATE_ARROW_WEST_NORTH_URL,
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
color: handleColor,
|
||||
alpha: handleAlpha,
|
||||
visible: false,
|
||||
size: 0.1,
|
||||
scale: 0.1,
|
||||
|
@ -1692,7 +1692,7 @@ SelectionDisplay = (function () {
|
|||
y: innerRadius * ROTATION_DISPLAY_SIZE_Y_MULTIPLIER
|
||||
},
|
||||
lineHeight: innerRadius * ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER,
|
||||
text: normalizeDegrees(angleFromZero),
|
||||
text: normalizeDegrees(angleFromZero) + "°",
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1713,15 +1713,17 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayInner,
|
||||
{
|
||||
visible: true,
|
||||
size: innerRadius,
|
||||
size: innerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
alpha: innerAlpha
|
||||
});
|
||||
|
||||
Overlays.editOverlay(rotateOverlayOuter,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
|
@ -1731,7 +1733,7 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayCurrent,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
startAt: 0,
|
||||
endAt: 0,
|
||||
innerRadius: 0.9,
|
||||
|
@ -1809,13 +1811,13 @@ SelectionDisplay = (function () {
|
|||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius * 2,
|
||||
majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0,
|
||||
majorTickMarksLength: -0.25, minorTickMarksLength: 0, });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius * 2,
|
||||
majorTickMarksAngle: 45.0, minorTickMarksAngle: 5,
|
||||
majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, });
|
||||
}
|
||||
|
@ -1840,15 +1842,17 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayInner,
|
||||
{
|
||||
visible: true,
|
||||
size: innerRadius,
|
||||
size: innerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
alpha: innerAlpha
|
||||
});
|
||||
|
||||
Overlays.editOverlay(rotateOverlayOuter,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
|
@ -1858,7 +1862,7 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayCurrent,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
startAt: 0,
|
||||
endAt: 0,
|
||||
innerRadius: 0.9,
|
||||
|
@ -1929,13 +1933,13 @@ SelectionDisplay = (function () {
|
|||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius * 2,
|
||||
majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0,
|
||||
majorTickMarksLength: -0.25, minorTickMarksLength: 0, });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius * 2,
|
||||
majorTickMarksAngle: 45.0, minorTickMarksAngle: 5,
|
||||
majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, });
|
||||
}
|
||||
|
@ -1959,15 +1963,17 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayInner,
|
||||
{
|
||||
visible: true,
|
||||
size: innerRadius,
|
||||
size: innerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
alpha: innerAlpha
|
||||
});
|
||||
|
||||
Overlays.editOverlay(rotateOverlayOuter,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
endAt: 360,
|
||||
|
@ -1977,7 +1983,7 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayCurrent,
|
||||
{
|
||||
visible: true,
|
||||
size: outerRadius,
|
||||
size: outerRadius * 2,
|
||||
startAt: 0,
|
||||
endAt: 0,
|
||||
innerRadius: 0.9,
|
||||
|
@ -2047,13 +2053,13 @@ SelectionDisplay = (function () {
|
|||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius * 2,
|
||||
majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0,
|
||||
majorTickMarksLength: -0.25, minorTickMarksLength: 0, });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius,
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius * 2,
|
||||
majorTickMarksAngle: 45.0, minorTickMarksAngle: 5,
|
||||
majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, });
|
||||
}
|
||||
|
@ -2342,14 +2348,14 @@ SelectionDisplay = (function () {
|
|||
case yawHandle:
|
||||
case pitchHandle:
|
||||
case rollHandle:
|
||||
pickedColor = rotateHandleColor;
|
||||
pickedAlpha = rotateHandleAlpha;
|
||||
pickedColor = handleColor;
|
||||
pickedAlpha = handleAlpha;
|
||||
highlightNeeded = true;
|
||||
break;
|
||||
|
||||
case grabberMoveUp:
|
||||
pickedColor = rotateHandleColor;
|
||||
pickedAlpha = rotateHandleAlpha;
|
||||
pickedColor = handleColor;
|
||||
pickedAlpha = handleAlpha;
|
||||
highlightNeeded = true;
|
||||
break;
|
||||
|
||||
|
|
|
@ -14,35 +14,33 @@
|
|||
// This script generates notifications created via a number of ways, such as:
|
||||
// keystroke:
|
||||
//
|
||||
// "q" returns number of users currently online (for debug purposes)
|
||||
|
||||
// CTRL/s for snapshot.
|
||||
// CTRL/m for mic mute and unmute.
|
||||
|
||||
// System generated notifications:
|
||||
// Displays users online at startup.
|
||||
// If Screen is resized.
|
||||
// Triggers notification if @MyUserName is mentioned in chat.
|
||||
// Announces existing user logging out.
|
||||
// Announces new user logging in.
|
||||
// If mic is muted for any reason.
|
||||
//
|
||||
// To add a new System notification type:
|
||||
//
|
||||
// 1. Set the Event Connector at the bottom of the script.
|
||||
// example:
|
||||
// GlobalServices.incomingMessage.connect(onIncomingMessage);
|
||||
// AudioDevice.muteToggled.connect(onMuteStateChanged);
|
||||
//
|
||||
// 2. Create a new function to produce a text string, do not include new line returns.
|
||||
// example:
|
||||
// function onIncomingMessage(user, message) {
|
||||
// //do stuff here;
|
||||
// var text = "This is a notification";
|
||||
// wordWrap(text);
|
||||
// function onMuteStateChanged() {
|
||||
// var muteState,
|
||||
// muteString;
|
||||
//
|
||||
// muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
||||
// muteString = "Microphone is now " + muteState;
|
||||
// createNotification(muteString, NotificationType.MUTE_TOGGLE);
|
||||
// }
|
||||
//
|
||||
// This new function must call wordWrap(text) if the length of message is longer than 42 chars or unknown.
|
||||
// wordWrap() will format the text to fit the notifications overlay and send it to createNotification(text).
|
||||
// wordWrap() will format the text to fit the notifications overlay and return it
|
||||
// after that we will send it to createNotification(text).
|
||||
// If the message is 42 chars or less you should bypass wordWrap() and call createNotification() directly.
|
||||
|
||||
|
||||
|
@ -50,13 +48,14 @@
|
|||
//
|
||||
// 1. Add a key to the keyPressEvent(key).
|
||||
// 2. Declare a text string.
|
||||
// 3. Call createNotifications(text) parsing the text.
|
||||
// 3. Call createNotifications(text, NotificationType) parsing the text.
|
||||
// example:
|
||||
// var welcome;
|
||||
// if (key.text == "q") { //queries number of users online
|
||||
// var welcome = "There are " + GlobalServices.onlineUsers.length + " users online now.";
|
||||
// createNotification(welcome);
|
||||
// }
|
||||
// if (key.text === "s") {
|
||||
// if (ctrlIsPressed === true) {
|
||||
// noteString = "Snapshot taken.";
|
||||
// createNotification(noteString, NotificationType.SNAPSHOT);
|
||||
// }
|
||||
// }
|
||||
Script.include("./libraries/globals.js");
|
||||
Script.include("./libraries/soundArray.js");
|
||||
|
||||
|
@ -79,10 +78,40 @@ var frame = 0;
|
|||
var ourWidth = Window.innerWidth;
|
||||
var ourHeight = Window.innerHeight;
|
||||
var text = "placeholder";
|
||||
var last_users = GlobalServices.onlineUsers;
|
||||
var users = [];
|
||||
var ctrlIsPressed = false;
|
||||
var ready = true;
|
||||
var MENU_NAME = 'Tools > Notifications';
|
||||
var PLAY_NOTIFICATION_SOUNDS_MENU_ITEM = "Play Notification Sounds";
|
||||
var NOTIFICATION_MENU_ITEM_POST = " Notifications";
|
||||
var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds";
|
||||
var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_";
|
||||
|
||||
var NotificationType = {
|
||||
UNKNOWN: 0,
|
||||
MUTE_TOGGLE: 1,
|
||||
SNAPSHOT: 2,
|
||||
WINDOW_RESIZE: 3,
|
||||
properties: [
|
||||
{ text: "Mute Toggle" },
|
||||
{ text: "Snapshot" },
|
||||
{ text: "Window Resize" }
|
||||
],
|
||||
getTypeFromMenuItem: function(menuItemName) {
|
||||
if (menuItemName.substr(menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length) !== NOTIFICATION_MENU_ITEM_POST) {
|
||||
return NotificationType.UNKNOWN;
|
||||
}
|
||||
var preMenuItemName = menuItemName.substr(0, menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length);
|
||||
for (type in this.properties) {
|
||||
if (this.properties[type].text === preMenuItemName) {
|
||||
return parseInt(type) + 1;
|
||||
}
|
||||
}
|
||||
return NotificationType.UNKNOWN;
|
||||
},
|
||||
getMenuString: function(type) {
|
||||
return this.properties[type - 1].text + NOTIFICATION_MENU_ITEM_POST;
|
||||
}
|
||||
};
|
||||
|
||||
var randomSounds = new SoundArray({ localOnly: true }, true);
|
||||
var numberOfSounds = 2;
|
||||
|
@ -90,15 +119,6 @@ for (var i = 1; i <= numberOfSounds; i++) {
|
|||
randomSounds.addSound(HIFI_PUBLIC_BUCKET + "sounds/UI/notification-general" + i + ".raw");
|
||||
}
|
||||
|
||||
// When our script shuts down, we should clean up all of our overlays
|
||||
function scriptEnding() {
|
||||
for (i = 0; i < notifications.length; i++) {
|
||||
Overlays.deleteOverlay(notifications[i]);
|
||||
Overlays.deleteOverlay(buttons[i]);
|
||||
}
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
var notifications = [];
|
||||
var buttons = [];
|
||||
var times = [];
|
||||
|
@ -211,8 +231,6 @@ function notify(notice, button, height) {
|
|||
positions,
|
||||
last;
|
||||
|
||||
randomSounds.playRandom();
|
||||
|
||||
if (isOnHMD) {
|
||||
// Calculate 3D values from 2D overlay properties.
|
||||
|
||||
|
@ -257,7 +275,7 @@ function notify(notice, button, height) {
|
|||
}
|
||||
|
||||
// This function creates and sizes the overlays
|
||||
function createNotification(text) {
|
||||
function createNotification(text, notificationType) {
|
||||
var count = (text.match(/\n/g) || []).length,
|
||||
breakPoint = 43.0, // length when new line is added
|
||||
extraLine = 0,
|
||||
|
@ -307,6 +325,12 @@ function createNotification(text) {
|
|||
alpha: backgroundAlpha
|
||||
};
|
||||
|
||||
if (Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) &&
|
||||
Menu.isOptionChecked(NotificationType.getMenuString(notificationType)))
|
||||
{
|
||||
randomSounds.playRandom();
|
||||
}
|
||||
|
||||
notify(noticeProperties, buttonProperties, height);
|
||||
}
|
||||
|
||||
|
@ -345,8 +369,7 @@ function stringDivider(str, slotWidth, spaceReplacer) {
|
|||
|
||||
// formats string to add newline every 43 chars
|
||||
function wordWrap(str) {
|
||||
var result = stringDivider(str, 43.0, "\n");
|
||||
createNotification(result);
|
||||
return stringDivider(str, 43.0, "\n");
|
||||
}
|
||||
|
||||
// This fires a notification on window resize
|
||||
|
@ -358,7 +381,7 @@ function checkSize() {
|
|||
windowDimensions = Controller.getViewportDimensions();
|
||||
overlayLocationX = (windowDimensions.x - (width + 60.0));
|
||||
buttonLocationX = overlayLocationX + (width - 35.0);
|
||||
createNotification(windowResize);
|
||||
createNotification(windowResize, NotificationType.WINDOW_RESIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -440,18 +463,9 @@ var STARTUP_TIMEOUT = 500, // ms
|
|||
startingUp = true,
|
||||
startupTimer = null;
|
||||
|
||||
// This reports the number of users online at startup
|
||||
function reportUsers() {
|
||||
var welcome;
|
||||
|
||||
welcome = "Welcome! There are " + GlobalServices.onlineUsers.length + " users online now.";
|
||||
createNotification(welcome);
|
||||
}
|
||||
|
||||
function finishStartup() {
|
||||
startingUp = false;
|
||||
Script.clearTimeout(startupTimer);
|
||||
reportUsers();
|
||||
}
|
||||
|
||||
function isStartingUp() {
|
||||
|
@ -465,50 +479,14 @@ function isStartingUp() {
|
|||
return startingUp;
|
||||
}
|
||||
|
||||
// Triggers notification if a user logs on or off
|
||||
function onOnlineUsersChanged(users) {
|
||||
var i;
|
||||
|
||||
if (!isStartingUp()) { // Skip user notifications at startup.
|
||||
for (i = 0; i < users.length; i += 1) {
|
||||
if (last_users.indexOf(users[i]) === -1.0) {
|
||||
createNotification(users[i] + " has joined");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < last_users.length; i += 1) {
|
||||
if (users.indexOf(last_users[i]) === -1.0) {
|
||||
createNotification(last_users[i] + " has left");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_users = users;
|
||||
}
|
||||
|
||||
// Triggers notification if @MyUserName is mentioned in chat and returns the message to the notification.
|
||||
function onIncomingMessage(user, message) {
|
||||
var myMessage,
|
||||
alertMe,
|
||||
thisAlert;
|
||||
|
||||
myMessage = message;
|
||||
alertMe = "@" + GlobalServices.myUsername;
|
||||
thisAlert = user + ": " + myMessage;
|
||||
|
||||
if (myMessage.indexOf(alertMe) > -1.0) {
|
||||
wordWrap(thisAlert);
|
||||
}
|
||||
}
|
||||
|
||||
// Triggers mic mute notification
|
||||
function onMuteStateChanged() {
|
||||
var muteState,
|
||||
muteString;
|
||||
|
||||
muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
||||
muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
||||
muteString = "Microphone is now " + muteState;
|
||||
createNotification(muteString);
|
||||
createNotification(muteString, NotificationType.MUTE_TOGGLE);
|
||||
}
|
||||
|
||||
// handles mouse clicks on buttons
|
||||
|
@ -540,43 +518,69 @@ function keyReleaseEvent(key) {
|
|||
|
||||
// Triggers notification on specific key driven events
|
||||
function keyPressEvent(key) {
|
||||
var numUsers,
|
||||
welcome,
|
||||
noteString;
|
||||
var noteString;
|
||||
|
||||
if (key.key === 16777249) {
|
||||
ctrlIsPressed = true;
|
||||
}
|
||||
|
||||
if (key.text === "q") { //queries number of users online
|
||||
numUsers = GlobalServices.onlineUsers.length;
|
||||
welcome = "There are " + numUsers + " users online now.";
|
||||
createNotification(welcome);
|
||||
}
|
||||
|
||||
if (key.text === "s") {
|
||||
if (ctrlIsPressed === true) {
|
||||
noteString = "Snapshot taken.";
|
||||
createNotification(noteString);
|
||||
createNotification(noteString, NotificationType.SNAPSHOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setup() {
|
||||
Menu.addMenu(MENU_NAME);
|
||||
var checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING);
|
||||
checked = checked === '' ? true : checked;
|
||||
Menu.addMenuItem({
|
||||
menuName: MENU_NAME,
|
||||
menuItemName: PLAY_NOTIFICATION_SOUNDS_MENU_ITEM,
|
||||
isCheckable: true,
|
||||
isChecked: Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING)
|
||||
});
|
||||
Menu.addSeparator(MENU_NAME, "Play sounds for:");
|
||||
for (type in NotificationType.properties) {
|
||||
checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + (parseInt(type) + 1));
|
||||
checked = checked === '' ? true : checked;
|
||||
Menu.addMenuItem({
|
||||
menuName: MENU_NAME,
|
||||
menuItemName: NotificationType.properties[type].text + NOTIFICATION_MENU_ITEM_POST,
|
||||
isCheckable: true,
|
||||
isChecked: checked
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// When our script shuts down, we should clean up all of our overlays
|
||||
function scriptEnding() {
|
||||
var i;
|
||||
|
||||
for (i = 0; i < notifications.length; i += 1) {
|
||||
for (var i = 0; i < notifications.length; i++) {
|
||||
Overlays.deleteOverlay(notifications[i]);
|
||||
Overlays.deleteOverlay(buttons[i]);
|
||||
}
|
||||
Menu.removeMenu(MENU_NAME);
|
||||
}
|
||||
|
||||
function menuItemEvent(menuItem) {
|
||||
if (menuItem === PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) {
|
||||
Settings.setValue(PLAY_NOTIFICATION_SOUNDS_SETTING, Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM));
|
||||
return;
|
||||
}
|
||||
var notificationType = NotificationType.getTypeFromMenuItem(menuItem);
|
||||
if (notificationType !== notificationType.UNKNOWN) {
|
||||
Settings.setValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + notificationType, Menu.isOptionChecked(menuItem));
|
||||
}
|
||||
}
|
||||
|
||||
AudioDevice.muteToggled.connect(onMuteStateChanged);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
GlobalServices.onlineUsersChanged.connect(onOnlineUsersChanged);
|
||||
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
|
||||
setup();
|
||||
|
|
|
@ -24,12 +24,11 @@ endif ()
|
|||
|
||||
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_project(glm)
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared networking audio-client avatars)
|
||||
include_dependency_includes()
|
||||
|
||||
if (ANDROID)
|
||||
find_package(LibOVR)
|
||||
|
@ -87,4 +86,6 @@ if (ANDROID)
|
|||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/templates/hockeyapp.xml.in" "${ANDROID_APK_BUILD_DIR}/res/values/hockeyapp.xml")
|
||||
qt_create_apk()
|
||||
|
||||
endif (ANDROID)
|
||||
endif (ANDROID)
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
|
@ -6,4 +6,4 @@ setup_hifi_project(Network)
|
|||
# link the shared hifi libraries
|
||||
link_hifi_libraries(embedded-webserver networking shared)
|
||||
|
||||
include_dependency_includes()
|
||||
copy_dlls_beside_windows_executable()
|
|
@ -2,7 +2,11 @@ set(TARGET_NAME interface)
|
|||
project(${TARGET_NAME})
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
<<<<<<< HEAD
|
||||
set(OPTIONAL_EXTERNALS "Faceshift" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "RSSDK")
|
||||
=======
|
||||
set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "Sixense" "LeapMotion" "RtMidi" "SDL2" "RSSDK")
|
||||
>>>>>>> upstream/master
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
|
||||
|
@ -32,8 +36,6 @@ elseif (WIN32)
|
|||
set(GL_HEADERS "#include <windowshacks.h>\n#include <GL/glew.h>\n#include <GL/wglew.h>")
|
||||
endif ()
|
||||
|
||||
include_bullet()
|
||||
|
||||
# create the InterfaceConfig.h file based on GL_HEADERS above
|
||||
configure_file(InterfaceConfig.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceConfig.h")
|
||||
configure_file(InterfaceVersion.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceVersion.h")
|
||||
|
@ -78,7 +80,7 @@ if (APPLE)
|
|||
set(MACOSX_BUNDLE_BUNDLE_NAME Interface)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER io.highfidelity.Interface)
|
||||
|
||||
if (${CMAKE_BUILD_TYPE} MATCHES "RELEASE")
|
||||
if (UPPER_CMAKE_BUILD_TYPE MATCHES RELEASE OR UPPER_CMAKE_BUILD_TYPE MATCHES RELWITHDEBINFO)
|
||||
set(ICON_FILENAME "interface.icns")
|
||||
else ()
|
||||
set(ICON_FILENAME "interface-beta.icns")
|
||||
|
@ -108,7 +110,7 @@ endif()
|
|||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
|
||||
|
||||
# set up the external glm library
|
||||
add_dependency_external_project(glm)
|
||||
add_dependency_external_projects(glm bullet)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${GLM_INCLUDE_DIRS})
|
||||
|
||||
|
@ -117,13 +119,16 @@ find_package(LibOVR REQUIRED)
|
|||
target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
|
||||
|
||||
find_package(Bullet REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_libraries(shared octree environment gpu model fbx metavoxels networking entities avatars
|
||||
link_hifi_libraries(shared octree environment gpu model fbx networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer)
|
||||
|
||||
# find any optional and required libraries
|
||||
find_package(ZLIB REQUIRED)
|
||||
add_dependency_external_projects(sdl2)
|
||||
|
||||
# perform standard include and linking for found externals
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
|
@ -179,16 +184,11 @@ if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI AND APPLE)
|
|||
target_link_libraries(${TARGET_NAME} ${CoreMIDI})
|
||||
endif ()
|
||||
|
||||
if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32)
|
||||
# assume we're linking a static Qt on windows
|
||||
add_definitions(-DQXMPP_STATIC)
|
||||
endif ()
|
||||
|
||||
# include headers for interface and InterfaceConfig.
|
||||
include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes")
|
||||
|
||||
target_link_libraries(
|
||||
${TARGET_NAME} ${ZLIB_LIBRARIES}
|
||||
${TARGET_NAME}
|
||||
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets
|
||||
)
|
||||
|
||||
|
@ -225,13 +225,11 @@ else (APPLE)
|
|||
|
||||
# link target to external libraries
|
||||
if (WIN32)
|
||||
add_dependency_external_projects(glew)
|
||||
find_package(GLEW REQUIRED)
|
||||
include_directories(${GLEW_INCLUDE_DIRS})
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS})
|
||||
|
||||
# we're using static GLEW, so define GLEW_STATIC
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} "${NSIGHT_LIBRARIES}" wsock32.lib opengl32.lib Winmm.lib)
|
||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} ${NSIGHT_LIBRARIES} wsock32.lib opengl32.lib Winmm.lib)
|
||||
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
find_package(NSIGHT)
|
||||
|
@ -244,5 +242,4 @@ else (APPLE)
|
|||
endif()
|
||||
endif (APPLE)
|
||||
|
||||
# link any dependencies bubbled up from our linked dependencies
|
||||
include_dependency_includes()
|
||||
copy_dlls_beside_windows_executable()
|
||||
|
|
16
interface/external/priovr/readme.txt
vendored
16
interface/external/priovr/readme.txt
vendored
|
@ -1,16 +0,0 @@
|
|||
|
||||
Instructions for adding the PrioVR driver to Interface
|
||||
Andrzej Kapolka, May 12, 2014
|
||||
|
||||
1. Download and install the YEI drivers from https://www.yeitechnology.com/yei-3-space-sensor-software-suite. If using
|
||||
Window 8+, follow the workaround instructions at http://forum.yeitechnology.com/viewtopic.php?f=3&t=24.
|
||||
|
||||
2. Get the PrioVR skeleton API, open ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/ThreeSpace_API_2.sln
|
||||
in Visual Studio, and build it.
|
||||
|
||||
3. Copy ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/Skeletal_API/yei_skeletal_api.h to interface/external/priovr/include,
|
||||
ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/Debug/Skeletal_API.lib to interface/external/priovr/lib, and
|
||||
ts_c_api2_priovr2/visual_studio/ThreeSpace_API_2/Debug/*.dll to your path.
|
||||
|
||||
4. Delete your build directory, run cmake and build, and you should be all set.
|
||||
|
|
@ -52,6 +52,7 @@
|
|||
#include <QMediaPlayer>
|
||||
#include <QMimeData>
|
||||
#include <QMessageBox>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include <AddressManager.h>
|
||||
#include <AccountManager.h>
|
||||
|
@ -75,13 +76,15 @@
|
|||
#include <PhysicsEngine.h>
|
||||
#include <ProgramObject.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <ScriptCache.h>
|
||||
//#include <ScriptCache.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <SoundCache.h>
|
||||
#include <TextRenderer.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include <SceneScriptingInterface.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AudioClient.h"
|
||||
#include "InterfaceVersion.h"
|
||||
|
@ -215,11 +218,10 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
|
||||
|
||||
// Set dependencies
|
||||
auto glCanvas = DependencyManager::set<GLCanvas>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
|
||||
auto geometryCache = DependencyManager::set<GeometryCache>();
|
||||
auto scriptCache = DependencyManager::set<ScriptCache>();
|
||||
//auto scriptCache = DependencyManager::set<ScriptCache>();
|
||||
auto soundCache = DependencyManager::set<SoundCache>();
|
||||
auto glowEffect = DependencyManager::set<GlowEffect>();
|
||||
auto faceshift = DependencyManager::set<Faceshift>();
|
||||
|
@ -240,6 +242,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
auto dialogsManager = DependencyManager::set<DialogsManager>();
|
||||
auto bandwidthRecorder = DependencyManager::set<BandwidthRecorder>();
|
||||
auto resouceCacheSharedItems = DependencyManager::set<ResouceCacheSharedItems>();
|
||||
auto entityScriptingInterface = DependencyManager::set<EntityScriptingInterface>();
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
auto speechRecognizer = DependencyManager::set<SpeechRecognizer>();
|
||||
#endif
|
||||
|
@ -307,7 +310,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
_myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
@ -416,8 +418,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
// tell the NodeList instance who to tell the domain server we care about
|
||||
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
|
||||
<< NodeType::EntityServer
|
||||
<< NodeType::MetavoxelServer);
|
||||
<< NodeType::EntityServer);
|
||||
|
||||
// connect to the packet sent signal of the _entityEditSender
|
||||
connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);
|
||||
|
@ -447,16 +448,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
ResourceCache::setRequestLimit(3);
|
||||
|
||||
_window->setCentralWidget(glCanvas.data());
|
||||
_window->setCentralWidget(_glWidget);
|
||||
|
||||
_window->restoreGeometry();
|
||||
|
||||
_window->setVisible(true);
|
||||
glCanvas->setFocusPolicy(Qt::StrongFocus);
|
||||
glCanvas->setFocus();
|
||||
_glWidget->setFocusPolicy(Qt::StrongFocus);
|
||||
_glWidget->setFocus();
|
||||
|
||||
// enable mouse tracking; otherwise, we only get drag events
|
||||
glCanvas->setMouseTracking(true);
|
||||
_glWidget->setMouseTracking(true);
|
||||
|
||||
_toolWindow = new ToolWindow();
|
||||
_toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
|
@ -474,7 +475,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
checkVersion();
|
||||
|
||||
_overlays.init(glCanvas.data()); // do this before scripts load
|
||||
_overlays.init(); // do this before scripts load
|
||||
|
||||
_runningScriptsWidget->setRunningScripts(getRunningScripts());
|
||||
connect(_runningScriptsWidget, &RunningScriptsWidget::stopScriptName, this, &Application::stopScript);
|
||||
|
@ -533,6 +534,10 @@ void Application::aboutToQuit() {
|
|||
}
|
||||
|
||||
void Application::cleanupBeforeQuit() {
|
||||
_datagramProcessor.shutdown(); // tell the datagram processor we're shutting down, so it can short circuit
|
||||
_entities.shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
|
||||
ScriptEngine::stopAllScripts(this); // stop all currently running global scripts
|
||||
|
||||
// first stop all timers directly or by invokeMethod
|
||||
// depending on what thread they run in
|
||||
locationUpdateTimer->stop();
|
||||
|
@ -580,8 +585,6 @@ Application::~Application() {
|
|||
_entities.getTree()->setSimulation(NULL);
|
||||
tree->unlock();
|
||||
|
||||
qInstallMessageHandler(NULL);
|
||||
|
||||
// ask the datagram processing thread to quit and wait until it is done
|
||||
_nodeThread->quit();
|
||||
_nodeThread->wait();
|
||||
|
@ -595,15 +598,13 @@ Application::~Application() {
|
|||
|
||||
ModelEntityItem::cleanupLoadedAnimations() ;
|
||||
|
||||
DependencyManager::destroy<GLCanvas>();
|
||||
|
||||
qDebug() << "start destroying ResourceCaches Application::~Application() line:" << __LINE__;
|
||||
DependencyManager::destroy<AnimationCache>();
|
||||
DependencyManager::destroy<TextureCache>();
|
||||
DependencyManager::destroy<GeometryCache>();
|
||||
DependencyManager::destroy<ScriptCache>();
|
||||
//DependencyManager::destroy<ScriptCache>();
|
||||
DependencyManager::destroy<SoundCache>();
|
||||
qDebug() << "done destroying ResourceCaches Application::~Application() line:" << __LINE__;
|
||||
|
||||
qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages
|
||||
}
|
||||
|
||||
void Application::initializeGL() {
|
||||
|
@ -688,7 +689,7 @@ void Application::paintGL() {
|
|||
if (OculusManager::isConnected()) {
|
||||
DependencyManager::get<TextureCache>()->setFrameBufferSize(OculusManager::getRenderTargetSize());
|
||||
} else {
|
||||
QSize fbSize = DependencyManager::get<GLCanvas>()->getDeviceSize() * getRenderResolutionScale();
|
||||
QSize fbSize = _glWidget->getDeviceSize() * getRenderResolutionScale();
|
||||
DependencyManager::get<TextureCache>()->setFrameBufferSize(fbSize);
|
||||
}
|
||||
|
||||
|
@ -1055,8 +1056,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
if (isShifted) {
|
||||
_viewFrustum.setFocalLength(_viewFrustum.getFocalLength() - 0.1f);
|
||||
if (TV3DManager::isConnected()) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
TV3DManager::configureCamera(_myCamera, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
TV3DManager::configureCamera(_myCamera, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
}
|
||||
} else {
|
||||
_myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(-0.001, 0, 0));
|
||||
|
@ -1068,8 +1068,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
if (isShifted) {
|
||||
_viewFrustum.setFocalLength(_viewFrustum.getFocalLength() + 0.1f);
|
||||
if (TV3DManager::isConnected()) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
TV3DManager::configureCamera(_myCamera, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
TV3DManager::configureCamera(_myCamera, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -1446,8 +1445,7 @@ void Application::sendPingPackets() {
|
|||
QByteArray pingPacket = DependencyManager::get<NodeList>()->constructPingPacket();
|
||||
controlledBroadcastToNodes(pingPacket, NodeSet()
|
||||
<< NodeType::EntityServer
|
||||
<< NodeType::AudioMixer << NodeType::AvatarMixer
|
||||
<< NodeType::MetavoxelServer);
|
||||
<< NodeType::AudioMixer << NodeType::AvatarMixer);
|
||||
}
|
||||
|
||||
// Every second, check the frame rates and other stuff
|
||||
|
@ -1469,6 +1467,10 @@ void Application::checkFPS() {
|
|||
|
||||
void Application::idle() {
|
||||
PerformanceTimer perfTimer("idle");
|
||||
|
||||
if (_aboutToQuit) {
|
||||
return; // bail early, nothing to do here.
|
||||
}
|
||||
|
||||
// Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing
|
||||
// details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing
|
||||
|
@ -1494,7 +1496,7 @@ void Application::idle() {
|
|||
{
|
||||
PerformanceTimer perfTimer("updateGL");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... updateGL()");
|
||||
DependencyManager::get<GLCanvas>()->updateGL();
|
||||
_glWidget->updateGL();
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("rest");
|
||||
|
@ -1535,8 +1537,7 @@ void Application::setFullscreen(bool fullscreen) {
|
|||
}
|
||||
|
||||
void Application::setEnable3DTVMode(bool enable3DTVMode) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
resizeGL(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
}
|
||||
|
||||
void Application::setEnableVRMode(bool enableVRMode) {
|
||||
|
@ -1561,8 +1562,7 @@ void Application::setEnableVRMode(bool enableVRMode) {
|
|||
_myCamera.setHmdRotation(glm::quat());
|
||||
}
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
resizeGL(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
|
||||
updateCursorVisibility();
|
||||
}
|
||||
|
@ -1573,9 +1573,8 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) {
|
|||
|
||||
bool Application::mouseOnScreen() const {
|
||||
if (OculusManager::isConnected()) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
return getMouseX() >= 0 && getMouseX() <= glCanvas->getDeviceWidth() &&
|
||||
getMouseY() >= 0 && getMouseY() <= glCanvas->getDeviceHeight();
|
||||
return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() &&
|
||||
getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1768,8 +1767,10 @@ void Application::init() {
|
|||
tree->setSimulation(&_physicsEngine);
|
||||
_physicsEngine.init(&_entityEditSender);
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
||||
connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity,
|
||||
ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity);
|
||||
entityScriptingInterface.data(), &EntityScriptingInterface::entityCollisionWithEntity);
|
||||
|
||||
// connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts
|
||||
connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity,
|
||||
|
@ -1777,16 +1778,13 @@ void Application::init() {
|
|||
|
||||
// connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing
|
||||
// of events related clicking, hovering over, and entering entities
|
||||
_entities.connectSignalsToSlots(ScriptEngine::getEntityScriptingInterface());
|
||||
_entities.connectSignalsToSlots(entityScriptingInterface.data());
|
||||
|
||||
_entityClipboardRenderer.init();
|
||||
_entityClipboardRenderer.setViewFrustum(getViewFrustum());
|
||||
_entityClipboardRenderer.setTree(&_entityClipboard);
|
||||
|
||||
_metavoxels.init();
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
_rearMirrorTools = new RearMirrorTools(glCanvas.data(), _mirrorViewRect);
|
||||
_rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect);
|
||||
|
||||
connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
|
||||
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
|
||||
|
@ -1794,10 +1792,10 @@ void Application::init() {
|
|||
connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
|
||||
|
||||
// make sure our texture cache knows about window size changes
|
||||
DependencyManager::get<TextureCache>()->associateWithWidget(glCanvas.data());
|
||||
DependencyManager::get<TextureCache>()->associateWithWidget(_glWidget);
|
||||
|
||||
// initialize the GlowEffect with our widget
|
||||
DependencyManager::get<GlowEffect>()->init(glCanvas.data(),
|
||||
DependencyManager::get<GlowEffect>()->init(_glWidget,
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect));
|
||||
}
|
||||
|
||||
|
@ -1863,35 +1861,6 @@ void Application::updateMouseRay() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::updateFaceshift() {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateFaceshift()");
|
||||
auto faceshift = DependencyManager::get<Faceshift>();
|
||||
// Update faceshift
|
||||
faceshift->update();
|
||||
|
||||
// Copy angular velocity if measured by faceshift, to the head
|
||||
if (faceshift->isActive()) {
|
||||
_myAvatar->getHead()->setAngularVelocity(faceshift->getHeadAngularVelocity());
|
||||
}
|
||||
}
|
||||
|
||||
void Application::updateVisage() {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateVisage()");
|
||||
|
||||
// Update Visage
|
||||
DependencyManager::get<Visage>()->update();
|
||||
}
|
||||
|
||||
void Application::updateDDE() {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateDDE()");
|
||||
|
||||
// Update Cara
|
||||
DependencyManager::get<DdeFaceTracker>()->update();
|
||||
}
|
||||
|
||||
void Application::updateMyAvatarLookAtPosition() {
|
||||
PerformanceTimer perfTimer("lookAt");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
|
@ -1977,16 +1946,6 @@ void Application::updateThreads(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::updateMetavoxels(float deltaTime) {
|
||||
PerformanceTimer perfTimer("updateMetavoxels");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()");
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) {
|
||||
_metavoxels.simulate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::cameraMenuChanged() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||
|
@ -2051,9 +2010,9 @@ void Application::updateCursor(float deltaTime) {
|
|||
|
||||
void Application::updateCursorVisibility() {
|
||||
if (!_cursorVisible || Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
||||
DependencyManager::get<GLCanvas>()->setCursor(Qt::BlankCursor);
|
||||
_glWidget->setCursor(Qt::BlankCursor);
|
||||
} else {
|
||||
DependencyManager::get<GLCanvas>()->unsetCursor();
|
||||
_glWidget->unsetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2071,12 +2030,12 @@ void Application::update(float deltaTime) {
|
|||
{
|
||||
PerformanceTimer perfTimer("devices");
|
||||
DeviceTracker::updateAll();
|
||||
updateFaceshift();
|
||||
updateVisage();
|
||||
FaceTracker* tracker = getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
tracker->update(deltaTime);
|
||||
}
|
||||
SixenseManager::getInstance().update(deltaTime);
|
||||
JoystickScriptingInterface::getInstance().update();
|
||||
_prioVR.update(deltaTime);
|
||||
|
||||
}
|
||||
|
||||
// Dispatch input events
|
||||
|
@ -2086,7 +2045,6 @@ void Application::update(float deltaTime) {
|
|||
|
||||
DependencyManager::get<AvatarManager>()->updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them...
|
||||
|
||||
updateMetavoxels(deltaTime); // update metavoxels
|
||||
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
|
||||
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||
updateCursor(deltaTime); // Handle cursor updates
|
||||
|
@ -2495,7 +2453,8 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {
|
|||
|
||||
glm::vec3 Application::getSunDirection() {
|
||||
// Sun direction is in fact just the location of the sun relative to the origin
|
||||
return glm::normalize(_environment.getClosestData(_myCamera.getPosition()).getSunLocation(_myCamera.getPosition()));
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
return skyStage->getSunLight()->getDirection();
|
||||
}
|
||||
|
||||
void Application::updateShadowMap() {
|
||||
|
@ -2505,7 +2464,7 @@ void Application::updateShadowMap() {
|
|||
glEnable(GL_DEPTH_TEST);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glm::vec3 lightDirection = -getSunDirection();
|
||||
glm::vec3 lightDirection = getSunDirection();
|
||||
glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection);
|
||||
glm::quat inverseRotation = glm::inverse(rotation);
|
||||
|
||||
|
@ -2575,7 +2534,9 @@ void Application::updateShadowMap() {
|
|||
glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation));
|
||||
|
||||
// update the shadow view frustum
|
||||
_shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f));
|
||||
// glm::vec3 shadowFrustumCenter = glm::vec3((minima.x + maxima.x) * 0.5f, (minima.y + maxima.y) * 0.5f, (minima.z + maxima.z) * 0.5f);
|
||||
glm::vec3 shadowFrustumCenter = rotation * ((minima + maxima) * 0.5f);
|
||||
_shadowViewFrustum.setPosition(shadowFrustumCenter);
|
||||
_shadowViewFrustum.setOrientation(rotation);
|
||||
_shadowViewFrustum.setOrthographic(true);
|
||||
_shadowViewFrustum.setWidth(maxima.x - minima.x);
|
||||
|
@ -2605,8 +2566,10 @@ void Application::updateShadowMap() {
|
|||
// this is what is used for rendering the Entities and avatars
|
||||
Transform viewTransform;
|
||||
viewTransform.setRotation(rotation);
|
||||
// viewTransform.postTranslate(shadowFrustumCenter);
|
||||
setViewTransform(viewTransform);
|
||||
|
||||
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
|
||||
|
||||
|
@ -2643,8 +2606,7 @@ void Application::updateShadowMap() {
|
|||
|
||||
fbo->release();
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
glViewport(0, 0, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
}
|
||||
|
||||
const GLfloat WORLD_AMBIENT_COLOR[] = { 0.525f, 0.525f, 0.6f };
|
||||
|
@ -2694,7 +2656,7 @@ QImage Application::renderAvatarBillboard() {
|
|||
Glower glower;
|
||||
|
||||
const int BILLBOARD_SIZE = 64;
|
||||
renderRearViewMirror(QRect(0, DependencyManager::get<GLCanvas>()->getDeviceHeight() - BILLBOARD_SIZE,
|
||||
renderRearViewMirror(QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE,
|
||||
BILLBOARD_SIZE, BILLBOARD_SIZE),
|
||||
true);
|
||||
|
||||
|
@ -2832,14 +2794,6 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
|||
float originSphereRadius = 0.05f;
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(originSphereRadius, 15, 15, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
// also, metavoxels
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) {
|
||||
PerformanceTimer perfTimer("metavoxels");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... metavoxels...");
|
||||
_metavoxels.render();
|
||||
}
|
||||
|
||||
// render models...
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) {
|
||||
PerformanceTimer perfTimer("entities");
|
||||
|
@ -2875,7 +2829,9 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
|||
|
||||
{
|
||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(-getSunDirection(), GLOBAL_LIGHT_COLOR, GLOBAL_LIGHT_INTENSITY);
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity());
|
||||
|
||||
PROFILE_RANGE("DeferredLighting");
|
||||
PerformanceTimer perfTimer("lighting");
|
||||
DependencyManager::get<DeferredLightingEffect>()->render();
|
||||
|
@ -2986,9 +2942,8 @@ bool Application::getCascadeShadowsEnabled() {
|
|||
}
|
||||
|
||||
glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
float horizontalScale = glCanvas->getDeviceWidth() / 2.0f;
|
||||
float verticalScale = glCanvas->getDeviceHeight() / 2.0f;
|
||||
float horizontalScale = _glWidget->getDeviceWidth() / 2.0f;
|
||||
float verticalScale = _glWidget->getDeviceHeight() / 2.0f;
|
||||
|
||||
// -1,-1 is 0,windowHeight
|
||||
// 1,1 is windowWidth,0
|
||||
|
@ -3007,7 +2962,7 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
|
|||
// -1,-1 1,-1
|
||||
|
||||
glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale,
|
||||
((projectedPoint.y + 1.0) * -verticalScale) + glCanvas->getDeviceHeight());
|
||||
((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->getDeviceHeight());
|
||||
|
||||
return screenPoint;
|
||||
}
|
||||
|
@ -3137,13 +3092,12 @@ void Application::resetSensors() {
|
|||
|
||||
OculusManager::reset();
|
||||
|
||||
_prioVR.reset();
|
||||
//_leapmotion.reset();
|
||||
|
||||
QScreen* currentScreen = _window->windowHandle()->screen();
|
||||
QWindow* mainWindow = _window->windowHandle();
|
||||
QPoint windowCenter = mainWindow->geometry().center();
|
||||
DependencyManager::get<GLCanvas>()->cursor().setPos(currentScreen, windowCenter);
|
||||
_glWidget->cursor().setPos(currentScreen, windowCenter);
|
||||
|
||||
_myAvatar->reset();
|
||||
|
||||
|
@ -3471,8 +3425,9 @@ void joystickFromScriptValue(const QScriptValue &object, Joystick* &out) {
|
|||
void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) {
|
||||
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
|
||||
// we can use the same ones from the application.
|
||||
scriptEngine->getEntityScriptingInterface()->setPacketSender(&_entityEditSender);
|
||||
scriptEngine->getEntityScriptingInterface()->setEntityTree(_entities.getTree());
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
entityScriptingInterface->setPacketSender(&_entityEditSender);
|
||||
entityScriptingInterface->setEntityTree(_entities.getTree());
|
||||
|
||||
// AvatarManager has some custom types
|
||||
AvatarManager::registerMetaTypes(scriptEngine);
|
||||
|
@ -3515,7 +3470,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("Metavoxels", &_metavoxels);
|
||||
|
||||
scriptEngine->registerGlobalObject("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
qScriptRegisterMetaType(scriptEngine, DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
|
||||
|
@ -3535,19 +3489,20 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance());
|
||||
#endif
|
||||
|
||||
// TODO: Consider moving some of this functionality into the ScriptEngine class instead. It seems wrong that this
|
||||
// work is being done in the Application class when really these dependencies are more related to the ScriptEngine's
|
||||
// implementation
|
||||
QThread* workerThread = new QThread(this);
|
||||
workerThread->setObjectName("Script Engine Thread");
|
||||
QString scriptEngineName = QString("Script Thread:") + scriptEngine->getFilename();
|
||||
workerThread->setObjectName(scriptEngineName);
|
||||
|
||||
// when the worker thread is started, call our engine's run..
|
||||
connect(workerThread, &QThread::started, scriptEngine, &ScriptEngine::run);
|
||||
|
||||
// when the thread is terminated, add both scriptEngine and thread to the deleteLater queue
|
||||
connect(scriptEngine, SIGNAL(finished(const QString&)), scriptEngine, SLOT(deleteLater()));
|
||||
connect(scriptEngine, SIGNAL(doneRunning()), scriptEngine, SLOT(deleteLater()));
|
||||
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
|
||||
|
||||
// when the application is about to quit, stop our script engine so it unwinds properly
|
||||
connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop()));
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
connect(nodeList.data(), &NodeList::nodeKilled, scriptEngine, &ScriptEngine::nodeKilled);
|
||||
|
||||
|
@ -3558,7 +3513,12 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
}
|
||||
|
||||
ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUserLoaded,
|
||||
bool loadScriptFromEditor, bool activateMainWindow) {
|
||||
bool loadScriptFromEditor, bool activateMainWindow) {
|
||||
|
||||
if (isAboutToQuit()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QUrl scriptUrl(scriptFilename);
|
||||
const QString& scriptURLString = scriptUrl.toString();
|
||||
if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor
|
||||
|
@ -3749,8 +3709,8 @@ void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject
|
|||
voxelWalletUUID = QUuid(voxelObject[VOXEL_WALLET_UUID].toString());
|
||||
}
|
||||
|
||||
qDebug() << "Voxel costs are" << satoshisPerVoxel << "per voxel and" << satoshisPerMeterCubed << "per meter cubed";
|
||||
qDebug() << "Destination wallet UUID for voxel payments is" << voxelWalletUUID;
|
||||
qDebug() << "Octree edits costs are" << satoshisPerVoxel << "per octree cell and" << satoshisPerMeterCubed << "per meter cubed";
|
||||
qDebug() << "Destination wallet UUID for edit payments is" << voxelWalletUUID;
|
||||
}
|
||||
|
||||
QString Application::getPreviousScriptLocation() {
|
||||
|
@ -3773,7 +3733,7 @@ void Application::setPreviousScriptLocation(const QString& previousScriptLocatio
|
|||
|
||||
void Application::loadDialog() {
|
||||
|
||||
QString fileNameString = QFileDialog::getOpenFileName(DependencyManager::get<GLCanvas>().data(),
|
||||
QString fileNameString = QFileDialog::getOpenFileName(_glWidget,
|
||||
tr("Open Script"),
|
||||
getPreviousScriptLocation(),
|
||||
tr("JavaScript Files (*.js)"));
|
||||
|
@ -3814,7 +3774,7 @@ void Application::setScriptsLocation(const QString& scriptsLocation) {
|
|||
|
||||
void Application::toggleLogDialog() {
|
||||
if (! _logDialog) {
|
||||
_logDialog = new LogDialog(DependencyManager::get<GLCanvas>().data(), getLogger());
|
||||
_logDialog = new LogDialog(_glWidget, getLogger());
|
||||
}
|
||||
|
||||
if (_logDialog->isVisible()) {
|
||||
|
@ -3871,7 +3831,7 @@ void Application::parseVersionXml() {
|
|||
}
|
||||
|
||||
if (!shouldSkipVersion(latestVersion) && applicationVersion() != latestVersion) {
|
||||
new UpdateDialog(DependencyManager::get<GLCanvas>().data(), releaseNotes, latestVersion, downloadUrl);
|
||||
new UpdateDialog(_glWidget, releaseNotes, latestVersion, downloadUrl);
|
||||
}
|
||||
sender->deleteLater();
|
||||
}
|
||||
|
@ -3904,7 +3864,7 @@ void Application::takeSnapshot() {
|
|||
}
|
||||
|
||||
if (!_snapshotShareDialog) {
|
||||
_snapshotShareDialog = new SnapshotShareDialog(fileName, DependencyManager::get<GLCanvas>().data());
|
||||
_snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget);
|
||||
}
|
||||
_snapshotShareDialog->show();
|
||||
}
|
||||
|
|
|
@ -45,13 +45,11 @@
|
|||
#include "FileLogger.h"
|
||||
#include "GLCanvas.h"
|
||||
#include "Menu.h"
|
||||
#include "MetavoxelSystem.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "Physics.h"
|
||||
#include "Stars.h"
|
||||
#include "avatar/Avatar.h"
|
||||
#include "avatar/MyAvatar.h"
|
||||
#include "devices/PrioVR.h"
|
||||
#include "devices/SixenseManager.h"
|
||||
#include "scripting/ControllerScriptingInterface.h"
|
||||
#include "ui/BandwidthDialog.h"
|
||||
|
@ -171,17 +169,16 @@ public:
|
|||
bool event(QEvent* event);
|
||||
bool eventFilter(QObject* object, QEvent* event);
|
||||
|
||||
bool isThrottleRendering() const { return DependencyManager::get<GLCanvas>()->isThrottleRendering(); }
|
||||
GLCanvas* getGLWidget() { return _glWidget; }
|
||||
bool isThrottleRendering() const { return _glWidget->isThrottleRendering(); }
|
||||
|
||||
Camera* getCamera() { return &_myCamera; }
|
||||
ViewFrustum* getViewFrustum() { return &_viewFrustum; }
|
||||
ViewFrustum* getDisplayViewFrustum() { return &_displayViewFrustum; }
|
||||
ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
|
||||
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
|
||||
MetavoxelSystem* getMetavoxels() { return &_metavoxels; }
|
||||
EntityTreeRenderer* getEntities() { return &_entities; }
|
||||
Environment* getEnvironment() { return &_environment; }
|
||||
PrioVR* getPrioVR() { return &_prioVR; }
|
||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
MainWindow* getWindow() { return _window; }
|
||||
OctreeQuery& getOctreeQuery() { return _octreeQuery; }
|
||||
|
@ -195,8 +192,8 @@ public:
|
|||
bool mouseOnScreen() const;
|
||||
int getMouseX() const;
|
||||
int getMouseY() const;
|
||||
int getTrueMouseX() const { return DependencyManager::get<GLCanvas>()->mapFromGlobal(QCursor::pos()).x(); }
|
||||
int getTrueMouseY() const { return DependencyManager::get<GLCanvas>()->mapFromGlobal(QCursor::pos()).y(); }
|
||||
int getTrueMouseX() const { return _glWidget->mapFromGlobal(QCursor::pos()).x(); }
|
||||
int getTrueMouseY() const { return _glWidget->mapFromGlobal(QCursor::pos()).y(); }
|
||||
int getMouseDragStartedX() const;
|
||||
int getMouseDragStartedY() const;
|
||||
int getTrueMouseDragStartedX() const { return _mouseDragStartedX; }
|
||||
|
@ -270,8 +267,8 @@ public:
|
|||
|
||||
FileLogger* getLogger() { return _logger; }
|
||||
|
||||
glm::vec2 getViewportDimensions() const { return glm::vec2(DependencyManager::get<GLCanvas>()->getDeviceWidth(),
|
||||
DependencyManager::get<GLCanvas>()->getDeviceHeight()); }
|
||||
glm::vec2 getViewportDimensions() const { return glm::vec2(_glWidget->getDeviceWidth(),
|
||||
_glWidget->getDeviceHeight()); }
|
||||
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
|
||||
|
||||
void skipVersion(QString latestVersion);
|
||||
|
@ -420,12 +417,8 @@ private:
|
|||
// Various helper functions called during update()
|
||||
void updateLOD();
|
||||
void updateMouseRay();
|
||||
void updateFaceshift();
|
||||
void updateVisage();
|
||||
void updateDDE();
|
||||
void updateMyAvatarLookAtPosition();
|
||||
void updateThreads(float deltaTime);
|
||||
void updateMetavoxels(float deltaTime);
|
||||
void updateCamera(float deltaTime);
|
||||
void updateDialogs(float deltaTime);
|
||||
void updateCursor(float deltaTime);
|
||||
|
@ -478,8 +471,6 @@ private:
|
|||
EntityTreeRenderer _entityClipboardRenderer;
|
||||
EntityTree _entityClipboard;
|
||||
|
||||
MetavoxelSystem _metavoxels;
|
||||
|
||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels)
|
||||
ViewFrustum _displayViewFrustum;
|
||||
|
@ -492,8 +483,6 @@ private:
|
|||
|
||||
MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
|
||||
|
||||
PrioVR _prioVR;
|
||||
|
||||
Camera _myCamera; // My view onto the world
|
||||
Camera _mirrorCamera; // Cammera for mirror view
|
||||
QRect _mirrorViewRect;
|
||||
|
@ -593,6 +582,8 @@ private:
|
|||
|
||||
QThread _settingsThread;
|
||||
QTimer _settingsTimer;
|
||||
|
||||
GLCanvas* _glWidget = new GLCanvas(); // our GLCanvas has a couple extra features
|
||||
};
|
||||
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -122,7 +122,7 @@ void Camera::setFarClip(float f) {
|
|||
}
|
||||
|
||||
PickRay Camera::computePickRay(float x, float y) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
return computeViewPickRay(x / glCanvas->width(), y / glCanvas->height());
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,10 @@ DatagramProcessor::DatagramProcessor(QObject* parent) :
|
|||
void DatagramProcessor::processDatagrams() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"DatagramProcessor::processDatagrams()");
|
||||
|
||||
if (_isShuttingDown) {
|
||||
return; // bail early... we're shutting down.
|
||||
}
|
||||
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
|
@ -96,9 +100,6 @@ void DatagramProcessor::processDatagrams() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case PacketTypeMetavoxelData:
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(incomingPacket);
|
||||
break;
|
||||
case PacketTypeBulkAvatarData:
|
||||
case PacketTypeKillAvatar:
|
||||
case PacketTypeAvatarIdentity:
|
||||
|
|
|
@ -25,14 +25,17 @@ public:
|
|||
int getOutByteCount() const { return _outByteCount; }
|
||||
|
||||
void resetCounters() { _inPacketCount = 0; _outPacketCount = 0; _inByteCount = 0; _outByteCount = 0; }
|
||||
|
||||
void shutdown() { _isShuttingDown = true; }
|
||||
public slots:
|
||||
void processDatagrams();
|
||||
|
||||
private:
|
||||
int _inPacketCount;
|
||||
int _outPacketCount;
|
||||
int _inByteCount;
|
||||
int _outByteCount;
|
||||
int _inPacketCount = 0;
|
||||
int _outPacketCount = 0;
|
||||
int _inByteCount = 0;
|
||||
int _outByteCount = 0;
|
||||
bool _isShuttingDown = false;
|
||||
};
|
||||
|
||||
#endif // hifi_DatagramProcessor_h
|
||||
|
|
|
@ -16,14 +16,13 @@
|
|||
#include <QGLWidget>
|
||||
#include <QTimer>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
/// customized canvas that simply forwards requests/events to the singleton application
|
||||
class GLCanvas : public QGLWidget, public Dependency {
|
||||
class GLCanvas : public QGLWidget {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
GLCanvas();
|
||||
|
||||
bool isThrottleRendering() const;
|
||||
|
||||
int getDeviceWidth() const;
|
||||
|
@ -60,12 +59,8 @@ private slots:
|
|||
void activeChanged(Qt::ApplicationState state);
|
||||
void throttleRender();
|
||||
bool eventFilter(QObject*, QEvent* event);
|
||||
|
||||
private:
|
||||
GLCanvas();
|
||||
~GLCanvas() {
|
||||
qDebug() << "Deleting GLCanvas";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_GLCanvas_h
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <PathUtils.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <XmppClient.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AccountManager.h"
|
||||
|
@ -148,8 +147,6 @@ Menu::Menu() {
|
|||
dialogsManager.data(), SLOT(editAnimations()));
|
||||
|
||||
QMenu* toolsMenu = addMenu("Tools");
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0,
|
||||
dialogsManager.data(), SLOT(showMetavoxelEditor()));
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S,
|
||||
dialogsManager.data(), SLOT(showScriptEditor()));
|
||||
|
||||
|
@ -162,12 +159,9 @@ Menu::Menu() {
|
|||
SLOT(setEnabled(bool)));
|
||||
connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool)));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, Qt::Key_Backslash,
|
||||
dialogsManager.data(), SLOT(showChat()));
|
||||
dialogsManager->setupChat();
|
||||
#endif
|
||||
dialogsManager.data(), SLOT(showIRCLink()));
|
||||
|
||||
addActionToQMenuAndActionHash(toolsMenu,
|
||||
MenuOption::ToolWindow,
|
||||
|
@ -295,7 +289,6 @@ Menu::Menu() {
|
|||
QMenu* renderOptionsMenu = developerMenu->addMenu("Render");
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Avatars, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Entities, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges);
|
||||
|
@ -394,13 +387,6 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false);
|
||||
|
||||
QMenu* metavoxelOptionsMenu = developerMenu->addMenu("Metavoxels");
|
||||
addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::DisplayHermiteData, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::RenderHeightfields, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::RenderDualContourSurfaces, 0, true);
|
||||
addActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::NetworkSimulator, 0,
|
||||
dialogsManager.data(), SLOT(showMetavoxelNetworkSimulator()));
|
||||
|
||||
QMenu* handOptionsMenu = developerMenu->addMenu("Hands");
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false);
|
||||
|
@ -453,7 +439,8 @@ Menu::Menu() {
|
|||
|
||||
QMenu* timingMenu = developerMenu->addMenu("Timing and Stats");
|
||||
QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarSimulateTiming, 0, false);
|
||||
|
|
|
@ -145,12 +145,11 @@ namespace MenuOption {
|
|||
const QString DisableNackPackets = "Disable NACK Packets";
|
||||
const QString DisplayHands = "Show Hand Info";
|
||||
const QString DisplayHandTargets = "Show Hand Targets";
|
||||
const QString DisplayHermiteData = "Display Hermite Data";
|
||||
const QString DisplayModelBounds = "Display Model Bounds";
|
||||
const QString DisplayModelTriangles = "Display Model Triangles";
|
||||
const QString DisplayModelElementChildProxies = "Display Model Element Children";
|
||||
const QString DisplayModelElementProxy = "Display Model Element Bounds";
|
||||
const QString DisplayTimingDetails = "Display Timing Details";
|
||||
const QString DisplayDebugTimingDetails = "Display Timing Details";
|
||||
const QString DontDoPrecisionPicking = "Don't Do Precision Picking";
|
||||
const QString DontFadeOnOctreeServerChanges = "Don't Fade In/Out on Octree Server Changes";
|
||||
const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene";
|
||||
|
@ -186,28 +185,24 @@ namespace MenuOption {
|
|||
const QString Login = "Login";
|
||||
const QString Log = "Log";
|
||||
const QString LowVelocityFilter = "Low Velocity Filter";
|
||||
const QString MetavoxelEditor = "Metavoxel Editor...";
|
||||
const QString Metavoxels = "Metavoxels";
|
||||
const QString Mirror = "Mirror";
|
||||
const QString MuteAudio = "Mute Microphone";
|
||||
const QString MuteEnvironment = "Mute Environment";
|
||||
const QString NetworkSimulator = "Network Simulator...";
|
||||
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
|
||||
const QString NoFaceTracking = "None";
|
||||
const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity";
|
||||
const QString OctreeStats = "Voxel and Entity Statistics";
|
||||
const QString OffAxisProjection = "Off-Axis Projection";
|
||||
const QString OldVoxelCullingMode = "Old Voxel Culling Mode";
|
||||
const QString OnlyDisplayTopTen = "Only Display Top Ten";
|
||||
const QString Pair = "Pair";
|
||||
const QString PipelineWarnings = "Log Render Pipeline Warnings";
|
||||
const QString Preferences = "Preferences...";
|
||||
const QString Quit = "Quit";
|
||||
const QString ReloadAllScripts = "Reload All Scripts";
|
||||
const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes";
|
||||
const QString RenderDualContourSurfaces = "Render Dual Contour Surfaces";
|
||||
const QString RenderFocusIndicator = "Show Eye Focus";
|
||||
const QString RenderHeadCollisionShapes = "Show Head Collision Shapes";
|
||||
const QString RenderHeightfields = "Render Heightfields";
|
||||
const QString RenderLookAtVectors = "Show Look-at Vectors";
|
||||
const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes";
|
||||
const QString RenderTargetFramerate = "Framerate";
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,445 +0,0 @@
|
|||
//
|
||||
// MetavoxelSystem.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/10/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_MetavoxelSystem_h
|
||||
#define hifi_MetavoxelSystem_h
|
||||
|
||||
#include <QList>
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QReadWriteLock>
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <MetavoxelClientManager.h>
|
||||
#include <ProgramObject.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
class HeightfieldBaseLayerBatch;
|
||||
class HeightfieldSplatBatch;
|
||||
class HermiteBatch;
|
||||
class MetavoxelBatch;
|
||||
class Model;
|
||||
class VoxelSplatBatch;
|
||||
|
||||
/// Renders a metavoxel tree.
|
||||
class MetavoxelSystem : public MetavoxelClientManager {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
class NetworkSimulation {
|
||||
public:
|
||||
float dropRate;
|
||||
float repeatRate;
|
||||
int minimumDelay;
|
||||
int maximumDelay;
|
||||
int bandwidthLimit;
|
||||
|
||||
NetworkSimulation(float dropRate = 0.0f, float repeatRate = 0.0f, int minimumDelay = 0,
|
||||
int maximumDelay = 0, int bandwidthLimit = 0);
|
||||
};
|
||||
|
||||
virtual ~MetavoxelSystem();
|
||||
|
||||
virtual void init();
|
||||
|
||||
virtual MetavoxelLOD getLOD();
|
||||
|
||||
const Frustum& getFrustum() const { return _frustum; }
|
||||
|
||||
void setNetworkSimulation(const NetworkSimulation& simulation);
|
||||
NetworkSimulation getNetworkSimulation();
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
void renderHeightfieldCursor(const glm::vec3& position, float radius);
|
||||
|
||||
Q_INVOKABLE void paintHeightfieldColor(const glm::vec3& position, float radius, const QColor& color);
|
||||
|
||||
Q_INVOKABLE void paintHeightfieldMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material);
|
||||
|
||||
Q_INVOKABLE void setHeightfieldColor(const SharedObjectPointer& spanner, const QColor& color, bool paint = false);
|
||||
|
||||
Q_INVOKABLE void setHeightfieldMaterial(const SharedObjectPointer& spanner,
|
||||
const SharedObjectPointer& material, bool paint = false);
|
||||
|
||||
void addHeightfieldBaseBatch(const HeightfieldBaseLayerBatch& batch) { _heightfieldBaseBatches.append(batch); }
|
||||
void addHeightfieldSplatBatch(const HeightfieldSplatBatch& batch) { _heightfieldSplatBatches.append(batch); }
|
||||
|
||||
void addVoxelBaseBatch(const MetavoxelBatch& batch) { _voxelBaseBatches.append(batch); }
|
||||
void addVoxelSplatBatch(const VoxelSplatBatch& batch) { _voxelSplatBatches.append(batch); }
|
||||
|
||||
void addHermiteBatch(const HermiteBatch& batch) { _hermiteBatches.append(batch); }
|
||||
|
||||
Q_INVOKABLE void deleteTextures(int heightTextureID, int colorTextureID, int materialTextureID) const;
|
||||
Q_INVOKABLE void deleteBuffers(int vertexBufferID, int indexBufferID, int hermiteBufferID) const;
|
||||
|
||||
signals:
|
||||
|
||||
void rendering();
|
||||
|
||||
protected:
|
||||
|
||||
Q_INVOKABLE void applyMaterialEdit(const MetavoxelEditMessage& message, bool reliable = false);
|
||||
|
||||
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
|
||||
|
||||
private:
|
||||
|
||||
void guideToAugmented(MetavoxelVisitor& visitor, bool render = false);
|
||||
|
||||
MetavoxelLOD _lod;
|
||||
QReadWriteLock _lodLock;
|
||||
Frustum _frustum;
|
||||
|
||||
NetworkSimulation _networkSimulation;
|
||||
QReadWriteLock _networkSimulationLock;
|
||||
|
||||
QVector<HeightfieldBaseLayerBatch> _heightfieldBaseBatches;
|
||||
QVector<HeightfieldSplatBatch> _heightfieldSplatBatches;
|
||||
QVector<MetavoxelBatch> _voxelBaseBatches;
|
||||
QVector<VoxelSplatBatch> _voxelSplatBatches;
|
||||
QVector<HermiteBatch> _hermiteBatches;
|
||||
|
||||
ProgramObject _baseHeightfieldProgram;
|
||||
int _baseHeightScaleLocation;
|
||||
int _baseColorScaleLocation;
|
||||
|
||||
class SplatLocations {
|
||||
public:
|
||||
int heightScale;
|
||||
int textureScale;
|
||||
int splatTextureOffset;
|
||||
int splatTextureScalesS;
|
||||
int splatTextureScalesT;
|
||||
int textureValueMinima;
|
||||
int textureValueMaxima;
|
||||
int materials;
|
||||
int materialWeights;
|
||||
};
|
||||
|
||||
ProgramObject _splatHeightfieldProgram;
|
||||
SplatLocations _splatHeightfieldLocations;
|
||||
|
||||
int _splatHeightScaleLocation;
|
||||
int _splatTextureScaleLocation;
|
||||
int _splatTextureOffsetLocation;
|
||||
int _splatTextureScalesSLocation;
|
||||
int _splatTextureScalesTLocation;
|
||||
int _splatTextureValueMinimaLocation;
|
||||
int _splatTextureValueMaximaLocation;
|
||||
|
||||
ProgramObject _heightfieldCursorProgram;
|
||||
|
||||
ProgramObject _baseVoxelProgram;
|
||||
ProgramObject _splatVoxelProgram;
|
||||
SplatLocations _splatVoxelLocations;
|
||||
|
||||
ProgramObject _voxelCursorProgram;
|
||||
|
||||
static void loadSplatProgram(const char* type, ProgramObject& program, SplatLocations& locations);
|
||||
};
|
||||
|
||||
/// Base class for all batches.
|
||||
class MetavoxelBatch {
|
||||
public:
|
||||
GLuint vertexBufferID;
|
||||
GLuint indexBufferID;
|
||||
glm::vec3 translation;
|
||||
glm::quat rotation;
|
||||
glm::vec3 scale;
|
||||
int vertexCount;
|
||||
int indexCount;
|
||||
};
|
||||
|
||||
/// Base class for heightfield batches.
|
||||
class HeightfieldBatch : public MetavoxelBatch {
|
||||
public:
|
||||
GLuint heightTextureID;
|
||||
glm::vec4 heightScale;
|
||||
};
|
||||
|
||||
/// A batch containing a heightfield base layer.
|
||||
class HeightfieldBaseLayerBatch : public HeightfieldBatch {
|
||||
public:
|
||||
GLuint colorTextureID;
|
||||
glm::vec2 colorScale;
|
||||
};
|
||||
|
||||
/// A batch containing a heightfield splat.
|
||||
class HeightfieldSplatBatch : public HeightfieldBatch {
|
||||
public:
|
||||
GLuint materialTextureID;
|
||||
glm::vec2 textureScale;
|
||||
glm::vec2 splatTextureOffset;
|
||||
int splatTextureIDs[4];
|
||||
glm::vec4 splatTextureScalesS;
|
||||
glm::vec4 splatTextureScalesT;
|
||||
int materialIndex;
|
||||
};
|
||||
|
||||
/// A batch containing a voxel splat.
|
||||
class VoxelSplatBatch : public MetavoxelBatch {
|
||||
public:
|
||||
glm::vec3 splatTextureOffset;
|
||||
int splatTextureIDs[4];
|
||||
glm::vec4 splatTextureScalesS;
|
||||
glm::vec4 splatTextureScalesT;
|
||||
int materialIndex;
|
||||
};
|
||||
|
||||
/// A batch containing Hermite data for debugging.
|
||||
class HermiteBatch {
|
||||
public:
|
||||
GLuint vertexBufferID;
|
||||
glm::vec3 translation;
|
||||
glm::quat rotation;
|
||||
glm::vec3 scale;
|
||||
int vertexCount;
|
||||
};
|
||||
|
||||
/// Generic abstract base class for objects that handle a signal.
|
||||
class SignalHandler : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public slots:
|
||||
|
||||
virtual void handle() = 0;
|
||||
};
|
||||
|
||||
/// Simple throttle for limiting bandwidth on a per-second basis.
|
||||
class Throttle {
|
||||
public:
|
||||
|
||||
Throttle();
|
||||
|
||||
/// Sets the per-second limit.
|
||||
void setLimit(int limit) { _limit = limit; }
|
||||
|
||||
/// Determines whether the message with the given size should be throttled (discarded). If not, registers the message
|
||||
/// as having been processed (i.e., contributing to later throttling).
|
||||
bool shouldThrottle(int bytes);
|
||||
|
||||
private:
|
||||
|
||||
int _limit;
|
||||
int _total;
|
||||
|
||||
typedef QPair<qint64, int> Bucket;
|
||||
QList<Bucket> _buckets;
|
||||
};
|
||||
|
||||
/// A client session associated with a single server.
|
||||
class MetavoxelSystemClient : public MetavoxelClient {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater);
|
||||
|
||||
Q_INVOKABLE void setAugmentedData(const MetavoxelData& data);
|
||||
|
||||
/// Returns a copy of the augmented data. This function is thread-safe.
|
||||
MetavoxelData getAugmentedData();
|
||||
|
||||
void setRenderedAugmentedData(const MetavoxelData& data) { _renderedAugmentedData = data; }
|
||||
|
||||
virtual int parseData(const QByteArray& packet);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void dataChanged(const MetavoxelData& oldData);
|
||||
virtual void sendDatagram(const QByteArray& data);
|
||||
|
||||
private:
|
||||
|
||||
MetavoxelData _augmentedData;
|
||||
MetavoxelData _renderedAugmentedData;
|
||||
QReadWriteLock _augmentedDataLock;
|
||||
|
||||
Throttle _sendThrottle;
|
||||
Throttle _receiveThrottle;
|
||||
};
|
||||
|
||||
/// Base class for cached static buffers.
|
||||
class BufferData : public QSharedData {
|
||||
public:
|
||||
|
||||
virtual ~BufferData();
|
||||
|
||||
virtual void render(const glm::vec3& translation, const glm::quat& rotation,
|
||||
const glm::vec3& scale, bool cursor = false) = 0;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<BufferData> BufferDataPointer;
|
||||
|
||||
/// Describes contents of a vertex in a voxel buffer.
|
||||
class VoxelPoint {
|
||||
public:
|
||||
glm::vec3 vertex;
|
||||
quint8 color[3];
|
||||
char normal[3];
|
||||
quint8 materials[4];
|
||||
quint8 materialWeights[4];
|
||||
|
||||
void setNormal(const glm::vec3& normal);
|
||||
};
|
||||
|
||||
/// A container for a coordinate within a voxel block.
|
||||
class VoxelCoord {
|
||||
public:
|
||||
QRgb encoded;
|
||||
|
||||
VoxelCoord(QRgb encoded) : encoded(encoded) { }
|
||||
|
||||
bool operator==(const VoxelCoord& other) const { return encoded == other.encoded; }
|
||||
};
|
||||
|
||||
inline uint qHash(const VoxelCoord& coord, uint seed) {
|
||||
// multiply by prime numbers greater than the possible size
|
||||
return qHash(qRed(coord.encoded) + 257 * (qGreen(coord.encoded) + 263 * qBlue(coord.encoded)), seed);
|
||||
}
|
||||
|
||||
/// Contains the information necessary to render a voxel block.
|
||||
class VoxelBuffer : public BufferData {
|
||||
public:
|
||||
|
||||
VoxelBuffer(const QVector<VoxelPoint>& vertices, const QVector<int>& indices, const QVector<glm::vec3>& hermite,
|
||||
const QMultiHash<VoxelCoord, int>& quadIndices, int size, const QVector<SharedObjectPointer>& materials =
|
||||
QVector<SharedObjectPointer>());
|
||||
virtual ~VoxelBuffer();
|
||||
|
||||
bool isHermiteEnabled() const { return _hermiteEnabled; }
|
||||
|
||||
/// Finds the first intersection between the described ray and the voxel data.
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float boundsDistance, float& distance) const;
|
||||
|
||||
virtual void render(const glm::vec3& translation, const glm::quat& rotation,
|
||||
const glm::vec3& scale, bool cursor = false);
|
||||
|
||||
private:
|
||||
|
||||
QVector<VoxelPoint> _vertices;
|
||||
QVector<int> _indices;
|
||||
QVector<glm::vec3> _hermite;
|
||||
bool _hermiteEnabled;
|
||||
QMultiHash<VoxelCoord, int> _quadIndices;
|
||||
int _size;
|
||||
int _vertexCount;
|
||||
int _indexCount;
|
||||
int _hermiteCount;
|
||||
GLuint _vertexBufferID;
|
||||
GLuint _indexBufferID;
|
||||
GLuint _hermiteBufferID;
|
||||
QVector<SharedObjectPointer> _materials;
|
||||
QVector<NetworkTexturePointer> _networkTextures;
|
||||
};
|
||||
|
||||
/// Renders metavoxels as points.
|
||||
class DefaultMetavoxelRendererImplementation : public MetavoxelRendererImplementation {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE DefaultMetavoxelRendererImplementation();
|
||||
|
||||
virtual void simulate(MetavoxelData& data, float deltaTime, MetavoxelInfo& info, const MetavoxelLOD& lod);
|
||||
virtual void render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod);
|
||||
};
|
||||
|
||||
/// Renders spheres.
|
||||
class SphereRenderer : public SpannerRenderer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE SphereRenderer();
|
||||
|
||||
virtual void render(const MetavoxelLOD& lod = MetavoxelLOD(), bool contained = false, bool cursor = false);
|
||||
};
|
||||
|
||||
/// Renders cuboids.
|
||||
class CuboidRenderer : public SpannerRenderer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE CuboidRenderer();
|
||||
|
||||
virtual void render(const MetavoxelLOD& lod = MetavoxelLOD(), bool contained = false, bool cursor = false);
|
||||
};
|
||||
|
||||
/// Renders static models.
|
||||
class StaticModelRenderer : public SpannerRenderer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE StaticModelRenderer();
|
||||
|
||||
virtual void init(Spanner* spanner);
|
||||
virtual void simulate(float deltaTime);
|
||||
virtual void render(const MetavoxelLOD& lod = MetavoxelLOD(), bool contained = false, bool cursor = false);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
|
||||
private slots:
|
||||
|
||||
void applyTranslation(const glm::vec3& translation);
|
||||
void applyRotation(const glm::quat& rotation);
|
||||
void applyScale(float scale);
|
||||
void applyURL(const QUrl& url);
|
||||
|
||||
private:
|
||||
|
||||
Model* _model;
|
||||
};
|
||||
|
||||
/// Renders heightfields.
|
||||
class HeightfieldRenderer : public SpannerRenderer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE HeightfieldRenderer();
|
||||
|
||||
virtual void render(const MetavoxelLOD& lod = MetavoxelLOD(), bool contained = false, bool cursor = false);
|
||||
};
|
||||
|
||||
/// Renders a single quadtree node.
|
||||
class HeightfieldNodeRenderer : public AbstractHeightfieldNodeRenderer {
|
||||
public:
|
||||
|
||||
HeightfieldNodeRenderer();
|
||||
virtual ~HeightfieldNodeRenderer();
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale,
|
||||
const glm::vec3& origin, const glm::vec3& direction, float boundsDistance, float& distance) const;
|
||||
|
||||
void render(const HeightfieldNodePointer& node, const glm::vec3& translation,
|
||||
const glm::quat& rotation, const glm::vec3& scale, bool cursor);
|
||||
|
||||
private:
|
||||
|
||||
GLuint _heightTextureID;
|
||||
GLuint _colorTextureID;
|
||||
GLuint _materialTextureID;
|
||||
QVector<NetworkTexturePointer> _networkTextures;
|
||||
|
||||
BufferDataPointer _voxels;
|
||||
|
||||
typedef QPair<int, int> IntPair;
|
||||
typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair;
|
||||
static QHash<IntPair, BufferPair> _bufferPairs;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelSystem_h
|
|
@ -12,7 +12,6 @@
|
|||
#include <QStyle>
|
||||
#include <QStyleOptionTitleBar>
|
||||
|
||||
#include "DependencyManager.h"
|
||||
#include "GLCanvas.h"
|
||||
|
||||
#include "UIUtil.h"
|
||||
|
@ -44,8 +43,6 @@ int UIUtil::getWindowTitleBarHeight(const QWidget* window) {
|
|||
// this function at all. If you mix both you will end up with inconsistent results
|
||||
// across platforms.
|
||||
void UIUtil::scaleWidgetFontSizes(QWidget* widget) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
|
||||
// This is the base dpi that we are targetting. This is based on Mac OSXs default DPI,
|
||||
// and is the basis for all font sizes.
|
||||
const float BASE_DPI = 72.0f;
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
//
|
||||
// XmppClient.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Dimitar Dobrev on 10/3/14.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include <AccountManager.h>
|
||||
|
||||
#include "XmppClient.h"
|
||||
|
||||
const QString DEFAULT_XMPP_SERVER = "chat.highfidelity.io";
|
||||
const QString DEFAULT_CHAT_ROOM = "public@public-chat.highfidelity.io";
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
XmppClient::XmppClient() :
|
||||
_xmppClient(),
|
||||
_xmppMUCManager()
|
||||
{
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
connect(&accountManager, SIGNAL(profileChanged()), this, SLOT(connectToServer()));
|
||||
connect(&accountManager, SIGNAL(logoutComplete()), this, SLOT(disconnectFromServer()));
|
||||
}
|
||||
#else
|
||||
XmppClient::XmppClient() {
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
XmppClient& XmppClient::getInstance() {
|
||||
static XmppClient sharedInstance;
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
void XmppClient::xmppConnected() {
|
||||
#ifdef HAVE_QXMPP
|
||||
_publicChatRoom = _xmppMUCManager.addRoom(DEFAULT_CHAT_ROOM);
|
||||
_publicChatRoom->setNickName(AccountManager::getInstance().getAccountInfo().getUsername());
|
||||
_publicChatRoom->join();
|
||||
emit joinedPublicChatRoom();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
void XmppClient::xmppError(QXmppClient::Error error) {
|
||||
qDebug() << "Error connnecting to XMPP for user "
|
||||
<< AccountManager::getInstance().getAccountInfo().getUsername() << ": " << error;
|
||||
}
|
||||
#endif
|
||||
|
||||
void XmppClient::connectToServer() {
|
||||
#ifdef HAVE_QXMPP
|
||||
disconnectFromServer();
|
||||
|
||||
if (_xmppClient.addExtension(&_xmppMUCManager)) {
|
||||
connect(&_xmppClient, SIGNAL(connected()), this, SLOT(xmppConnected()));
|
||||
connect(&_xmppClient, SIGNAL(error(QXmppClient::Error)), this, SLOT(xmppError(QXmppClient::Error)));
|
||||
}
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
QString user = accountManager.getAccountInfo().getUsername();
|
||||
const QString& password = accountManager.getAccountInfo().getXMPPPassword();
|
||||
_xmppClient.connectToServer(user + "@" + DEFAULT_XMPP_SERVER, password);
|
||||
#endif
|
||||
}
|
||||
|
||||
void XmppClient::disconnectFromServer() {
|
||||
#ifdef HAVE_QXMPP
|
||||
if (_xmppClient.isConnected()) {
|
||||
_xmppClient.disconnectFromServer();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
XmppClient::XmppClient(const XmppClient& other) {
|
||||
Q_UNUSED(other);
|
||||
}
|
||||
|
||||
void XmppClient::operator =(XmppClient const& other) {
|
||||
Q_UNUSED(other);
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
//
|
||||
// XmppClient.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Dimitar Dobrev on 10/3/14.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_XmppClient_h
|
||||
#define hifi_XmppClient_h
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
#include <QXmppClient.h>
|
||||
#include <QXmppMucManager.h>
|
||||
#endif
|
||||
|
||||
/// Generalized threaded processor for handling received inbound packets.
|
||||
class XmppClient : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static XmppClient& getInstance();
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
QXmppClient& getXMPPClient() { return _xmppClient; }
|
||||
const QXmppMucRoom* getPublicChatRoom() const { return _publicChatRoom; }
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void joinedPublicChatRoom();
|
||||
|
||||
private slots:
|
||||
void xmppConnected();
|
||||
#ifdef HAVE_QXMPP
|
||||
void xmppError(QXmppClient::Error error);
|
||||
#endif
|
||||
|
||||
void connectToServer();
|
||||
void disconnectFromServer();
|
||||
|
||||
private:
|
||||
XmppClient();
|
||||
XmppClient(XmppClient const& other); // not implemented
|
||||
void operator=(XmppClient const& other); // not implemented
|
||||
|
||||
#ifdef HAVE_QXMPP
|
||||
QXmppClient _xmppClient;
|
||||
QXmppMucManager _xmppMUCManager;
|
||||
QXmppMucRoom* _publicChatRoom;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // hifi_XmppClient_h
|
|
@ -16,6 +16,7 @@
|
|||
#include <PathUtils.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AudioToolBox.h"
|
||||
|
||||
// Mute icon configration
|
||||
|
@ -37,7 +38,7 @@ bool AudioToolBox::mousePressEvent(int x, int y) {
|
|||
void AudioToolBox::render(int x, int y, bool boxed) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
if (_micTextureId == 0) {
|
||||
_micTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/mic.svg"));
|
||||
}
|
||||
|
@ -105,8 +106,12 @@ void AudioToolBox::render(int x, int y, bool boxed) {
|
|||
glm::vec2 bottomRight(_iconBounds.right(), _iconBounds.bottom());
|
||||
glm::vec2 texCoordTopLeft(1,1);
|
||||
glm::vec2 texCoordBottomRight(0,0);
|
||||
|
||||
if (_boxQuadID == GeometryCache::UNKNOWN_ID) {
|
||||
_boxQuadID = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor, _boxQuadID);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_AudioToolBox_h
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
class AudioToolBox : public Dependency {
|
||||
SINGLETON_DEPENDENCY
|
||||
|
@ -26,6 +27,7 @@ private:
|
|||
GLuint _micTextureId = 0;
|
||||
GLuint _muteTextureId = 0;
|
||||
GLuint _boxTextureId = 0;
|
||||
int _boxQuadID = GeometryCache::UNKNOWN_ID;
|
||||
QRect _iconBounds;
|
||||
qint64 _iconPulseTimeReference = 0;
|
||||
};
|
||||
|
|
|
@ -77,7 +77,8 @@ Avatar::Avatar() :
|
|||
_moving(false),
|
||||
_collisionGroups(0),
|
||||
_initialized(false),
|
||||
_shouldRenderBillboard(true)
|
||||
_shouldRenderBillboard(true),
|
||||
_voiceSphereID(GeometryCache::UNKNOWN_ID)
|
||||
{
|
||||
// we may have been created in the network thread, but we live in the main thread
|
||||
moveToThread(Application::getInstance()->thread());
|
||||
|
@ -366,7 +367,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
|
||||
// render body
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
|
||||
renderBody(renderMode, postLighting, glowLevel);
|
||||
renderBody(frustum, renderMode, postLighting, glowLevel);
|
||||
}
|
||||
|
||||
if (!postLighting && renderMode != SHADOW_RENDER_MODE) {
|
||||
|
@ -380,8 +381,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
foreach (const AvatarManager::LocalLight& light, DependencyManager::get<AvatarManager>()->getLocalLights()) {
|
||||
glm::vec3 direction = orientation * light.direction;
|
||||
DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position - direction * distance,
|
||||
distance * 2.0f, glm::vec3(), light.color, light.color, 1.0f, 0.5f, 0.0f, direction,
|
||||
LIGHT_EXPONENT, LIGHT_CUTOFF);
|
||||
distance * 2.0f, light.color, 0.5f, orientation, LIGHT_EXPONENT, LIGHT_CUTOFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,8 +439,13 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
|
|||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
glScalef(height, height, height);
|
||||
|
||||
if (_voiceSphereID == GeometryCache::UNKNOWN_ID) {
|
||||
_voiceSphereID = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(sphereRadius, 15, 15,
|
||||
glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE));
|
||||
glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true,
|
||||
_voiceSphereID);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
@ -472,7 +477,7 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
|||
return glm::angleAxis(angle * proportion, axis);
|
||||
}
|
||||
|
||||
void Avatar::renderBody(RenderMode renderMode, bool postLighting, float glowLevel) {
|
||||
void Avatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel) {
|
||||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
{
|
||||
|
@ -489,11 +494,13 @@ void Avatar::renderBody(RenderMode renderMode, bool postLighting, float glowLeve
|
|||
if (postLighting) {
|
||||
getHand()->render(false, modelRenderMode);
|
||||
} else {
|
||||
_skeletonModel.render(1.0f, modelRenderMode);
|
||||
renderAttachments(renderMode);
|
||||
RenderArgs args;
|
||||
args._viewFrustum = renderFrustum;
|
||||
_skeletonModel.render(1.0f, modelRenderMode, &args);
|
||||
renderAttachments(renderMode, &args);
|
||||
}
|
||||
}
|
||||
getHead()->render(1.0f, modelRenderMode, postLighting);
|
||||
getHead()->render(1.0f, renderFrustum, modelRenderMode, postLighting);
|
||||
}
|
||||
|
||||
bool Avatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const {
|
||||
|
@ -520,11 +527,11 @@ void Avatar::simulateAttachments(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
void Avatar::renderAttachments(RenderMode renderMode) {
|
||||
void Avatar::renderAttachments(RenderMode renderMode, RenderArgs* args) {
|
||||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
foreach (Model* model, _attachmentModels) {
|
||||
model->render(1.0f, modelRenderMode);
|
||||
model->render(1.0f, modelRenderMode, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,18 +544,13 @@ void Avatar::renderBillboard() {
|
|||
return;
|
||||
}
|
||||
if (!_billboardTexture) {
|
||||
QImage image = QImage::fromData(_billboard);
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
_billboardTexture.reset(new Texture());
|
||||
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
|
||||
// Using a unique URL ensures we don't get another avatar's texture from TextureCache
|
||||
QUrl uniqueUrl = QUrl(QUuid::createUuid().toString());
|
||||
_billboardTexture = DependencyManager::get<TextureCache>()->getTexture(
|
||||
uniqueUrl, DEFAULT_TEXTURE, false, _billboard);
|
||||
}
|
||||
if (!_billboardTexture->isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
|
@ -556,6 +558,8 @@ void Avatar::renderBillboard() {
|
|||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
|
|
|
@ -223,18 +223,18 @@ protected:
|
|||
|
||||
float calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD);
|
||||
void renderDisplayName();
|
||||
virtual void renderBody(RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
|
||||
virtual void renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
|
||||
virtual bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const;
|
||||
|
||||
void simulateAttachments(float deltaTime);
|
||||
virtual void renderAttachments(RenderMode renderMode);
|
||||
virtual void renderAttachments(RenderMode renderMode, RenderArgs* args);
|
||||
|
||||
virtual void updateJointMappings();
|
||||
|
||||
private:
|
||||
|
||||
bool _initialized;
|
||||
QScopedPointer<Texture> _billboardTexture;
|
||||
NetworkTexturePointer _billboardTexture;
|
||||
bool _shouldRenderBillboard;
|
||||
bool _isLookAtTarget;
|
||||
|
||||
|
@ -243,6 +243,8 @@ private:
|
|||
float getBillboardSize() const;
|
||||
|
||||
static int _jointConesID;
|
||||
|
||||
int _voiceSphereID;
|
||||
};
|
||||
|
||||
#endif // hifi_Avatar_h
|
||||
|
|
|
@ -39,6 +39,8 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
setPupilDilation(_owningHead->getPupilDilation());
|
||||
setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients());
|
||||
|
||||
invalidCalculatedMeshBoxes();
|
||||
|
||||
if (isActive()) {
|
||||
setOffset(-_geometry->getFBXGeometry().neckPivot);
|
||||
Model::simulateInternal(deltaTime);
|
||||
|
|
|
@ -42,7 +42,6 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_mouth2(0.0f),
|
||||
_mouth3(0.0f),
|
||||
_mouth4(0.0f),
|
||||
_angularVelocity(0,0,0),
|
||||
_renderLookatVectors(false),
|
||||
_saccade(0.0f, 0.0f, 0.0f),
|
||||
_saccadeTarget(0.0f, 0.0f, 0.0f),
|
||||
|
@ -244,13 +243,15 @@ void Head::relaxLean(float deltaTime) {
|
|||
_deltaLeanForward *= relaxationFactor;
|
||||
}
|
||||
|
||||
void Head::render(float alpha, Model::RenderMode mode, bool postLighting) {
|
||||
void Head::render(float alpha, ViewFrustum* renderFrustum, Model::RenderMode mode, bool postLighting) {
|
||||
if (postLighting) {
|
||||
if (_renderLookatVectors) {
|
||||
renderLookatVectors(_leftEyePosition, _rightEyePosition, getCorrectedLookAtPosition());
|
||||
}
|
||||
} else {
|
||||
_faceModel.render(alpha, mode);
|
||||
RenderArgs args;
|
||||
args._viewFrustum = renderFrustum;
|
||||
_faceModel.render(alpha, mode, &args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
void init();
|
||||
void reset();
|
||||
void simulate(float deltaTime, bool isMine, bool billboard = false);
|
||||
void render(float alpha, Model::RenderMode mode, bool postLighting);
|
||||
void render(float alpha, ViewFrustum* renderFrustum, Model::RenderMode mode, bool postLighting);
|
||||
void setScale(float scale);
|
||||
void setPosition(glm::vec3 position) { _position = position; }
|
||||
void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; }
|
||||
|
@ -55,9 +55,6 @@ public:
|
|||
|
||||
/// \return orientationBody * orientationBasePitch
|
||||
glm::quat getCameraOrientation () const;
|
||||
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; }
|
||||
|
||||
void setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition);
|
||||
glm::vec3 getCorrectedLookAtPosition();
|
||||
|
@ -130,7 +127,6 @@ private:
|
|||
float _mouth2;
|
||||
float _mouth3;
|
||||
float _mouth4;
|
||||
glm::vec3 _angularVelocity;
|
||||
bool _renderLookatVectors;
|
||||
glm::vec3 _saccade;
|
||||
glm::vec3 _saccadeTarget;
|
||||
|
|
|
@ -294,12 +294,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Application::getInstance()->getPrioVR()->hasHeadRotation()) {
|
||||
estimatedRotation = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getHeadRotation()));
|
||||
estimatedRotation.x *= -1.0f;
|
||||
estimatedRotation.z *= -1.0f;
|
||||
|
||||
} else if (OculusManager::isConnected()) {
|
||||
if (OculusManager::isConnected()) {
|
||||
estimatedPosition = OculusManager::getRelativePosition();
|
||||
estimatedPosition.x *= -1.0f;
|
||||
_trackedHeadPosition = estimatedPosition;
|
||||
|
@ -349,13 +344,6 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
|||
}
|
||||
head->setDeltaRoll(estimatedRotation.z);
|
||||
|
||||
// the priovr can give us exact lean
|
||||
if (Application::getInstance()->getPrioVR()->isActive()) {
|
||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getTorsoRotation()));
|
||||
head->setLeanSideways(eulers.z);
|
||||
head->setLeanForward(eulers.x);
|
||||
return;
|
||||
}
|
||||
// Update torso lean distance based on accelerometer data
|
||||
const float TORSO_LENGTH = 0.5f;
|
||||
glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f);
|
||||
|
@ -892,13 +880,7 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
|||
_lookAtTargetAvatar.clear();
|
||||
_targetAvatarPosition = glm::vec3(0.0f);
|
||||
|
||||
glm::quat faceRotation = Application::getInstance()->getViewFrustum()->getOrientation();
|
||||
FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
// If faceshift or other face tracker in use, add on the actual angle of the head
|
||||
faceRotation *= tracker->getHeadRotation();
|
||||
}
|
||||
glm::vec3 lookForward = faceRotation * IDENTITY_FRONT;
|
||||
glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT;
|
||||
glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();
|
||||
|
||||
float smallestAngleTo = glm::radians(Application::getInstance()->getCamera()->getFieldOfView()) / 2.0f;
|
||||
|
@ -1085,7 +1067,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g
|
|||
Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved);
|
||||
}
|
||||
|
||||
void MyAvatar::renderBody(RenderMode renderMode, bool postLighting, float glowLevel) {
|
||||
void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel) {
|
||||
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
|
||||
return; // wait until both models are loaded
|
||||
}
|
||||
|
@ -1094,15 +1076,17 @@ void MyAvatar::renderBody(RenderMode renderMode, bool postLighting, float glowLe
|
|||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
if (!postLighting) {
|
||||
_skeletonModel.render(1.0f, modelRenderMode);
|
||||
renderAttachments(renderMode);
|
||||
RenderArgs args;
|
||||
args._viewFrustum = renderFrustum;
|
||||
_skeletonModel.render(1.0f, modelRenderMode, &args);
|
||||
renderAttachments(renderMode, &args);
|
||||
}
|
||||
|
||||
// Render head so long as the camera isn't inside it
|
||||
const Camera *camera = Application::getInstance()->getCamera();
|
||||
const glm::vec3 cameraPos = camera->getPosition();
|
||||
if (shouldRenderHead(cameraPos, renderMode)) {
|
||||
getHead()->render(1.0f, modelRenderMode, postLighting);
|
||||
getHead()->render(1.0f, renderFrustum, modelRenderMode, postLighting);
|
||||
}
|
||||
if (postLighting) {
|
||||
getHand()->render(true, modelRenderMode);
|
||||
|
@ -1164,15 +1148,8 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
pitch *= DEGREES_PER_RADIAN;
|
||||
roll *= DEGREES_PER_RADIAN;
|
||||
|
||||
// Record the angular velocity
|
||||
Head* head = getHead();
|
||||
if (deltaTime > 0.0f) {
|
||||
glm::vec3 angularVelocity(pitch - head->getBasePitch(), yaw - head->getBaseYaw(), roll - head->getBaseRoll());
|
||||
angularVelocity *= 1.0f / deltaTime;
|
||||
head->setAngularVelocity(angularVelocity);
|
||||
}
|
||||
|
||||
//Invert yaw and roll when in mirror mode
|
||||
Head* head = getHead();
|
||||
if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
|
||||
head->setBaseYaw(-yaw);
|
||||
head->setBasePitch(pitch);
|
||||
|
@ -1900,9 +1877,9 @@ void MyAvatar::onToggleRagdoll() {
|
|||
}
|
||||
}
|
||||
|
||||
void MyAvatar::renderAttachments(RenderMode renderMode) {
|
||||
void MyAvatar::renderAttachments(RenderMode renderMode, RenderArgs* args) {
|
||||
if (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON || renderMode == MIRROR_RENDER_MODE) {
|
||||
Avatar::renderAttachments(renderMode);
|
||||
Avatar::renderAttachments(renderMode, args);
|
||||
return;
|
||||
}
|
||||
const FBXGeometry& geometry = _skeletonModel.getGeometry()->getFBXGeometry();
|
||||
|
@ -1912,7 +1889,7 @@ void MyAvatar::renderAttachments(RenderMode renderMode) {
|
|||
for (int i = 0; i < _attachmentData.size(); i++) {
|
||||
const QString& jointName = _attachmentData.at(i).jointName;
|
||||
if (jointName != headJointName && jointName != "Head") {
|
||||
_attachmentModels.at(i)->render(1.0f, modelRenderMode);
|
||||
_attachmentModels.at(i)->render(1.0f, modelRenderMode, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
void updateFromTrackers(float deltaTime);
|
||||
|
||||
void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE, bool postLighting = false);
|
||||
void renderBody(RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
|
||||
void renderBody(ViewFrustum* renderFrustum, RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
|
||||
bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const;
|
||||
void renderDebugBodyPoints();
|
||||
|
||||
|
@ -187,7 +187,7 @@ signals:
|
|||
void transformChanged();
|
||||
|
||||
protected:
|
||||
virtual void renderAttachments(RenderMode renderMode);
|
||||
virtual void renderAttachments(RenderMode renderMode, RenderArgs* args);
|
||||
|
||||
private:
|
||||
float _turningKeyPressTime;
|
||||
|
|
|
@ -106,21 +106,6 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
}
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
PrioVR* prioVR = Application::getInstance()->getPrioVR();
|
||||
if (prioVR->isActive()) {
|
||||
for (int i = 0; i < prioVR->getJointRotations().size(); i++) {
|
||||
int humanIKJointIndex = prioVR->getHumanIKJointIndices().at(i);
|
||||
if (humanIKJointIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex);
|
||||
if (jointIndex != -1) {
|
||||
JointState& state = _jointStates[jointIndex];
|
||||
state.setRotationInBindFrame(prioVR->getJointRotations().at(i), PALM_PRIORITY);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// find the left and rightmost active palms
|
||||
int leftPalmIndex, rightPalmIndex;
|
||||
|
@ -294,7 +279,7 @@ void SkeletonModel::updateJointState(int index) {
|
|||
}
|
||||
|
||||
void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, JointState& state) {
|
||||
if (!_owningAvatar->isMyAvatar() || Application::getInstance()->getPrioVR()->isActive()) {
|
||||
if (!_owningAvatar->isMyAvatar()) {
|
||||
return;
|
||||
}
|
||||
// get the rotation axes in joint space and use them to adjust the rotation
|
||||
|
|
|
@ -17,15 +17,89 @@
|
|||
#include <QElapsedTimer>
|
||||
|
||||
#include "DdeFaceTracker.h"
|
||||
#include "FaceshiftConstants.h"
|
||||
|
||||
static const QHostAddress DDE_FEATURE_POINT_SERVER_ADDR("127.0.0.1");
|
||||
static const quint16 DDE_FEATURE_POINT_SERVER_PORT = 5555;
|
||||
|
||||
static const int NUM_EXPRESSION = 46;
|
||||
static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSION) * sizeof(float) + sizeof(int);
|
||||
static const int NUM_EXPRESSIONS = 46;
|
||||
static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSIONS) * sizeof(float) + sizeof(int);
|
||||
static const int MAX_NAME_SIZE = 31;
|
||||
|
||||
struct Packet{
|
||||
// There's almost but not quite a 1-1 correspondence between DDE's 46 and Faceshift 1.3's 48 packets.
|
||||
// The best guess at mapping is to:
|
||||
// - Swap L and R values
|
||||
// - Skip two Faceshift values: JawChew (22) and LipsLowerDown (37)
|
||||
static const int DDE_TO_FACESHIFT_MAPPING[] = {
|
||||
1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
|
||||
16,
|
||||
18, 17,
|
||||
19,
|
||||
23,
|
||||
21,
|
||||
// Skip JawChew
|
||||
20,
|
||||
25, 24, 27, 26, 29, 28, 31, 30, 33, 32,
|
||||
34, 35, 36,
|
||||
// Skip LipsLowerDown
|
||||
38, 39, 40, 41, 42, 43, 44, 45,
|
||||
47, 46
|
||||
};
|
||||
|
||||
// The DDE coefficients, overall, range from -0.2 to 1.5 or so. However, individual coefficients typically vary much
|
||||
// less than this.
|
||||
static const float DDE_COEFFICIENT_SCALES[] = {
|
||||
4.0f, // EyeBlink_L
|
||||
4.0f, // EyeBlink_R
|
||||
1.0f, // EyeSquint_L
|
||||
1.0f, // EyeSquint_R
|
||||
1.0f, // EyeDown_L
|
||||
1.0f, // EyeDown_R
|
||||
1.0f, // EyeIn_L
|
||||
1.0f, // EyeIn_R
|
||||
4.0f, // EyeOpen_L
|
||||
4.0f, // EyeOpen_R
|
||||
1.0f, // EyeOut_L
|
||||
1.0f, // EyeOut_R
|
||||
1.0f, // EyeUp_L
|
||||
1.0f, // EyeUp_R
|
||||
3.0f, // BrowsD_L
|
||||
3.0f, // BrowsD_R
|
||||
3.0f, // BrowsU_C
|
||||
3.0f, // BrowsU_L
|
||||
3.0f, // BrowsU_R
|
||||
1.0f, // JawFwd
|
||||
1.5f, // JawLeft
|
||||
1.8f, // JawOpen
|
||||
1.0f, // JawChew
|
||||
1.5f, // JawRight
|
||||
1.5f, // MouthLeft
|
||||
1.5f, // MouthRight
|
||||
1.5f, // MouthFrown_L
|
||||
1.5f, // MouthFrown_R
|
||||
1.5f, // MouthSmile_L
|
||||
1.5f, // MouthSmile_R
|
||||
1.0f, // MouthDimple_L
|
||||
1.0f, // MouthDimple_R
|
||||
1.0f, // LipsStretch_L
|
||||
1.0f, // LipsStretch_R
|
||||
1.0f, // LipsUpperClose
|
||||
1.0f, // LipsLowerClose
|
||||
1.0f, // LipsUpperUp
|
||||
1.0f, // LipsLowerDown
|
||||
1.0f, // LipsUpperOpen
|
||||
1.0f, // LipsLowerOpen
|
||||
2.5f, // LipsFunnel
|
||||
2.0f, // LipsPucker
|
||||
1.5f, // ChinLowerRaise
|
||||
1.5f, // ChinUpperRaise
|
||||
1.0f, // Sneer
|
||||
3.0f, // Puff
|
||||
1.0f, // CheekSquint_L
|
||||
1.0f // CheekSquint_R
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
//roughly in mm
|
||||
float focal_length[1];
|
||||
float translation[3];
|
||||
|
@ -33,8 +107,9 @@ struct Packet{
|
|||
//quaternion
|
||||
float rotation[4];
|
||||
|
||||
//blendshape coefficients ranging between -0.2 and 1.5
|
||||
float expressions[NUM_EXPRESSION];
|
||||
// The DDE coefficients, overall, range from -0.2 to 1.5 or so. However, individual coefficients typically vary much
|
||||
// less than this.
|
||||
float expressions[NUM_EXPRESSIONS];
|
||||
|
||||
//avatar id selected on the UI
|
||||
int avatar_id;
|
||||
|
@ -50,6 +125,8 @@ DdeFaceTracker::DdeFaceTracker() :
|
|||
}
|
||||
|
||||
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
||||
_host(host),
|
||||
_port(port),
|
||||
_lastReceiveTimestamp(0),
|
||||
_reset(false),
|
||||
_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||
|
@ -64,10 +141,13 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
|||
_mouthSmileLeftIndex(28),
|
||||
_mouthSmileRightIndex(29),
|
||||
_jawOpenIndex(21),
|
||||
_host(host),
|
||||
_port(port)
|
||||
_previousTranslation(glm::vec3()),
|
||||
_previousRotation(glm::quat())
|
||||
{
|
||||
_blendshapeCoefficients.resize(NUM_EXPRESSION);
|
||||
_coefficients.resize(NUM_FACESHIFT_BLENDSHAPES);
|
||||
_previousCoefficients.resize(NUM_FACESHIFT_BLENDSHAPES);
|
||||
|
||||
_blendshapeCoefficients.resize(NUM_FACESHIFT_BLENDSHAPES);
|
||||
|
||||
connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams()));
|
||||
connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketErrorOccurred(QAbstractSocket::SocketError)));
|
||||
|
@ -80,18 +160,6 @@ DdeFaceTracker::~DdeFaceTracker() {
|
|||
}
|
||||
}
|
||||
|
||||
void DdeFaceTracker::init() {
|
||||
|
||||
}
|
||||
|
||||
void DdeFaceTracker::reset() {
|
||||
_reset = true;
|
||||
}
|
||||
|
||||
void DdeFaceTracker::update() {
|
||||
|
||||
}
|
||||
|
||||
void DdeFaceTracker::setEnabled(bool enabled) {
|
||||
// isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket.
|
||||
_udpSocket.close();
|
||||
|
@ -151,37 +219,6 @@ float DdeFaceTracker::getBlendshapeCoefficient(int index) const {
|
|||
return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f;
|
||||
}
|
||||
|
||||
static const float DDE_MIN_RANGE = -0.2f;
|
||||
static const float DDE_MAX_RANGE = 1.5f;
|
||||
float rescaleCoef(float ddeCoef) {
|
||||
return (ddeCoef - DDE_MIN_RANGE) / (DDE_MAX_RANGE - DDE_MIN_RANGE);
|
||||
}
|
||||
|
||||
const int MIN = 0;
|
||||
const int AVG = 1;
|
||||
const int MAX = 2;
|
||||
const float LONG_TERM_AVERAGE = 0.999f;
|
||||
|
||||
|
||||
void resetCoefficient(float * coefficient, float currentValue) {
|
||||
coefficient[MIN] = coefficient[MAX] = coefficient[AVG] = currentValue;
|
||||
}
|
||||
|
||||
float updateAndGetCoefficient(float * coefficient, float currentValue, bool scaleToRange = false) {
|
||||
coefficient[MIN] = (currentValue < coefficient[MIN]) ? currentValue : coefficient[MIN];
|
||||
coefficient[MAX] = (currentValue > coefficient[MAX]) ? currentValue : coefficient[MAX];
|
||||
coefficient[AVG] = LONG_TERM_AVERAGE * coefficient[AVG] + (1.0f - LONG_TERM_AVERAGE) * currentValue;
|
||||
if (coefficient[MAX] > coefficient[MIN]) {
|
||||
if (scaleToRange) {
|
||||
return glm::clamp((currentValue - coefficient[AVG]) / (coefficient[MAX] - coefficient[MIN]), 0.0f, 1.0f);
|
||||
} else {
|
||||
return glm::clamp(currentValue - coefficient[AVG], 0.0f, 1.0f);
|
||||
}
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
||||
if(buffer.size() > MIN_PACKET_SIZE) {
|
||||
Packet packet;
|
||||
|
@ -196,9 +233,6 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
|||
if (_reset || (_lastReceiveTimestamp == 0)) {
|
||||
memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3));
|
||||
memcpy(&_referenceRotation, &rotation, sizeof(glm::quat));
|
||||
|
||||
resetCoefficient(_rightEye, packet.expressions[0]);
|
||||
resetCoefficient(_leftEye, packet.expressions[1]);
|
||||
_reset = false;
|
||||
}
|
||||
|
||||
|
@ -207,51 +241,61 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
|||
translation -= _referenceTranslation;
|
||||
translation /= LEAN_DAMPING_FACTOR;
|
||||
translation.x *= -1;
|
||||
|
||||
_headTranslation = (translation + _previousTranslation) / 2.0f;
|
||||
_previousTranslation = translation;
|
||||
|
||||
// Compute relative rotation
|
||||
rotation = glm::inverse(_referenceRotation) * rotation;
|
||||
|
||||
// copy values
|
||||
_headTranslation = translation;
|
||||
_headRotation = rotation;
|
||||
|
||||
if (_lastReceiveTimestamp == 0) {
|
||||
// On first packet, reset coefficients
|
||||
}
|
||||
|
||||
// Set blendshapes
|
||||
float EYE_MAGNIFIER = 4.0f;
|
||||
float rightEye = glm::clamp((updateAndGetCoefficient(_rightEye, packet.expressions[0])) * EYE_MAGNIFIER, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_rightBlinkIndex] = rightEye;
|
||||
float leftEye = glm::clamp((updateAndGetCoefficient(_leftEye, packet.expressions[1])) * EYE_MAGNIFIER, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_leftBlinkIndex] = leftEye;
|
||||
_headRotation = (rotation + _previousRotation) / 2.0f;
|
||||
_previousRotation = rotation;
|
||||
|
||||
|
||||
float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]);
|
||||
if (leftBrow < 0.5f) {
|
||||
_blendshapeCoefficients[_browDownLeftIndex] = 1.0f - 2.0f * leftBrow;
|
||||
_blendshapeCoefficients[_browUpLeftIndex] = 0.0f;
|
||||
} else {
|
||||
_blendshapeCoefficients[_browDownLeftIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_browUpLeftIndex] = 2.0f * (leftBrow - 0.5f);
|
||||
// Translate DDE coefficients to Faceshift compatible coefficients
|
||||
for (int i = 0; i < NUM_EXPRESSIONS; i += 1) {
|
||||
_coefficients[DDE_TO_FACESHIFT_MAPPING[i]] = packet.expressions[i];
|
||||
}
|
||||
float rightBrow = 1.0f - rescaleCoef(packet.expressions[15]);
|
||||
if (rightBrow < 0.5f) {
|
||||
_blendshapeCoefficients[_browDownRightIndex] = 1.0f - 2.0f * rightBrow;
|
||||
_blendshapeCoefficients[_browUpRightIndex] = 0.0f;
|
||||
|
||||
// Use EyeBlink values to control both EyeBlink and EyeOpen
|
||||
static const float RELAXED_EYE_VALUE = 0.1f;
|
||||
float leftEye = (_coefficients[_leftBlinkIndex] + _previousCoefficients[_leftBlinkIndex]) / 2.0f;
|
||||
float rightEye = (_coefficients[_rightBlinkIndex] + _previousCoefficients[_rightBlinkIndex]) / 2.0f;
|
||||
if (leftEye > RELAXED_EYE_VALUE) {
|
||||
_coefficients[_leftBlinkIndex] = leftEye - RELAXED_EYE_VALUE;
|
||||
_coefficients[_leftEyeOpenIndex] = 0.0f;
|
||||
} else {
|
||||
_blendshapeCoefficients[_browDownRightIndex] = 0.0f;
|
||||
_blendshapeCoefficients[_browUpRightIndex] = 2.0f * (rightBrow - 0.5f);
|
||||
_coefficients[_leftBlinkIndex] = 0.0f;
|
||||
_coefficients[_leftEyeOpenIndex] = RELAXED_EYE_VALUE - leftEye;
|
||||
}
|
||||
|
||||
float JAW_OPEN_MAGNIFIER = 1.4f;
|
||||
_blendshapeCoefficients[_jawOpenIndex] = rescaleCoef(packet.expressions[21]) * JAW_OPEN_MAGNIFIER;
|
||||
|
||||
float SMILE_MULTIPLIER = 2.0f;
|
||||
_blendshapeCoefficients[_mouthSmileLeftIndex] = glm::clamp(packet.expressions[24] * SMILE_MULTIPLIER, 0.0f, 1.0f);
|
||||
_blendshapeCoefficients[_mouthSmileRightIndex] = glm::clamp(packet.expressions[23] * SMILE_MULTIPLIER, 0.0f, 1.0f);
|
||||
|
||||
|
||||
if (rightEye > RELAXED_EYE_VALUE) {
|
||||
_coefficients[_rightBlinkIndex] = rightEye - RELAXED_EYE_VALUE;
|
||||
_coefficients[_rightEyeOpenIndex] = 0.0f;
|
||||
} else {
|
||||
_coefficients[_rightBlinkIndex] = 0.0f;
|
||||
_coefficients[_rightEyeOpenIndex] = RELAXED_EYE_VALUE - rightEye;
|
||||
}
|
||||
|
||||
// Use BrowsU_C to control both brows' up and down
|
||||
_coefficients[_browDownLeftIndex] = -_coefficients[_browUpCenterIndex];
|
||||
_coefficients[_browDownRightIndex] = -_coefficients[_browUpCenterIndex];
|
||||
_coefficients[_browUpLeftIndex] = _coefficients[_browUpCenterIndex];
|
||||
_coefficients[_browUpRightIndex] = _coefficients[_browUpCenterIndex];
|
||||
|
||||
// Offset jaw open coefficient
|
||||
static const float JAW_OPEN_THRESHOLD = 0.16f;
|
||||
_coefficients[_jawOpenIndex] = _coefficients[_jawOpenIndex] - JAW_OPEN_THRESHOLD;
|
||||
|
||||
// Offset smile coefficients
|
||||
static const float SMILE_THRESHOLD = 0.18f;
|
||||
_coefficients[_mouthSmileLeftIndex] = _coefficients[_mouthSmileLeftIndex] - SMILE_THRESHOLD;
|
||||
_coefficients[_mouthSmileRightIndex] = _coefficients[_mouthSmileRightIndex] - SMILE_THRESHOLD;
|
||||
|
||||
|
||||
// Scale all coefficients
|
||||
for (int i = 0; i < NUM_EXPRESSIONS; i += 1) {
|
||||
_blendshapeCoefficients[i]
|
||||
= glm::clamp(DDE_COEFFICIENT_SCALES[i] * (_coefficients[i] + _previousCoefficients[i]) / 2.0f, 0.0f, 1.0f);
|
||||
_previousCoefficients[i] = _coefficients[i];
|
||||
}
|
||||
|
||||
} else {
|
||||
qDebug() << "[Error] DDE Face Tracker Decode Error";
|
||||
}
|
||||
|
|
|
@ -23,12 +23,10 @@ class DdeFaceTracker : public FaceTracker, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
//initialization
|
||||
void init();
|
||||
void reset();
|
||||
void update();
|
||||
|
||||
bool isActive() const;
|
||||
virtual void reset() { _reset = true; }
|
||||
|
||||
virtual bool isActive() const;
|
||||
virtual bool isTracking() const { return isActive(); }
|
||||
|
||||
float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); }
|
||||
float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); }
|
||||
|
@ -90,10 +88,13 @@ private:
|
|||
int _mouthSmileRightIndex;
|
||||
|
||||
int _jawOpenIndex;
|
||||
|
||||
float _leftEye[3];
|
||||
float _rightEye[3];
|
||||
|
||||
|
||||
QVector<float> _coefficients;
|
||||
|
||||
// Previous values for simple smoothing
|
||||
glm::vec3 _previousTranslation;
|
||||
glm::quat _previousRotation;
|
||||
QVector<float> _previousCoefficients;
|
||||
};
|
||||
|
||||
#endif // hifi_DdeFaceTracker_h
|
|
@ -9,9 +9,60 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
FaceTracker::FaceTracker() :
|
||||
_estimatedEyePitch(0.0f),
|
||||
_estimatedEyeYaw(0.0f) {
|
||||
inline float FaceTracker::getBlendshapeCoefficient(int index) const {
|
||||
return isValidBlendshapeIndex(index) ? glm::mix(0.0f, _blendshapeCoefficients[index], getFadeCoefficient())
|
||||
: 0.0f;
|
||||
}
|
||||
|
||||
const QVector<float>& FaceTracker::getBlendshapeCoefficients() const {
|
||||
static QVector<float> blendshapes;
|
||||
float fadeCoefficient = getFadeCoefficient();
|
||||
if (fadeCoefficient == 1.0f) {
|
||||
return _blendshapeCoefficients;
|
||||
} else {
|
||||
blendshapes.resize(_blendshapeCoefficients.size());
|
||||
for (int i = 0; i < _blendshapeCoefficients.size(); i++) {
|
||||
blendshapes[i] = glm::mix(0.0f, _blendshapeCoefficients[i], fadeCoefficient);
|
||||
}
|
||||
return blendshapes;
|
||||
}
|
||||
}
|
||||
|
||||
float FaceTracker::getFadeCoefficient() const {
|
||||
return _fadeCoefficient;
|
||||
}
|
||||
|
||||
const glm::vec3 FaceTracker::getHeadTranslation() const {
|
||||
return glm::mix(glm::vec3(0.0f), _headTranslation, getFadeCoefficient());
|
||||
}
|
||||
|
||||
const glm::quat FaceTracker::getHeadRotation() const {
|
||||
return safeMix(glm::quat(), _headRotation, getFadeCoefficient());
|
||||
}
|
||||
|
||||
void FaceTracker::update(float deltaTime) {
|
||||
// Based on exponential distributions: http://en.wikipedia.org/wiki/Exponential_distribution
|
||||
static const float EPSILON = 0.02f; // MUST BE < 1.0f
|
||||
static const float INVERSE_AT_EPSILON = -std::log(EPSILON); // So that f(1.0f) = EPSILON ~ 0.0f
|
||||
static const float RELAXATION_TIME = 0.8f; // sec
|
||||
|
||||
if (isTracking()) {
|
||||
if (_relaxationStatus == 1.0f) {
|
||||
_fadeCoefficient = 1.0f;
|
||||
return;
|
||||
}
|
||||
_relaxationStatus = glm::clamp(_relaxationStatus + deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
|
||||
_fadeCoefficient = 1.0f - std::exp(-_relaxationStatus * INVERSE_AT_EPSILON);
|
||||
} else {
|
||||
if (_relaxationStatus == 0.0f) {
|
||||
_fadeCoefficient = 0.0f;
|
||||
return;
|
||||
}
|
||||
_relaxationStatus = glm::clamp(_relaxationStatus - deltaTime / RELAXATION_TIME, 0.0f, 1.0f);
|
||||
_fadeCoefficient = std::exp(-(1.0f - _relaxationStatus) * INVERSE_AT_EPSILON);
|
||||
}
|
||||
}
|
|
@ -18,29 +18,40 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
/// Base class for face trackers (Faceshift, Visage).
|
||||
/// Base class for face trackers (Faceshift, Visage, DDE).
|
||||
class FaceTracker : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FaceTracker();
|
||||
virtual ~FaceTracker() {}
|
||||
virtual bool isActive() const { return false; }
|
||||
virtual bool isTracking() const { return false; }
|
||||
|
||||
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
||||
const glm::quat& getHeadRotation() const { return _headRotation; }
|
||||
virtual void init() {}
|
||||
virtual void update(float deltaTime);
|
||||
virtual void reset() {}
|
||||
|
||||
float getFadeCoefficient() const;
|
||||
|
||||
const glm::vec3 getHeadTranslation() const;
|
||||
const glm::quat getHeadRotation() const;
|
||||
|
||||
float getEstimatedEyePitch() const { return _estimatedEyePitch; }
|
||||
float getEstimatedEyeYaw() const { return _estimatedEyeYaw; }
|
||||
|
||||
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||
int getNumBlendshapes() const { return _blendshapeCoefficients.size(); }
|
||||
bool isValidBlendshapeIndex(int index) const { return index >= 0 && index < getNumBlendshapes(); }
|
||||
const QVector<float>& getBlendshapeCoefficients() const;
|
||||
float getBlendshapeCoefficient(int index) const;
|
||||
|
||||
protected:
|
||||
|
||||
glm::vec3 _headTranslation;
|
||||
glm::quat _headRotation;
|
||||
float _estimatedEyePitch;
|
||||
float _estimatedEyeYaw;
|
||||
glm::vec3 _headTranslation = glm::vec3(0.0f);
|
||||
glm::quat _headRotation = glm::quat();
|
||||
float _estimatedEyePitch = 0.0f;
|
||||
float _estimatedEyeYaw = 0.0f;
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
|
||||
float _relaxationStatus = 0.0f; // Between 0.0f and 1.0f
|
||||
float _fadeCoefficient = 0.0f; // Between 0.0f and 1.0f
|
||||
};
|
||||
|
||||
#endif // hifi_FaceTracker_h
|
||||
|
|
|
@ -25,37 +25,11 @@ using namespace fs;
|
|||
|
||||
using namespace std;
|
||||
|
||||
const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
|
||||
const quint16 FACESHIFT_PORT = 33433;
|
||||
float STARTING_FACESHIFT_FRAME_TIME = 0.033f;
|
||||
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
||||
|
||||
Faceshift::Faceshift() :
|
||||
_tcpEnabled(true),
|
||||
_tcpRetryCount(0),
|
||||
_lastTrackingStateReceived(0),
|
||||
_averageFrameTime(STARTING_FACESHIFT_FRAME_TIME),
|
||||
_headAngularVelocity(0),
|
||||
_headLinearVelocity(0),
|
||||
_lastHeadTranslation(0),
|
||||
_filteredHeadTranslation(0),
|
||||
_eyeGazeLeftPitch(0.0f),
|
||||
_eyeGazeLeftYaw(0.0f),
|
||||
_eyeGazeRightPitch(0.0f),
|
||||
_eyeGazeRightYaw(0.0f),
|
||||
_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||
_rightBlinkIndex(1),
|
||||
_leftEyeOpenIndex(8),
|
||||
_rightEyeOpenIndex(9),
|
||||
_browDownLeftIndex(14),
|
||||
_browDownRightIndex(15),
|
||||
_browUpCenterIndex(16),
|
||||
_browUpLeftIndex(17),
|
||||
_browUpRightIndex(18),
|
||||
_mouthSmileLeftIndex(28),
|
||||
_mouthSmileRightIndex(29),
|
||||
_jawOpenIndex(21),
|
||||
_longTermAverageEyePitch(0.0f),
|
||||
_longTermAverageEyeYaw(0.0f),
|
||||
_longTermAverageInitialized(false),
|
||||
_eyeDeflection("faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION),
|
||||
_hostname("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME)
|
||||
{
|
||||
|
@ -71,31 +45,17 @@ Faceshift::Faceshift() :
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_FACESHIFT
|
||||
void Faceshift::init() {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Faceshift::isConnectedOrConnecting() const {
|
||||
return _tcpSocket.state() == QAbstractSocket::ConnectedState ||
|
||||
(_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState);
|
||||
}
|
||||
|
||||
bool Faceshift::isActive() const {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
const quint64 ACTIVE_TIMEOUT_USECS = 1000000;
|
||||
return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Faceshift::update() {
|
||||
void Faceshift::update(float deltaTime) {
|
||||
if (!isActive()) {
|
||||
return;
|
||||
}
|
||||
PerformanceTimer perfTimer("faceshift");
|
||||
FaceTracker::update(deltaTime);
|
||||
|
||||
// get the euler angles relative to the window
|
||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(_headRotation * glm::quat(glm::radians(glm::vec3(
|
||||
(_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f)))));
|
||||
|
@ -116,14 +76,28 @@ void Faceshift::update() {
|
|||
}
|
||||
|
||||
void Faceshift::reset() {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
if (_tcpSocket.state() == QAbstractSocket::ConnectedState) {
|
||||
string message;
|
||||
fsBinaryStream::encode_message(message, fsMsgCalibrateNeutral());
|
||||
send(message);
|
||||
}
|
||||
_longTermAverageInitialized = false;
|
||||
}
|
||||
|
||||
bool Faceshift::isActive() const {
|
||||
const quint64 ACTIVE_TIMEOUT_USECS = 1000000;
|
||||
return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS;
|
||||
}
|
||||
|
||||
bool Faceshift::isTracking() const {
|
||||
return isActive() && _tracking;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool Faceshift::isConnectedOrConnecting() const {
|
||||
return _tcpSocket.state() == QAbstractSocket::ConnectedState ||
|
||||
(_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState);
|
||||
}
|
||||
|
||||
void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp,
|
||||
|
@ -148,12 +122,13 @@ void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float
|
|||
}
|
||||
|
||||
void Faceshift::setTCPEnabled(bool enabled) {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
if ((_tcpEnabled = enabled)) {
|
||||
connectSocket();
|
||||
|
||||
} else {
|
||||
_tcpSocket.disconnectFromHost();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Faceshift::connectSocket() {
|
||||
|
@ -202,10 +177,6 @@ void Faceshift::readFromSocket() {
|
|||
receive(_tcpSocket.readAll());
|
||||
}
|
||||
|
||||
float Faceshift::getBlendshapeCoefficient(int index) const {
|
||||
return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f;
|
||||
}
|
||||
|
||||
void Faceshift::send(const std::string& message) {
|
||||
_tcpSocket.write(message.data(), message.size());
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@
|
|||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
|
||||
const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
|
||||
const float STARTING_FACESHIFT_FRAME_TIME = 0.033f;
|
||||
|
||||
/// Handles interaction with the Faceshift software, which provides head position/orientation and facial features.
|
||||
class Faceshift : public FaceTracker, public Dependency {
|
||||
|
@ -33,11 +32,17 @@ class Faceshift : public FaceTracker, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
void init();
|
||||
#ifdef HAVE_FACESHIFT
|
||||
// If we don't have faceshift, use the base class' methods
|
||||
virtual void init();
|
||||
virtual void update(float deltaTime);
|
||||
virtual void reset();
|
||||
|
||||
bool isConnectedOrConnecting() const;
|
||||
virtual bool isActive() const;
|
||||
virtual bool isTracking() const;
|
||||
#endif
|
||||
|
||||
bool isActive() const;
|
||||
bool isConnectedOrConnecting() const;
|
||||
|
||||
const glm::vec3& getHeadAngularVelocity() const { return _headAngularVelocity; }
|
||||
|
||||
|
@ -68,9 +73,6 @@ public:
|
|||
|
||||
QString getHostname() { return _hostname.get(); }
|
||||
void setHostname(const QString& hostname);
|
||||
|
||||
void update();
|
||||
void reset();
|
||||
|
||||
void updateFakeCoefficients(float leftBlink,
|
||||
float rightBlink,
|
||||
|
@ -82,15 +84,12 @@ public:
|
|||
QVector<float>& coefficients) const;
|
||||
|
||||
signals:
|
||||
|
||||
void connectionStateChanged();
|
||||
|
||||
public slots:
|
||||
|
||||
void setTCPEnabled(bool enabled);
|
||||
|
||||
private slots:
|
||||
|
||||
void connectSocket();
|
||||
void noteConnected();
|
||||
void noteError(QAbstractSocket::SocketError error);
|
||||
|
@ -101,8 +100,6 @@ private:
|
|||
Faceshift();
|
||||
virtual ~Faceshift() {}
|
||||
|
||||
float getBlendshapeCoefficient(int index) const;
|
||||
|
||||
void send(const std::string& message);
|
||||
void receive(const QByteArray& buffer);
|
||||
|
||||
|
@ -113,48 +110,48 @@ private:
|
|||
fs::fsBinaryStream _stream;
|
||||
#endif
|
||||
|
||||
bool _tcpEnabled;
|
||||
int _tcpRetryCount;
|
||||
bool _tracking;
|
||||
quint64 _lastTrackingStateReceived;
|
||||
float _averageFrameTime;
|
||||
bool _tcpEnabled = true;
|
||||
int _tcpRetryCount = 0;
|
||||
bool _tracking = false;
|
||||
quint64 _lastTrackingStateReceived = 0;
|
||||
float _averageFrameTime = STARTING_FACESHIFT_FRAME_TIME;
|
||||
|
||||
glm::vec3 _headAngularVelocity;
|
||||
glm::vec3 _headLinearVelocity;
|
||||
glm::vec3 _lastHeadTranslation;
|
||||
glm::vec3 _filteredHeadTranslation;
|
||||
glm::vec3 _headAngularVelocity = glm::vec3(0.0f);
|
||||
glm::vec3 _headLinearVelocity = glm::vec3(0.0f);
|
||||
glm::vec3 _lastHeadTranslation = glm::vec3(0.0f);
|
||||
glm::vec3 _filteredHeadTranslation = glm::vec3(0.0f);
|
||||
|
||||
// degrees
|
||||
float _eyeGazeLeftPitch;
|
||||
float _eyeGazeLeftYaw;
|
||||
float _eyeGazeRightPitch;
|
||||
float _eyeGazeRightYaw;
|
||||
|
||||
int _leftBlinkIndex;
|
||||
int _rightBlinkIndex;
|
||||
int _leftEyeOpenIndex;
|
||||
int _rightEyeOpenIndex;
|
||||
|
||||
// Brows
|
||||
int _browDownLeftIndex;
|
||||
int _browDownRightIndex;
|
||||
int _browUpCenterIndex;
|
||||
int _browUpLeftIndex;
|
||||
int _browUpRightIndex;
|
||||
|
||||
int _mouthSmileLeftIndex;
|
||||
int _mouthSmileRightIndex;
|
||||
|
||||
int _jawOpenIndex;
|
||||
float _eyeGazeLeftPitch = 0.0f;
|
||||
float _eyeGazeLeftYaw = 0.0f;
|
||||
float _eyeGazeRightPitch = 0.0f;
|
||||
float _eyeGazeRightYaw = 0.0f;
|
||||
|
||||
// degrees
|
||||
float _longTermAverageEyePitch;
|
||||
float _longTermAverageEyeYaw;
|
||||
bool _longTermAverageInitialized;
|
||||
float _longTermAverageEyePitch = 0.0f;
|
||||
float _longTermAverageEyeYaw = 0.0f;
|
||||
bool _longTermAverageInitialized = false;
|
||||
|
||||
Setting::Handle<float> _eyeDeflection;
|
||||
Setting::Handle<QString> _hostname;
|
||||
|
||||
// see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||
int _leftBlinkIndex = 0;
|
||||
int _rightBlinkIndex = 1;
|
||||
int _leftEyeOpenIndex = 8;
|
||||
int _rightEyeOpenIndex = 9;
|
||||
|
||||
// Brows
|
||||
int _browDownLeftIndex = 14;
|
||||
int _browDownRightIndex = 15;
|
||||
int _browUpCenterIndex = 16;
|
||||
int _browUpLeftIndex = 17;
|
||||
int _browUpRightIndex = 18;
|
||||
|
||||
int _mouthSmileLeftIndex = 28;
|
||||
int _mouthSmileRightIndex = 29;
|
||||
|
||||
int _jawOpenIndex = 21;
|
||||
};
|
||||
|
||||
#endif // hifi_Faceshift_h
|
||||
|
|
|
@ -437,7 +437,7 @@ void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenH
|
|||
|
||||
//Displays everything for the oculus, frame timing must be active
|
||||
void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) {
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
static bool attached = false;
|
||||
if (!attached) {
|
||||
|
@ -586,7 +586,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) {
|
||||
|
||||
glLoadIdentity();
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
glOrtho(0, glCanvas->getDeviceWidth(), 0, glCanvas->getDeviceHeight(), -1.0, 1.0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
|
|
@ -1,224 +0,0 @@
|
|||
//
|
||||
// PrioVR.cpp
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/12/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QTimer>
|
||||
#include <QtDebug>
|
||||
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <FBXReader.h>
|
||||
#include <PerfStat.h>
|
||||
#include <TextRenderer.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "PrioVR.h"
|
||||
#include "scripting/JoystickScriptingInterface.h"
|
||||
|
||||
#ifdef HAVE_PRIOVR
|
||||
const unsigned int SERIAL_LIST[] = { 0x00000001, 0x00000000, 0x00000008, 0x00000009, 0x0000000A,
|
||||
0x0000000C, 0x0000000D, 0x0000000E, 0x00000004, 0x00000005, 0x00000010, 0x00000011 };
|
||||
const unsigned char AXIS_LIST[] = { 9, 43, 37, 37, 37, 13, 13, 13, 52, 52, 28, 28 };
|
||||
const int LIST_LENGTH = sizeof(SERIAL_LIST) / sizeof(SERIAL_LIST[0]);
|
||||
|
||||
const char* JOINT_NAMES[] = { "Neck", "Spine", "LeftArm", "LeftForeArm", "LeftHand", "RightArm",
|
||||
"RightForeArm", "RightHand", "LeftUpLeg", "LeftLeg", "RightUpLeg", "RightLeg" };
|
||||
|
||||
static int indexOfHumanIKJoint(const char* jointName) {
|
||||
for (int i = 0;; i++) {
|
||||
QByteArray humanIKJoint = HUMANIK_JOINTS[i];
|
||||
if (humanIKJoint.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
if (humanIKJoint == jointName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void setPalm(float deltaTime, int index) {
|
||||
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
Hand* hand = avatar->getHand();
|
||||
PalmData* palm;
|
||||
bool foundHand = false;
|
||||
for (size_t j = 0; j < hand->getNumPalms(); j++) {
|
||||
if (hand->getPalms()[j].getSixenseID() == index) {
|
||||
palm = &(hand->getPalms()[j]);
|
||||
foundHand = true;
|
||||
}
|
||||
}
|
||||
if (!foundHand) {
|
||||
PalmData newPalm(hand);
|
||||
hand->getPalms().push_back(newPalm);
|
||||
palm = &(hand->getPalms()[hand->getNumPalms() - 1]);
|
||||
palm->setSixenseID(index);
|
||||
}
|
||||
|
||||
palm->setActive(true);
|
||||
|
||||
// Read controller buttons and joystick into the hand
|
||||
const QString PRIO_JOYSTICK_NAME = "PrioVR";
|
||||
Joystick* prioJoystick = JoystickScriptingInterface::getInstance().joystickWithName(PRIO_JOYSTICK_NAME);
|
||||
if (prioJoystick) {
|
||||
const QVector<float> axes = prioJoystick->getAxes();
|
||||
const QVector<bool> buttons = prioJoystick->getButtons();
|
||||
|
||||
if (axes.size() >= 4 && buttons.size() >= 4) {
|
||||
if (index == LEFT_HAND_INDEX) {
|
||||
palm->setControllerButtons(buttons[1] ? BUTTON_FWD : 0);
|
||||
palm->setTrigger(buttons[0] ? 1.0f : 0.0f);
|
||||
palm->setJoystick(axes[0], -axes[1]);
|
||||
|
||||
} else {
|
||||
palm->setControllerButtons(buttons[3] ? BUTTON_FWD : 0);
|
||||
palm->setTrigger(buttons[2] ? 1.0f : 0.0f);
|
||||
palm->setJoystick(axes[2], -axes[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this math is done in the worl-frame with unecessary complexity.
|
||||
// TODO: transfom this to stay in the model-frame.
|
||||
glm::vec3 position;
|
||||
glm::quat rotation;
|
||||
SkeletonModel* skeletonModel = &DependencyManager::get<AvatarManager>()->getMyAvatar()->getSkeletonModel();
|
||||
int jointIndex;
|
||||
glm::quat inverseRotation = glm::inverse(DependencyManager::get<AvatarManager>()->getMyAvatar()->getOrientation());
|
||||
if (index == LEFT_HAND_INDEX) {
|
||||
jointIndex = skeletonModel->getLeftHandJointIndex();
|
||||
skeletonModel->getJointRotationInWorldFrame(jointIndex, rotation);
|
||||
rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f));
|
||||
|
||||
} else {
|
||||
jointIndex = skeletonModel->getRightHandJointIndex();
|
||||
skeletonModel->getJointRotationInWorldFrame(jointIndex, rotation);
|
||||
rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, -PI_OVER_TWO, 0.0f));
|
||||
}
|
||||
skeletonModel->getJointPositionInWorldFrame(jointIndex, position);
|
||||
position = inverseRotation * (position - skeletonModel->getTranslation());
|
||||
|
||||
palm->setRawRotation(rotation);
|
||||
|
||||
// Compute current velocity from position change
|
||||
glm::vec3 rawVelocity;
|
||||
if (deltaTime > 0.0f) {
|
||||
rawVelocity = (position - palm->getRawPosition()) / deltaTime;
|
||||
} else {
|
||||
rawVelocity = glm::vec3(0.0f);
|
||||
}
|
||||
palm->setRawVelocity(rawVelocity);
|
||||
palm->setRawPosition(position);
|
||||
|
||||
// Store the one fingertip in the palm structure so we can track velocity
|
||||
const float FINGER_LENGTH = 0.3f; // meters
|
||||
const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH);
|
||||
const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
|
||||
glm::vec3 oldTipPosition = palm->getTipRawPosition();
|
||||
if (deltaTime > 0.0f) {
|
||||
palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
|
||||
} else {
|
||||
palm->setTipVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
palm->setTipPosition(newTipPosition);
|
||||
}
|
||||
#endif
|
||||
|
||||
PrioVR::PrioVR() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
char jointsDiscovered[LIST_LENGTH];
|
||||
_skeletalDevice = yei_setUpPrioVRSensors(0x00000000, const_cast<unsigned int*>(SERIAL_LIST),
|
||||
const_cast<unsigned char*>(AXIS_LIST), jointsDiscovered, LIST_LENGTH, YEI_TIMESTAMP_SYSTEM);
|
||||
if (!_skeletalDevice) {
|
||||
return;
|
||||
}
|
||||
_jointRotations.resize(LIST_LENGTH);
|
||||
_lastJointRotations.resize(LIST_LENGTH);
|
||||
for (int i = 0; i < LIST_LENGTH; i++) {
|
||||
_humanIKJointIndices.append(jointsDiscovered[i] ? indexOfHumanIKJoint(JOINT_NAMES[i]) : -1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PrioVR::~PrioVR() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
if (_skeletalDevice) {
|
||||
yei_stopStreaming(_skeletalDevice);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const int HEAD_ROTATION_INDEX = 0;
|
||||
|
||||
bool PrioVR::hasHeadRotation() const {
|
||||
return _humanIKJointIndices.size() > HEAD_ROTATION_INDEX && _humanIKJointIndices.at(HEAD_ROTATION_INDEX) != -1;
|
||||
}
|
||||
|
||||
glm::quat PrioVR::getHeadRotation() const {
|
||||
return _jointRotations.size() > HEAD_ROTATION_INDEX ? _jointRotations.at(HEAD_ROTATION_INDEX) : glm::quat();
|
||||
}
|
||||
|
||||
glm::quat PrioVR::getTorsoRotation() const {
|
||||
const int TORSO_ROTATION_INDEX = 1;
|
||||
return _jointRotations.size() > TORSO_ROTATION_INDEX ? _jointRotations.at(TORSO_ROTATION_INDEX) : glm::quat();
|
||||
}
|
||||
|
||||
void PrioVR::update(float deltaTime) {
|
||||
#ifdef HAVE_PRIOVR
|
||||
if (!_skeletalDevice) {
|
||||
return;
|
||||
}
|
||||
PerformanceTimer perfTimer("PrioVR");
|
||||
unsigned int timestamp;
|
||||
yei_getLastStreamDataAll(_skeletalDevice, (char*)_jointRotations.data(),
|
||||
_jointRotations.size() * sizeof(glm::quat), ×tamp);
|
||||
|
||||
// convert to our expected coordinate system, average with last rotations to smooth
|
||||
for (int i = 0; i < _jointRotations.size(); i++) {
|
||||
_jointRotations[i].y *= -1.0f;
|
||||
_jointRotations[i].z *= -1.0f;
|
||||
|
||||
glm::quat lastRotation = _lastJointRotations.at(i);
|
||||
_lastJointRotations[i] = _jointRotations.at(i);
|
||||
_jointRotations[i] = safeMix(lastRotation, _jointRotations.at(i), 0.5f);
|
||||
}
|
||||
|
||||
// convert the joysticks into palm data
|
||||
setPalm(deltaTime, LEFT_HAND_INDEX);
|
||||
setPalm(deltaTime, RIGHT_HAND_INDEX);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PrioVR::reset() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
if (!_skeletalDevice) {
|
||||
return;
|
||||
}
|
||||
connect(Application::getInstance(), SIGNAL(renderingOverlay()), SLOT(renderCalibrationCountdown()));
|
||||
_calibrationCountdownStarted = QDateTime::currentDateTime();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PrioVR::renderCalibrationCountdown() {
|
||||
#ifdef HAVE_PRIOVR
|
||||
const int COUNTDOWN_SECONDS = 3;
|
||||
int secondsRemaining = COUNTDOWN_SECONDS - _calibrationCountdownStarted.secsTo(QDateTime::currentDateTime());
|
||||
if (secondsRemaining == 0) {
|
||||
yei_tareSensors(_skeletalDevice);
|
||||
Application::getInstance()->disconnect(this);
|
||||
return;
|
||||
}
|
||||
static TextRenderer* textRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY, 18, QFont::Bold,
|
||||
false, TextRenderer::OUTLINE_EFFECT, 2);
|
||||
QByteArray text = "Assume T-Pose in " + QByteArray::number(secondsRemaining) + "...";
|
||||
auto glCanvas = DependencyManager::get<GLCanvas>();
|
||||
textRenderer->draw((glCanvas->width() - textRenderer->computeExtent(text.constData()).x) / 2,
|
||||
glCanvas->height() / 2,
|
||||
text, glm::vec4(1,1,1,1));
|
||||
#endif
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue