mirror of
https://github.com/lubosz/overte.git
synced 2025-04-09 01:22:36 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into low-latency-audio
This commit is contained in:
commit
9457d49103
191 changed files with 4669 additions and 2658 deletions
12
BUILD.md
12
BUILD.md
|
@ -1,7 +1,7 @@
|
|||
###Dependencies
|
||||
|
||||
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 3.3.2
|
||||
* [Qt](http://www.qt.io/download-open-source) ~> 5.5.1
|
||||
* [Qt](http://www.qt.io/download-open-source) ~> 5.6.1
|
||||
* [OpenSSL](https://www.openssl.org/community/binaries.html) ~> 1.0.1m
|
||||
* IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities.
|
||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||
|
@ -41,14 +41,14 @@ If you would like to use a specific install of a dependency instead of the versi
|
|||
Hifi uses CMake to generate build files and project files for your platform.
|
||||
|
||||
####Qt
|
||||
In order for CMake to find the Qt5 find modules, you will need to set an ENV variable pointing to your Qt installation.
|
||||
In order for CMake to find the Qt5 find modules, you will need to set a QT_CMAKE_PREFIX_PATH environment variable pointing to your Qt installation.
|
||||
|
||||
For example, a Qt5 5.5.1 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||
This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||
|
||||
The path it needs to be set to will depend on where and how Qt5 was installed. e.g.
|
||||
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.5.1/clang_64/lib/cmake/
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.5.1/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.6.1/clang_64/lib/cmake/
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.6.1-1/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
||||
|
||||
####Generating build files
|
||||
|
@ -65,7 +65,7 @@ Any variables that need to be set for CMake to find dependencies can be set as E
|
|||
|
||||
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
|
||||
|
||||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.5.1/lib/cmake
|
||||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.6.1/lib/cmake
|
||||
|
||||
####Finding Dependencies
|
||||
|
||||
|
|
|
@ -4,13 +4,11 @@ Please read the [general build guide](BUILD.md) for information on dependencies
|
|||
|
||||
You will need the following tools to build our Android targets.
|
||||
|
||||
* [cmake](http://www.cmake.org/download/) ~> 3.1.0
|
||||
* Note that this is a newer version required than the minimum for hifi desktop targets.
|
||||
* [Qt](http://www.qt.io/download-open-source/#) ~> 5.4.0
|
||||
* Note that this is a newer version required than the minimum for hifi desktop targets.
|
||||
* [cmake](http://www.cmake.org/download/) ~> 3.5.1
|
||||
* [Qt](http://www.qt.io/download-open-source/#) ~> 5.5.1
|
||||
* [ant](http://ant.apache.org/bindownload.cgi) ~> 1.9.4
|
||||
* [Android NDK](https://developer.android.com/tools/sdk/ndk/index.html) = r10c
|
||||
* [Android SDK](http://developer.android.com/sdk/installing/index.html) ~> 24.0.2
|
||||
* [Android NDK](https://developer.android.com/tools/sdk/ndk/index.html) ~> r10d
|
||||
* [Android SDK](http://developer.android.com/sdk/installing/index.html) ~> 24.4.1.1
|
||||
* Install the latest Platform-tools
|
||||
* Install the latest Build-tools
|
||||
* Install the SDK Platform for API Level 19
|
||||
|
@ -19,6 +17,12 @@ You will need the following tools to build our Android targets.
|
|||
|
||||
You will also need to cross-compile the dependencies required for all platforms for Android, and help CMake find these compiled libraries on your machine.
|
||||
|
||||
####Scribe
|
||||
|
||||
High Fidelity has a shader pre-processing tool called `scribe` that various libraries will call on during the build process. You must compile scribe using your native toolchain (following the build instructions for your platform) and then pass a CMake variable or set an ENV variable `SCRIBE_PATH` that is a path to the scribe executable.
|
||||
|
||||
CMake will fatally error if it does not find the scribe executable while using the android toolchain.
|
||||
|
||||
####Optional Components
|
||||
|
||||
* [Oculus Mobile SDK](https://developer.oculus.com/downloads/#sdk=mobile) ~> 0.4.2
|
||||
|
@ -31,11 +35,11 @@ This is most easily accomplished by installing all Android dependencies in the s
|
|||
|
||||
####Qt
|
||||
|
||||
Install Qt 5.4 for Android for your host environment from the [Qt downloads page](http://www.qt.io/download/). Install Qt to ``$ANDROID_LIB_DIR/Qt``. This is required so that our root CMakeLists file can help CMake find your Android Qt installation.
|
||||
Install Qt 5.5.1 for Android for your host environment from the [Qt downloads page](http://www.qt.io/download/). Install Qt to ``$ANDROID_LIB_DIR/Qt``. This is required so that our root CMakeLists file can help CMake find your Android Qt installation.
|
||||
|
||||
The component required for the Android build is the `Android armv7` component.
|
||||
|
||||
If you would like to install Qt to a different location, or attempt to build with a different Qt version, you can pass `ANDROID_QT_CMAKE_PREFIX_PATH` to CMake. Point to the `cmake` folder inside `$VERSION_NUMBER/android_armv7/lib`. Otherwise, our root CMakeLists will set it to `$ANDROID_LIB_DIR/Qt/5.3/android_armv7/lib/cmake`.
|
||||
If you would like to install Qt to a different location, or attempt to build with a different Qt version, you can pass `ANDROID_QT_CMAKE_PREFIX_PATH` to CMake. Point to the `cmake` folder inside `$VERSION_NUMBER/android_armv7/lib`. Otherwise, our root CMakeLists will set it to `$ANDROID_LIB_DIR/Qt/5.5/android_armv7/lib/cmake`.
|
||||
|
||||
####OpenSSL
|
||||
|
||||
|
|
26
BUILD_OSX.md
26
BUILD_OSX.md
|
@ -1,25 +1,31 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
|
||||
|
||||
###Homebrew
|
||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all High Fidelity dependencies very simple.
|
||||
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of some High Fidelity dependencies very simple.
|
||||
|
||||
brew tap homebrew/versions
|
||||
brew install cmake openssl qt55
|
||||
brew install cmake openssl
|
||||
|
||||
We no longer require install of qt5 via our [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas). Versions of Qt that are 5.5.x provide a mechanism to disable the wireless scanning we previously had a custom patch for.
|
||||
###OpenSSL
|
||||
|
||||
###OpenSSL and Qt
|
||||
|
||||
Assuming you've installed OpenSSL or Qt 5 using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR and QT_CMAKE_PREFIX_PATH so CMake can find your installations.
|
||||
Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations.
|
||||
For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR:
|
||||
|
||||
export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2h_1/
|
||||
|
||||
For Qt 5.5.1 installed via homebrew, set QT_CMAKE_PREFIX_PATH as follows.
|
||||
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt55/5.5.1/lib/cmake
|
||||
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
|
||||
|
||||
Note that these use the versions from homebrew formulae at the time of this writing, and the version in the path will likely change.
|
||||
###Qt
|
||||
You can use the online installer or the offline installer.
|
||||
|
||||
* [Download the online installer](http://www.qt.io/download-open-source/#section-2)
|
||||
* When it asks you to select components, select the following:
|
||||
* Qt > Qt 5.6
|
||||
|
||||
* [Download the offline installer](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-mac-x64-clang-5.6.1-1.dmg)
|
||||
|
||||
Once Qt is installed, you need to manually configure the following:
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt5.6.1/5.6/clang_64/lib/cmake/` directory.
|
||||
|
||||
###Xcode
|
||||
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
||||
|
|
12
BUILD_WIN.md
12
BUILD_WIN.md
|
@ -27,17 +27,17 @@ We expect nmake.exe to be located at the following path.
|
|||
###Qt
|
||||
You can use the online installer or the offline installer. If you use the offline installer, be sure to select the "OpenGL" version.
|
||||
|
||||
* [Download the online installer](http://qt-project.org/downloads)
|
||||
* [Download the online installer](http://www.qt.io/download-open-source/#section-2)
|
||||
* When it asks you to select components, ONLY select one of the following, 32- or 64-bit to match your build preference:
|
||||
* Qt > Qt 5.5.1 > **msvc2013 32-bit**
|
||||
* Qt > Qt 5.5.1 > **msvc2013 64-bit**
|
||||
* Qt > Qt 5.6.1 > **msvc2013 32-bit**
|
||||
* Qt > Qt 5.6.1 > **msvc2013 64-bit**
|
||||
|
||||
* Download the offline installer, 32- or 64-bit to match your build preference:
|
||||
* [32-bit](http://download.qt.io/official_releases/qt/5.5/5.5.1/qt-opensource-windows-x86-msvc2013-5.5.1.exe)
|
||||
* [64-bit](http://download.qt.io/official_releases/qt/5.5/5.5.1/qt-opensource-windows-x86-msvc2013_64-5.5.1.exe)
|
||||
* [32-bit](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013-5.6.1-1.exe)
|
||||
* [64-bit](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013_64-5.6.1-1.exe)
|
||||
|
||||
Once Qt is installed, you need to manually configure the following:
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.5.1\msvc2013\lib\cmake` or `Qt\5.5.1\msvc2013_64\lib\cmake` directory.
|
||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.6.1\msvc2013\lib\cmake` or `Qt\5.6.1\msvc2013_64\lib\cmake` directory.
|
||||
* You can set an environment variable from Control Panel > System > Advanced System Settings > Environment Variables > New
|
||||
|
||||
###External Libraries
|
||||
|
|
|
@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.2)
|
|||
if (USE_ANDROID_TOOLCHAIN)
|
||||
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/android/android.toolchain.cmake")
|
||||
set(ANDROID_NATIVE_API_LEVEL 19)
|
||||
set(ANDROID_TOOLCHAIN_NAME arm-linux-androideabi-clang3.5)
|
||||
set(ANDROID_STL c++_shared)
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
|
@ -64,7 +66,7 @@ if (WIN32)
|
|||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG /OPT:REF /OPT:ICF")
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter")
|
||||
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -Woverloaded-virtual -Wdouble-promotion")
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "5.1") # gcc 5.1 and on have suggest-override
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override")
|
||||
|
@ -72,18 +74,23 @@ else ()
|
|||
endif ()
|
||||
endif(WIN32)
|
||||
|
||||
if ((NOT MSVC12) AND (NOT MSVC14))
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
||||
if (NOT ANDROID)
|
||||
if ((NOT MSVC12) AND (NOT MSVC14))
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
||||
|
||||
if (COMPILER_SUPPORTS_CXX11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
elseif(COMPILER_SUPPORTS_CXX0X)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
else()
|
||||
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||
endif()
|
||||
if (COMPILER_SUPPORTS_CXX11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
elseif(COMPILER_SUPPORTS_CXX0X)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
else()
|
||||
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||
endif()
|
||||
endif ()
|
||||
else ()
|
||||
# assume that the toolchain selected for android has C++11 support
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
|
@ -98,7 +105,7 @@ endif ()
|
|||
|
||||
if (ANDROID)
|
||||
if (NOT ANDROID_QT_CMAKE_PREFIX_PATH)
|
||||
set(QT_CMAKE_PREFIX_PATH ${ANDROID_LIB_DIR}/Qt/5.4/android_armv7/lib/cmake)
|
||||
set(QT_CMAKE_PREFIX_PATH ${ANDROID_LIB_DIR}/Qt/5.5/android_armv7/lib/cmake)
|
||||
else ()
|
||||
set(QT_CMAKE_PREFIX_PATH ${ANDROID_QT_CMAKE_PREFIX_PATH})
|
||||
endif ()
|
||||
|
@ -236,7 +243,9 @@ if (NOT ANDROID)
|
|||
endif()
|
||||
|
||||
if (ANDROID OR DESKTOP_GVR)
|
||||
add_subdirectory(interface)
|
||||
add_subdirectory(gvr-interface)
|
||||
add_subdirectory(plugins)
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{HIFI_MEMORY_DEBUGGING})
|
||||
|
|
|
@ -2,6 +2,11 @@ set(TARGET_NAME assignment-client)
|
|||
|
||||
setup_hifi_project(Core Gui Network Script Quick Widgets WebSockets)
|
||||
|
||||
# Fix up the rpath so macdeployqt works
|
||||
if (APPLE)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
|
||||
endif ()
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
audio avatars octree gpu model fbx entities
|
||||
|
|
|
@ -413,6 +413,9 @@ void AvatarMixer::handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message
|
|||
}
|
||||
|
||||
void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->getOrCreateLinkedData(senderNode);
|
||||
|
||||
if (senderNode->getLinkedData()) {
|
||||
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
|
||||
if (nodeData != nullptr) {
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Android CMake toolchain file, for use with the Android NDK r5-r10c
|
||||
# Requires cmake 2.6.3 or newer (2.8.5 or newer is recommended).
|
||||
# Android CMake toolchain file, for use with the Android NDK r5-r10d
|
||||
# Requires cmake 2.6.3 or newer (2.8.9 or newer is recommended).
|
||||
# See home page: https://github.com/taka-no-me/android-cmake
|
||||
#
|
||||
# Usage Linux:
|
||||
|
@ -39,12 +39,6 @@
|
|||
# $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake ..
|
||||
# $ make -j8
|
||||
#
|
||||
# Usage Linux (using standalone toolchain):
|
||||
# $ export ANDROID_STANDALONE_TOOLCHAIN=/absolute/path/to/android-toolchain
|
||||
# $ mkdir build && cd build
|
||||
# $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake ..
|
||||
# $ make -j8
|
||||
#
|
||||
# Usage Windows:
|
||||
# You need native port of make to build your project.
|
||||
# Android NDK r7 (and newer) already has make.exe on board.
|
||||
|
@ -63,11 +57,6 @@
|
|||
# ANDROID_NDK=/opt/android-ndk - path to the NDK root.
|
||||
# Can be set as environment variable. Can be set only at first cmake run.
|
||||
#
|
||||
# ANDROID_STANDALONE_TOOLCHAIN=/opt/android-toolchain - path to the
|
||||
# standalone toolchain. This option is not used if full NDK is found
|
||||
# (ignored if ANDROID_NDK is set).
|
||||
# Can be set as environment variable. Can be set only at first cmake run.
|
||||
#
|
||||
# ANDROID_ABI=armeabi-v7a - specifies the target Application Binary
|
||||
# Interface (ABI). This option nearly matches to the APP_ABI variable
|
||||
# used by ndk-build tool from Android NDK.
|
||||
|
@ -123,8 +112,8 @@
|
|||
# * x86_64-clang3.5
|
||||
#
|
||||
# ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions
|
||||
# instead of Thumb. Is not available for "x86" (inapplicable) and
|
||||
# "armeabi-v6 with VFP" (is forced to be ON) ABIs.
|
||||
# instead of Thumb. Is not available for "armeabi-v6 with VFP"
|
||||
# (is forced to be ON) ABI.
|
||||
#
|
||||
# ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker
|
||||
# errors even if they are not used.
|
||||
|
@ -133,13 +122,6 @@
|
|||
# libraries. Automatically turned for NDK r5x and r6x due to GLESv2
|
||||
# problems.
|
||||
#
|
||||
# LIBRARY_OUTPUT_PATH_ROOT=${CMAKE_SOURCE_DIR} - where to output binary
|
||||
# files. See additional details below.
|
||||
#
|
||||
# ANDROID_SET_OBSOLETE_VARIABLES=ON - if set, then toolchain defines some
|
||||
# obsolete variables which were used by previous versions of this file for
|
||||
# backward compatibility.
|
||||
#
|
||||
# ANDROID_STL=gnustl_static - specify the runtime to use.
|
||||
#
|
||||
# Possible values are:
|
||||
|
@ -172,6 +154,8 @@
|
|||
# Implies -frtti -fno-exceptions.
|
||||
# Available for NDK r7b and newer.
|
||||
# Silently degrades to gnustl_static if not available.
|
||||
# c++_static -> Use the LLVM libc++ runtime as a static library.
|
||||
# c++_shared -> Use the LLVM libc++ runtime as a shared library.
|
||||
#
|
||||
# ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on
|
||||
# chosen runtime. If disabled, then the user is responsible for settings
|
||||
|
@ -200,12 +184,6 @@
|
|||
# will be set true, mutually exclusive. NEON option will be set true
|
||||
# if VFP is set to NEON.
|
||||
#
|
||||
# LIBRARY_OUTPUT_PATH_ROOT should be set in cache to determine where Android
|
||||
# libraries will be installed.
|
||||
# Default is ${CMAKE_SOURCE_DIR}, and the android libs will always be
|
||||
# under the ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}
|
||||
# (depending on the target ABI). This is convenient for Android packaging.
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
cmake_minimum_required( VERSION 2.6.3 )
|
||||
|
@ -235,22 +213,22 @@ endif()
|
|||
# this one not so much
|
||||
set( CMAKE_SYSTEM_VERSION 1 )
|
||||
|
||||
# rpath makes low sence for Android
|
||||
# rpath makes low sense for Android
|
||||
set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" )
|
||||
set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." )
|
||||
|
||||
# NDK search paths
|
||||
set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
|
||||
if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS)
|
||||
set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10d -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
|
||||
if( NOT DEFINED ANDROID_NDK_SEARCH_PATHS )
|
||||
if( CMAKE_HOST_WIN32 )
|
||||
file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS )
|
||||
set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}/android-ndk" "$ENV{SystemDrive}/NVPACK/android-ndk" )
|
||||
set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}" "$ENV{SystemDrive}/NVPACK" )
|
||||
else()
|
||||
file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS )
|
||||
set( ANDROID_NDK_SEARCH_PATHS /opt/android-ndk "${ANDROID_NDK_SEARCH_PATHS}/NVPACK/android-ndk" )
|
||||
set( ANDROID_NDK_SEARCH_PATHS /opt "${ANDROID_NDK_SEARCH_PATHS}/NVPACK" )
|
||||
endif()
|
||||
endif()
|
||||
if(NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH)
|
||||
if( NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH )
|
||||
set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain )
|
||||
endif()
|
||||
|
||||
|
@ -272,106 +250,90 @@ set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 )
|
|||
|
||||
|
||||
macro( __LIST_FILTER listvar regex )
|
||||
if( ${listvar} )
|
||||
foreach( __val ${${listvar}} )
|
||||
if( __val MATCHES "${regex}" )
|
||||
list( REMOVE_ITEM ${listvar} "${__val}" )
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
if( ${listvar} )
|
||||
foreach( __val ${${listvar}} )
|
||||
if( __val MATCHES "${regex}" )
|
||||
list( REMOVE_ITEM ${listvar} "${__val}" )
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro( __INIT_VARIABLE var_name )
|
||||
set( __test_path 0 )
|
||||
foreach( __var ${ARGN} )
|
||||
if( __var STREQUAL "PATH" )
|
||||
set( __test_path 1 )
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
if( __test_path AND NOT EXISTS "${${var_name}}" )
|
||||
unset( ${var_name} CACHE )
|
||||
endif()
|
||||
if( "${${var_name}}" STREQUAL "" )
|
||||
set( __values 0 )
|
||||
set( __test_path 0 )
|
||||
foreach( __var ${ARGN} )
|
||||
if( __var STREQUAL "VALUES" )
|
||||
set( __values 1 )
|
||||
elseif( NOT __var STREQUAL "PATH" )
|
||||
set( __obsolete 0 )
|
||||
if( __var MATCHES "^OBSOLETE_.*$" )
|
||||
string( REPLACE "OBSOLETE_" "" __var "${__var}" )
|
||||
set( __obsolete 1 )
|
||||
endif()
|
||||
if( __var MATCHES "^ENV_.*$" )
|
||||
string( REPLACE "ENV_" "" __var "${__var}" )
|
||||
set( __value "$ENV{${__var}}" )
|
||||
elseif( DEFINED ${__var} )
|
||||
set( __value "${${__var}}" )
|
||||
else()
|
||||
if( __values )
|
||||
set( __value "${__var}" )
|
||||
else()
|
||||
set( __value "" )
|
||||
endif()
|
||||
endif()
|
||||
if( NOT "${__value}" STREQUAL "" )
|
||||
if( __test_path )
|
||||
if( EXISTS "${__value}" )
|
||||
file( TO_CMAKE_PATH "${__value}" ${var_name} )
|
||||
if( __obsolete AND NOT _CMAKE_IN_TRY_COMPILE )
|
||||
message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." )
|
||||
endif()
|
||||
break()
|
||||
endif()
|
||||
else()
|
||||
set( ${var_name} "${__value}" )
|
||||
if( __obsolete AND NOT _CMAKE_IN_TRY_COMPILE )
|
||||
message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." )
|
||||
endif()
|
||||
if( __var STREQUAL "PATH" )
|
||||
set( __test_path 1 )
|
||||
break()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
unset( __value )
|
||||
unset( __values )
|
||||
unset( __obsolete )
|
||||
elseif( __test_path )
|
||||
file( TO_CMAKE_PATH "${${var_name}}" ${var_name} )
|
||||
endif()
|
||||
unset( __test_path )
|
||||
|
||||
if( __test_path AND NOT EXISTS "${${var_name}}" )
|
||||
unset( ${var_name} CACHE )
|
||||
endif()
|
||||
|
||||
if( " ${${var_name}}" STREQUAL " " )
|
||||
set( __values 0 )
|
||||
foreach( __var ${ARGN} )
|
||||
if( __var STREQUAL "VALUES" )
|
||||
set( __values 1 )
|
||||
elseif( NOT __var STREQUAL "PATH" )
|
||||
if( __var MATCHES "^ENV_.*$" )
|
||||
string( REPLACE "ENV_" "" __var "${__var}" )
|
||||
set( __value "$ENV{${__var}}" )
|
||||
elseif( DEFINED ${__var} )
|
||||
set( __value "${${__var}}" )
|
||||
elseif( __values )
|
||||
set( __value "${__var}" )
|
||||
else()
|
||||
set( __value "" )
|
||||
endif()
|
||||
|
||||
if( NOT " ${__value}" STREQUAL " " AND (NOT __test_path OR EXISTS "${__value}") )
|
||||
set( ${var_name} "${__value}" )
|
||||
break()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
unset( __value )
|
||||
unset( __values )
|
||||
endif()
|
||||
|
||||
if( __test_path )
|
||||
file( TO_CMAKE_PATH "${${var_name}}" ${var_name} )
|
||||
endif()
|
||||
unset( __test_path )
|
||||
endmacro()
|
||||
|
||||
macro( __DETECT_NATIVE_API_LEVEL _var _path )
|
||||
SET( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" )
|
||||
FILE( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" )
|
||||
if( NOT __apiFileContent )
|
||||
message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." )
|
||||
endif()
|
||||
string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" )
|
||||
unset( __apiFileContent )
|
||||
unset( __ndkApiLevelRegex )
|
||||
set( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" )
|
||||
file( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" )
|
||||
if( NOT __apiFileContent )
|
||||
message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." )
|
||||
endif()
|
||||
string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" )
|
||||
unset( __apiFileContent )
|
||||
unset( __ndkApiLevelRegex )
|
||||
endmacro()
|
||||
|
||||
macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root )
|
||||
if( EXISTS "${_root}" )
|
||||
file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" )
|
||||
__LIST_FILTER( __gccExePath "^[.].*" )
|
||||
list( LENGTH __gccExePath __gccExePathsCount )
|
||||
if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE )
|
||||
message( WARNING "Could not determine machine name for compiler from ${_root}" )
|
||||
set( ${_var} "" )
|
||||
file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" )
|
||||
__LIST_FILTER( __gccExePath "^[.].*" )
|
||||
list( LENGTH __gccExePath __gccExePathsCount )
|
||||
if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE )
|
||||
message( WARNING "Could not determine machine name for compiler from ${_root}" )
|
||||
set( ${_var} "" )
|
||||
else()
|
||||
get_filename_component( __gccExeName "${__gccExePath}" NAME_WE )
|
||||
string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" )
|
||||
endif()
|
||||
unset( __gccExePath )
|
||||
unset( __gccExePathsCount )
|
||||
unset( __gccExeName )
|
||||
else()
|
||||
get_filename_component( __gccExeName "${__gccExePath}" NAME_WE )
|
||||
string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" )
|
||||
set( ${_var} "" )
|
||||
endif()
|
||||
unset( __gccExePath )
|
||||
unset( __gccExePathsCount )
|
||||
unset( __gccExeName )
|
||||
else()
|
||||
set( ${_var} "" )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
|
@ -419,17 +381,19 @@ if( NOT ANDROID_NDK_HOST_X64 )
|
|||
endif()
|
||||
|
||||
# see if we have path to Android NDK
|
||||
__INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK )
|
||||
if( NOT ANDROID_NDK AND NOT ANDROID_STANDALONE_TOOLCHAIN )
|
||||
__INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK )
|
||||
endif()
|
||||
if( NOT ANDROID_NDK )
|
||||
# see if we have path to Android standalone toolchain
|
||||
__INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN OBSOLETE_ANDROID_NDK_TOOLCHAIN_ROOT OBSOLETE_ENV_ANDROID_NDK_TOOLCHAIN_ROOT )
|
||||
__INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN )
|
||||
|
||||
if( NOT ANDROID_STANDALONE_TOOLCHAIN )
|
||||
#try to find Android NDK in one of the the default locations
|
||||
set( __ndkSearchPaths )
|
||||
foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} )
|
||||
foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} )
|
||||
list( APPEND __ndkSearchPaths "${__ndkSearchPath}${suffix}" )
|
||||
list( APPEND __ndkSearchPaths "${__ndkSearchPath}/android-ndk${suffix}" )
|
||||
endforeach()
|
||||
endforeach()
|
||||
__INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} )
|
||||
|
@ -487,7 +451,7 @@ else()
|
|||
or
|
||||
export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain
|
||||
or put the toolchain or NDK in the default path:
|
||||
sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}
|
||||
sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}/android-ndk
|
||||
sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" )
|
||||
endif()
|
||||
|
||||
|
@ -636,7 +600,7 @@ if( BUILD_WITH_ANDROID_NDK )
|
|||
endif()
|
||||
if( NOT __availableToolchains )
|
||||
file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" )
|
||||
if( __availableToolchains )
|
||||
if( __availableToolchainsLst )
|
||||
list(SORT __availableToolchainsLst) # we need clang to go after gcc
|
||||
endif()
|
||||
__LIST_FILTER( __availableToolchainsLst "^[.]" )
|
||||
|
@ -669,7 +633,7 @@ if( NOT ANDROID_SUPPORTED_ABIS )
|
|||
endif()
|
||||
|
||||
# choose target ABI
|
||||
__INIT_VARIABLE( ANDROID_ABI OBSOLETE_ARM_TARGET OBSOLETE_ARM_TARGETS VALUES ${ANDROID_SUPPORTED_ABIS} )
|
||||
__INIT_VARIABLE( ANDROID_ABI VALUES ${ANDROID_SUPPORTED_ABIS} )
|
||||
# verify that target ABI is supported
|
||||
list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx )
|
||||
if( __androidAbiIdx EQUAL -1 )
|
||||
|
@ -760,7 +724,7 @@ if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMa
|
|||
endif()
|
||||
|
||||
if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 )
|
||||
__INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD OBSOLETE_FORCE_ARM VALUES OFF )
|
||||
__INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD VALUES OFF )
|
||||
set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE )
|
||||
mark_as_advanced( ANDROID_FORCE_ARM_BUILD )
|
||||
else()
|
||||
|
@ -845,6 +809,7 @@ else()
|
|||
unset( __realApiLevel )
|
||||
endif()
|
||||
set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE )
|
||||
set( CMAKE_ANDROID_API ${ANDROID_NATIVE_API_LEVEL} )
|
||||
if( CMAKE_VERSION VERSION_GREATER "2.8" )
|
||||
list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS )
|
||||
set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
|
||||
|
@ -863,23 +828,14 @@ endif()
|
|||
|
||||
# runtime choice (STL, rtti, exceptions)
|
||||
if( NOT ANDROID_STL )
|
||||
# honor legacy ANDROID_USE_STLPORT
|
||||
if( DEFINED ANDROID_USE_STLPORT )
|
||||
if( ANDROID_USE_STLPORT )
|
||||
set( ANDROID_STL stlport_static )
|
||||
endif()
|
||||
message( WARNING "You are using an obsolete variable ANDROID_USE_STLPORT to select the STL variant. Use -DANDROID_STL=stlport_static instead." )
|
||||
endif()
|
||||
if( NOT ANDROID_STL )
|
||||
set( ANDROID_STL gnustl_static )
|
||||
endif()
|
||||
endif()
|
||||
set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" )
|
||||
set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" )
|
||||
mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES )
|
||||
|
||||
if( BUILD_WITH_ANDROID_NDK )
|
||||
if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$")
|
||||
if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared|c\\+\\+_static|c\\+\\+_shared)$")
|
||||
message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\".
|
||||
The possible values are:
|
||||
none -> Do not configure the runtime.
|
||||
|
@ -891,6 +847,8 @@ The possible values are:
|
|||
stlport_shared -> Use the STLport runtime as a shared library.
|
||||
gnustl_static -> (default) Use the GNU STL as a static library.
|
||||
gnustl_shared -> Use the GNU STL as a shared library.
|
||||
c++_static -> Use the LLVM libc++ runtime as a static library.
|
||||
c++_shared -> Use the LLVM libc++ runtime as a shared library.
|
||||
" )
|
||||
endif()
|
||||
elseif( BUILD_WITH_STANDALONE_TOOLCHAIN )
|
||||
|
@ -1033,7 +991,7 @@ if( BUILD_WITH_ANDROID_NDK )
|
|||
set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" )
|
||||
elseif( ANDROID_STL MATCHES "gabi" )
|
||||
if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
|
||||
message( FATAL_ERROR "gabi++ is not awailable in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.")
|
||||
message( FATAL_ERROR "gabi++ is not available in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.")
|
||||
endif()
|
||||
set( ANDROID_RTTI ON )
|
||||
set( ANDROID_EXCEPTIONS OFF )
|
||||
|
@ -1066,12 +1024,40 @@ if( BUILD_WITH_ANDROID_NDK )
|
|||
else()
|
||||
set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" )
|
||||
endif()
|
||||
set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" )
|
||||
set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" "${__libstl}/include/backward" )
|
||||
if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" )
|
||||
set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" )
|
||||
else()
|
||||
set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" )
|
||||
endif()
|
||||
elseif( ANDROID_STL MATCHES "c\\+\\+_shared" OR ANDROID_STL MATCHES "c\\+\\+_static" )
|
||||
set( ANDROID_EXCEPTIONS ON )
|
||||
set( ANDROID_RTTI ON )
|
||||
set( ANDROID_CXX_ROOT "${ANDROID_NDK}/sources/cxx-stl/" )
|
||||
set( ANDROID_LLVM_ROOT "${ANDROID_CXX_ROOT}/llvm-libc++" )
|
||||
|
||||
if( X86 )
|
||||
set( ANDROID_ABI_INCLUDE_DIRS "${ANDROID_CXX_ROOT}/gabi++/include" )
|
||||
else()
|
||||
set( ANDROID_ABI_INCLUDE_DIRS "${ANDROID_CXX_ROOT}/llvm-libc++abi/include" )
|
||||
endif()
|
||||
|
||||
set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_LLVM_ROOT}/libcxx/include" "${ANDROID_ABI_INCLUDE_DIRS}" )
|
||||
|
||||
# android support sfiles
|
||||
include_directories ( SYSTEM ${ANDROID_NDK}/sources/android/support/include )
|
||||
|
||||
if(ANDROID_STL MATCHES "c\\+\\+_shared")
|
||||
set ( LLVM_LIBRARY_NAME "libc++_shared.so")
|
||||
else()
|
||||
set ( LLVM_LIBRARY_NAME "libc++_static.a" )
|
||||
endif ()
|
||||
|
||||
if( EXISTS "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/${LLVM_LIBRARY_NAME}" )
|
||||
set( __libstl "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/${LLVM_LIBRARY_NAME}" )
|
||||
else()
|
||||
message( FATAL_ERROR "Could not find libc++ library" )
|
||||
endif()
|
||||
else()
|
||||
message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" )
|
||||
endif()
|
||||
|
@ -1144,7 +1130,12 @@ if( NOT CMAKE_C_COMPILER )
|
|||
endif()
|
||||
set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" )
|
||||
set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" )
|
||||
set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
|
||||
if( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" )
|
||||
# Use gcc-ar if we have it for better LTO support.
|
||||
set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
|
||||
else()
|
||||
set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
|
||||
endif()
|
||||
set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" )
|
||||
set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" )
|
||||
set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" )
|
||||
|
@ -1168,7 +1159,7 @@ endif()
|
|||
include( CMakeForceCompiler )
|
||||
CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU )
|
||||
if( ANDROID_COMPILER_IS_CLANG )
|
||||
set( CMAKE_C_COMPILER_ID Clang)
|
||||
set( CMAKE_C_COMPILER_ID Clang )
|
||||
endif()
|
||||
set( CMAKE_C_PLATFORM_ID Linux )
|
||||
if( X86_64 OR MIPS64 OR ARM64_V8A )
|
||||
|
@ -1195,6 +1186,14 @@ set( CMAKE_ASM_COMPILER_FORCED TRUE )
|
|||
set( CMAKE_COMPILER_IS_GNUASM 1)
|
||||
set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm )
|
||||
|
||||
foreach( lang C CXX ASM )
|
||||
if( ANDROID_COMPILER_IS_CLANG )
|
||||
set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_CLANG_VERSION} )
|
||||
else()
|
||||
set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_COMPILER_VERSION} )
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# flags and definitions
|
||||
remove_definitions( -DANDROID )
|
||||
add_definitions( -DANDROID )
|
||||
|
@ -1225,14 +1224,14 @@ endif()
|
|||
|
||||
# NDK flags
|
||||
if (ARM64_V8A )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -ffunction-sections -funwind-tables" )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
|
||||
set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" )
|
||||
set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" )
|
||||
if( NOT ANDROID_COMPILER_IS_CLANG )
|
||||
set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" )
|
||||
endif()
|
||||
elseif( ARMEABI OR ARMEABI_V7A)
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -funwind-tables" )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
|
||||
if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 )
|
||||
set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" )
|
||||
set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" )
|
||||
|
@ -1251,13 +1250,11 @@ elseif( X86 OR X86_64 )
|
|||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
|
||||
if( NOT ANDROID_COMPILER_IS_CLANG )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" )
|
||||
else()
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fPIC" )
|
||||
endif()
|
||||
set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" )
|
||||
set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" )
|
||||
elseif( MIPS OR MIPS64 )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0" )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-strict-aliasing -finline-functions -funwind-tables -fmessage-length=0" )
|
||||
set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" )
|
||||
set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" )
|
||||
if( NOT ANDROID_COMPILER_IS_CLANG )
|
||||
|
@ -1342,7 +1339,7 @@ if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
|
|||
else()
|
||||
__INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF )
|
||||
endif()
|
||||
__INIT_VARIABLE( ANDROID_NO_UNDEFINED OBSOLETE_NO_UNDEFINED VALUES ON )
|
||||
__INIT_VARIABLE( ANDROID_NO_UNDEFINED VALUES ON )
|
||||
__INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON )
|
||||
__INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON )
|
||||
__INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON )
|
||||
|
@ -1350,7 +1347,7 @@ __INIT_VARIABLE( ANDROID_RELRO VALUES ON )
|
|||
|
||||
set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" )
|
||||
set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
|
||||
set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
|
||||
set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Put each function in separate section and enable garbage collection of unused input sections at link time" )
|
||||
set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker" )
|
||||
set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
|
||||
set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" )
|
||||
|
@ -1452,6 +1449,16 @@ if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" )
|
|||
set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" )
|
||||
endif()
|
||||
|
||||
# pie/pic
|
||||
if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE) AND (CMAKE_VERSION VERSION_GREATER 2.8.8) )
|
||||
set( CMAKE_POSITION_INDEPENDENT_CODE TRUE )
|
||||
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie")
|
||||
else()
|
||||
set( CMAKE_POSITION_INDEPENDENT_CODE FALSE )
|
||||
set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" )
|
||||
set( CMAKE_C_FLAGS "-fpic ${CMAKE_C_FLAGS}" )
|
||||
endif()
|
||||
|
||||
# configure rtti
|
||||
if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES )
|
||||
if( ANDROID_RTTI )
|
||||
|
@ -1515,27 +1522,31 @@ if( ANDROID_EXPLICIT_CRT_LINK )
|
|||
endif()
|
||||
|
||||
# setup output directories
|
||||
set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library output, set this to change where android libs are installed to" )
|
||||
set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" )
|
||||
|
||||
if(NOT _CMAKE_IN_TRY_COMPILE)
|
||||
if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" )
|
||||
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" )
|
||||
else()
|
||||
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" )
|
||||
endif()
|
||||
set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" )
|
||||
if( DEFINED LIBRARY_OUTPUT_PATH_ROOT
|
||||
OR EXISTS "${CMAKE_SOURCE_DIR}/AndroidManifest.xml"
|
||||
OR (EXISTS "${CMAKE_SOURCE_DIR}/../AndroidManifest.xml" AND EXISTS "${CMAKE_SOURCE_DIR}/../jni/") )
|
||||
set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "Root for binaries output, set this to change where Android libs are installed to" )
|
||||
if( NOT _CMAKE_IN_TRY_COMPILE )
|
||||
if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" )
|
||||
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" )
|
||||
else()
|
||||
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" )
|
||||
endif()
|
||||
set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for Android libs" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# copy shaed stl library to build directory
|
||||
if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" )
|
||||
get_filename_component( __libstlname "${__libstl}" NAME )
|
||||
execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess )
|
||||
if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}")
|
||||
message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" )
|
||||
endif()
|
||||
unset( __fileCopyProcess )
|
||||
unset( __libstlname )
|
||||
if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" AND DEFINED LIBRARY_OUTPUT_PATH )
|
||||
get_filename_component( __libstlname "${__libstl}" NAME )
|
||||
execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess )
|
||||
if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}")
|
||||
message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" )
|
||||
endif()
|
||||
unset( __fileCopyProcess )
|
||||
unset( __libstlname )
|
||||
endif()
|
||||
|
||||
|
||||
|
@ -1596,28 +1607,10 @@ macro( find_host_program )
|
|||
endmacro()
|
||||
|
||||
|
||||
macro( ANDROID_GET_ABI_RAWNAME TOOLCHAIN_FLAG VAR )
|
||||
if( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI" )
|
||||
set( ${VAR} "armeabi" )
|
||||
elseif( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI_V7A" )
|
||||
set( ${VAR} "armeabi-v7a" )
|
||||
elseif( "${TOOLCHAIN_FLAG}" STREQUAL "X86" )
|
||||
set( ${VAR} "x86" )
|
||||
elseif( "${TOOLCHAIN_FLAG}" STREQUAL "MIPS" )
|
||||
set( ${VAR} "mips" )
|
||||
else()
|
||||
set( ${VAR} "unknown" )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
if (POLICY CMP0054)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif ()
|
||||
|
||||
# export toolchain settings for the try_compile() command
|
||||
if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" )
|
||||
if( NOT _CMAKE_IN_TRY_COMPILE )
|
||||
set( __toolchain_config "")
|
||||
foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN ANDROID_SET_OBSOLETE_VARIABLES
|
||||
foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN
|
||||
ANDROID_NDK_HOST_X64
|
||||
ANDROID_NDK
|
||||
ANDROID_NDK_LAYOUT
|
||||
|
@ -1636,9 +1629,10 @@ if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" )
|
|||
ANDROID_RELRO
|
||||
ANDROID_LIBM_PATH
|
||||
ANDROID_EXPLICIT_CRT_LINK
|
||||
ANDROID_APP_PIE
|
||||
)
|
||||
if( DEFINED ${__var} )
|
||||
if( "${__var}" MATCHES " ")
|
||||
if( ${__var} MATCHES " ")
|
||||
set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" )
|
||||
else()
|
||||
set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" )
|
||||
|
@ -1663,16 +1657,6 @@ if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 )
|
|||
endif()
|
||||
|
||||
|
||||
# set some obsolete variables for backward compatibility
|
||||
set( ANDROID_SET_OBSOLETE_VARIABLES ON CACHE BOOL "Define obsolete Andrid-specific cmake variables" )
|
||||
mark_as_advanced( ANDROID_SET_OBSOLETE_VARIABLES )
|
||||
if( ANDROID_SET_OBSOLETE_VARIABLES )
|
||||
set( ANDROID_API_LEVEL ${ANDROID_NATIVE_API_LEVEL} )
|
||||
set( ARM_TARGET "${ANDROID_ABI}" )
|
||||
set( ARMEABI_NDK_NAME "${ANDROID_NDK_ABI_NAME}" )
|
||||
endif()
|
||||
|
||||
|
||||
# Variables controlling behavior or set by cmake toolchain:
|
||||
# ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64"
|
||||
# ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version)
|
||||
|
@ -1686,22 +1670,15 @@ endif()
|
|||
# ANDROID_RELRO : ON/OFF
|
||||
# ANDROID_FORCE_ARM_BUILD : ON/OFF
|
||||
# ANDROID_STL_FORCE_FEATURES : ON/OFF
|
||||
# ANDROID_SET_OBSOLETE_VARIABLES : ON/OFF
|
||||
# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product/<product_name>/obj/lib/libm.so) to workaround unresolved `sincos`
|
||||
# Can be set only at the first run:
|
||||
# ANDROID_NDK
|
||||
# ANDROID_STANDALONE_TOOLCHAIN
|
||||
# ANDROID_NDK : path to your NDK install
|
||||
# NDK_CCACHE : path to your ccache executable
|
||||
# ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain
|
||||
# ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems)
|
||||
# ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID)
|
||||
# LIBRARY_OUTPUT_PATH_ROOT : <any valid path>
|
||||
# NDK_CCACHE : <path to your ccache executable>
|
||||
# Obsolete:
|
||||
# ANDROID_API_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL
|
||||
# ARM_TARGET : superseded by ANDROID_ABI
|
||||
# ARM_TARGETS : superseded by ANDROID_ABI (can be set only)
|
||||
# ANDROID_NDK_TOOLCHAIN_ROOT : superseded by ANDROID_STANDALONE_TOOLCHAIN (can be set only)
|
||||
# ANDROID_USE_STLPORT : superseded by ANDROID_STL=stlport_static
|
||||
# ANDROID_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL (completely removed)
|
||||
# ANDROID_STANDALONE_TOOLCHAIN
|
||||
#
|
||||
# Primary read-only variables:
|
||||
# ANDROID : always TRUE
|
||||
|
@ -1715,19 +1692,16 @@ endif()
|
|||
# X86_64 : TRUE if configured for x86_64
|
||||
# MIPS : TRUE if configured for mips
|
||||
# MIPS64 : TRUE if configured for mips64
|
||||
# BUILD_ANDROID : always TRUE
|
||||
# BUILD_WITH_ANDROID_NDK : TRUE if NDK is used
|
||||
# BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used
|
||||
# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform
|
||||
# ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI
|
||||
# ANDROID_NDK_RELEASE : from r5 to r10c; set only for NDK
|
||||
# ANDROID_NDK_RELEASE : from r5 to r10d; set only for NDK
|
||||
# ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor)
|
||||
# ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI
|
||||
# ANDROID_SYSROOT : path to the compiler sysroot
|
||||
# TOOL_OS_SUFFIX : "" or ".exe" depending on host platform
|
||||
# ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used
|
||||
# Obsolete:
|
||||
# ARMEABI_NDK_NAME : superseded by ANDROID_NDK_ABI_NAME
|
||||
#
|
||||
# Secondary (less stable) read-only variables:
|
||||
# ANDROID_COMPILER_VERSION : GCC version used (not Clang version)
|
||||
|
@ -1742,12 +1716,10 @@ endif()
|
|||
# ANDROID_RTTI : if rtti is enabled by the runtime
|
||||
# ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime
|
||||
# ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used
|
||||
# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product/<product_name>/obj/lib/libm.so) to workaround unresolved `sincos`
|
||||
#
|
||||
# Defaults:
|
||||
# ANDROID_DEFAULT_NDK_API_LEVEL
|
||||
# ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH}
|
||||
# ANDROID_NDK_SEARCH_PATHS
|
||||
# ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH
|
||||
# ANDROID_SUPPORTED_ABIS_${ARCH}
|
||||
# ANDROID_SUPPORTED_NDK_VERSIONS
|
||||
# ANDROID_SUPPORTED_NDK_VERSIONS
|
||||
|
|
3
cmake/externals/glew/CMakeLists.txt
vendored
3
cmake/externals/glew/CMakeLists.txt
vendored
|
@ -15,7 +15,6 @@ ExternalProject_Add(
|
|||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
|
@ -32,4 +31,4 @@ elseif (WIN32)
|
|||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/${LIB_PREFIX}glew_d.${LIB_EXT} CACHE FILEPATH "Path to glew debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/${LIB_PREFIX}glew.${LIB_EXT} CACHE FILEPATH "Path to glew release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/${LIB_PREFIX}glew.${LIB_EXT} CACHE FILEPATH "Path to glew release library")
|
||||
|
|
74
cmake/externals/hifiAudioCodec/CMakeLists.txt
vendored
74
cmake/externals/hifiAudioCodec/CMakeLists.txt
vendored
|
@ -5,39 +5,43 @@ set(EXTERNAL_NAME hifiAudioCodec)
|
|||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (WIN32 OR APPLE)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-1.zip
|
||||
URL_MD5 23ec3fe51eaa155ea159a4971856fc13
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
elseif(NOT ANDROID)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux.zip
|
||||
URL_MD5 7d37914a18aa4de971d2f45dd3043bde
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
endif()
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL)
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL)
|
||||
elseif(APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
|
||||
elseif(NOT ANDROID)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
|
||||
if (NOT ANDROID)
|
||||
|
||||
if (WIN32 OR APPLE)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-1.zip
|
||||
URL_MD5 23ec3fe51eaa155ea159a4971856fc13
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
else ()
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux.zip
|
||||
URL_MD5 7d37914a18aa4de971d2f45dd3043bde
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
endif()
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL)
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL)
|
||||
elseif(APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
|
||||
elseif(NOT ANDROID)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
|
7
cmake/externals/sdl2/CMakeLists.txt
vendored
7
cmake/externals/sdl2/CMakeLists.txt
vendored
|
@ -46,7 +46,7 @@ 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
|
||||
|
@ -61,7 +61,6 @@ endif ()
|
|||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
|
||||
if (APPLE)
|
||||
|
||||
# NOOP
|
||||
|
@ -78,9 +77,9 @@ elseif (WIN32)
|
|||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${SOURCE_DIR}/lib/x86/SDL2.lib CACHE FILEPATH "Path to SDL2 library")
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/lib/x86 CACHE PATH "Location of SDL2 DLL")
|
||||
endif()
|
||||
|
||||
|
||||
add_paths_to_fixup_libs(${${EXTERNAL_NAME_UPPER}_DLL_PATH})
|
||||
|
||||
|
||||
else ()
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
|
28
cmake/externals/tbb/CMakeLists.txt
vendored
28
cmake/externals/tbb/CMakeLists.txt
vendored
|
@ -3,9 +3,9 @@ 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_20150316oss_src.tgz
|
||||
|
@ -20,7 +20,7 @@ if (ANDROID)
|
|||
)
|
||||
elseif (APPLE)
|
||||
find_program(MAKE_COMMAND NAMES make DOC "Path to the make command")
|
||||
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_src.tgz
|
||||
|
@ -37,11 +37,11 @@ else ()
|
|||
if (WIN32)
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_win.zip)
|
||||
set(DOWNLOAD_MD5 d250d40bb93b255f75bcbb19e976a440)
|
||||
else ()
|
||||
else ()
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_lin.tgz)
|
||||
set(DOWNLOAD_MD5 7830ba2bc62438325fba2ec0c95367a5)
|
||||
endif ()
|
||||
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL ${DOWNLOAD_URL}
|
||||
|
@ -60,11 +60,11 @@ ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
|||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (APPLE)
|
||||
if (APPLE)
|
||||
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib")
|
||||
set(_LIB_PREFIX "lib")
|
||||
set(_LIB_EXT "dylib")
|
||||
|
||||
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
change-install-name
|
||||
|
@ -74,7 +74,7 @@ if (APPLE)
|
|||
WORKING_DIRECTORY <SOURCE_DIR>
|
||||
LOG 1
|
||||
)
|
||||
|
||||
|
||||
elseif (WIN32)
|
||||
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/intel64/vc12")
|
||||
|
@ -91,18 +91,18 @@ elseif (ANDROID)
|
|||
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)
|
||||
|
@ -110,9 +110,9 @@ elseif (UNIX)
|
|||
else ()
|
||||
message(STATUS "Could not find a compatible version of Threading Building Blocks library for your compiler.")
|
||||
endif ()
|
||||
|
||||
|
||||
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")
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
#
|
||||
# AutoMTC.cmake
|
||||
#
|
||||
# Created by Andrzej Kapolka on 12/31/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
|
||||
#
|
||||
|
||||
macro(AUTO_MTC)
|
||||
set(AUTOMTC_SRC ${TARGET_NAME}_automtc.cpp)
|
||||
|
||||
file(GLOB INCLUDE_FILES src/*.h)
|
||||
|
||||
if (NOT ANDROID)
|
||||
set(MTC_EXECUTABLE mtc)
|
||||
else ()
|
||||
set(MTC_EXECUTABLE $ENV{MTC_PATH}/mtc)
|
||||
endif ()
|
||||
|
||||
add_custom_command(OUTPUT ${AUTOMTC_SRC} COMMAND ${MTC_EXECUTABLE} -o ${AUTOMTC_SRC} ${INCLUDE_FILES} DEPENDS ${MTC_EXECUTABLE} ${INCLUDE_FILES})
|
||||
endmacro()
|
|
@ -1,77 +1,92 @@
|
|||
#
|
||||
#
|
||||
# AutoScribeShader.cmake
|
||||
#
|
||||
#
|
||||
# Created by Sam Gateau on 12/17/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
|
||||
#
|
||||
#
|
||||
|
||||
function(AUTOSCRIBE_SHADER SHADER_FILE)
|
||||
|
||||
# Grab include files
|
||||
foreach(includeFile ${ARGN})
|
||||
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
|
||||
endforeach()
|
||||
# Grab include files
|
||||
foreach(includeFile ${ARGN})
|
||||
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
|
||||
endforeach()
|
||||
|
||||
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
|
||||
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
|
||||
endforeach()
|
||||
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(${TARGET_NAME} Hifi for includes ${INCLUDES})
|
||||
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
|
||||
endforeach()
|
||||
|
||||
#Extract the unique include shader paths
|
||||
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
|
||||
#message(${TARGET_NAME} 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})
|
||||
|
||||
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
|
||||
#message(ready for includes ${SHADER_INCLUDES_PATHS})
|
||||
# make the scribe include arguments
|
||||
set(SCRIBE_INCLUDES)
|
||||
foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS})
|
||||
set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/)
|
||||
endforeach()
|
||||
|
||||
# make the scribe include arguments
|
||||
set(SCRIBE_INCLUDES)
|
||||
foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS})
|
||||
set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/)
|
||||
endforeach()
|
||||
# Define the final name of the generated shader file
|
||||
get_filename_component(SHADER_TARGET ${SHADER_FILE} NAME_WE)
|
||||
get_filename_component(SHADER_EXT ${SHADER_FILE} EXT)
|
||||
if(SHADER_EXT STREQUAL .slv)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_vert.h)
|
||||
elseif(${SHADER_EXT} STREQUAL .slf)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_frag.h)
|
||||
elseif(${SHADER_EXT} STREQUAL .slg)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_geom.h)
|
||||
endif()
|
||||
|
||||
# Define the final name of the generated shader file
|
||||
get_filename_component(SHADER_TARGET ${SHADER_FILE} NAME_WE)
|
||||
get_filename_component(SHADER_EXT ${SHADER_FILE} EXT)
|
||||
if(SHADER_EXT STREQUAL .slv)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_vert.h)
|
||||
elseif(${SHADER_EXT} STREQUAL .slf)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_frag.h)
|
||||
elseif(${SHADER_EXT} STREQUAL .slg)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_geom.h)
|
||||
endif()
|
||||
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_TARGET}")
|
||||
|
||||
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_TARGET}")
|
||||
# Target dependant Custom rule on the SHADER_FILE
|
||||
if (APPLE)
|
||||
set(GLPROFILE MAC_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
|
||||
# Target dependant Custom rule on the SHADER_FILE
|
||||
if (APPLE)
|
||||
set(GLPROFILE MAC_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
elseif (ANDROID)
|
||||
set(GLPROFILE LINUX_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
elseif (UNIX)
|
||||
set(GLPROFILE LINUX_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
# for an android build, we can't use the scribe that cmake would normally produce as a target,
|
||||
# since it's unrunnable by the cross-compiling build machine
|
||||
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
else ()
|
||||
set(GLPROFILE PC_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
# so, we require the compiling user to point us at a compiled executable version for their native toolchain
|
||||
find_program(NATIVE_SCRIBE scribe PATHS ${SCRIBE_PATH} ENV SCRIBE_PATH)
|
||||
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
endif()
|
||||
if (NOT NATIVE_SCRIBE)
|
||||
message(FATAL_ERROR "The High Fidelity scribe tool is required for shader pre-processing. \
|
||||
Please compile scribe using your native toolchain and set SCRIBE_PATH to the path containing the scribe executable in your ENV.\
|
||||
")
|
||||
endif ()
|
||||
|
||||
#output the generated file name
|
||||
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE)
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND ${NATIVE_SCRIBE} ${SCRIBE_ARGS} DEPENDS ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
elseif (UNIX)
|
||||
set(GLPROFILE LINUX_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
|
||||
file(GLOB INCLUDE_FILES ${SHADER_TARGET})
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
else ()
|
||||
set(GLPROFILE PC_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
endif()
|
||||
|
||||
#output the generated file name
|
||||
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE)
|
||||
|
||||
file(GLOB INCLUDE_FILES ${SHADER_TARGET})
|
||||
|
||||
endfunction()
|
||||
|
||||
|
@ -79,11 +94,11 @@ endfunction()
|
|||
macro(AUTOSCRIBE_SHADER_LIB)
|
||||
set(HIFI_LIBRARIES_SHADER_INCLUDE_FILES "")
|
||||
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
|
||||
foreach(HIFI_LIBRARY ${ARGN})
|
||||
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()
|
||||
|
@ -99,9 +114,9 @@ macro(AUTOSCRIBE_SHADER_LIB)
|
|||
#message("${TARGET_NAME} ${SHADER_INCLUDE_FILES}")
|
||||
set(AUTOSCRIBE_SHADER_SRC "")
|
||||
foreach(SHADER_FILE ${SHADER_SOURCE_FILES})
|
||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
||||
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
|
||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
||||
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
|
||||
endforeach()
|
||||
#message(${TARGET_NAME} ${AUTOSCRIBE_SHADER_SRC})
|
||||
|
||||
|
@ -118,4 +133,4 @@ macro(AUTOSCRIBE_SHADER_LIB)
|
|||
# Link library shaders, if they exist
|
||||
include_directories("${SHADERS_DIR}")
|
||||
|
||||
endmacro()
|
||||
endmacro()
|
||||
|
|
|
@ -16,26 +16,6 @@ macro(fixup_interface)
|
|||
string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${INTERFACE_INSTALL_DIR})
|
||||
set(_INTERFACE_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app")
|
||||
|
||||
# install QtWebProcess from Qt to the application bundle
|
||||
# since it is missed by macdeployqt
|
||||
# https://bugreports.qt.io/browse/QTBUG-35211
|
||||
set(LIBEXEC_PATH "${_INTERFACE_INSTALL_PATH}/Contents/libexec")
|
||||
install(
|
||||
PROGRAMS "${QT_DIR}/libexec/QtWebProcess"
|
||||
DESTINATION ${LIBEXEC_PATH}
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
set(QTWEBPROCESS_PATH "\${CMAKE_INSTALL_PREFIX}/${LIBEXEC_PATH}")
|
||||
|
||||
# we also need a qt.conf in the directory of QtWebProcess
|
||||
install(CODE "
|
||||
file(WRITE ${QTWEBPROCESS_PATH}/qt.conf
|
||||
\"[Paths]\nPlugins = ../PlugIns\nImports = ../Resources/qml\nQml2Imports = ../Resources/qml\"
|
||||
)"
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
||||
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD))
|
||||
|
@ -49,7 +29,6 @@ macro(fixup_interface)
|
|||
execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\
|
||||
\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/\
|
||||
-verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\
|
||||
-executable=\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/Contents/libexec/QtWebProcess\
|
||||
)"
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
|
|
|
@ -59,7 +59,12 @@ macro(install_beside_console)
|
|||
set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_INSTALL_DIR}/${TARGET_NAME}")
|
||||
string(REPLACE " " "\\ " ESCAPED_EXECUTABLE_NAME ${EXECUTABLE_NEEDING_FIXUP})
|
||||
|
||||
# configure Info.plist for COMPONENT_APP
|
||||
install(CODE "
|
||||
set(MACOSX_BUNDLE_EXECUTABLE_NAME domain-server)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.server-components)
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME Sandbox\\ Components)
|
||||
configure_file(${HF_CMAKE_DIR}/templates/MacOSXBundleSandboxComponentsInfo.plist.in ${ESCAPED_BUNDLE_NAME}/Contents/Info.plist)
|
||||
execute_process(COMMAND ${MACDEPLOYQT_COMMAND} ${ESCAPED_BUNDLE_NAME} -verbose=2 -executable=${ESCAPED_EXECUTABLE_NAME})"
|
||||
COMPONENT ${SERVER_COMPONENT}
|
||||
)
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#
|
||||
#
|
||||
# SetupHifiLibrary.cmake
|
||||
#
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
macro(SETUP_HIFI_LIBRARY)
|
||||
|
||||
|
||||
project(${TARGET_NAME})
|
||||
|
||||
|
||||
# grab the implementation and header files
|
||||
file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c")
|
||||
list(APPEND ${TARGET_NAME}_SRCS ${LIB_SRCS})
|
||||
|
@ -34,19 +34,19 @@ macro(SETUP_HIFI_LIBRARY)
|
|||
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS "-mavx2 -mfma")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
|
||||
setup_memory_debugger()
|
||||
|
||||
# create a library and set the property so it can be referenced later
|
||||
if (${${TARGET_NAME}_SHARED})
|
||||
add_library(${TARGET_NAME} SHARED ${LIB_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
|
||||
add_library(${TARGET_NAME} SHARED ${LIB_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
|
||||
else ()
|
||||
add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
|
||||
add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
|
||||
endif ()
|
||||
|
||||
|
||||
set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN})
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
|
||||
|
||||
|
||||
# find these Qt modules and link them to our own target
|
||||
find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED)
|
||||
|
||||
|
@ -59,7 +59,7 @@ macro(SETUP_HIFI_LIBRARY)
|
|||
set(QT_RESOURCES_FILE "")
|
||||
|
||||
target_glm()
|
||||
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Libraries")
|
||||
|
||||
endmacro(SETUP_HIFI_LIBRARY)
|
||||
|
||||
endmacro(SETUP_HIFI_LIBRARY)
|
||||
|
|
|
@ -22,7 +22,7 @@ macro(SETUP_HIFI_PROJECT)
|
|||
endif ()
|
||||
endforeach()
|
||||
|
||||
add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC})
|
||||
add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC})
|
||||
|
||||
# include the generated application version header
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")
|
||||
|
|
36
cmake/templates/MacOSXBundleSandboxComponentsInfo.plist.in
Normal file
36
cmake/templates/MacOSXBundleSandboxComponentsInfo.plist.in
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>LSRequiresCarbon</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -130,6 +130,11 @@ Var AR_RegFlags
|
|||
SectionSetFlags ${${SecName}} $AR_SecFlags
|
||||
|
||||
"default_${SecName}:"
|
||||
; The client is always selected by default
|
||||
${If} ${SecName} == @CLIENT_COMPONENT_NAME@
|
||||
SectionSetFlags ${${SecName}} 17
|
||||
${EndIf}
|
||||
|
||||
!insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
|
||||
!macroend
|
||||
|
||||
|
@ -243,6 +248,12 @@ FunctionEnd
|
|||
|
||||
;--------------------------------
|
||||
; Installation types
|
||||
|
||||
Section "-Previous Install Cleanup"
|
||||
; Remove the resources folder so we don't end up including removed QML files
|
||||
RMDir /r "$INSTDIR\resources"
|
||||
SectionEnd
|
||||
|
||||
@CPACK_NSIS_INSTALLATION_TYPES@
|
||||
|
||||
;--------------------------------
|
||||
|
|
|
@ -9,6 +9,11 @@ endif ()
|
|||
# setup the project and link required Qt modules
|
||||
setup_hifi_project(Network)
|
||||
|
||||
# Fix up the rpath so macdeployqt works
|
||||
if (APPLE)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
|
||||
endif ()
|
||||
|
||||
# TODO: find a solution that will handle web file changes in resources on windows without a re-build.
|
||||
# Currently the resources are only copied on post-build. If one is changed but the domain-server is not, they will
|
||||
# not be re-copied. This is worked-around on OS X/UNIX by using a symlink.
|
||||
|
|
|
@ -121,9 +121,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
if (_type != NonMetaverse) {
|
||||
// if we have a metaverse domain, we'll use an access token for API calls
|
||||
resetAccountManagerAccessToken();
|
||||
}
|
||||
|
||||
setupAutomaticNetworking();
|
||||
setupAutomaticNetworking();
|
||||
}
|
||||
|
||||
if (!getID().isNull() && _type != NonMetaverse) {
|
||||
// setup periodic heartbeats to metaverse API
|
||||
|
@ -1756,6 +1756,7 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
|
|||
.arg(authorizationCode, oauthRedirectURL().toString(), _oauthClientID, _oauthClientSecret);
|
||||
|
||||
QNetworkRequest tokenRequest(tokenRequestUrl);
|
||||
tokenRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
tokenRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
|
@ -1949,6 +1950,7 @@ QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenR
|
|||
profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken));
|
||||
|
||||
QNetworkRequest profileRequest(profileURL);
|
||||
profileRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
return NetworkAccessManager::getInstance().get(profileRequest);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ set(TARGET_NAME gvr-interface)
|
|||
if (ANDROID)
|
||||
set(ANDROID_APK_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk-build")
|
||||
set(ANDROID_APK_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk")
|
||||
|
||||
|
||||
set(ANDROID_SDK_ROOT $ENV{ANDROID_HOME})
|
||||
set(ANDROID_APP_DISPLAY_NAME Interface)
|
||||
set(ANDROID_API_LEVEL 19)
|
||||
|
@ -13,10 +13,10 @@ if (ANDROID)
|
|||
set(ANDROID_APK_VERSION_CODE 1)
|
||||
set(ANDROID_APK_FULLSCREEN TRUE)
|
||||
set(ANDROID_DEPLOY_QT_INSTALL "--install")
|
||||
|
||||
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${ANDROID_APK_OUTPUT_DIR}/libs/${ANDROID_ABI}")
|
||||
|
||||
|
||||
setup_hifi_library(Gui Widgets AndroidExtras)
|
||||
else ()
|
||||
setup_hifi_project(Gui Widgets)
|
||||
|
@ -28,12 +28,12 @@ link_hifi_libraries(shared networking audio-client avatars)
|
|||
|
||||
if (ANDROID)
|
||||
find_package(LibOVR)
|
||||
|
||||
|
||||
if (LIBOVR_FOUND)
|
||||
add_definitions(-DHAVE_LIBOVR)
|
||||
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES} ${LIBOVR_ANDROID_LIBRARIES} ${TURBOJPEG_LIBRARY})
|
||||
include_directories(SYSTEM ${LIBOVR_INCLUDE_DIRS})
|
||||
|
||||
|
||||
# we need VRLib, so add a project.properties to our apk build folder that says that
|
||||
file(RELATIVE_PATH RELATIVE_VRLIB_PATH ${ANDROID_APK_OUTPUT_DIR} "${LIBOVR_VRLIB_DIR}")
|
||||
file(WRITE "${ANDROID_APK_BUILD_DIR}/project.properties" "android.library.reference.1=${RELATIVE_VRLIB_PATH}")
|
||||
|
@ -50,7 +50,7 @@ if (ANDROID AND HOCKEY_APP_ID)
|
|||
set(ANDROID_ACTIVITY_NAME io.highfidelity.gvrinterface.InterfaceBetaActivity)
|
||||
set(ANDROID_DEPLOY_QT_INSTALL "")
|
||||
set(ANDROID_APK_CUSTOM_NAME "Interface-beta.apk")
|
||||
|
||||
|
||||
# set the ANDROID_APK_VERSION_CODE to the number of git commits
|
||||
execute_process(
|
||||
COMMAND git rev-list --first-parent --count HEAD
|
||||
|
@ -58,16 +58,16 @@ if (ANDROID AND HOCKEY_APP_ID)
|
|||
OUTPUT_VARIABLE GIT_COMMIT_COUNT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
|
||||
set(ANDROID_APK_VERSION_CODE ${GIT_COMMIT_COUNT})
|
||||
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/templates/InterfaceBetaActivity.java.in" "${ANDROID_APK_BUILD_DIR}/src/io/highfidelity/gvrinterface/InterfaceBetaActivity.java")
|
||||
elseif (ANDROID)
|
||||
set(HOCKEY_APP_ENABLED false)
|
||||
endif ()
|
||||
|
||||
if (ANDROID)
|
||||
|
||||
|
||||
set(HIFI_URL_INTENT "<intent-filter>\
|
||||
\n <action android:name='android.intent.action.VIEW' />\
|
||||
\n <category android:name='android.intent.category.DEFAULT' />\
|
||||
|
@ -75,13 +75,11 @@ if (ANDROID)
|
|||
\n <data android:scheme='hifi' />\
|
||||
\n </intent-filter>"
|
||||
)
|
||||
|
||||
|
||||
set(ANDROID_EXTRA_APPLICATION_XML "${HOCKEY_APP_ACTIVITY}")
|
||||
set(ANDROID_EXTRA_ACTIVITY_XML "${HIFI_URL_INTENT}")
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/templates/hockeyapp.xml.in" "${ANDROID_APK_BUILD_DIR}/res/values/hockeyapp.xml")
|
||||
qt_create_apk()
|
||||
|
||||
endif (ANDROID)
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
||||
endif (ANDROID)
|
||||
|
|
|
@ -213,6 +213,7 @@ void IceServer::requestDomainPublicKey(const QUuid& domainID) {
|
|||
publicKeyURL.setPath(publicKeyPath);
|
||||
|
||||
QNetworkRequest publicKeyRequest { publicKeyURL };
|
||||
publicKeyRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
publicKeyRequest.setAttribute(QNetworkRequest::User, domainID);
|
||||
|
||||
qDebug() << "Requesting public key for domain with ID" << domainID;
|
||||
|
|
|
@ -39,9 +39,18 @@ else ()
|
|||
list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP})
|
||||
endif ()
|
||||
|
||||
find_package(Qt5 COMPONENTS
|
||||
Gui Multimedia Network OpenGL Qml Quick Script ScriptTools Svg
|
||||
WebChannel WebEngine WebEngineWidgets WebKitWidgets WebSockets)
|
||||
if (ANDROID)
|
||||
set(PLATFORM_QT_COMPONENTS AndroidExtras)
|
||||
else ()
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
|
||||
endif ()
|
||||
|
||||
find_package(
|
||||
Qt5 COMPONENTS
|
||||
Gui Multimedia Network OpenGL Qml Quick Script Svg
|
||||
${PLATFORM_QT_COMPONENTS}
|
||||
WebChannel WebSockets
|
||||
)
|
||||
|
||||
# grab the ui files in resources/ui
|
||||
file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
|
||||
|
@ -57,6 +66,26 @@ set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}")
|
|||
# set(TS ${TARGET_NAME}_en.ts)
|
||||
# qt5_create_translation_custom(${QM} ${INTERFACE_SRCS} ${QT_UI_FILES} ${TS})
|
||||
|
||||
# setup the android parameters that will help us produce an APK
|
||||
if (ANDROID)
|
||||
set(ANDROID_APK_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk-build")
|
||||
set(ANDROID_APK_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk")
|
||||
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${ANDROID_APK_OUTPUT_DIR}/libs/${ANDROID_ABI}")
|
||||
|
||||
set(ANDROID_SDK_ROOT $ENV{ANDROID_HOME})
|
||||
set(ANDROID_APP_DISPLAY_NAME Interface)
|
||||
set(ANDROID_API_LEVEL 19)
|
||||
set(ANDROID_APK_PACKAGE io.highfidelity.interface)
|
||||
set(ANDROID_ACTIVITY_NAME io.highfidelity.interface.InterfaceActivity)
|
||||
set(ANDROID_APK_VERSION_NAME "0.1")
|
||||
set(ANDROID_APK_VERSION_CODE 1)
|
||||
set(ANDROID_APK_FULLSCREEN TRUE)
|
||||
set(ANDROID_DEPLOY_QT_INSTALL "--install")
|
||||
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
|
||||
# configure CMake to use a custom Info.plist
|
||||
|
@ -94,8 +123,9 @@ if (APPLE)
|
|||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
|
||||
|
||||
# make sure the output name for the .app bundle is correct
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${INTERFACE_BUNDLE_NAME})
|
||||
elseif(WIN32)
|
||||
# Fix up the rpath so macdeployqt works
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
|
||||
elseif (WIN32)
|
||||
# configure an rc file for the chosen icon
|
||||
set(CONFIGURE_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME}")
|
||||
set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc")
|
||||
|
@ -104,7 +134,7 @@ elseif(WIN32)
|
|||
# add an executable that also has the icon itself and the configured rc file as resources
|
||||
add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT})
|
||||
|
||||
if ( NOT DEV_BUILD )
|
||||
if (NOT DEV_BUILD)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
|
@ -113,9 +143,12 @@ elseif(WIN32)
|
|||
)
|
||||
endif()
|
||||
|
||||
else()
|
||||
elseif (ANDROID)
|
||||
# on android the Interface target is a library that gets linked/used by the APK shell that qtcreateapk produces
|
||||
add_library(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
||||
else ()
|
||||
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")
|
||||
|
||||
|
@ -136,21 +169,32 @@ if (WIN32)
|
|||
set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG "/OPT:NOREF /OPT:NOICF")
|
||||
endif()
|
||||
|
||||
if (NOT ANDROID)
|
||||
set(NON_ANDROID_LIBRARIES steamworks-wrapper)
|
||||
endif ()
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_libraries(shared octree gpu gl gpu-gl procedural model render
|
||||
recording fbx networking model-networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer ui auto-updater
|
||||
controllers plugins ui-plugins display-plugins input-plugins steamworks-wrapper)
|
||||
link_hifi_libraries(
|
||||
shared octree gpu gl gpu-gl procedural model render
|
||||
recording fbx networking model-networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer ui auto-updater
|
||||
controllers plugins
|
||||
ui-plugins display-plugins input-plugins
|
||||
${NON_ANDROID_LIBRARIES}
|
||||
)
|
||||
|
||||
# include the binary directory of render-utils for shader includes
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils")
|
||||
|
||||
#fixme find a way to express faceshift as a plugin
|
||||
target_bullet()
|
||||
target_glew()
|
||||
target_opengl()
|
||||
|
||||
if (NOT ANDROID)
|
||||
target_glew()
|
||||
endif ()
|
||||
|
||||
if (WIN32 OR APPLE)
|
||||
target_faceshift()
|
||||
endif()
|
||||
|
@ -199,16 +243,10 @@ include_directories("${PROJECT_SOURCE_DIR}/src")
|
|||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL
|
||||
Qt5::Qml Qt5::Quick Qt5::Script Qt5::ScriptTools Qt5::Svg
|
||||
Qt5::WebChannel Qt5::WebEngine Qt5::WebEngineWidgets Qt5::WebKitWidgets
|
||||
Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
|
||||
Qt5::WebChannel Qt5::WebEngine
|
||||
)
|
||||
|
||||
# Issue causes build failure unless we add this directory.
|
||||
# See https://bugreports.qt.io/browse/QTBUG-43351
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine)
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(${TARGET_NAME} pthread)
|
||||
endif(UNIX)
|
||||
|
@ -292,3 +330,17 @@ if (WIN32)
|
|||
|
||||
package_libraries_for_deployment()
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
set(HIFI_URL_INTENT "<intent-filter>\
|
||||
\n <action android:name='android.intent.action.VIEW' />\
|
||||
\n <category android:name='android.intent.category.DEFAULT' />\
|
||||
\n <category android:name='android.intent.category.BROWSABLE' />\
|
||||
\n <data android:scheme='hifi' />\
|
||||
\n </intent-filter>"
|
||||
)
|
||||
|
||||
set(ANDROID_EXTRA_ACTIVITY_XML "${HIFI_URL_INTENT}")
|
||||
|
||||
qt_create_apk()
|
||||
endif ()
|
||||
|
|
|
@ -223,12 +223,12 @@ ScrollingWindow {
|
|||
var newWindow = component.createObject(desktop);
|
||||
request.openIn(newWindow.webView)
|
||||
}
|
||||
Component.onCompleted: {
|
||||
desktop.initWebviewProfileHandlers(webview.profile)
|
||||
}
|
||||
|
||||
|
||||
//profile: desktop.browserProfile
|
||||
Component.onCompleted: {
|
||||
desktop.initWebviewProfileHandlers(webview.profile)
|
||||
}
|
||||
|
||||
profile: desktop.browserProfile
|
||||
}
|
||||
|
||||
} // item
|
||||
|
@ -245,4 +245,4 @@ ScrollingWindow {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} // dialog
|
||||
} // dialog
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
//
|
||||
// MarketplaceComboBox.qml
|
||||
//
|
||||
// Created by Elisa Lupin-Jimenez on 3 Aug 2016
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtWebChannel 1.0
|
||||
import QtWebEngine 1.1
|
||||
import QtWebSockets 1.0
|
||||
import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel
|
||||
|
||||
import "controls"
|
||||
import "controls-uit" as Controls
|
||||
import "styles"
|
||||
import "styles-uit"
|
||||
|
||||
|
||||
Rectangle {
|
||||
HifiConstants { id: hifi }
|
||||
id: marketplaceComboBox
|
||||
anchors.fill: parent
|
||||
color: hifi.colors.baseGrayShadow
|
||||
property var currentUrl: "https://metaverse.highfidelity.com/marketplace"
|
||||
|
||||
Controls.WebView {
|
||||
id: webview
|
||||
url: currentUrl
|
||||
anchors.top: switchMarketView.bottom
|
||||
width: parent.width
|
||||
height: parent.height - 40
|
||||
focus: true
|
||||
|
||||
Timer {
|
||||
id: zipTimer
|
||||
running: false
|
||||
repeat: false
|
||||
interval: 1500
|
||||
property var handler;
|
||||
onTriggered: handler();
|
||||
}
|
||||
|
||||
property var autoCancel: 'var element = $("a.btn.cancel");
|
||||
element.click();'
|
||||
|
||||
onNewViewRequested: {
|
||||
var component = Qt.createComponent("Browser.qml");
|
||||
var newWindow = component.createObject(desktop);
|
||||
request.openIn(newWindow.webView);
|
||||
if (File.isZippedFbx(desktop.currentUrl)) {
|
||||
zipTimer.handler = function() {
|
||||
newWindow.destroy();
|
||||
runJavaScript(autoCancel);
|
||||
}
|
||||
zipTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
property var simpleDownload: 'var element = $("a.download-file");
|
||||
element.removeClass("download-file");
|
||||
element.removeAttr("download");'
|
||||
|
||||
onLinkHovered: {
|
||||
desktop.currentUrl = hoveredUrl;
|
||||
// add an error message for non-fbx files
|
||||
if (File.isZippedFbx(desktop.currentUrl)) {
|
||||
runJavaScript(simpleDownload, function(){console.log("ran the JS");});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Controls.ComboBox {
|
||||
id: switchMarketView
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
width: 200
|
||||
height: 40
|
||||
visible: true
|
||||
model: ["Marketplace", "Clara.io"]
|
||||
onCurrentIndexChanged: {
|
||||
if (currentIndex === 0) { webview.url = "https://metaverse.highfidelity.com/marketplace"; }
|
||||
if (currentIndex === 1) { webview.url = "https://clara.io/library"; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
id: switchMarketLabel
|
||||
anchors.verticalCenter: switchMarketView.verticalCenter
|
||||
anchors.right: switchMarketView.left
|
||||
color: hifi.colors.white
|
||||
text: "Explore interesting content from: "
|
||||
}
|
||||
|
||||
}
|
167
interface/resources/qml/Marketplaces.qml
Normal file
167
interface/resources/qml/Marketplaces.qml
Normal file
|
@ -0,0 +1,167 @@
|
|||
//
|
||||
// Marketplaces.qml
|
||||
//
|
||||
// Created by Elisa Lupin-Jimenez on 3 Aug 2016
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtWebChannel 1.0
|
||||
import QtWebEngine 1.1
|
||||
import QtWebSockets 1.0
|
||||
import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel
|
||||
|
||||
import "controls"
|
||||
import "controls-uit" as Controls
|
||||
import "styles"
|
||||
import "styles-uit"
|
||||
|
||||
|
||||
Rectangle {
|
||||
HifiConstants { id: hifi }
|
||||
id: marketplace
|
||||
anchors.fill: parent
|
||||
property var marketplacesUrl: "../../scripts/system/html/marketplaces.html"
|
||||
property int statusBarHeight: 50
|
||||
property int statusMargin: 50
|
||||
property string standardMessage: "Check out other marketplaces."
|
||||
property string claraMessage: "Choose a model and click Download -> Autodesk FBX."
|
||||
property string claraError: "High Fidelity only supports Autodesk FBX models."
|
||||
|
||||
Controls.BaseWebView {
|
||||
id: webview
|
||||
url: marketplacesUrl
|
||||
anchors.top: marketplace.top
|
||||
width: parent.width
|
||||
height: parent.height - statusBarHeight
|
||||
focus: true
|
||||
|
||||
Timer {
|
||||
id: zipTimer
|
||||
running: false
|
||||
repeat: false
|
||||
interval: 1500
|
||||
property var handler;
|
||||
onTriggered: handler();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: alertTimer
|
||||
running: false
|
||||
repeat: false
|
||||
interval: 9000
|
||||
property var handler;
|
||||
onTriggered: handler();
|
||||
}
|
||||
|
||||
property var autoCancel: 'var element = $("a.btn.cancel");
|
||||
element.click();'
|
||||
|
||||
property var simpleDownload: 'var element = $("a.download-file");
|
||||
element.removeClass("download-file");
|
||||
element.removeAttr("download");'
|
||||
|
||||
function displayErrorStatus() {
|
||||
alertTimer.handler = function() {
|
||||
statusLabel.text = claraMessage;
|
||||
statusBar.color = hifi.colors.blueHighlight;
|
||||
statusIcon.text = hifi.glyphs.info;
|
||||
}
|
||||
alertTimer.start();
|
||||
}
|
||||
|
||||
property var notFbxHandler: 'var element = $("a.btn.btn-primary.viewer-button.download-file")
|
||||
element.click();'
|
||||
|
||||
// this code is for removing other file types from Clara.io's download options
|
||||
//property var checkFileType: "$('[data-extension]:not([data-extension=\"fbx\"])').parent().remove()"
|
||||
|
||||
onLinkHovered: {
|
||||
desktop.currentUrl = hoveredUrl;
|
||||
//runJavaScript(checkFileType, function(){console.log("Remove filetypes JS injection");});
|
||||
if (File.isZippedFbx(desktop.currentUrl)) {
|
||||
runJavaScript(simpleDownload, function(){console.log("Download JS injection");});
|
||||
return;
|
||||
}
|
||||
|
||||
if (File.isZipped(desktop.currentUrl)) {
|
||||
statusLabel.text = claraError;
|
||||
statusBar.color = hifi.colors.redHighlight;
|
||||
statusIcon.text = hifi.glyphs.alert;
|
||||
runJavaScript(notFbxHandler, displayErrorStatus());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onLoadingChanged: {
|
||||
if (File.isClaraLink(webview.url)) {
|
||||
statusLabel.text = claraMessage;
|
||||
} else {
|
||||
statusLabel.text = standardMessage;
|
||||
}
|
||||
statusBar.color = hifi.colors.blueHighlight;
|
||||
statusIcon.text = hifi.glyphs.info;
|
||||
}
|
||||
|
||||
onNewViewRequested: {
|
||||
var component = Qt.createComponent("Browser.qml");
|
||||
var newWindow = component.createObject(desktop);
|
||||
request.openIn(newWindow.webView);
|
||||
if (File.isZippedFbx(desktop.currentUrl)) {
|
||||
runJavaScript(autoCancel);
|
||||
zipTimer.handler = function() {
|
||||
newWindow.destroy();
|
||||
}
|
||||
zipTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: statusBar
|
||||
anchors.top: webview.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: hifi.colors.blueHighlight
|
||||
|
||||
Controls.Button {
|
||||
id: switchMarketView
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: statusMargin
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 150
|
||||
text: "See all markets"
|
||||
onClicked: {
|
||||
webview.url = "../../scripts/system/html/marketplaces.html";
|
||||
statusLabel.text = standardMessage;
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
id: statusLabel
|
||||
anchors.verticalCenter: switchMarketView.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: statusMargin
|
||||
color: hifi.colors.white
|
||||
text: standardMessage
|
||||
size: 18
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
id: statusIcon
|
||||
anchors.right: statusLabel.left
|
||||
anchors.verticalCenter: statusLabel.verticalCenter
|
||||
text: hifi.glyphs.info
|
||||
color: hifi.colors.white
|
||||
size: hifi.fontSizes.tableHeadingIcon
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -59,6 +59,11 @@ Item {
|
|||
font.pixelSize: root.fontSize
|
||||
text: "Avatars: " + root.avatarCount
|
||||
}
|
||||
Text {
|
||||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
text: "Frame Rate: " + root.framerate.toFixed(2);
|
||||
}
|
||||
Text {
|
||||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
|
|
68
interface/resources/qml/controls-uit/BaseWebView.qml
Normal file
68
interface/resources/qml/controls-uit/BaseWebView.qml
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// WebView.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 12 Jan 2016
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtWebEngine 1.1
|
||||
|
||||
WebEngineView {
|
||||
id: root
|
||||
property var newUrl;
|
||||
|
||||
profile.httpUserAgent: "Mozilla/5.0 Chrome/38.0 (HighFidelityInterface)"
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging")
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
|
||||
Timer {
|
||||
id: urlReplacementTimer
|
||||
running: false
|
||||
repeat: false
|
||||
interval: 50
|
||||
onTriggered: url = newUrl;
|
||||
}
|
||||
|
||||
onUrlChanged: {
|
||||
var originalUrl = url.toString();
|
||||
newUrl = urlHandler.fixupUrl(originalUrl).toString();
|
||||
if (newUrl !== originalUrl) {
|
||||
root.stop();
|
||||
if (urlReplacementTimer.running) {
|
||||
console.warn("Replacement timer already running");
|
||||
return;
|
||||
}
|
||||
urlReplacementTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
onLoadingChanged: {
|
||||
// Required to support clicking on "hifi://" links
|
||||
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
|
||||
var url = loadRequest.url.toString();
|
||||
if (urlHandler.canHandleUrl(url)) {
|
||||
if (urlHandler.handleUrl(url)) {
|
||||
root.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6
|
||||
// See https://bugreports.qt.io/browse/QTBUG-49521
|
||||
//profile: desktop.browserProfile
|
||||
}
|
|
@ -9,60 +9,12 @@
|
|||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtWebEngine 1.1
|
||||
import "."
|
||||
|
||||
WebEngineView {
|
||||
id: root
|
||||
property var newUrl;
|
||||
|
||||
profile.httpUserAgent: "Mozilla/5.0 Chrome/38.0 (HighFidelityInterface)"
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging")
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
BaseWebView {
|
||||
onNewViewRequested: {
|
||||
var component = Qt.createComponent("../Browser.qml");
|
||||
var newWindow = component.createObject(desktop);
|
||||
request.openIn(newWindow.webView)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
|
||||
Timer {
|
||||
id: urlReplacementTimer
|
||||
running: false
|
||||
repeat: false
|
||||
interval: 50
|
||||
onTriggered: url = newUrl;
|
||||
}
|
||||
|
||||
onUrlChanged: {
|
||||
var originalUrl = url.toString();
|
||||
newUrl = urlHandler.fixupUrl(originalUrl).toString();
|
||||
if (newUrl !== originalUrl) {
|
||||
root.stop();
|
||||
if (urlReplacementTimer.running) {
|
||||
console.warn("Replacement timer already running");
|
||||
return;
|
||||
}
|
||||
urlReplacementTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
onLoadingChanged: {
|
||||
// Required to support clicking on "hifi://" links
|
||||
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
|
||||
var url = loadRequest.url.toString();
|
||||
if (urlHandler.canHandleUrl(url)) {
|
||||
if (urlHandler.handleUrl(url)) {
|
||||
root.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6
|
||||
// See https://bugreports.qt.io/browse/QTBUG-49521
|
||||
//profile: desktop.browserProfile
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ WebEngineView {
|
|||
id: root
|
||||
property var newUrl;
|
||||
|
||||
profile.httpUserAgent: "Mozilla/5.0 Chrome (HighFidelityInterface)"
|
||||
profile: desktop.browserProfile
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging")
|
||||
|
@ -13,7 +13,6 @@ WebEngineView {
|
|||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
|
||||
|
@ -61,8 +60,4 @@ WebEngineView {
|
|||
request.openIn(newWindow.webView);
|
||||
}
|
||||
}
|
||||
|
||||
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6
|
||||
// See https://bugreports.qt.io/browse/QTBUG-49521
|
||||
//profile: desktop.browserProfile
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ ModalWindow {
|
|||
// Set from OffscreenUi::getOpenFile()
|
||||
property int options; // <-- FIXME unused
|
||||
|
||||
property string iconText: text !== "" ? hifi.glyphs.scriptUpload : ""
|
||||
property string iconText: root.title !== "" ? hifi.glyphs.scriptUpload : ""
|
||||
property int iconSize: 40
|
||||
|
||||
property bool selectDirectory: false;
|
||||
|
|
|
@ -89,6 +89,7 @@ Rectangle {
|
|||
property int dropSamples: 9;
|
||||
property int dropSpread: 0;
|
||||
DropShadow {
|
||||
visible: desktop.gradientsSupported;
|
||||
source: place;
|
||||
anchors.fill: place;
|
||||
horizontalOffset: dropHorizontalOffset;
|
||||
|
@ -99,6 +100,7 @@ Rectangle {
|
|||
spread: dropSpread;
|
||||
}
|
||||
DropShadow {
|
||||
visible: desktop.gradientsSupported;
|
||||
source: users;
|
||||
anchors.fill: users;
|
||||
horizontalOffset: dropHorizontalOffset;
|
||||
|
|
|
@ -109,7 +109,7 @@ Decoration {
|
|||
verticalOffset: 2
|
||||
samples: 2
|
||||
color: hifi.colors.baseGrayShadow60
|
||||
visible: (window && window.focus)
|
||||
visible: (desktop.gradientsSupported && window && window.focus)
|
||||
cached: true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,7 +133,6 @@
|
|||
#include "scripting/LocationScriptingInterface.h"
|
||||
#include "scripting/MenuScriptingInterface.h"
|
||||
#include "scripting/SettingsScriptingInterface.h"
|
||||
#include "scripting/WebWindowClass.h"
|
||||
#include "scripting/WindowScriptingInterface.h"
|
||||
#include "scripting/ControllerScriptingInterface.h"
|
||||
#include "scripting/ToolbarScriptingInterface.h"
|
||||
|
@ -176,8 +175,6 @@ static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;
|
|||
// For processing on QThreadPool, target 2 less than the ideal number of threads, leaving
|
||||
// 2 logical cores available for time sensitive tasks.
|
||||
static const int MIN_PROCESSING_THREAD_POOL_SIZE = 2;
|
||||
static const int PROCESSING_THREAD_POOL_SIZE = std::max(MIN_PROCESSING_THREAD_POOL_SIZE,
|
||||
QThread::idealThreadCount() - 2);
|
||||
|
||||
static const QString SNAPSHOT_EXTENSION = ".jpg";
|
||||
static const QString SVO_EXTENSION = ".svo";
|
||||
|
@ -537,7 +534,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
PluginContainer* pluginContainer = dynamic_cast<PluginContainer*>(this); // set the container for any plugins that care
|
||||
PluginManager::getInstance()->setContainer(pluginContainer);
|
||||
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(PROCESSING_THREAD_POOL_SIZE);
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(MIN_PROCESSING_THREAD_POOL_SIZE);
|
||||
thread()->setPriority(QThread::HighPriority);
|
||||
thread()->setObjectName("Main Thread");
|
||||
|
||||
|
@ -707,6 +704,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle);
|
||||
connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress);
|
||||
|
||||
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount);
|
||||
|
||||
// Save avatar location immediately after a teleport.
|
||||
connect(getMyAvatar(), &MyAvatar::positionGoneTo,
|
||||
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
|
||||
|
@ -778,8 +777,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
|
||||
// enable mouse tracking; otherwise, we only get drag events
|
||||
_glWidget->setMouseTracking(true);
|
||||
// Make sure the window is set to the correct size by processing the pending events
|
||||
QCoreApplication::processEvents();
|
||||
_glWidget->createContext();
|
||||
_glWidget->makeCurrent();
|
||||
_glWidget->initializeGL();
|
||||
|
||||
initializeGL();
|
||||
// Make sure we don't time out during slow operations at startup
|
||||
|
@ -1484,7 +1485,7 @@ void Application::initializeGL() {
|
|||
_glWidget->makeCurrent();
|
||||
_chromiumShareContext = new OffscreenGLCanvas();
|
||||
_chromiumShareContext->setObjectName("ChromiumShareContext");
|
||||
_chromiumShareContext->create(_glWidget->context()->contextHandle());
|
||||
_chromiumShareContext->create(_glWidget->qglContext());
|
||||
_chromiumShareContext->makeCurrent();
|
||||
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
|
||||
|
||||
|
@ -1531,7 +1532,7 @@ void Application::initializeGL() {
|
|||
|
||||
_offscreenContext = new OffscreenGLCanvas();
|
||||
_offscreenContext->setObjectName("MainThreadContext");
|
||||
_offscreenContext->create(_glWidget->context()->contextHandle());
|
||||
_offscreenContext->create(_glWidget->qglContext());
|
||||
_offscreenContext->makeCurrent();
|
||||
|
||||
// update before the first render
|
||||
|
@ -1553,7 +1554,7 @@ void Application::initializeUi() {
|
|||
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->create(_glWidget->context()->contextHandle());
|
||||
offscreenUi->create(_glWidget->qglContext());
|
||||
|
||||
auto rootContext = offscreenUi->getRootContext();
|
||||
|
||||
|
@ -1683,7 +1684,6 @@ void Application::paintGL() {
|
|||
Finally clearFlag([this] { _inPaint = false; });
|
||||
|
||||
_frameCount++;
|
||||
_frameCounter.increment();
|
||||
|
||||
auto lastPaintBegin = usecTimestampNow();
|
||||
PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount);
|
||||
|
@ -1920,6 +1920,7 @@ void Application::paintGL() {
|
|||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/pluginOutput");
|
||||
PerformanceTimer perfTimer("pluginOutput");
|
||||
_frameCounter.increment();
|
||||
displayPlugin->submitFrame(frame);
|
||||
}
|
||||
|
||||
|
@ -4316,18 +4317,14 @@ namespace render {
|
|||
|
||||
switch (backgroundMode) {
|
||||
case model::SunSkyStage::SKY_DEFAULT: {
|
||||
static const glm::vec3 DEFAULT_SKYBOX_COLOR{ 255.0f / 255.0f, 220.0f / 255.0f, 194.0f / 255.0f };
|
||||
static const float DEFAULT_SKYBOX_INTENSITY{ 0.2f };
|
||||
static const float DEFAULT_SKYBOX_AMBIENT_INTENSITY{ 2.0f };
|
||||
static const glm::vec3 DEFAULT_SKYBOX_DIRECTION{ 0.0f, 0.0f, -1.0f };
|
||||
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
|
||||
scene->setSunModelEnable(false);
|
||||
sceneKeyLight->setColor(DEFAULT_SKYBOX_COLOR);
|
||||
sceneKeyLight->setIntensity(DEFAULT_SKYBOX_INTENSITY);
|
||||
sceneKeyLight->setAmbientIntensity(DEFAULT_SKYBOX_AMBIENT_INTENSITY);
|
||||
sceneKeyLight->setDirection(DEFAULT_SKYBOX_DIRECTION);
|
||||
sceneKeyLight->setColor(ColorUtils::toVec3(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR));
|
||||
sceneKeyLight->setIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY);
|
||||
sceneKeyLight->setAmbientIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY);
|
||||
sceneKeyLight->setDirection(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION);
|
||||
// fall through: render a skybox (if available), or the defaults (if requested)
|
||||
}
|
||||
|
||||
|
@ -4346,8 +4343,7 @@ namespace render {
|
|||
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
|
||||
auto sceneKeyLight = scene->getKeyLight();
|
||||
auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
|
||||
// set the ambient sphere uniformly - the defaultSkyboxAmbientTexture has peaks that cause flashing when turning
|
||||
sceneKeyLight->setAmbientSphere(DependencyManager::get<TextureCache>()->getWhiteTexture()->getIrradiance());
|
||||
sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
|
||||
// fall through: render defaults skybox
|
||||
} else {
|
||||
|
@ -4861,7 +4857,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
LocationScriptingInterface::locationSetter);
|
||||
|
||||
scriptEngine->registerFunction("WebWindow", WebWindowClass::constructor, 1);
|
||||
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
|
||||
scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor);
|
||||
|
||||
|
@ -5037,6 +5032,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
|
|||
bool Application::askToWearAvatarAttachmentUrl(const QString& url) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
int requestNumber = ++_avatarAttachmentRequest;
|
||||
|
@ -5675,7 +5671,7 @@ MainWindow* Application::getPrimaryWindow() {
|
|||
}
|
||||
|
||||
QOpenGLContext* Application::getPrimaryContext() {
|
||||
return _glWidget->context()->contextHandle();
|
||||
return _glWidget->qglContext();
|
||||
}
|
||||
|
||||
bool Application::makeRenderingContextCurrent() {
|
||||
|
@ -5730,3 +5726,18 @@ void Application::sendHoverLeaveEntity(QUuid id, PointerEvent event) {
|
|||
EntityItemID entityItemID(id);
|
||||
emit getEntities()->hoverLeaveEntity(entityItemID, event);
|
||||
}
|
||||
|
||||
// FIXME? perhaps two, one for the main thread and one for the offscreen UI rendering thread?
|
||||
static const int UI_RESERVED_THREADS = 1;
|
||||
// Windows won't let you have all the cores
|
||||
static const int OS_RESERVED_THREADS = 1;
|
||||
|
||||
void Application::updateThreadPoolCount() const {
|
||||
auto reservedThreads = UI_RESERVED_THREADS + OS_RESERVED_THREADS + _displayPlugin->getRequiredThreadCount();
|
||||
auto availableThreads = QThread::idealThreadCount() - reservedThreads;
|
||||
auto threadPoolSize = std::max(MIN_PROCESSING_THREAD_POOL_SIZE, availableThreads);
|
||||
qDebug() << "Ideal Thread Count " << QThread::idealThreadCount();
|
||||
qDebug() << "Reserved threads " << reservedThreads;
|
||||
qDebug() << "Setting thread pool size to " << threadPoolSize;
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(threadPoolSize);
|
||||
}
|
||||
|
|
|
@ -286,6 +286,7 @@ public slots:
|
|||
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs, const glm::vec3* givenOffset = nullptr);
|
||||
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
|
||||
bool importEntities(const QString& url);
|
||||
void updateThreadPoolCount() const;
|
||||
|
||||
static void setLowVelocityFilter(bool lowVelocityFilter);
|
||||
Q_INVOKABLE void loadDialog();
|
||||
|
|
|
@ -29,7 +29,9 @@ void ConnectionMonitor::init() {
|
|||
|
||||
_timer.setSingleShot(true);
|
||||
_timer.setInterval(DISPLAY_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
_timer.start();
|
||||
if (!domainHandler.isConnected()) {
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||
connect(&_timer, &QTimer::timeout, dialogsManager.data(), &DialogsManager::showAddressBar);
|
||||
|
|
|
@ -111,7 +111,7 @@ void DiscoverabilityManager::updateLocation() {
|
|||
}
|
||||
|
||||
// Update Steam
|
||||
SteamClient::updateLocation(domainHandler.getHostname(), addressManager->currentFacingAddress());
|
||||
SteamClient::updateLocation(domainHandler.getHostname(), addressManager->currentFacingShareableAddress());
|
||||
}
|
||||
|
||||
void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <avatar/AvatarActionHold.h>
|
||||
#include <ObjectActionOffset.h>
|
||||
#include <ObjectActionSpring.h>
|
||||
#include <ObjectActionTravelOriented.h>
|
||||
#include <LogHandler.h>
|
||||
|
||||
#include "InterfaceActionFactory.h"
|
||||
|
@ -29,6 +30,8 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& i
|
|||
return std::make_shared<ObjectActionSpring>(id, ownerEntity);
|
||||
case ACTION_TYPE_HOLD:
|
||||
return std::make_shared<AvatarActionHold>(id, ownerEntity);
|
||||
case ACTION_TYPE_TRAVEL_ORIENTED:
|
||||
return std::make_shared<ObjectActionTravelOriented>(id, ownerEntity);
|
||||
}
|
||||
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown entity action type");
|
||||
|
|
|
@ -59,8 +59,6 @@ const float DISPLAYNAME_ALPHA = 1.0f;
|
|||
const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
|
||||
const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
|
||||
|
||||
const int SENSOR_TO_WORLD_MATRIX_INDEX = 65534;
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
|
||||
return ItemKey::Builder::opaqueShape();
|
||||
|
@ -853,32 +851,54 @@ glm::vec3 Avatar::getDefaultJointTranslation(int index) const {
|
|||
}
|
||||
|
||||
glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||
if (index == SENSOR_TO_WORLD_MATRIX_INDEX) {
|
||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||
bool success;
|
||||
Transform avatarTransform;
|
||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return glmExtractRotation(invAvatarMat * sensorToWorldMatrix);
|
||||
} else {
|
||||
glm::quat rotation;
|
||||
_skeletonModel->getAbsoluteJointRotationInRigFrame(index, rotation);
|
||||
return Quaternions::Y_180 * rotation;
|
||||
switch(index) {
|
||||
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||
bool success;
|
||||
Transform avatarTransform;
|
||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return glmExtractRotation(invAvatarMat * sensorToWorldMatrix);
|
||||
}
|
||||
case CONTROLLER_LEFTHAND_INDEX: {
|
||||
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
||||
return controllerLeftHandTransform.getRotation();
|
||||
}
|
||||
case CONTROLLER_RIGHTHAND_INDEX: {
|
||||
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
|
||||
return controllerRightHandTransform.getRotation();
|
||||
}
|
||||
default: {
|
||||
glm::quat rotation;
|
||||
_skeletonModel->getAbsoluteJointRotationInRigFrame(index, rotation);
|
||||
return Quaternions::Y_180 * rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||
if (index == SENSOR_TO_WORLD_MATRIX_INDEX) {
|
||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||
bool success;
|
||||
Transform avatarTransform;
|
||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return extractTranslation(invAvatarMat * sensorToWorldMatrix);
|
||||
} else {
|
||||
glm::vec3 translation;
|
||||
_skeletonModel->getAbsoluteJointTranslationInRigFrame(index, translation);
|
||||
return Quaternions::Y_180 * translation;
|
||||
switch(index) {
|
||||
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||
bool success;
|
||||
Transform avatarTransform;
|
||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return extractTranslation(invAvatarMat * sensorToWorldMatrix);
|
||||
}
|
||||
case CONTROLLER_LEFTHAND_INDEX: {
|
||||
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
||||
return controllerLeftHandTransform.getTranslation();
|
||||
}
|
||||
case CONTROLLER_RIGHTHAND_INDEX: {
|
||||
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
|
||||
return controllerRightHandTransform.getTranslation();
|
||||
}
|
||||
default: {
|
||||
glm::vec3 translation;
|
||||
_skeletonModel->getAbsoluteJointTranslationInRigFrame(index, translation);
|
||||
return Quaternions::Y_180 * translation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -889,6 +909,10 @@ int Avatar::getJointIndex(const QString& name) const {
|
|||
Q_RETURN_ARG(int, result), Q_ARG(const QString&, name));
|
||||
return result;
|
||||
}
|
||||
int result = getFauxJointIndex(name);
|
||||
if (result != -1) {
|
||||
return result;
|
||||
}
|
||||
return _skeletonModel->isActive() ? _skeletonModel->getFBXGeometry().getJointIndex(name) : -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,10 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
|
|||
}
|
||||
|
||||
withWriteLock([&]{
|
||||
glm::vec3 avatarRigidBodyPosition;
|
||||
glm::quat avatarRigidBodyRotation;
|
||||
getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation);
|
||||
|
||||
if (_ignoreIK) {
|
||||
return;
|
||||
}
|
||||
|
@ -70,9 +74,6 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
|
|||
palmRotation = holdingAvatar->getUncachedLeftPalmRotation();
|
||||
}
|
||||
|
||||
glm::vec3 avatarRigidBodyPosition;
|
||||
glm::quat avatarRigidBodyRotation;
|
||||
getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation);
|
||||
|
||||
// determine the difference in translation and rotation between the avatar's
|
||||
// rigid body and the palm position. The avatar's rigid body will be moved by bullet
|
||||
|
@ -124,13 +125,20 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
|
|||
if (pose.isValid()) {
|
||||
linearVelocity = pose.getVelocity();
|
||||
angularVelocity = pose.getAngularVelocity();
|
||||
|
||||
if (isRightHand) {
|
||||
pose = avatarManager->getMyAvatar()->getRightHandControllerPoseInAvatarFrame();
|
||||
} else {
|
||||
pose = avatarManager->getMyAvatar()->getLeftHandControllerPoseInAvatarFrame();
|
||||
}
|
||||
}
|
||||
|
||||
if (_ignoreIK && pose.isValid()) {
|
||||
// We cannot ignore other avatars IK and this is not the point of this option
|
||||
// This is meant to make the grabbing behavior more reactive.
|
||||
palmPosition = pose.getTranslation();
|
||||
palmRotation = pose.getRotation();
|
||||
Transform avatarTransform;
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
avatarTransform = myAvatar->getTransform();
|
||||
palmPosition = avatarTransform.transform(pose.getTranslation() / myAvatar->getTargetScale());
|
||||
palmRotation = avatarTransform.getRotation() * pose.getRotation();
|
||||
} else {
|
||||
glm::vec3 avatarRigidBodyPosition;
|
||||
glm::quat avatarRigidBodyRotation;
|
||||
|
@ -159,11 +167,17 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
|
|||
}
|
||||
} else { // regular avatar
|
||||
if (isRightHand) {
|
||||
palmPosition = holdingAvatar->getRightPalmPosition();
|
||||
palmRotation = holdingAvatar->getRightPalmRotation();
|
||||
Transform controllerRightTransform = Transform(holdingAvatar->getControllerRightHandMatrix());
|
||||
Transform avatarTransform = holdingAvatar->getTransform();
|
||||
palmRotation = avatarTransform.getRotation() * controllerRightTransform.getRotation();
|
||||
palmPosition = avatarTransform.getTranslation() +
|
||||
(avatarTransform.getRotation() * controllerRightTransform.getTranslation());
|
||||
} else {
|
||||
palmPosition = holdingAvatar->getLeftPalmPosition();
|
||||
palmRotation = holdingAvatar->getLeftPalmRotation();
|
||||
Transform controllerLeftTransform = Transform(holdingAvatar->getControllerLeftHandMatrix());
|
||||
Transform avatarTransform = holdingAvatar->getTransform();
|
||||
palmRotation = avatarTransform.getRotation() * controllerLeftTransform.getRotation();
|
||||
palmPosition = avatarTransform.getTranslation() +
|
||||
(avatarTransform.getRotation() * controllerLeftTransform.getTranslation());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -532,11 +532,21 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
|||
_hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation);
|
||||
}
|
||||
|
||||
void MyAvatar::updateJointFromController(controller::Action poseKey, ThreadSafeValueCache<glm::mat4>& matrixCache) {
|
||||
assert(QThread::currentThread() == thread());
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
controller::Pose controllerPose = userInputMapper->getPoseState(poseKey);
|
||||
Transform transform;
|
||||
transform.setTranslation(controllerPose.getTranslation());
|
||||
transform.setRotation(controllerPose.getRotation());
|
||||
glm::mat4 controllerMatrix = transform.getMatrix();
|
||||
matrixCache.set(controllerMatrix);
|
||||
}
|
||||
|
||||
// best called at end of main loop, after physics.
|
||||
// update sensor to world matrix from current body position and hmd sensor.
|
||||
// This is so the correct camera can be used for rendering.
|
||||
void MyAvatar::updateSensorToWorldMatrix() {
|
||||
|
||||
// update the sensor mat so that the body position will end up in the desired
|
||||
// position when driven from the head.
|
||||
glm::mat4 desiredMat = createMatFromQuatAndPos(getOrientation(), getPosition());
|
||||
|
@ -545,10 +555,14 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
|||
lateUpdatePalms();
|
||||
|
||||
if (_enableDebugDrawSensorToWorldMatrix) {
|
||||
DebugDraw::getInstance().addMarker("sensorToWorldMatrix", glmExtractRotation(_sensorToWorldMatrix), extractTranslation(_sensorToWorldMatrix), glm::vec4(1));
|
||||
DebugDraw::getInstance().addMarker("sensorToWorldMatrix", glmExtractRotation(_sensorToWorldMatrix),
|
||||
extractTranslation(_sensorToWorldMatrix), glm::vec4(1));
|
||||
}
|
||||
|
||||
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
|
||||
|
||||
updateJointFromController(controller::Action::LEFT_HAND, _controllerLeftHandMatrixCache);
|
||||
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
|
||||
}
|
||||
|
||||
// Update avatar head rotation with sensor data
|
||||
|
@ -2215,3 +2229,31 @@ bool MyAvatar::didTeleport() {
|
|||
bool MyAvatar::hasDriveInput() const {
|
||||
return fabsf(_driveKeys[TRANSLATE_X]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Y]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Z]) > 0.0f;
|
||||
}
|
||||
|
||||
glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||
switch(index) {
|
||||
case CONTROLLER_LEFTHAND_INDEX: {
|
||||
return getLeftHandControllerPoseInAvatarFrame().getRotation();
|
||||
}
|
||||
case CONTROLLER_RIGHTHAND_INDEX: {
|
||||
return getRightHandControllerPoseInAvatarFrame().getRotation();
|
||||
}
|
||||
default: {
|
||||
return Avatar::getAbsoluteJointRotationInObjectFrame(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||
switch(index) {
|
||||
case CONTROLLER_LEFTHAND_INDEX: {
|
||||
return getLeftHandControllerPoseInAvatarFrame().getTranslation();
|
||||
}
|
||||
case CONTROLLER_RIGHTHAND_INDEX: {
|
||||
return getRightHandControllerPoseInAvatarFrame().getTranslation();
|
||||
}
|
||||
default: {
|
||||
return Avatar::getAbsoluteJointTranslationInObjectFrame(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <Sound.h>
|
||||
|
||||
#include <controllers/Pose.h>
|
||||
#include <controllers/Actions.h>
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "AtRestDetector.h"
|
||||
|
@ -117,6 +118,9 @@ public:
|
|||
// as it moves through the world.
|
||||
void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix);
|
||||
|
||||
// read the location of a hand controller and save the transform
|
||||
void updateJointFromController(controller::Action poseKey, ThreadSafeValueCache<glm::mat4>& matrixCache);
|
||||
|
||||
// best called at end of main loop, just before rendering.
|
||||
// update sensor to world matrix from current body position and hmd sensor.
|
||||
// This is so the correct camera can be used for rendering.
|
||||
|
@ -270,6 +274,9 @@ public:
|
|||
Q_INVOKABLE void setCharacterControllerEnabled(bool enabled);
|
||||
Q_INVOKABLE bool getCharacterControllerEnabled();
|
||||
|
||||
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
|
||||
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
|
||||
|
||||
public slots:
|
||||
void increaseSize();
|
||||
void decreaseSize();
|
||||
|
@ -410,9 +417,8 @@ private:
|
|||
bool _useSnapTurn { true };
|
||||
bool _clearOverlayWhenMoving { true };
|
||||
|
||||
// working copy of sensorToWorldMatrix.
|
||||
// See AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
|
||||
glm::mat4 _sensorToWorldMatrix;
|
||||
// working copies -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
|
||||
glm::mat4 _sensorToWorldMatrix { glm::mat4() };
|
||||
|
||||
// cache of the current HMD sensor position and orientation
|
||||
// in sensor space.
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// InterfaceActivity.java
|
||||
// gvr-interface/java
|
||||
//
|
||||
// Created by Stephen Birarda on 1/26/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
|
||||
//
|
||||
|
||||
package io.highfidelity.gvrinterface;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
import android.util.Log;
|
||||
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||
|
||||
public class InterfaceActivity extends QtActivity {
|
||||
|
||||
public static native void handleHifiURL(String hifiURLString);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
||||
// Get the intent that started this activity in case we have a hifi:// URL to parse
|
||||
Intent intent = getIntent();
|
||||
if (intent.getAction() == Intent.ACTION_VIEW) {
|
||||
Uri data = intent.getData();
|
||||
|
||||
if (data.getScheme().equals("hifi")) {
|
||||
handleHifiURL(data.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
//
|
||||
// WebWindowClass.cpp
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Ryan Huffman on 11/06/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 <QVBoxLayout>
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
#include <QDockWidget>
|
||||
#include <QWebFrame>
|
||||
#include <QWebView>
|
||||
#include <QListWidget>
|
||||
#include <QStyleFactory>
|
||||
|
||||
#include "Application.h"
|
||||
#include "ui/DataWebPage.h"
|
||||
#include "MainWindow.h"
|
||||
#include "WebWindowClass.h"
|
||||
#include "WindowScriptingInterface.h"
|
||||
|
||||
ScriptEventBridge::ScriptEventBridge(QObject* parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
void ScriptEventBridge::emitWebEvent(const QString& data) {
|
||||
emit webEventReceived(data);
|
||||
}
|
||||
|
||||
void ScriptEventBridge::emitScriptEvent(const QString& data) {
|
||||
emit scriptEventReceived(data);
|
||||
}
|
||||
|
||||
WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height)
|
||||
: QObject(NULL), _eventBridge(new ScriptEventBridge(this)) {
|
||||
auto dialogWidget = new QDialog(qApp->getWindow(), Qt::Window);
|
||||
dialogWidget->setWindowTitle(title);
|
||||
dialogWidget->resize(width, height);
|
||||
dialogWidget->installEventFilter(this);
|
||||
connect(dialogWidget, &QDialog::finished, this, &WebWindowClass::hasClosed);
|
||||
|
||||
auto layout = new QVBoxLayout(dialogWidget);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
dialogWidget->setLayout(layout);
|
||||
|
||||
_webView = new QWebView(dialogWidget);
|
||||
|
||||
layout->addWidget(_webView);
|
||||
|
||||
addEventBridgeToWindowObject();
|
||||
|
||||
_windowWidget = dialogWidget;
|
||||
|
||||
auto style = QStyleFactory::create("fusion");
|
||||
if (style) {
|
||||
_webView->setStyle(style);
|
||||
}
|
||||
|
||||
_webView->setPage(new DataWebPage());
|
||||
if (!url.startsWith("http") && !url.startsWith("file://")) {
|
||||
_webView->setUrl(QUrl::fromLocalFile(url));
|
||||
} else {
|
||||
_webView->setUrl(url);
|
||||
}
|
||||
|
||||
connect(this, &WebWindowClass::destroyed, _windowWidget, &QWidget::deleteLater);
|
||||
connect(_webView->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared,
|
||||
this, &WebWindowClass::addEventBridgeToWindowObject);
|
||||
}
|
||||
|
||||
WebWindowClass::~WebWindowClass() {
|
||||
}
|
||||
|
||||
bool WebWindowClass::eventFilter(QObject* sender, QEvent* event) {
|
||||
if (sender == _windowWidget) {
|
||||
if (event->type() == QEvent::Move) {
|
||||
emit moved(getPosition());
|
||||
}
|
||||
if (event->type() == QEvent::Resize) {
|
||||
emit resized(getSize());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebWindowClass::hasClosed() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void WebWindowClass::addEventBridgeToWindowObject() {
|
||||
_webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge);
|
||||
}
|
||||
|
||||
void WebWindowClass::setVisible(bool visible) {
|
||||
if (visible) {
|
||||
QMetaObject::invokeMethod(_windowWidget, "showNormal", Qt::AutoConnection);
|
||||
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection);
|
||||
}
|
||||
QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible));
|
||||
}
|
||||
|
||||
void WebWindowClass::setURL(const QString& url) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setURL", Qt::AutoConnection, Q_ARG(QString, url));
|
||||
return;
|
||||
}
|
||||
_webView->setUrl(url);
|
||||
}
|
||||
|
||||
QSizeF WebWindowClass::getSize() const {
|
||||
QSizeF size = _windowWidget->size();
|
||||
return size;
|
||||
}
|
||||
|
||||
void WebWindowClass::setSize(QSizeF size) {
|
||||
setSize(size.width(), size.height());
|
||||
}
|
||||
|
||||
void WebWindowClass::setSize(int width, int height) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setSize", Qt::AutoConnection, Q_ARG(int, width), Q_ARG(int, height));
|
||||
return;
|
||||
}
|
||||
_windowWidget->resize(width, height);
|
||||
}
|
||||
|
||||
glm::vec2 WebWindowClass::getPosition() const {
|
||||
QPoint position = _windowWidget->pos();
|
||||
return glm::vec2(position.x(), position.y());
|
||||
}
|
||||
|
||||
void WebWindowClass::setPosition(glm::vec2 position) {
|
||||
setPosition(position.x, position.y);
|
||||
}
|
||||
|
||||
void WebWindowClass::setPosition(int x, int y) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setPosition", Qt::AutoConnection, Q_ARG(int, x), Q_ARG(int, y));
|
||||
return;
|
||||
}
|
||||
_windowWidget->move(x, y);
|
||||
}
|
||||
|
||||
void WebWindowClass::raise() {
|
||||
QMetaObject::invokeMethod(_windowWidget, "showNormal", Qt::AutoConnection);
|
||||
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection);
|
||||
}
|
||||
|
||||
QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
WebWindowClass* retVal;
|
||||
QString file = context->argument(0).toString();
|
||||
if (context->argument(4).toBool()) {
|
||||
qWarning() << "ToolWindow views with WebWindow are no longer supported. Use OverlayWebWindow instead";
|
||||
return QScriptValue();
|
||||
} else {
|
||||
qWarning() << "WebWindow views are deprecated. Use OverlayWebWindow instead";
|
||||
}
|
||||
QMetaObject::invokeMethod(DependencyManager::get<WindowScriptingInterface>().data(), "doCreateWebWindow", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(WebWindowClass*, retVal),
|
||||
Q_ARG(const QString&, file),
|
||||
Q_ARG(QString, context->argument(1).toString()),
|
||||
Q_ARG(int, context->argument(2).toInteger()),
|
||||
Q_ARG(int, context->argument(3).toInteger()));
|
||||
|
||||
connect(engine, &QScriptEngine::destroyed, retVal, &WebWindowClass::deleteLater);
|
||||
|
||||
return engine->newQObject(retVal);
|
||||
}
|
||||
|
||||
void WebWindowClass::setTitle(const QString& title) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setTitle", Qt::AutoConnection, Q_ARG(QString, title));
|
||||
return;
|
||||
}
|
||||
_windowWidget->setWindowTitle(title);
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
//
|
||||
// WebWindowClass.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Ryan Huffman on 11/06/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
|
||||
//
|
||||
|
||||
#ifndef hifi_WebWindowClass_h
|
||||
#define hifi_WebWindowClass_h
|
||||
|
||||
#include <QScriptContext>
|
||||
#include <QScriptEngine>
|
||||
#include <QWebView>
|
||||
|
||||
class ScriptEventBridge : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ScriptEventBridge(QObject* parent = NULL);
|
||||
|
||||
public slots:
|
||||
void emitWebEvent(const QString& data);
|
||||
void emitScriptEvent(const QString& data);
|
||||
|
||||
signals:
|
||||
void webEventReceived(const QString& data);
|
||||
void scriptEventReceived(const QString& data);
|
||||
|
||||
};
|
||||
|
||||
class WebWindowClass : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QObject* eventBridge READ getEventBridge)
|
||||
Q_PROPERTY(QString url READ getURL)
|
||||
Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition);
|
||||
Q_PROPERTY(QSizeF size READ getSize WRITE setSize);
|
||||
|
||||
public:
|
||||
WebWindowClass(const QString& title, const QString& url, int width, int height);
|
||||
~WebWindowClass();
|
||||
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||
|
||||
public slots:
|
||||
void setVisible(bool visible);
|
||||
glm::vec2 getPosition() const;
|
||||
void setPosition(int x, int y);
|
||||
void setPosition(glm::vec2 position);
|
||||
QSizeF getSize() const;
|
||||
void setSize(QSizeF size);
|
||||
void setSize(int width, int height);
|
||||
QString getURL() const { return _webView->url().url(); }
|
||||
void setURL(const QString& url);
|
||||
void raise();
|
||||
ScriptEventBridge* getEventBridge() const { return _eventBridge; }
|
||||
void addEventBridgeToWindowObject();
|
||||
void setTitle(const QString& title);
|
||||
|
||||
signals:
|
||||
void visibilityChanged(bool visible); // Tool window
|
||||
void moved(glm::vec2 position);
|
||||
void resized(QSizeF size);
|
||||
void closed();
|
||||
|
||||
protected:
|
||||
virtual bool eventFilter(QObject* sender, QEvent* event) override;
|
||||
|
||||
private slots:
|
||||
void hasClosed();
|
||||
|
||||
private:
|
||||
QWidget* _windowWidget;
|
||||
QWebView* _webView;
|
||||
ScriptEventBridge* _eventBridge;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -21,7 +21,6 @@
|
|||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
#include "OffscreenUi.h"
|
||||
#include "WebWindowClass.h"
|
||||
|
||||
#include "WindowScriptingInterface.h"
|
||||
|
||||
|
@ -61,10 +60,6 @@ WindowScriptingInterface::WindowScriptingInterface() {
|
|||
});
|
||||
}
|
||||
|
||||
WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height) {
|
||||
return new WebWindowClass(title, url, width, height);
|
||||
}
|
||||
|
||||
QScriptValue WindowScriptingInterface::hasFocus() {
|
||||
return qApp->hasFocus();
|
||||
}
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
#include <QtCore/QString>
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
class WebWindowClass;
|
||||
|
||||
|
||||
class CustomPromptResult {
|
||||
public:
|
||||
QVariant value;
|
||||
|
@ -65,9 +62,6 @@ signals:
|
|||
void snapshotTaken(const QString& path, bool notify);
|
||||
void snapshotShared(const QString& error);
|
||||
|
||||
private slots:
|
||||
WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height);
|
||||
|
||||
private:
|
||||
QString getPreviousBrowseLocation() const;
|
||||
void setPreviousBrowseLocation(const QString& location);
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
//
|
||||
// DataWebPage.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-09-22.
|
||||
// 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 <qnetworkrequest.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include <AddressManager.h>
|
||||
#include <OAuthNetworkAccessManager.h>
|
||||
|
||||
#include "DataWebPage.h"
|
||||
|
||||
DataWebPage::DataWebPage(QObject* parent) :
|
||||
QWebPage(parent)
|
||||
{
|
||||
// use an OAuthNetworkAccessManager instead of regular QNetworkAccessManager so our requests are authed
|
||||
setNetworkAccessManager(OAuthNetworkAccessManager::getInstance());
|
||||
|
||||
// give the page an empty stylesheet
|
||||
settings()->setUserStyleSheetUrl(QUrl());
|
||||
}
|
||||
|
||||
void DataWebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID) {
|
||||
qDebug() << "JS console message at line" << lineNumber << "from" << sourceID << "-" << message;
|
||||
}
|
||||
|
||||
bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) {
|
||||
// Handle hifi:// links and links to files with particular extensions
|
||||
QString urlString = request.url().toString();
|
||||
if (qApp->canAcceptURL(urlString)) {
|
||||
if (qApp->acceptURL(urlString)) {
|
||||
return false; // we handled it, so QWebPage doesn't need to handle it
|
||||
}
|
||||
}
|
||||
|
||||
// Make hyperlinks with target="_blank" open in user's Web browser
|
||||
if (type == QWebPage::NavigationTypeLinkClicked && frame == nullptr) {
|
||||
qApp->openUrl(request.url());
|
||||
return false; // We handled it.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString DataWebPage::userAgentForUrl(const QUrl& url) const {
|
||||
return HIGH_FIDELITY_USER_AGENT;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
//
|
||||
// DataWebPage.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-09-22.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_DataWebPage_h
|
||||
#define hifi_DataWebPage_h
|
||||
|
||||
#include <qwebpage.h>
|
||||
|
||||
class DataWebPage : public QWebPage {
|
||||
public:
|
||||
DataWebPage(QObject* parent = 0);
|
||||
protected:
|
||||
void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID) override;
|
||||
bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) override;
|
||||
virtual QString userAgentForUrl(const QUrl& url) const override;
|
||||
};
|
||||
|
||||
#endif // hifi_DataWebPage_h
|
|
@ -228,6 +228,7 @@ void ModelHandler::update() {
|
|||
QUrl url(_model.item(i,0)->data(Qt::UserRole).toString());
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.head(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
|
||||
|
@ -280,6 +281,7 @@ void ModelHandler::queryNewFiles(QString marker) {
|
|||
url.setQuery(query);
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(request);
|
||||
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
|
||||
|
|
|
@ -161,6 +161,7 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) {
|
|||
} else {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
qDebug() << "Downloading included script at" << scriptPath;
|
||||
|
|
|
@ -117,10 +117,12 @@ void Stats::updateStats(bool force) {
|
|||
// we need to take one avatar out so we don't include ourselves
|
||||
STAT_UPDATE(avatarCount, avatarManager->size() - 1);
|
||||
STAT_UPDATE(serverCount, (int)nodeList->size());
|
||||
STAT_UPDATE(renderrate, qApp->getFps());
|
||||
STAT_UPDATE(framerate, qApp->getFps());
|
||||
if (qApp->getActiveDisplayPlugin()) {
|
||||
STAT_UPDATE(presentrate, qApp->getActiveDisplayPlugin()->presentRate());
|
||||
STAT_UPDATE(presentnewrate, qApp->getActiveDisplayPlugin()->newFramePresentRate());
|
||||
auto displayPlugin = qApp->getActiveDisplayPlugin();
|
||||
STAT_UPDATE(renderrate, displayPlugin->renderRate());
|
||||
STAT_UPDATE(presentrate, displayPlugin->presentRate());
|
||||
STAT_UPDATE(presentnewrate, displayPlugin->newFramePresentRate());
|
||||
STAT_UPDATE(presentdroprate, qApp->getActiveDisplayPlugin()->droppedFrameRate());
|
||||
} else {
|
||||
STAT_UPDATE(presentrate, -1);
|
||||
|
|
|
@ -32,8 +32,13 @@ class Stats : public QQuickItem {
|
|||
Q_PROPERTY(float audioPacketlossDownstream READ getAudioPacketLossDownstream)
|
||||
|
||||
STATS_PROPERTY(int, serverCount, 0)
|
||||
// How often the app is creating new gpu::Frames
|
||||
STATS_PROPERTY(float, framerate, 0)
|
||||
// How often the display plugin is executing a given frame
|
||||
STATS_PROPERTY(float, renderrate, 0)
|
||||
// How often the display plugin is presenting to the device
|
||||
STATS_PROPERTY(float, presentrate, 0)
|
||||
|
||||
STATS_PROPERTY(float, presentnewrate, 0)
|
||||
STATS_PROPERTY(float, presentdroprate, 0)
|
||||
STATS_PROPERTY(int, simrate, 0)
|
||||
|
@ -116,6 +121,7 @@ public slots:
|
|||
void forceUpdateStats() { updateStats(true); }
|
||||
|
||||
signals:
|
||||
void framerateChanged();
|
||||
void expandedChanged();
|
||||
void timingExpandedChanged();
|
||||
void serverCountChanged();
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
set(TARGET_NAME audio)
|
||||
setup_hifi_library(Network)
|
||||
|
||||
if (ANDROID)
|
||||
add_definitions("-D__STDC_CONSTANT_MACROS")
|
||||
endif ()
|
||||
|
||||
link_hifi_libraries(networking shared plugins)
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AudioInjector.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDataStream>
|
||||
|
||||
|
@ -24,8 +26,6 @@
|
|||
#include "SoundCache.h"
|
||||
#include "AudioSRC.h"
|
||||
|
||||
#include "AudioInjector.h"
|
||||
|
||||
int audioInjectorPtrMetaTypeId = qRegisterMetaType<AudioInjector*>();
|
||||
|
||||
AudioInjectorState operator& (AudioInjectorState lhs, AudioInjectorState rhs) {
|
||||
|
@ -52,7 +52,7 @@ AudioInjector::AudioInjector(const Sound& sound, const AudioInjectorOptions& inj
|
|||
|
||||
AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions) :
|
||||
_audioData(audioData),
|
||||
_options(injectorOptions)
|
||||
_options(injectorOptions)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ bool AudioInjector::stateHas(AudioInjectorState state) const {
|
|||
}
|
||||
|
||||
void AudioInjector::setOptions(const AudioInjectorOptions& options) {
|
||||
// since options.stereo is computed from the audio stream,
|
||||
// since options.stereo is computed from the audio stream,
|
||||
// we need to copy it from existing options just in case.
|
||||
bool currentlyStereo = _options.stereo;
|
||||
_options = options;
|
||||
|
@ -71,7 +71,7 @@ void AudioInjector::setOptions(const AudioInjectorOptions& options) {
|
|||
|
||||
void AudioInjector::finishNetworkInjection() {
|
||||
_state |= AudioInjectorState::NetworkInjectionFinished;
|
||||
|
||||
|
||||
// if we are already finished with local
|
||||
// injection, then we are finished
|
||||
if(stateHas(AudioInjectorState::LocalInjectionFinished)) {
|
||||
|
@ -154,13 +154,13 @@ void AudioInjector::restart() {
|
|||
_hasSetup = false;
|
||||
_shouldStop = false;
|
||||
_state = AudioInjectorState::NotFinished;
|
||||
|
||||
|
||||
// call inject audio to start injection over again
|
||||
setupInjection();
|
||||
|
||||
// inject locally
|
||||
if(injectLocally()) {
|
||||
|
||||
|
||||
// if not localOnly, wake the AudioInjectorManager back up if it is stuck waiting
|
||||
if (!_options.localOnly) {
|
||||
|
||||
|
@ -221,7 +221,7 @@ qint64 writeStringToStream(const QString& string, QDataStream& stream) {
|
|||
stream << static_cast<quint32>(length);
|
||||
} else {
|
||||
// http://doc.qt.io/qt-5/datastreamformat.html
|
||||
// QDataStream << QByteArray -
|
||||
// QDataStream << QByteArray -
|
||||
// If the byte array is null : 0xFFFFFFFF (quint32)
|
||||
// Otherwise : the array size(quint32) followed by the array bytes, i.e.size bytes
|
||||
stream << data;
|
||||
|
@ -239,7 +239,7 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
static int positionOptionOffset = -1;
|
||||
static int volumeOptionOffset = -1;
|
||||
static int audioDataOffset = -1;
|
||||
|
||||
|
||||
if (!_currentPacket) {
|
||||
if (_currentSendOffset < 0 ||
|
||||
_currentSendOffset >= _audioData.size()) {
|
||||
|
@ -277,7 +277,7 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
|
||||
// current injectors don't use codecs, so pack in the unknown codec name
|
||||
QString noCodecForInjectors("");
|
||||
writeStringToStream(noCodecForInjectors, audioPacketStream);
|
||||
writeStringToStream(noCodecForInjectors, audioPacketStream);
|
||||
|
||||
// pack stream identifier (a generated UUID)
|
||||
audioPacketStream << QUuid::createUuid();
|
||||
|
@ -286,7 +286,7 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
audioPacketStream << _options.stereo;
|
||||
|
||||
// pack the flag for loopback. Now, we don't loopback
|
||||
// and _always_ play locally, so loopbackFlag should be
|
||||
// and _always_ play locally, so loopbackFlag should be
|
||||
// false always.
|
||||
uchar loopbackFlag = (uchar)false;
|
||||
audioPacketStream << loopbackFlag;
|
||||
|
@ -365,7 +365,7 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
_currentSendOffset = 0;
|
||||
}
|
||||
}
|
||||
// FIXME -- good place to call codec encode here. We need to figure out how to tell the AudioInjector which
|
||||
// FIXME -- good place to call codec encode here. We need to figure out how to tell the AudioInjector which
|
||||
// codec to use... possible through AbstractAudioInterface.
|
||||
QByteArray encodedAudio = decodedAudio;
|
||||
_currentPacket->write(encodedAudio.data(), encodedAudio.size());
|
||||
|
@ -407,7 +407,7 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
}
|
||||
|
||||
int64_t playNextFrameAt = ++_nextFrame * AudioConstants::NETWORK_FRAME_USECS;
|
||||
|
||||
|
||||
return std::max(INT64_C(0), playNextFrameAt - currentTime);
|
||||
}
|
||||
|
||||
|
@ -491,7 +491,7 @@ AudioInjector* AudioInjector::playSound(const QByteArray& buffer, const AudioInj
|
|||
|
||||
// we always inject locally, except when there is no localInterface
|
||||
injector->injectLocally();
|
||||
|
||||
|
||||
// if localOnly, we are done, just return injector.
|
||||
if (!options.localOnly) {
|
||||
|
||||
|
|
|
@ -24,33 +24,34 @@
|
|||
#include "AudioRingBuffer.h"
|
||||
|
||||
static const QString RING_BUFFER_OVERFLOW_DEBUG { "AudioRingBuffer::writeData has overflown the buffer. Overwriting old data." };
|
||||
static const QString DROPPED_SILENT_DEBUG { "AudioRingBuffer::addSilentSamples dropping silent samples to prevent overflow." };
|
||||
|
||||
AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) :
|
||||
AudioRingBuffer::AudioRingBuffer(int numFrameSamples, int numFramesCapacity) :
|
||||
_numFrameSamples(numFrameSamples),
|
||||
_frameCapacity(numFramesCapacity),
|
||||
_sampleCapacity(numFrameSamples * numFramesCapacity),
|
||||
_bufferLength(numFrameSamples * (numFramesCapacity + 1)),
|
||||
_numFrameSamples(numFrameSamples),
|
||||
_randomAccessMode(randomAccessMode),
|
||||
_overflowCount(0)
|
||||
_bufferLength(numFrameSamples * (numFramesCapacity + 1))
|
||||
{
|
||||
if (numFrameSamples) {
|
||||
_buffer = new int16_t[_bufferLength];
|
||||
memset(_buffer, 0, _bufferLength * sizeof(int16_t));
|
||||
_nextOutput = _buffer;
|
||||
_endOfLastWrite = _buffer;
|
||||
} else {
|
||||
_buffer = NULL;
|
||||
_nextOutput = NULL;
|
||||
_endOfLastWrite = NULL;
|
||||
}
|
||||
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
static QString repeatedOverflowMessage = LogHandler::getInstance().addRepeatedMessageRegex(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
static QString repeatedDroppedMessage = LogHandler::getInstance().addRepeatedMessageRegex(DROPPED_SILENT_DEBUG);
|
||||
};
|
||||
|
||||
AudioRingBuffer::~AudioRingBuffer() {
|
||||
delete[] _buffer;
|
||||
}
|
||||
|
||||
void AudioRingBuffer::clear() {
|
||||
_endOfLastWrite = _buffer;
|
||||
_nextOutput = _buffer;
|
||||
}
|
||||
|
||||
void AudioRingBuffer::reset() {
|
||||
clear();
|
||||
_overflowCount = 0;
|
||||
|
@ -58,109 +59,82 @@ void AudioRingBuffer::reset() {
|
|||
|
||||
void AudioRingBuffer::resizeForFrameSize(int numFrameSamples) {
|
||||
delete[] _buffer;
|
||||
_numFrameSamples = numFrameSamples;
|
||||
_sampleCapacity = numFrameSamples * _frameCapacity;
|
||||
_bufferLength = numFrameSamples * (_frameCapacity + 1);
|
||||
_numFrameSamples = numFrameSamples;
|
||||
_buffer = new int16_t[_bufferLength];
|
||||
memset(_buffer, 0, _bufferLength * sizeof(int16_t));
|
||||
if (_randomAccessMode) {
|
||||
memset(_buffer, 0, _bufferLength * sizeof(int16_t));
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
void AudioRingBuffer::clear() {
|
||||
_endOfLastWrite = _buffer;
|
||||
_nextOutput = _buffer;
|
||||
if (numFrameSamples) {
|
||||
_buffer = new int16_t[_bufferLength];
|
||||
memset(_buffer, 0, _bufferLength * sizeof(int16_t));
|
||||
} else {
|
||||
_buffer = nullptr;
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
int AudioRingBuffer::readSamples(int16_t* destination, int maxSamples) {
|
||||
return readData((char*)destination, maxSamples * sizeof(int16_t)) / sizeof(int16_t);
|
||||
}
|
||||
|
||||
int AudioRingBuffer::writeSamples(const int16_t* source, int maxSamples) {
|
||||
return writeData((char*)source, maxSamples * sizeof(int16_t)) / sizeof(int16_t);
|
||||
}
|
||||
|
||||
int AudioRingBuffer::readData(char *data, int maxSize) {
|
||||
|
||||
// only copy up to the number of samples we have available
|
||||
int numReadSamples = std::min((int)(maxSize / sizeof(int16_t)), samplesAvailable());
|
||||
|
||||
// If we're in random access mode, then we consider our number of available read samples slightly
|
||||
// differently. Namely, if anything has been written, we say we have as many samples as they ask for
|
||||
// otherwise we say we have nothing available
|
||||
if (_randomAccessMode) {
|
||||
numReadSamples = _endOfLastWrite ? (maxSize / sizeof(int16_t)) : 0;
|
||||
}
|
||||
int maxSamples = maxSize / sizeof(int16_t);
|
||||
int numReadSamples = std::min(maxSamples, samplesAvailable());
|
||||
|
||||
if (_nextOutput + numReadSamples > _buffer + _bufferLength) {
|
||||
// we're going to need to do two reads to get this data, it wraps around the edge
|
||||
int numSamplesToEnd = (_buffer + _bufferLength) - _nextOutput;
|
||||
|
||||
// read to the end of the buffer
|
||||
int numSamplesToEnd = (_buffer + _bufferLength) - _nextOutput;
|
||||
memcpy(data, _nextOutput, numSamplesToEnd * sizeof(int16_t));
|
||||
if (_randomAccessMode) {
|
||||
memset(_nextOutput, 0, numSamplesToEnd * sizeof(int16_t)); // clear it
|
||||
}
|
||||
|
||||
// read the rest from the beginning of the buffer
|
||||
memcpy(data + (numSamplesToEnd * sizeof(int16_t)), _buffer, (numReadSamples - numSamplesToEnd) * sizeof(int16_t));
|
||||
if (_randomAccessMode) {
|
||||
memset(_buffer, 0, (numReadSamples - numSamplesToEnd) * sizeof(int16_t)); // clear it
|
||||
}
|
||||
} else {
|
||||
// read the data
|
||||
memcpy(data, _nextOutput, numReadSamples * sizeof(int16_t));
|
||||
if (_randomAccessMode) {
|
||||
memset(_nextOutput, 0, numReadSamples * sizeof(int16_t)); // clear it
|
||||
}
|
||||
}
|
||||
|
||||
// push the position of _nextOutput by the number of samples read
|
||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, numReadSamples);
|
||||
shiftReadPosition(numReadSamples);
|
||||
|
||||
return numReadSamples * sizeof(int16_t);
|
||||
}
|
||||
|
||||
int AudioRingBuffer::writeSamples(const int16_t* source, int maxSamples) {
|
||||
return writeData((const char*)source, maxSamples * sizeof(int16_t)) / sizeof(int16_t);
|
||||
}
|
||||
|
||||
int AudioRingBuffer::writeData(const char* data, int maxSize) {
|
||||
// make sure we have enough bytes left for this to be the right amount of audio
|
||||
// otherwise we should not copy that data, and leave the buffer pointers where they are
|
||||
int samplesToCopy = std::min((int)(maxSize / sizeof(int16_t)), _sampleCapacity);
|
||||
|
||||
// only copy up to the number of samples we have capacity for
|
||||
int maxSamples = maxSize / sizeof(int16_t);
|
||||
int numWriteSamples = std::min(maxSamples, _sampleCapacity);
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
if (samplesToCopy > samplesRoomFor) {
|
||||
// there's not enough room for this write. erase old data to make room for this new data
|
||||
int samplesToDelete = samplesToCopy - samplesRoomFor;
|
||||
|
||||
if (numWriteSamples > samplesRoomFor) {
|
||||
// there's not enough room for this write. erase old data to make room for this new data
|
||||
int samplesToDelete = numWriteSamples - samplesRoomFor;
|
||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
||||
_overflowCount++;
|
||||
|
||||
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
}
|
||||
|
||||
if (_endOfLastWrite + samplesToCopy <= _buffer + _bufferLength) {
|
||||
memcpy(_endOfLastWrite, data, samplesToCopy * sizeof(int16_t));
|
||||
} else {
|
||||
if (_endOfLastWrite + numWriteSamples > _buffer + _bufferLength) {
|
||||
// we're going to need to do two writes to set this data, it wraps around the edge
|
||||
int numSamplesToEnd = (_buffer + _bufferLength) - _endOfLastWrite;
|
||||
|
||||
// write to the end of the buffer
|
||||
memcpy(_endOfLastWrite, data, numSamplesToEnd * sizeof(int16_t));
|
||||
memcpy(_buffer, data + (numSamplesToEnd * sizeof(int16_t)), (samplesToCopy - numSamplesToEnd) * sizeof(int16_t));
|
||||
|
||||
// write the rest to the beginning of the buffer
|
||||
memcpy(_buffer, data + (numSamplesToEnd * sizeof(int16_t)), (numWriteSamples - numSamplesToEnd) * sizeof(int16_t));
|
||||
} else {
|
||||
memcpy(_endOfLastWrite, data, numWriteSamples * sizeof(int16_t));
|
||||
}
|
||||
|
||||
_endOfLastWrite = shiftedPositionAccomodatingWrap(_endOfLastWrite, samplesToCopy);
|
||||
_endOfLastWrite = shiftedPositionAccomodatingWrap(_endOfLastWrite, numWriteSamples);
|
||||
|
||||
return samplesToCopy * sizeof(int16_t);
|
||||
}
|
||||
|
||||
int16_t& AudioRingBuffer::operator[](const int index) {
|
||||
return *shiftedPositionAccomodatingWrap(_nextOutput, index);
|
||||
}
|
||||
|
||||
const int16_t& AudioRingBuffer::operator[] (const int index) const {
|
||||
return *shiftedPositionAccomodatingWrap(_nextOutput, index);
|
||||
}
|
||||
|
||||
void AudioRingBuffer::shiftReadPosition(unsigned int numSamples) {
|
||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, numSamples);
|
||||
return numWriteSamples * sizeof(int16_t);
|
||||
}
|
||||
|
||||
int AudioRingBuffer::samplesAvailable() const {
|
||||
|
@ -176,35 +150,31 @@ int AudioRingBuffer::samplesAvailable() const {
|
|||
}
|
||||
|
||||
int AudioRingBuffer::addSilentSamples(int silentSamples) {
|
||||
|
||||
// NOTE: This implementation is nearly identical to writeData save for s/memcpy/memset, refer to comments there
|
||||
int numWriteSamples = std::min(silentSamples, _sampleCapacity);
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
if (silentSamples > samplesRoomFor) {
|
||||
// there's not enough room for this write. write as many silent samples as we have room for
|
||||
silentSamples = samplesRoomFor;
|
||||
|
||||
static const QString DROPPED_SILENT_DEBUG {
|
||||
"AudioRingBuffer::addSilentSamples dropping silent samples to prevent overflow."
|
||||
};
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(DROPPED_SILENT_DEBUG);
|
||||
if (numWriteSamples > samplesRoomFor) {
|
||||
numWriteSamples = samplesRoomFor;
|
||||
|
||||
qCDebug(audio) << qPrintable(DROPPED_SILENT_DEBUG);
|
||||
}
|
||||
|
||||
// memset zeroes into the buffer, accomodate a wrap around the end
|
||||
// push the _endOfLastWrite to the correct spot
|
||||
if (_endOfLastWrite + silentSamples <= _buffer + _bufferLength) {
|
||||
memset(_endOfLastWrite, 0, silentSamples * sizeof(int16_t));
|
||||
} else {
|
||||
if (_endOfLastWrite + numWriteSamples > _buffer + _bufferLength) {
|
||||
int numSamplesToEnd = (_buffer + _bufferLength) - _endOfLastWrite;
|
||||
memset(_endOfLastWrite, 0, numSamplesToEnd * sizeof(int16_t));
|
||||
memset(_buffer, 0, (silentSamples - numSamplesToEnd) * sizeof(int16_t));
|
||||
memset(_buffer, 0, (numWriteSamples - numSamplesToEnd) * sizeof(int16_t));
|
||||
} else {
|
||||
memset(_endOfLastWrite, 0, numWriteSamples * sizeof(int16_t));
|
||||
}
|
||||
_endOfLastWrite = shiftedPositionAccomodatingWrap(_endOfLastWrite, silentSamples);
|
||||
|
||||
return silentSamples;
|
||||
_endOfLastWrite = shiftedPositionAccomodatingWrap(_endOfLastWrite, numWriteSamples);
|
||||
|
||||
return numWriteSamples;
|
||||
}
|
||||
|
||||
int16_t* AudioRingBuffer::shiftedPositionAccomodatingWrap(int16_t* position, int numSamplesShift) const {
|
||||
|
||||
// NOTE: It is possible to shift out-of-bounds if (|numSamplesShift| > 2 * _bufferLength), but this should not occur
|
||||
if (numSamplesShift > 0 && position + numSamplesShift >= _buffer + _bufferLength) {
|
||||
// this shift will wrap the position around to the beginning of the ring
|
||||
return position + numSamplesShift - _bufferLength;
|
||||
|
@ -217,13 +187,15 @@ int16_t* AudioRingBuffer::shiftedPositionAccomodatingWrap(int16_t* position, int
|
|||
}
|
||||
|
||||
float AudioRingBuffer::getFrameLoudness(const int16_t* frameStart) const {
|
||||
// FIXME: This is a bad measure of loudness - normal estimation uses sqrt(sum(x*x))
|
||||
float loudness = 0.0f;
|
||||
const int16_t* sampleAt = frameStart;
|
||||
const int16_t* _bufferLastAt = _buffer + _bufferLength - 1;
|
||||
const int16_t* bufferLastAt = _buffer + _bufferLength - 1;
|
||||
|
||||
for (int i = 0; i < _numFrameSamples; ++i) {
|
||||
loudness += (float) std::abs(*sampleAt);
|
||||
sampleAt = sampleAt == _bufferLastAt ? _buffer : sampleAt + 1;
|
||||
// wrap if necessary
|
||||
sampleAt = sampleAt == bufferLastAt ? _buffer : sampleAt + 1;
|
||||
}
|
||||
loudness /= _numFrameSamples;
|
||||
loudness /= AudioConstants::MAX_SAMPLE_VALUE;
|
||||
|
@ -238,10 +210,6 @@ float AudioRingBuffer::getFrameLoudness(ConstIterator frameStart) const {
|
|||
return getFrameLoudness(&(*frameStart));
|
||||
}
|
||||
|
||||
float AudioRingBuffer::getNextOutputFrameLoudness() const {
|
||||
return getFrameLoudness(_nextOutput);
|
||||
}
|
||||
|
||||
int AudioRingBuffer::writeSamples(ConstIterator source, int maxSamples) {
|
||||
int samplesToCopy = std::min(maxSamples, _sampleCapacity);
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
|
|
|
@ -23,73 +23,69 @@ const int DEFAULT_RING_BUFFER_FRAME_CAPACITY = 10;
|
|||
|
||||
class AudioRingBuffer {
|
||||
public:
|
||||
AudioRingBuffer(int numFrameSamples, bool randomAccessMode = false, int numFramesCapacity = DEFAULT_RING_BUFFER_FRAME_CAPACITY);
|
||||
AudioRingBuffer(int numFrameSamples, int numFramesCapacity = DEFAULT_RING_BUFFER_FRAME_CAPACITY);
|
||||
~AudioRingBuffer();
|
||||
|
||||
void reset();
|
||||
void resizeForFrameSize(int numFrameSamples);
|
||||
// disallow copying
|
||||
AudioRingBuffer(const AudioRingBuffer&) = delete;
|
||||
AudioRingBuffer(AudioRingBuffer&&) = delete;
|
||||
AudioRingBuffer& operator=(const AudioRingBuffer&) = delete;
|
||||
|
||||
/// Invalidate any data in the buffer
|
||||
void clear();
|
||||
|
||||
int getSampleCapacity() const { return _sampleCapacity; }
|
||||
int getFrameCapacity() const { return _frameCapacity; }
|
||||
/// Clear and reset the overflow count
|
||||
void reset();
|
||||
|
||||
/// Resize frame size (causes a reset())
|
||||
// FIXME: discards any data in the buffer
|
||||
void resizeForFrameSize(int numFrameSamples);
|
||||
|
||||
/// Read up to maxSamples into destination (will only read up to samplesAvailable())
|
||||
/// Returns number of read samples
|
||||
int readSamples(int16_t* destination, int maxSamples);
|
||||
|
||||
/// Write up to maxSamples from source (will only write up to sample capacity)
|
||||
/// Returns number of written samples
|
||||
int writeSamples(const int16_t* source, int maxSamples);
|
||||
|
||||
int readData(char* data, int maxSize);
|
||||
int writeData(const char* data, int maxSize);
|
||||
/// Write up to maxSamples silent samples (will only write until other data exists in the buffer)
|
||||
/// This method will not overwrite existing data in the buffer, instead dropping silent samples that would overflow
|
||||
/// Returns number of written silent samples
|
||||
int addSilentSamples(int maxSamples);
|
||||
|
||||
int16_t& operator[](const int index);
|
||||
const int16_t& operator[] (const int index) const;
|
||||
/// Read up to maxSize into destination
|
||||
/// Returns number of read bytes
|
||||
int readData(char* destination, int maxSize);
|
||||
|
||||
void shiftReadPosition(unsigned int numSamples);
|
||||
/// Write up to maxSize from source
|
||||
/// Returns number of written bytes
|
||||
int writeData(const char* source, int maxSize);
|
||||
|
||||
float getNextOutputFrameLoudness() const;
|
||||
/// Returns a reference to the index-th sample offset from the current read sample
|
||||
int16_t& operator[](const int index) { return *shiftedPositionAccomodatingWrap(_nextOutput, index); }
|
||||
const int16_t& operator[] (const int index) const { return *shiftedPositionAccomodatingWrap(_nextOutput, index); }
|
||||
|
||||
/// Essentially discards the next numSamples from the ring buffer
|
||||
/// NOTE: This is not checked - it is possible to shift past written data
|
||||
/// Use samplesAvailable() to see the distance a valid shift can go
|
||||
void shiftReadPosition(unsigned int numSamples) { _nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, numSamples); }
|
||||
|
||||
int samplesAvailable() const;
|
||||
int framesAvailable() const { return (_numFrameSamples == 0) ? 0 : samplesAvailable() / _numFrameSamples; }
|
||||
float getNextOutputFrameLoudness() const { return getFrameLoudness(_nextOutput); }
|
||||
|
||||
|
||||
int getNumFrameSamples() const { return _numFrameSamples; }
|
||||
int getFrameCapacity() const { return _frameCapacity; }
|
||||
int getSampleCapacity() const { return _sampleCapacity; }
|
||||
/// Return times the ring buffer has overwritten old data
|
||||
int getOverflowCount() const { return _overflowCount; }
|
||||
|
||||
int getOverflowCount() const { return _overflowCount; } /// how many times has the ring buffer has overwritten old data
|
||||
|
||||
int addSilentSamples(int samples);
|
||||
|
||||
private:
|
||||
float getFrameLoudness(const int16_t* frameStart) const;
|
||||
|
||||
protected:
|
||||
// disallow copying of AudioRingBuffer objects
|
||||
AudioRingBuffer(const AudioRingBuffer&);
|
||||
AudioRingBuffer& operator= (const AudioRingBuffer&);
|
||||
|
||||
int16_t* shiftedPositionAccomodatingWrap(int16_t* position, int numSamplesShift) const;
|
||||
|
||||
int _frameCapacity;
|
||||
int _sampleCapacity;
|
||||
int _bufferLength; // actual length of _buffer: will be one frame larger than _sampleCapacity
|
||||
int _numFrameSamples;
|
||||
int16_t* _nextOutput;
|
||||
int16_t* _endOfLastWrite;
|
||||
int16_t* _buffer;
|
||||
bool _randomAccessMode; /// will this ringbuffer be used for random access? if so, do some special processing
|
||||
|
||||
int _overflowCount; /// how many times has the ring buffer has overwritten old data
|
||||
|
||||
public:
|
||||
class ConstIterator { //public std::iterator < std::forward_iterator_tag, int16_t > {
|
||||
class ConstIterator {
|
||||
public:
|
||||
ConstIterator()
|
||||
: _bufferLength(0),
|
||||
_bufferFirst(NULL),
|
||||
_bufferLast(NULL),
|
||||
_at(NULL) {}
|
||||
ConstIterator(int16_t* bufferFirst, int capacity, int16_t* at)
|
||||
: _bufferLength(capacity),
|
||||
_bufferFirst(bufferFirst),
|
||||
_bufferLast(bufferFirst + capacity - 1),
|
||||
_at(at) {}
|
||||
ConstIterator();
|
||||
ConstIterator(int16_t* bufferFirst, int capacity, int16_t* at);
|
||||
ConstIterator(const ConstIterator& rhs) = default;
|
||||
|
||||
bool isNull() const { return _at == NULL; }
|
||||
|
@ -98,95 +94,143 @@ public:
|
|||
bool operator!=(const ConstIterator& rhs) { return _at != rhs._at; }
|
||||
const int16_t& operator*() { return *_at; }
|
||||
|
||||
ConstIterator& operator=(const ConstIterator& rhs) {
|
||||
_bufferLength = rhs._bufferLength;
|
||||
_bufferFirst = rhs._bufferFirst;
|
||||
_bufferLast = rhs._bufferLast;
|
||||
_at = rhs._at;
|
||||
return *this;
|
||||
}
|
||||
ConstIterator& operator=(const ConstIterator& rhs);
|
||||
ConstIterator& operator++();
|
||||
ConstIterator operator++(int);
|
||||
ConstIterator& operator--();
|
||||
ConstIterator operator--(int);
|
||||
const int16_t& operator[] (int i);
|
||||
ConstIterator operator+(int i);
|
||||
ConstIterator operator-(int i);
|
||||
|
||||
ConstIterator& operator++() {
|
||||
_at = (_at == _bufferLast) ? _bufferFirst : _at + 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConstIterator operator++(int) {
|
||||
ConstIterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
ConstIterator& operator--() {
|
||||
_at = (_at == _bufferFirst) ? _bufferLast : _at - 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConstIterator operator--(int) {
|
||||
ConstIterator tmp(*this);
|
||||
--(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const int16_t& operator[] (int i) {
|
||||
return *atShiftedBy(i);
|
||||
}
|
||||
|
||||
ConstIterator operator+(int i) {
|
||||
return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(i));
|
||||
}
|
||||
|
||||
ConstIterator operator-(int i) {
|
||||
return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(-i));
|
||||
}
|
||||
|
||||
void readSamples(int16_t* dest, int numSamples) {
|
||||
auto samplesToEnd = _bufferLast - _at + 1;
|
||||
|
||||
if (samplesToEnd >= numSamples) {
|
||||
memcpy(dest, _at, numSamples * sizeof(int16_t));
|
||||
_at += numSamples;
|
||||
} else {
|
||||
auto samplesFromStart = numSamples - samplesToEnd;
|
||||
memcpy(dest, _at, samplesToEnd * sizeof(int16_t));
|
||||
memcpy(dest + samplesToEnd, _bufferFirst, samplesFromStart * sizeof(int16_t));
|
||||
|
||||
_at = _bufferFirst + samplesFromStart;
|
||||
}
|
||||
}
|
||||
|
||||
void readSamplesWithFade(int16_t* dest, int numSamples, float fade) {
|
||||
int16_t* at = _at;
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
*dest = (float)*at * fade;
|
||||
++dest;
|
||||
at = (at == _bufferLast) ? _bufferFirst : at + 1;
|
||||
}
|
||||
}
|
||||
void readSamples(int16_t* dest, int numSamples);
|
||||
void readSamplesWithFade(int16_t* dest, int numSamples, float fade);
|
||||
|
||||
private:
|
||||
int16_t* atShiftedBy(int i) {
|
||||
i = (_at - _bufferFirst + i) % _bufferLength;
|
||||
if (i < 0) {
|
||||
i += _bufferLength;
|
||||
}
|
||||
return _bufferFirst + i;
|
||||
}
|
||||
int16_t* atShiftedBy(int i);
|
||||
|
||||
private:
|
||||
int _bufferLength;
|
||||
int16_t* _bufferFirst;
|
||||
int16_t* _bufferLast;
|
||||
int16_t* _at;
|
||||
};
|
||||
|
||||
ConstIterator nextOutput() const { return ConstIterator(_buffer, _bufferLength, _nextOutput); }
|
||||
ConstIterator lastFrameWritten() const { return ConstIterator(_buffer, _bufferLength, _endOfLastWrite) - _numFrameSamples; }
|
||||
|
||||
float getFrameLoudness(ConstIterator frameStart) const;
|
||||
ConstIterator nextOutput() const;
|
||||
ConstIterator lastFrameWritten() const;
|
||||
|
||||
int writeSamples(ConstIterator source, int maxSamples);
|
||||
int writeSamplesWithFade(ConstIterator source, int maxSamples, float fade);
|
||||
|
||||
float getFrameLoudness(ConstIterator frameStart) const;
|
||||
|
||||
protected:
|
||||
int16_t* shiftedPositionAccomodatingWrap(int16_t* position, int numSamplesShift) const;
|
||||
float getFrameLoudness(const int16_t* frameStart) const;
|
||||
|
||||
int _numFrameSamples;
|
||||
int _frameCapacity;
|
||||
int _sampleCapacity;
|
||||
int _bufferLength; // actual _buffer length (_sampleCapacity + 1)
|
||||
int _overflowCount{ 0 }; // times the ring buffer has overwritten data
|
||||
|
||||
int16_t* _nextOutput{ nullptr };
|
||||
int16_t* _endOfLastWrite{ nullptr };
|
||||
int16_t* _buffer{ nullptr };
|
||||
};
|
||||
|
||||
// inline the iterator:
|
||||
inline AudioRingBuffer::ConstIterator::ConstIterator() :
|
||||
_bufferLength(0),
|
||||
_bufferFirst(NULL),
|
||||
_bufferLast(NULL),
|
||||
_at(NULL) {}
|
||||
|
||||
inline AudioRingBuffer::ConstIterator::ConstIterator(int16_t* bufferFirst, int capacity, int16_t* at) :
|
||||
_bufferLength(capacity),
|
||||
_bufferFirst(bufferFirst),
|
||||
_bufferLast(bufferFirst + capacity - 1),
|
||||
_at(at) {}
|
||||
|
||||
inline AudioRingBuffer::ConstIterator& AudioRingBuffer::ConstIterator::operator=(const ConstIterator& rhs) {
|
||||
_bufferLength = rhs._bufferLength;
|
||||
_bufferFirst = rhs._bufferFirst;
|
||||
_bufferLast = rhs._bufferLast;
|
||||
_at = rhs._at;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline AudioRingBuffer::ConstIterator& AudioRingBuffer::ConstIterator::operator++() {
|
||||
_at = (_at == _bufferLast) ? _bufferFirst : _at + 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline AudioRingBuffer::ConstIterator AudioRingBuffer::ConstIterator::operator++(int) {
|
||||
ConstIterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline AudioRingBuffer::ConstIterator& AudioRingBuffer::ConstIterator::operator--() {
|
||||
_at = (_at == _bufferFirst) ? _bufferLast : _at - 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline AudioRingBuffer::ConstIterator AudioRingBuffer::ConstIterator::operator--(int) {
|
||||
ConstIterator tmp(*this);
|
||||
--(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline const int16_t& AudioRingBuffer::ConstIterator::operator[] (int i) {
|
||||
return *atShiftedBy(i);
|
||||
}
|
||||
|
||||
inline AudioRingBuffer::ConstIterator AudioRingBuffer::ConstIterator::operator+(int i) {
|
||||
return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(i));
|
||||
}
|
||||
|
||||
inline AudioRingBuffer::ConstIterator AudioRingBuffer::ConstIterator::operator-(int i) {
|
||||
return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(-i));
|
||||
}
|
||||
|
||||
inline int16_t* AudioRingBuffer::ConstIterator::atShiftedBy(int i) {
|
||||
i = (_at - _bufferFirst + i) % _bufferLength;
|
||||
if (i < 0) {
|
||||
i += _bufferLength;
|
||||
}
|
||||
return _bufferFirst + i;
|
||||
}
|
||||
|
||||
inline void AudioRingBuffer::ConstIterator::readSamples(int16_t* dest, int numSamples) {
|
||||
auto samplesToEnd = _bufferLast - _at + 1;
|
||||
|
||||
if (samplesToEnd >= numSamples) {
|
||||
memcpy(dest, _at, numSamples * sizeof(int16_t));
|
||||
_at += numSamples;
|
||||
} else {
|
||||
auto samplesFromStart = numSamples - samplesToEnd;
|
||||
memcpy(dest, _at, samplesToEnd * sizeof(int16_t));
|
||||
memcpy(dest + samplesToEnd, _bufferFirst, samplesFromStart * sizeof(int16_t));
|
||||
|
||||
_at = _bufferFirst + samplesFromStart;
|
||||
}
|
||||
}
|
||||
|
||||
inline void AudioRingBuffer::ConstIterator::readSamplesWithFade(int16_t* dest, int numSamples, float fade) {
|
||||
int16_t* at = _at;
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
*dest = (float)*at * fade;
|
||||
++dest;
|
||||
at = (at == _bufferLast) ? _bufferFirst : at + 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline AudioRingBuffer::ConstIterator AudioRingBuffer::nextOutput() const {
|
||||
return ConstIterator(_buffer, _bufferLength, _nextOutput);
|
||||
}
|
||||
|
||||
inline AudioRingBuffer::ConstIterator AudioRingBuffer::lastFrameWritten() const {
|
||||
return ConstIterator(_buffer, _bufferLength, _endOfLastWrite) - _numFrameSamples;
|
||||
}
|
||||
|
||||
#endif // hifi_AudioRingBuffer_h
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
const int STARVE_HISTORY_CAPACITY = 50;
|
||||
|
||||
InboundAudioStream::InboundAudioStream(int numFrameSamples, int numFramesCapacity, const Settings& settings) :
|
||||
_ringBuffer(numFrameSamples, false, numFramesCapacity),
|
||||
_ringBuffer(numFrameSamples, numFramesCapacity),
|
||||
_lastPopSucceeded(false),
|
||||
_lastPopOutput(),
|
||||
_dynamicJitterBuffers(settings._dynamicJitterBuffers),
|
||||
|
|
|
@ -33,6 +33,7 @@ void AutoUpdater::checkForUpdate() {
|
|||
void AutoUpdater::getLatestVersionData() {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest latestVersionRequest(BUILDS_XML_URL);
|
||||
latestVersionRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
latestVersionRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(latestVersionRequest);
|
||||
connect(reply, &QNetworkReply::finished, this, &AutoUpdater::parseLatestVersionData);
|
||||
|
|
|
@ -374,6 +374,16 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
|||
}
|
||||
}
|
||||
|
||||
// faux joints
|
||||
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
||||
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerLeftHandTransform.getRotation());
|
||||
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerLeftHandTransform.getTranslation(),
|
||||
TRANSLATION_COMPRESSION_RADIX);
|
||||
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
|
||||
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerRightHandTransform.getRotation());
|
||||
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerRightHandTransform.getTranslation(),
|
||||
TRANSLATION_COMPRESSION_RADIX);
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
if (sendAll) {
|
||||
qDebug() << "AvatarData::toByteArray" << cullSmallChanges << sendAll
|
||||
|
@ -429,6 +439,20 @@ bool AvatarData::shouldLogError(const quint64& now) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
const unsigned char* unpackFauxJoint(const unsigned char* sourceBuffer, ThreadSafeValueCache<glm::mat4>& matrixCache) {
|
||||
glm::quat orientation;
|
||||
glm::vec3 position;
|
||||
Transform transform;
|
||||
sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, orientation);
|
||||
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, position, TRANSLATION_COMPRESSION_RADIX);
|
||||
transform.setTranslation(position);
|
||||
transform.setRotation(orientation);
|
||||
matrixCache.set(transform.getMatrix());
|
||||
return sourceBuffer;
|
||||
}
|
||||
|
||||
|
||||
#define PACKET_READ_CHECK(ITEM_NAME, SIZE_TO_READ) \
|
||||
if ((endPosition - sourceBuffer) < (int)SIZE_TO_READ) { \
|
||||
if (shouldLogError(now)) { \
|
||||
|
@ -655,6 +679,10 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// faux joints
|
||||
sourceBuffer = unpackFauxJoint(sourceBuffer, _controllerLeftHandMatrixCache);
|
||||
sourceBuffer = unpackFauxJoint(sourceBuffer, _controllerRightHandMatrixCache);
|
||||
|
||||
int numBytesRead = sourceBuffer - startPosition;
|
||||
_averageBytesReceived.updateAverage(numBytesRead);
|
||||
return numBytesRead;
|
||||
|
@ -915,7 +943,24 @@ void AvatarData::clearJointsData() {
|
|||
}
|
||||
}
|
||||
|
||||
int AvatarData::getFauxJointIndex(const QString& name) const {
|
||||
if (name == "_SENSOR_TO_WORLD_MATRIX") {
|
||||
return SENSOR_TO_WORLD_MATRIX_INDEX;
|
||||
}
|
||||
if (name == "_CONTROLLER_LEFTHAND") {
|
||||
return CONTROLLER_LEFTHAND_INDEX;
|
||||
}
|
||||
if (name == "_CONTROLLER_RIGHTHAND") {
|
||||
return CONTROLLER_RIGHTHAND_INDEX;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int AvatarData::getJointIndex(const QString& name) const {
|
||||
int result = getFauxJointIndex(name);
|
||||
if (result != -1) {
|
||||
return result;
|
||||
}
|
||||
QReadLocker readLock(&_jointDataLock);
|
||||
return _jointIndices.value(name) - 1;
|
||||
}
|
||||
|
@ -1161,6 +1206,7 @@ void AvatarData::updateJointMappings() {
|
|||
if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(_skeletonModelURL);
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* networkReply = networkAccessManager.get(networkRequest);
|
||||
connect(networkReply, &QNetworkReply::finished, this, &AvatarData::setJointMappingsFromNetworkReply);
|
||||
|
@ -1743,6 +1789,17 @@ glm::mat4 AvatarData::getSensorToWorldMatrix() const {
|
|||
return _sensorToWorldMatrixCache.get();
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::mat4 AvatarData::getControllerLeftHandMatrix() const {
|
||||
return _controllerLeftHandMatrixCache.get();
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::mat4 AvatarData::getControllerRightHandMatrix() const {
|
||||
return _controllerRightHandMatrixCache.get();
|
||||
}
|
||||
|
||||
|
||||
QScriptValue RayToAvatarIntersectionResultToScriptValue(QScriptEngine* engine, const RayToAvatarIntersectionResult& value) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("intersects", value.intersects);
|
||||
|
|
|
@ -173,6 +173,8 @@ class AvatarData : public QObject, public SpatiallyNestable {
|
|||
Q_PROPERTY(QUuid sessionUUID READ getSessionUUID)
|
||||
|
||||
Q_PROPERTY(glm::mat4 sensorToWorldMatrix READ getSensorToWorldMatrix)
|
||||
Q_PROPERTY(glm::mat4 controllerLeftHandMatrix READ getControllerLeftHandMatrix)
|
||||
Q_PROPERTY(glm::mat4 controllerRightHandMatrix READ getControllerRightHandMatrix)
|
||||
|
||||
public:
|
||||
|
||||
|
@ -356,6 +358,8 @@ public:
|
|||
|
||||
// thread safe
|
||||
Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const;
|
||||
Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const;
|
||||
Q_INVOKABLE glm::mat4 getControllerRightHandMatrix() const;
|
||||
|
||||
public slots:
|
||||
void sendAvatarDataPacket();
|
||||
|
@ -369,6 +373,8 @@ public slots:
|
|||
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
|
||||
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; }
|
||||
|
||||
float getTargetScale() { return _targetScale; }
|
||||
|
||||
protected:
|
||||
glm::vec3 _handPosition;
|
||||
|
||||
|
@ -433,6 +439,10 @@ protected:
|
|||
|
||||
// used to transform any sensor into world space, including the _hmdSensorMat, or hand controllers.
|
||||
ThreadSafeValueCache<glm::mat4> _sensorToWorldMatrixCache { glm::mat4() };
|
||||
ThreadSafeValueCache<glm::mat4> _controllerLeftHandMatrixCache { glm::mat4() };
|
||||
ThreadSafeValueCache<glm::mat4> _controllerRightHandMatrixCache { glm::mat4() };
|
||||
|
||||
int getFauxJointIndex(const QString& name) const;
|
||||
|
||||
private:
|
||||
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
||||
|
@ -519,5 +529,10 @@ Q_DECLARE_METATYPE(RayToAvatarIntersectionResult)
|
|||
QScriptValue RayToAvatarIntersectionResultToScriptValue(QScriptEngine* engine, const RayToAvatarIntersectionResult& results);
|
||||
void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, RayToAvatarIntersectionResult& results);
|
||||
|
||||
// faux joint indexes (-1 means invalid)
|
||||
const int SENSOR_TO_WORLD_MATRIX_INDEX = 65534; // -2
|
||||
const int CONTROLLER_RIGHTHAND_INDEX = 65533; // -3
|
||||
const int CONTROLLER_LEFTHAND_INDEX = 65532; // -4
|
||||
|
||||
|
||||
#endif // hifi_AvatarData_h
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
set(TARGET_NAME controllers)
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
setup_hifi_library(Script)
|
||||
setup_hifi_library(Script Qml)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
link_hifi_libraries(shared)
|
||||
|
@ -11,4 +11,3 @@ GroupSources("src/controllers")
|
|||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
|
|
|
@ -325,7 +325,6 @@ QString UserInputMapper::getActionName(Action action) const {
|
|||
return QString();
|
||||
}
|
||||
|
||||
|
||||
QVector<QString> UserInputMapper::getActionNames() const {
|
||||
Locker locker(_lock);
|
||||
QVector<QString> result;
|
||||
|
@ -335,6 +334,12 @@ QVector<QString> UserInputMapper::getActionNames() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
Pose UserInputMapper::getPoseState(Action action) const {
|
||||
assert(QThread::currentThread() == thread());
|
||||
return _poseStates[toInt(action)];
|
||||
}
|
||||
|
||||
|
||||
bool UserInputMapper::triggerHapticPulse(float strength, float duration, controller::Hand hand) {
|
||||
Locker locker(_lock);
|
||||
bool toReturn = false;
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace controller {
|
|||
QVector<Action> getAllActions() const;
|
||||
QString getActionName(Action action) const;
|
||||
float getActionState(Action action) const { return _actionStates[toInt(action)]; }
|
||||
Pose getPoseState(Action action) const { return _poseStates[toInt(action)]; }
|
||||
Pose getPoseState(Action action) const;
|
||||
int findAction(const QString& actionName) const;
|
||||
QVector<QString> getActionNames() const;
|
||||
Input inputFromAction(Action action) const { return getActionInputs()[toInt(action)].first; }
|
||||
|
|
|
@ -7,4 +7,6 @@ target_opengl()
|
|||
|
||||
GroupSources("src/display-plugins")
|
||||
|
||||
target_oglplus()
|
||||
if (NOT ANDROID)
|
||||
target_oglplus()
|
||||
endif ()
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <gl/GLWidget.h>
|
||||
#include <gl/Config.h>
|
||||
#include <gl/GLEscrow.h>
|
||||
#include <gl/Context.h>
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
@ -108,7 +109,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void setContext(QGLContext * context) {
|
||||
void setContext(gl::Context* context) {
|
||||
// Move the OpenGL context to the present thread
|
||||
// Extra code because of the widget 'wrapper' context
|
||||
_context = context;
|
||||
|
@ -126,7 +127,6 @@ public:
|
|||
OpenGLDisplayPlugin* currentPlugin{ nullptr };
|
||||
Q_ASSERT(_context);
|
||||
_context->makeCurrent();
|
||||
Q_ASSERT(isCurrentContext(_context->contextHandle()));
|
||||
while (!_shutdown) {
|
||||
if (_pendingMainThreadOperation) {
|
||||
PROFILE_RANGE("MainThreadOp")
|
||||
|
@ -250,7 +250,7 @@ private:
|
|||
bool _finishedMainThreadOperation { false };
|
||||
QThread* _mainThread { nullptr };
|
||||
std::queue<OpenGLDisplayPlugin*> _newPluginQueue;
|
||||
QGLContext* _context { nullptr };
|
||||
gl::Context* _context { nullptr };
|
||||
};
|
||||
|
||||
bool OpenGLDisplayPlugin::activate() {
|
||||
|
@ -475,32 +475,28 @@ bool OpenGLDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
|
|||
}
|
||||
|
||||
void OpenGLDisplayPlugin::submitFrame(const gpu::FramePointer& newFrame) {
|
||||
if (_lockCurrentTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
withNonPresentThreadLock([&] {
|
||||
_newFrameQueue.push(newFrame);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::updateFrameData() {
|
||||
if (_lockCurrentTexture) {
|
||||
return;
|
||||
}
|
||||
withPresentThreadLock([&] {
|
||||
gpu::FramePointer oldFrame = _currentFrame;
|
||||
uint32_t skippedCount = 0;
|
||||
if (!_newFrameQueue.empty()) {
|
||||
// We're changing frames, so we can cleanup any GL resources that might have been used by the old frame
|
||||
_gpuContext->recycle();
|
||||
}
|
||||
if (_newFrameQueue.size() > 1) {
|
||||
_droppedFrameRate.increment(_newFrameQueue.size() - 1);
|
||||
}
|
||||
while (!_newFrameQueue.empty()) {
|
||||
_currentFrame = _newFrameQueue.front();
|
||||
_newFrameQueue.pop();
|
||||
_gpuContext->consumeFrameUpdates(_currentFrame);
|
||||
if (_currentFrame && oldFrame) {
|
||||
skippedCount += (_currentFrame->frameIndex - oldFrame->frameIndex) - 1;
|
||||
}
|
||||
}
|
||||
_droppedFrameRate.increment(skippedCount);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -598,6 +594,7 @@ void OpenGLDisplayPlugin::internalPresent() {
|
|||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
swapBuffers();
|
||||
_presentRate.increment();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::present() {
|
||||
|
@ -612,6 +609,13 @@ void OpenGLDisplayPlugin::present() {
|
|||
|
||||
if (_currentFrame) {
|
||||
{
|
||||
withPresentThreadLock([&] {
|
||||
_renderRate.increment();
|
||||
if (_currentFrame != _lastFrame) {
|
||||
_newFrameRate.increment();
|
||||
}
|
||||
_lastFrame = _currentFrame;
|
||||
});
|
||||
// Execute the frame rendering commands
|
||||
PROFILE_RANGE_EX("execute", 0xff00ff00, (uint64_t)presentCount())
|
||||
_gpuContext->executeFrame(_currentFrame);
|
||||
|
@ -628,7 +632,6 @@ void OpenGLDisplayPlugin::present() {
|
|||
PROFILE_RANGE_EX("internalPresent", 0xff00ffff, (uint64_t)presentCount())
|
||||
internalPresent();
|
||||
}
|
||||
_presentRate.increment();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -637,20 +640,21 @@ float OpenGLDisplayPlugin::newFramePresentRate() const {
|
|||
}
|
||||
|
||||
float OpenGLDisplayPlugin::droppedFrameRate() const {
|
||||
float result;
|
||||
withNonPresentThreadLock([&] {
|
||||
result = _droppedFrameRate.rate();
|
||||
});
|
||||
return result;
|
||||
return _droppedFrameRate.rate();
|
||||
}
|
||||
|
||||
float OpenGLDisplayPlugin::presentRate() const {
|
||||
return _presentRate.rate();
|
||||
}
|
||||
|
||||
float OpenGLDisplayPlugin::renderRate() const {
|
||||
return _renderRate.rate();
|
||||
}
|
||||
|
||||
|
||||
void OpenGLDisplayPlugin::swapBuffers() {
|
||||
static auto widget = _container->getPrimaryWidget();
|
||||
widget->swapBuffers();
|
||||
static auto context = _container->getPrimaryWidget()->context();
|
||||
context->swapBuffers();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::withMainThreadContext(std::function<void()> f) const {
|
||||
|
|
|
@ -62,11 +62,15 @@ public:
|
|||
|
||||
float droppedFrameRate() const override;
|
||||
|
||||
float renderRate() const override;
|
||||
|
||||
bool beginFrameRender(uint32_t frameIndex) override;
|
||||
|
||||
virtual bool wantVsync() const { return true; }
|
||||
void setVsyncEnabled(bool vsyncEnabled) { _vsyncEnabled = vsyncEnabled; }
|
||||
bool isVsyncEnabled() const { return _vsyncEnabled; }
|
||||
// Three threads, one for rendering, one for texture transfers, one reserved for the GL driver
|
||||
int getRequiredThreadCount() const override { return 3; }
|
||||
|
||||
protected:
|
||||
friend class PresentThread;
|
||||
|
@ -109,8 +113,10 @@ protected:
|
|||
RateCounter<> _droppedFrameRate;
|
||||
RateCounter<> _newFrameRate;
|
||||
RateCounter<> _presentRate;
|
||||
RateCounter<> _renderRate;
|
||||
|
||||
gpu::FramePointer _currentFrame;
|
||||
gpu::FramePointer _lastFrame;
|
||||
gpu::FramebufferPointer _compositeFramebuffer;
|
||||
gpu::PipelinePointer _overlayPipeline;
|
||||
gpu::PipelinePointer _simplePipeline;
|
||||
|
|
|
@ -527,9 +527,11 @@ void HmdDisplayPlugin::compositeExtra() {
|
|||
if (_presentHandPoses[index] == IDENTITY_MATRIX) {
|
||||
return;
|
||||
}
|
||||
const auto& points = _presentHandLaserPoints[index];
|
||||
const auto& lasers = _presentHandLasers[index];
|
||||
geometryCache->renderGlowLine(batch, points.first, points.second, lasers.color);
|
||||
const auto& laser = _presentHandLasers[index];
|
||||
if (laser.valid()) {
|
||||
const auto& points = _presentHandLaserPoints[index];
|
||||
geometryCache->renderGlowLine(batch, points.first, points.second, laser.color);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -52,7 +52,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
_viewState(viewState),
|
||||
_scriptingServices(scriptingServices),
|
||||
_displayModelBounds(false),
|
||||
_dontDoPrecisionPicking(false)
|
||||
_dontDoPrecisionPicking(false),
|
||||
_layeredZones(this)
|
||||
{
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
|
||||
|
@ -135,8 +136,8 @@ void EntityTreeRenderer::clear() {
|
|||
_entitiesInScene.clear();
|
||||
|
||||
// reset the zone to the default (while we load the next scene)
|
||||
_bestZone = nullptr;
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
_layeredZones.clear();
|
||||
applyZoneAndHasSkybox(nullptr);
|
||||
|
||||
OctreeRenderer::clear();
|
||||
}
|
||||
|
@ -192,10 +193,10 @@ void EntityTreeRenderer::update() {
|
|||
|
||||
// If we haven't already updated and previously attempted to load a texture,
|
||||
// check if the texture loaded and apply it
|
||||
if (!updated && (
|
||||
(_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())) ||
|
||||
(_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())))) {
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
if (!updated &&
|
||||
((_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())) ||
|
||||
(_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())))) {
|
||||
applySkyboxAndHasAmbient();
|
||||
}
|
||||
|
||||
// Even if we're not moving the mouse, if we started clicking on an entity and we have
|
||||
|
@ -210,7 +211,7 @@ void EntityTreeRenderer::update() {
|
|||
deleteReleasedModels();
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar) {
|
||||
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar) {
|
||||
bool didUpdate = false;
|
||||
float radius = 0.01f; // for now, assume 0.01 meter radius, because we actually check the point inside later
|
||||
QVector<EntityItemPointer> foundEntities;
|
||||
|
@ -220,12 +221,10 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3&
|
|||
_tree->withReadLock([&] {
|
||||
|
||||
// FIXME - if EntityTree had a findEntitiesContainingPoint() this could theoretically be a little faster
|
||||
std::static_pointer_cast<EntityTree>(_tree)->findEntities(avatarPosition, radius, foundEntities);
|
||||
std::static_pointer_cast<EntityTree>(_tree)->findEntities(_avatarPosition, radius, foundEntities);
|
||||
|
||||
// Whenever you're in an intersection between zones, we will always choose the smallest zone.
|
||||
auto oldBestZone = _bestZone;
|
||||
_bestZone = nullptr; // NOTE: Is this what we want?
|
||||
_bestZoneVolume = std::numeric_limits<float>::max();
|
||||
LayeredZones oldLayeredZones(std::move(_layeredZones));
|
||||
_layeredZones.clear();
|
||||
|
||||
// create a list of entities that actually contain the avatar's position
|
||||
for (auto& entity : foundEntities) {
|
||||
|
@ -239,38 +238,34 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3&
|
|||
if (isZone || hasScript) {
|
||||
// now check to see if the point contains our entity, this can be expensive if
|
||||
// the entity has a collision hull
|
||||
if (entity->contains(avatarPosition)) {
|
||||
if (entity->contains(_avatarPosition)) {
|
||||
if (entitiesContainingAvatar) {
|
||||
*entitiesContainingAvatar << entity->getEntityItemID();
|
||||
}
|
||||
|
||||
// if this entity is a zone and visible, determine if it is the bestZone
|
||||
if (isZone && entity->getVisible()) {
|
||||
float entityVolumeEstimate = entity->getVolumeEstimate();
|
||||
if (entityVolumeEstimate < _bestZoneVolume) {
|
||||
_bestZoneVolume = entityVolumeEstimate;
|
||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
} else if (entityVolumeEstimate == _bestZoneVolume) {
|
||||
// in the case of the volume being equal, we will use the
|
||||
// EntityItemID to deterministically pick one entity over the other
|
||||
if (!_bestZone) {
|
||||
_bestZoneVolume = entityVolumeEstimate;
|
||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
} else if (entity->getEntityItemID() < _bestZone->getEntityItemID()) {
|
||||
_bestZoneVolume = entityVolumeEstimate;
|
||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
}
|
||||
}
|
||||
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
_layeredZones.insert(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_bestZone != oldBestZone) {
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
didUpdate = true;
|
||||
// check if our layered zones have changed
|
||||
if (_layeredZones.empty()) {
|
||||
if (oldLayeredZones.empty()) {
|
||||
return;
|
||||
}
|
||||
} else if (!oldLayeredZones.empty()) {
|
||||
if (_layeredZones.contains(oldLayeredZones)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_layeredZones.apply();
|
||||
didUpdate = true;
|
||||
});
|
||||
|
||||
return didUpdate;
|
||||
}
|
||||
|
||||
|
@ -286,13 +281,14 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
// if some amount of time has elapsed since we last checked. We check the time
|
||||
// elapsed because zones or entities might have been created "around us" while we've
|
||||
// been stationary
|
||||
auto movedEnough = glm::distance(avatarPosition, _lastAvatarPosition) > ZONE_CHECK_DISTANCE;
|
||||
auto movedEnough = glm::distance(avatarPosition, _avatarPosition) > ZONE_CHECK_DISTANCE;
|
||||
auto enoughTimeElapsed = (now - _lastZoneCheck) > ZONE_CHECK_INTERVAL;
|
||||
|
||||
if (movedEnough || enoughTimeElapsed) {
|
||||
_avatarPosition = avatarPosition;
|
||||
_lastZoneCheck = now;
|
||||
QVector<EntityItemID> entitiesContainingAvatar;
|
||||
didUpdate = findBestZoneAndMaybeContainingEntities(avatarPosition, &entitiesContainingAvatar);
|
||||
didUpdate = findBestZoneAndMaybeContainingEntities(&entitiesContainingAvatar);
|
||||
|
||||
// Note: at this point we don't need to worry about the tree being locked, because we only deal with
|
||||
// EntityItemIDs from here. The callEntityScriptMethod() method is robust against attempting to call scripts
|
||||
|
@ -318,7 +314,6 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
}
|
||||
}
|
||||
_currentEntitiesInside = entitiesContainingAvatar;
|
||||
_lastAvatarPosition = avatarPosition;
|
||||
}
|
||||
}
|
||||
return didUpdate;
|
||||
|
@ -342,24 +337,20 @@ void EntityTreeRenderer::leaveAllEntities() {
|
|||
void EntityTreeRenderer::forceRecheckEntities() {
|
||||
// make sure our "last avatar position" is something other than our current position,
|
||||
// so that on our next chance, we'll check for enter/leave entity events.
|
||||
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||
_avatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||
}
|
||||
|
||||
|
||||
void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone) {
|
||||
bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto sceneStage = scene->getStage();
|
||||
auto skyStage = scene->getSkyStage();
|
||||
auto sceneKeyLight = sceneStage->getKeyLight();
|
||||
|
||||
// Skybox and procedural skybox data
|
||||
auto skybox = std::dynamic_pointer_cast<ProceduralSkybox>(skyStage->getSkybox());
|
||||
|
||||
// If there is no zone, use the default background
|
||||
if (!zone) {
|
||||
_zoneUserData = QString();
|
||||
skybox->clear();
|
||||
skyStage->getSkybox()->clear();
|
||||
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
|
@ -371,7 +362,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
sceneKeyLight->setAmbientMap(nullptr);
|
||||
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the keylight
|
||||
|
@ -394,90 +385,127 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
}
|
||||
|
||||
// Set the ambient texture
|
||||
bool isAmbientTextureSet = false;
|
||||
if (zone->getKeyLightProperties().getAmbientURL().isEmpty()) {
|
||||
_ambientTextureURL = zone->getKeyLightProperties().getAmbientURL();
|
||||
if (_ambientTextureURL.isEmpty()) {
|
||||
_pendingAmbientTexture = false;
|
||||
_ambientTexture.clear();
|
||||
} else {
|
||||
_ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), NetworkTexture::CUBE_TEXTURE);
|
||||
_pendingAmbientTexture = true;
|
||||
|
||||
if (_ambientTexture && _ambientTexture->isLoaded()) {
|
||||
_pendingAmbientTexture = false;
|
||||
|
||||
auto texture = _ambientTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
isAmbientTextureSet = true;
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << zone->getKeyLightProperties().getAmbientURL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the skybox texture
|
||||
return layerZoneAndHasSkybox(zone);
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
|
||||
assert(zone);
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto skyStage = scene->getSkyStage();
|
||||
auto skybox = skyStage->getSkybox();
|
||||
|
||||
bool hasSkybox = false;
|
||||
|
||||
switch (zone->getBackgroundMode()) {
|
||||
case BACKGROUND_MODE_SKYBOX: {
|
||||
case BACKGROUND_MODE_SKYBOX:
|
||||
hasSkybox = true;
|
||||
|
||||
skybox->setColor(zone->getSkyboxProperties().getColorVec3());
|
||||
|
||||
if (_zoneUserData != zone->getUserData()) {
|
||||
_zoneUserData = zone->getUserData();
|
||||
skybox->parse(_zoneUserData);
|
||||
std::dynamic_pointer_cast<ProceduralSkybox>(skybox)->parse(_zoneUserData);
|
||||
}
|
||||
if (zone->getSkyboxProperties().getURL().isEmpty()) {
|
||||
skybox->setCubemap(nullptr);
|
||||
|
||||
_skyboxTextureURL = zone->getSkyboxProperties().getURL();
|
||||
if (_skyboxTextureURL.isEmpty()) {
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
} else {
|
||||
// Update the Texture of the Skybox with the one pointed by this zone
|
||||
_skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), NetworkTexture::CUBE_TEXTURE);
|
||||
_pendingSkyboxTexture = true;
|
||||
|
||||
if (_skyboxTexture && _skyboxTexture->isLoaded()) {
|
||||
_pendingSkyboxTexture = false;
|
||||
|
||||
auto texture = _skyboxTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
skybox->setCubemap(texture);
|
||||
if (!isAmbientTextureSet) {
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
isAmbientTextureSet = true;
|
||||
}
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load skybox texture:" << zone->getSkyboxProperties().getURL();
|
||||
skybox->setCubemap(nullptr);
|
||||
}
|
||||
} else {
|
||||
skybox->setCubemap(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
applySkyboxAndHasAmbient();
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BACKGROUND_MODE_INHERIT:
|
||||
default:
|
||||
// Clear the skybox to release its textures
|
||||
_zoneUserData = QString();
|
||||
skybox->clear();
|
||||
_zoneUserData = QString();
|
||||
|
||||
_skyboxTexture.clear();
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
|
||||
// Let the application background through
|
||||
if (isAmbientTextureSet) {
|
||||
if (applySkyboxAndHasAmbient()) {
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_TEXTURE);
|
||||
} else {
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isAmbientTextureSet) {
|
||||
return hasSkybox;
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::applySkyboxAndHasAmbient() {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto sceneStage = scene->getStage();
|
||||
auto skyStage = scene->getSkyStage();
|
||||
auto sceneKeyLight = sceneStage->getKeyLight();
|
||||
auto skybox = skyStage->getSkybox();
|
||||
|
||||
bool isAmbientSet = false;
|
||||
if (_pendingAmbientTexture && !_ambientTexture) {
|
||||
_ambientTexture = textureCache->getTexture(_ambientTextureURL, NetworkTexture::CUBE_TEXTURE);
|
||||
}
|
||||
if (_ambientTexture && _ambientTexture->isLoaded()) {
|
||||
_pendingAmbientTexture = false;
|
||||
|
||||
auto texture = _ambientTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
isAmbientSet = true;
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << _ambientTexture->getURL();
|
||||
}
|
||||
}
|
||||
|
||||
if (_pendingSkyboxTexture && !_skyboxTexture) {
|
||||
_skyboxTexture = textureCache->getTexture(_skyboxTextureURL, NetworkTexture::CUBE_TEXTURE);
|
||||
}
|
||||
if (_skyboxTexture && _skyboxTexture->isLoaded()) {
|
||||
_pendingSkyboxTexture = false;
|
||||
|
||||
auto texture = _skyboxTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
skybox->setCubemap(texture);
|
||||
if (!isAmbientSet) {
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
isAmbientSet = true;
|
||||
}
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load skybox texture:" << _skyboxTexture->getURL();
|
||||
skybox->setCubemap(nullptr);
|
||||
}
|
||||
} else {
|
||||
skybox->setCubemap(nullptr);
|
||||
}
|
||||
|
||||
if (!isAmbientSet) {
|
||||
sceneKeyLight->resetAmbientSphere();
|
||||
sceneKeyLight->setAmbientMap(nullptr);
|
||||
}
|
||||
|
||||
return isAmbientSet;
|
||||
}
|
||||
|
||||
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) {
|
||||
|
@ -528,14 +556,13 @@ ModelPointer EntityTreeRenderer::allocateModel(const QString& url, float loading
|
|||
return model;
|
||||
}
|
||||
|
||||
ModelPointer EntityTreeRenderer::updateModel(ModelPointer model, const QString& newUrl, const QString& collisionUrl) {
|
||||
ModelPointer EntityTreeRenderer::updateModel(ModelPointer model, const QString& newUrl) {
|
||||
// Only create and delete models on the thread that owns the EntityTreeRenderer
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateModel", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(ModelPointer, model),
|
||||
Q_ARG(ModelPointer, model),
|
||||
Q_ARG(const QString&, newUrl),
|
||||
Q_ARG(const QString&, collisionUrl));
|
||||
Q_ARG(const QString&, newUrl));
|
||||
|
||||
return model;
|
||||
}
|
||||
|
@ -1046,21 +1073,128 @@ void EntityTreeRenderer::updateEntityRenderStatus(bool shouldRenderEntities) {
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::updateZone(const EntityItemID& id) {
|
||||
if (!_bestZone) {
|
||||
// Get in the zone!
|
||||
auto zone = getTree()->findEntityByEntityItemID(id);
|
||||
if (zone && zone->contains(_lastAvatarPosition)) {
|
||||
_currentEntitiesInside << id;
|
||||
emit enterEntity(id);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(id, "enterEntity");
|
||||
}
|
||||
if (zone->getVisible()) {
|
||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_bestZone && _bestZone->getID() == id) {
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
// Get in the zone!
|
||||
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(getTree()->findEntityByEntityItemID(id));
|
||||
if (zone && zone->contains(_avatarPosition)) {
|
||||
_layeredZones.update(zone);
|
||||
}
|
||||
}
|
||||
|
||||
EntityTreeRenderer::LayeredZones::LayeredZones(LayeredZones&& other) {
|
||||
// In a swap:
|
||||
// > All iterators and references remain valid. The past-the-end iterator is invalidated.
|
||||
bool isSkyboxLayerValid = (other._skyboxLayer != other.end());
|
||||
|
||||
swap(other);
|
||||
_map.swap(other._map);
|
||||
_skyboxLayer = other._skyboxLayer;
|
||||
|
||||
if (!isSkyboxLayerValid) {
|
||||
_skyboxLayer = end();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::clear() {
|
||||
std::set<LayeredZone>::clear();
|
||||
_map.clear();
|
||||
_skyboxLayer = end();
|
||||
}
|
||||
|
||||
std::pair<EntityTreeRenderer::LayeredZones::iterator, bool> EntityTreeRenderer::LayeredZones::insert(const LayeredZone& layer) {
|
||||
iterator it;
|
||||
bool success;
|
||||
std::tie(it, success) = std::set<LayeredZone>::insert(layer);
|
||||
|
||||
if (success) {
|
||||
_map.emplace(it->id, it);
|
||||
}
|
||||
|
||||
return { it, success };
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::apply() {
|
||||
assert(_entityTreeRenderer);
|
||||
|
||||
applyPartial(begin());
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::update(std::shared_ptr<ZoneEntityItem> zone) {
|
||||
assert(_entityTreeRenderer);
|
||||
bool isVisible = zone->isVisible();
|
||||
|
||||
if (empty() && isVisible) {
|
||||
// there are no zones: set this one
|
||||
insert(zone);
|
||||
apply();
|
||||
return;
|
||||
} else {
|
||||
LayeredZone zoneLayer(zone);
|
||||
|
||||
// should we update? only if this zone is tighter than the current skybox zone
|
||||
bool shouldUpdate = false;
|
||||
if (_skyboxLayer == end() || zoneLayer <= *_skyboxLayer) {
|
||||
shouldUpdate = true;
|
||||
}
|
||||
|
||||
// find this zone's layer, if it exists
|
||||
iterator layer = end();
|
||||
auto it = _map.find(zoneLayer.id);
|
||||
if (it != _map.end()) {
|
||||
layer = it->second;
|
||||
// if the volume changed, we need to resort the layer (reinsertion)
|
||||
// if the visibility changed, we need to erase the layer
|
||||
if (zoneLayer.volume != layer->volume || !isVisible) {
|
||||
erase(layer);
|
||||
_map.erase(it);
|
||||
layer = end();
|
||||
}
|
||||
}
|
||||
|
||||
// (re)insert this zone's layer if necessary
|
||||
if (layer == end() && isVisible) {
|
||||
std::tie(layer, std::ignore) = insert(zoneLayer);
|
||||
_map.emplace(layer->id, layer);
|
||||
}
|
||||
|
||||
if (shouldUpdate) {
|
||||
applyPartial(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::applyPartial(iterator layer) {
|
||||
bool hasSkybox = false;
|
||||
_skyboxLayer = end();
|
||||
|
||||
if (layer == end()) {
|
||||
if (empty()) {
|
||||
_entityTreeRenderer->applyZoneAndHasSkybox(nullptr);
|
||||
return;
|
||||
} else { // a layer was removed - reapply from beginning
|
||||
layer = begin();
|
||||
}
|
||||
}
|
||||
|
||||
if (layer == begin()) {
|
||||
hasSkybox = _entityTreeRenderer->applyZoneAndHasSkybox(layer->zone);
|
||||
} else {
|
||||
hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone);
|
||||
}
|
||||
|
||||
if (layer != end()) {
|
||||
while (!hasSkybox && ++layer != end()) {
|
||||
hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone);
|
||||
}
|
||||
}
|
||||
|
||||
_skyboxLayer = layer;
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::LayeredZones::contains(const LayeredZones& other) {
|
||||
bool result = std::equal(other.begin(), other._skyboxLayer, begin());
|
||||
if (result) {
|
||||
// if valid, set the _skyboxLayer from the other LayeredZones
|
||||
_skyboxLayer = std::next(begin(), std::distance(other.begin(), other._skyboxLayer));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
Q_INVOKABLE ModelPointer allocateModel(const QString& url, float loadingPriority = 0.0f);
|
||||
|
||||
/// if a renderable entity item needs to update the URL of a model, we will handle that for the entity
|
||||
Q_INVOKABLE ModelPointer updateModel(ModelPointer original, const QString& newUrl, const QString& collisionUrl);
|
||||
Q_INVOKABLE ModelPointer updateModel(ModelPointer original, const QString& newUrl);
|
||||
|
||||
/// if a renderable entity item is done with a model, it should return it to us
|
||||
void releaseModel(ModelPointer model);
|
||||
|
@ -95,7 +95,7 @@ public:
|
|||
// For Scene.shouldRenderEntities
|
||||
QList<EntityItemID>& getEntitiesLastInScene() { return _entityIDsLastInScene; }
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _bestZone; }
|
||||
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _layeredZones.getZone(); }
|
||||
|
||||
signals:
|
||||
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
|
@ -138,9 +138,12 @@ private:
|
|||
void resetEntitiesScriptEngine();
|
||||
|
||||
void addEntityToScene(EntityItemPointer entity);
|
||||
bool findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar);
|
||||
bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr);
|
||||
|
||||
bool applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||
bool layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||
bool applySkyboxAndHasAmbient();
|
||||
|
||||
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
|
||||
void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false);
|
||||
|
||||
QList<ModelPointer> _releasedModels;
|
||||
|
@ -156,15 +159,9 @@ private:
|
|||
void leaveAllEntities();
|
||||
void forceRecheckEntities();
|
||||
|
||||
glm::vec3 _lastAvatarPosition { 0.0f };
|
||||
glm::vec3 _avatarPosition { 0.0f };
|
||||
QVector<EntityItemID> _currentEntitiesInside;
|
||||
|
||||
bool _pendingSkyboxTexture { false };
|
||||
NetworkTexturePointer _skyboxTexture;
|
||||
|
||||
bool _pendingAmbientTexture { false };
|
||||
NetworkTexturePointer _ambientTexture;
|
||||
|
||||
bool _wantScripts;
|
||||
QSharedPointer<ScriptEngine> _entitiesScriptEngine;
|
||||
|
||||
|
@ -185,26 +182,62 @@ private:
|
|||
|
||||
QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> _bestZone;
|
||||
float _bestZoneVolume;
|
||||
class LayeredZone {
|
||||
public:
|
||||
LayeredZone(std::shared_ptr<ZoneEntityItem> zone, QUuid id, float volume) : zone(zone), id(id), volume(volume) {}
|
||||
LayeredZone(std::shared_ptr<ZoneEntityItem> zone) : LayeredZone(zone, zone->getID(), zone->getVolumeEstimate()) {}
|
||||
|
||||
bool operator<(const LayeredZone& r) const { return std::tie(volume, id) < std::tie(r.volume, r.id); }
|
||||
bool operator==(const LayeredZone& r) const { return id == r.id; }
|
||||
bool operator<=(const LayeredZone& r) const { return (*this < r) || (*this == r); }
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> zone;
|
||||
QUuid id;
|
||||
float volume;
|
||||
};
|
||||
|
||||
class LayeredZones : public std::set<LayeredZone> {
|
||||
public:
|
||||
LayeredZones(EntityTreeRenderer* parent) : _entityTreeRenderer(parent) {}
|
||||
LayeredZones(LayeredZones&& other);
|
||||
|
||||
// avoid accidental misconstruction
|
||||
LayeredZones() = delete;
|
||||
LayeredZones(const LayeredZones&) = delete;
|
||||
LayeredZones& operator=(const LayeredZones&) = delete;
|
||||
LayeredZones& operator=(LayeredZones&&) = delete;
|
||||
|
||||
void clear();
|
||||
std::pair<iterator, bool> insert(const LayeredZone& layer);
|
||||
|
||||
void apply();
|
||||
void update(std::shared_ptr<ZoneEntityItem> zone);
|
||||
|
||||
bool contains(const LayeredZones& other);
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> getZone() { return empty() ? nullptr : begin()->zone; }
|
||||
|
||||
private:
|
||||
void applyPartial(iterator layer);
|
||||
|
||||
std::map<QUuid, iterator> _map;
|
||||
iterator _skyboxLayer{ end() };
|
||||
EntityTreeRenderer* _entityTreeRenderer;
|
||||
};
|
||||
|
||||
LayeredZones _layeredZones;
|
||||
QString _zoneUserData;
|
||||
NetworkTexturePointer _ambientTexture;
|
||||
NetworkTexturePointer _skyboxTexture;
|
||||
QString _ambientTextureURL;
|
||||
QString _skyboxTextureURL;
|
||||
bool _pendingAmbientTexture { false };
|
||||
bool _pendingSkyboxTexture { false };
|
||||
|
||||
quint64 _lastZoneCheck { 0 };
|
||||
const quint64 ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz
|
||||
const float ZONE_CHECK_DISTANCE = 0.001f;
|
||||
|
||||
glm::vec3 _previousKeyLightColor;
|
||||
float _previousKeyLightIntensity;
|
||||
float _previousKeyLightAmbientIntensity;
|
||||
glm::vec3 _previousKeyLightDirection;
|
||||
bool _previousStageSunModelEnabled;
|
||||
float _previousStageLongitude;
|
||||
float _previousStageLatitude;
|
||||
float _previousStageAltitude;
|
||||
float _previousStageHour;
|
||||
int _previousStageDay;
|
||||
|
||||
QHash<EntityItemID, EntityItemPointer> _entitiesInScene;
|
||||
// For Scene.shouldRenderEntities
|
||||
QList<EntityItemID> _entityIDsLastInScene;
|
||||
|
|
|
@ -548,6 +548,15 @@ EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlag
|
|||
if (_originalTexturesRead) {
|
||||
properties.setTextureNames(_originalTextures);
|
||||
}
|
||||
|
||||
if (_model) {
|
||||
properties.setRenderInfoVertexCount(_model->getRenderInfoVertexCount());
|
||||
properties.setRenderInfoTextureCount(_model->getRenderInfoTextureCount());
|
||||
properties.setRenderInfoTextureSize(_model->getRenderInfoTextureSize());
|
||||
properties.setRenderInfoDrawCalls(_model->getRenderInfoDrawCalls());
|
||||
properties.setRenderInfoHasTransparent(_model->getRenderInfoHasTransparent());
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,9 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS
|
|||
if (normalizedActionTypeString == "hold") {
|
||||
return ACTION_TYPE_HOLD;
|
||||
}
|
||||
if (normalizedActionTypeString == "traveloriented") {
|
||||
return ACTION_TYPE_TRAVEL_ORIENTED;
|
||||
}
|
||||
|
||||
qDebug() << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
|
||||
return ACTION_TYPE_NONE;
|
||||
|
@ -115,6 +118,8 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) {
|
|||
return "spring";
|
||||
case ACTION_TYPE_HOLD:
|
||||
return "hold";
|
||||
case ACTION_TYPE_TRAVEL_ORIENTED:
|
||||
return "travel-oriented";
|
||||
}
|
||||
assert(false);
|
||||
return "none";
|
||||
|
|
|
@ -28,7 +28,8 @@ enum EntityActionType {
|
|||
ACTION_TYPE_NONE = 0,
|
||||
ACTION_TYPE_OFFSET = 1000,
|
||||
ACTION_TYPE_SPRING = 2000,
|
||||
ACTION_TYPE_HOLD = 3000
|
||||
ACTION_TYPE_HOLD = 3000,
|
||||
ACTION_TYPE_TRAVEL_ORIENTED = 4000
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -580,6 +580,24 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID);
|
||||
|
||||
// Rendering info
|
||||
if (!skipDefaults) {
|
||||
QScriptValue renderInfo = engine->newObject();
|
||||
|
||||
// currently only supported by models
|
||||
if (_type == EntityTypes::Model) {
|
||||
renderInfo.setProperty("verticesCount", (int)getRenderInfoVertexCount()); // FIXME - theoretically the number of vertex could be > max int
|
||||
renderInfo.setProperty("texturesSize", (int)getRenderInfoTextureSize()); // FIXME - theoretically the size of textures could be > max int
|
||||
renderInfo.setProperty("hasTransparent", getRenderInfoHasTransparent());
|
||||
renderInfo.setProperty("drawCalls", getRenderInfoDrawCalls());
|
||||
}
|
||||
|
||||
if (_type == EntityTypes::Model || _type == EntityTypes::PolyLine || _type == EntityTypes::ParticleEffect) {
|
||||
renderInfo.setProperty("texturesCount", QScriptValue(_textureNames.count()));
|
||||
}
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(renderInfo, renderInfo); // Gettable but not settable
|
||||
}
|
||||
|
||||
properties.setProperty("clientOnly", convertScriptValue(engine, getClientOnly()));
|
||||
properties.setProperty("owningAvatarID", convertScriptValue(engine, getOwningAvatarID()));
|
||||
|
||||
|
|
|
@ -285,6 +285,19 @@ public:
|
|||
void setJointRotationsDirty() { _jointRotationsSetChanged = true; _jointRotationsChanged = true; }
|
||||
void setJointTranslationsDirty() { _jointTranslationsSetChanged = true; _jointTranslationsChanged = true; }
|
||||
|
||||
// render info related items
|
||||
size_t getRenderInfoVertexCount() const { return _renderInfoVertexCount; }
|
||||
void setRenderInfoVertexCount(size_t value) { _renderInfoVertexCount = value; }
|
||||
int getRenderInfoTextureCount() const { return _renderInfoTextureCount; }
|
||||
void setRenderInfoTextureCount(int value) { _renderInfoTextureCount = value; }
|
||||
size_t getRenderInfoTextureSize() const { return _renderInfoTextureSize; }
|
||||
void setRenderInfoTextureSize(size_t value) { _renderInfoTextureSize = value; }
|
||||
int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; }
|
||||
void setRenderInfoDrawCalls(int value) { _renderInfoDrawCalls = value; }
|
||||
bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; }
|
||||
void setRenderInfoHasTransparent(bool value) { _renderInfoHasTransparent = value; }
|
||||
|
||||
|
||||
protected:
|
||||
QString getCollisionMaskAsString() const;
|
||||
void setCollisionMaskFromString(const QString& maskString);
|
||||
|
@ -308,6 +321,12 @@ private:
|
|||
glm::vec3 _naturalDimensions;
|
||||
glm::vec3 _naturalPosition;
|
||||
|
||||
size_t _renderInfoVertexCount { 0 };
|
||||
int _renderInfoTextureCount { 0 };
|
||||
size_t _renderInfoTextureSize { 0 };
|
||||
int _renderInfoDrawCalls { 0 };
|
||||
bool _renderInfoHasTransparent { false };
|
||||
|
||||
EntityPropertyFlags _desiredProperties; // if set will narrow scopes of copy/to/from to just these properties
|
||||
};
|
||||
|
||||
|
|
|
@ -140,17 +140,35 @@ QVariant parseBinaryFBXProperty(QDataStream& in, int& position) {
|
|||
}
|
||||
}
|
||||
|
||||
FBXNode parseBinaryFBXNode(QDataStream& in, int& position) {
|
||||
qint32 endOffset;
|
||||
quint32 propertyCount;
|
||||
quint32 propertyListLength;
|
||||
FBXNode parseBinaryFBXNode(QDataStream& in, int& position, bool has64BitPositions = false) {
|
||||
qint64 endOffset;
|
||||
quint64 propertyCount;
|
||||
quint64 propertyListLength;
|
||||
quint8 nameLength;
|
||||
|
||||
in >> endOffset;
|
||||
in >> propertyCount;
|
||||
in >> propertyListLength;
|
||||
// FBX 2016 and beyond uses 64bit positions in the node headers, pre-2016 used 32bit values
|
||||
// our code generally doesn't care about the size that much, so we will use 64bit values
|
||||
// from here on out, but if the file is an older format we read the stream into temp 32bit
|
||||
// values and then assign to our actual 64bit values.
|
||||
if (has64BitPositions) {
|
||||
in >> endOffset;
|
||||
in >> propertyCount;
|
||||
in >> propertyListLength;
|
||||
position += sizeof(quint64) * 3;
|
||||
} else {
|
||||
qint32 tempEndOffset;
|
||||
quint32 tempPropertyCount;
|
||||
quint32 tempPropertyListLength;
|
||||
in >> tempEndOffset;
|
||||
in >> tempPropertyCount;
|
||||
in >> tempPropertyListLength;
|
||||
position += sizeof(quint32) * 3;
|
||||
endOffset = tempEndOffset;
|
||||
propertyCount = tempPropertyCount;
|
||||
propertyListLength = tempPropertyListLength;
|
||||
}
|
||||
in >> nameLength;
|
||||
position += sizeof(quint32) * 3 + sizeof(quint8);
|
||||
position += sizeof(quint8);
|
||||
|
||||
FBXNode node;
|
||||
const int MIN_VALID_OFFSET = 40;
|
||||
|
@ -166,7 +184,7 @@ FBXNode parseBinaryFBXNode(QDataStream& in, int& position) {
|
|||
}
|
||||
|
||||
while (endOffset > position) {
|
||||
FBXNode child = parseBinaryFBXNode(in, position);
|
||||
FBXNode child = parseBinaryFBXNode(in, position, has64BitPositions);
|
||||
if (child.name.isNull()) {
|
||||
return node;
|
||||
|
||||
|
@ -327,15 +345,24 @@ FBXNode FBXReader::parseFBX(QIODevice* device) {
|
|||
// see http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ for an explanation
|
||||
// of the FBX binary format
|
||||
|
||||
// skip the rest of the header
|
||||
const int HEADER_SIZE = 27;
|
||||
in.skipRawData(HEADER_SIZE);
|
||||
int position = HEADER_SIZE;
|
||||
// The first 27 bytes contain the header.
|
||||
// Bytes 0 - 20: Kaydara FBX Binary \x00(file - magic, with 2 spaces at the end, then a NULL terminator).
|
||||
// Bytes 21 - 22: [0x1A, 0x00](unknown but all observed files show these bytes).
|
||||
// Bytes 23 - 26 : unsigned int, the version number. 7300 for version 7.3 for example.
|
||||
const int HEADER_BEFORE_VERSION = 23;
|
||||
const quint32 VERSION_FBX2016 = 7500;
|
||||
in.skipRawData(HEADER_BEFORE_VERSION);
|
||||
int position = HEADER_BEFORE_VERSION;
|
||||
quint32 fileVersion;
|
||||
in >> fileVersion;
|
||||
position += sizeof(fileVersion);
|
||||
qDebug() << "fileVersion:" << fileVersion;
|
||||
bool has64BitPositions = (fileVersion >= VERSION_FBX2016);
|
||||
|
||||
// parse the top-level node
|
||||
FBXNode top;
|
||||
while (device->bytesAvailable()) {
|
||||
FBXNode next = parseBinaryFBXNode(in, position);
|
||||
FBXNode next = parseBinaryFBXNode(in, position, has64BitPositions);
|
||||
if (next.name.isNull()) {
|
||||
return top;
|
||||
|
||||
|
|
|
@ -191,6 +191,7 @@ FSTReader::ModelType FSTReader::predictModelType(const QVariantHash& mapping) {
|
|||
QVariantHash FSTReader::downloadMapping(const QString& url) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
qDebug() << "Downloading avatar file at " << url;
|
||||
|
|
|
@ -282,6 +282,7 @@ QNetworkReply* OBJReader::request(QUrl& url, bool isTest) {
|
|||
});
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest netRequest(url);
|
||||
netRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply* netReply = isTest ? networkAccessManager.head(netRequest) : networkAccessManager.get(netRequest);
|
||||
if (!qApp || aboutToQuit) {
|
||||
netReply->deleteLater();
|
||||
|
|
|
@ -2,6 +2,9 @@ set(TARGET_NAME gl)
|
|||
setup_hifi_library(OpenGL Qml Quick)
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
target_glew()
|
||||
target_opengl()
|
||||
target_oglplus()
|
||||
|
||||
if (NOT ANDROID)
|
||||
target_glew()
|
||||
target_oglplus()
|
||||
endif ()
|
||||
|
|
281
libraries/gl/src/gl/Context.cpp
Normal file
281
libraries/gl/src/gl/Context.cpp
Normal file
|
@ -0,0 +1,281 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/08/21
|
||||
// Copyright 2013-2016 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 "Context.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool enableDebugLogger = true;
|
||||
#else
|
||||
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENGL");
|
||||
static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "Config.h"
|
||||
#include "GLHelpers.h"
|
||||
|
||||
|
||||
using namespace gl;
|
||||
|
||||
Context* Context::PRIMARY = nullptr;
|
||||
|
||||
Context::Context() {}
|
||||
|
||||
Context::Context(QWindow* window) {
|
||||
setWindow(window);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void Context::destroyWin32Context(HGLRC hglrc) {
|
||||
wglDeleteContext(hglrc);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Context::release() {
|
||||
doneCurrent();
|
||||
#ifdef Q_OS_WIN
|
||||
if (_wrappedContext) {
|
||||
destroyContext(_wrappedContext);
|
||||
_wrappedContext = nullptr;
|
||||
}
|
||||
if (_hglrc) {
|
||||
destroyWin32Context(_hglrc);
|
||||
_hglrc = 0;
|
||||
}
|
||||
if (_hdc) {
|
||||
ReleaseDC(_hwnd, _hdc);
|
||||
_hdc = 0;
|
||||
}
|
||||
_hwnd = 0;
|
||||
#else
|
||||
destroyContext(_context);
|
||||
_context = nullptr;
|
||||
#endif
|
||||
_window = nullptr;
|
||||
if (PRIMARY == this) {
|
||||
PRIMARY = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Context::~Context() {
|
||||
release();
|
||||
}
|
||||
|
||||
void Context::setWindow(QWindow* window) {
|
||||
release();
|
||||
_window = window;
|
||||
#ifdef Q_OS_WIN
|
||||
_hwnd = (HWND)window->winId();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static const char* PRIMARY_CONTEXT_PROPERTY_NAME = "com.highfidelity.gl.primaryContext";
|
||||
|
||||
bool Context::makeCurrent() {
|
||||
BOOL result = wglMakeCurrent(_hdc, _hglrc);
|
||||
assert(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Context::swapBuffers() {
|
||||
SwapBuffers(_hdc);
|
||||
}
|
||||
|
||||
void Context::doneCurrent() {
|
||||
wglMakeCurrent(0, 0);
|
||||
}
|
||||
|
||||
void GLAPIENTRY debugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
|
||||
if (GL_DEBUG_SEVERITY_NOTIFICATION == severity) {
|
||||
return;
|
||||
}
|
||||
qDebug() << "QQQ " << message;
|
||||
}
|
||||
|
||||
// FIXME build the PFD based on the
|
||||
static const PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be
|
||||
{
|
||||
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
|
||||
1, // Version Number
|
||||
PFD_DRAW_TO_WINDOW | // Format Must Support Window
|
||||
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
|
||||
PFD_DOUBLEBUFFER, // Must Support Double Buffering
|
||||
PFD_TYPE_RGBA, // Request An RGBA Format
|
||||
24, // Select Our Color Depth
|
||||
0, 0, 0, 0, 0, 0, // Color Bits Ignored
|
||||
1, // Alpha Buffer
|
||||
0, // Shift Bit Ignored
|
||||
0, // No Accumulation Buffer
|
||||
0, 0, 0, 0, // Accumulation Bits Ignored
|
||||
24, // 24 Bit Z-Buffer (Depth Buffer)
|
||||
8, // 8 Bit Stencil Buffer
|
||||
0, // No Auxiliary Buffer
|
||||
PFD_MAIN_PLANE, // Main Drawing Layer
|
||||
0, // Reserved
|
||||
0, 0, 0 // Layer Masks Ignored
|
||||
};
|
||||
|
||||
void setupPixelFormatSimple(HDC hdc) {
|
||||
auto pixelFormat = ChoosePixelFormat(hdc, &pfd);
|
||||
if (pixelFormat == 0) {
|
||||
throw std::runtime_error("Unable to create initial context");
|
||||
}
|
||||
|
||||
if (SetPixelFormat(hdc, pixelFormat, &pfd) == FALSE) {
|
||||
throw std::runtime_error("Unable to create initial context");
|
||||
}
|
||||
}
|
||||
|
||||
void Context::create() {
|
||||
if (!PRIMARY) {
|
||||
PRIMARY = static_cast<Context*>(qApp->property(PRIMARY_CONTEXT_PROPERTY_NAME).value<void*>());
|
||||
}
|
||||
|
||||
if (PRIMARY) {
|
||||
_version = PRIMARY->_version;
|
||||
}
|
||||
|
||||
assert(0 != _hwnd);
|
||||
assert(0 == _hdc);
|
||||
auto hwnd = _hwnd;
|
||||
// Create a temporary context to initialize glew
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
auto hdc = GetDC(hwnd);
|
||||
setupPixelFormatSimple(hdc);
|
||||
auto glrc = wglCreateContext(hdc);
|
||||
BOOL makeCurrentResult;
|
||||
makeCurrentResult = wglMakeCurrent(hdc, glrc);
|
||||
if (!makeCurrentResult) {
|
||||
throw std::runtime_error("Unable to create initial context");
|
||||
}
|
||||
glewExperimental = true;
|
||||
glewInit();
|
||||
if (glewIsSupported("GL_VERSION_4_5")) {
|
||||
_version = 0x0405;
|
||||
} else if (glewIsSupported("GL_VERSION_4_3")) {
|
||||
_version = 0x0403;
|
||||
}
|
||||
glGetError();
|
||||
wglMakeCurrent(0, 0);
|
||||
wglDeleteContext(glrc);
|
||||
ReleaseDC(hwnd, hdc);
|
||||
});
|
||||
|
||||
_hdc = GetDC(_hwnd);
|
||||
static int pixelFormat = 0;
|
||||
static PIXELFORMATDESCRIPTOR pfd;
|
||||
if (!pixelFormat) {
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.nSize = sizeof(pfd);
|
||||
std::vector<int> formatAttribs;
|
||||
formatAttribs.push_back(WGL_DRAW_TO_WINDOW_ARB);
|
||||
formatAttribs.push_back(GL_TRUE);
|
||||
formatAttribs.push_back(WGL_SUPPORT_OPENGL_ARB);
|
||||
formatAttribs.push_back(GL_TRUE);
|
||||
formatAttribs.push_back(WGL_DOUBLE_BUFFER_ARB);
|
||||
formatAttribs.push_back(GL_TRUE);
|
||||
formatAttribs.push_back(WGL_PIXEL_TYPE_ARB);
|
||||
formatAttribs.push_back(WGL_TYPE_RGBA_ARB);
|
||||
formatAttribs.push_back(WGL_COLOR_BITS_ARB);
|
||||
formatAttribs.push_back(32);
|
||||
formatAttribs.push_back(WGL_DEPTH_BITS_ARB);
|
||||
formatAttribs.push_back(24);
|
||||
formatAttribs.push_back(WGL_STENCIL_BITS_ARB);
|
||||
formatAttribs.push_back(8);
|
||||
#ifdef NATIVE_SRGB_FRAMEBUFFER
|
||||
// formatAttribs.push_back(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
|
||||
// formatAttribs.push_back(GL_TRUE);
|
||||
#endif
|
||||
// terminate the list
|
||||
formatAttribs.push_back(0);
|
||||
UINT numFormats;
|
||||
wglChoosePixelFormatARB(_hdc, &formatAttribs[0], NULL, 1, &pixelFormat, &numFormats);
|
||||
DescribePixelFormat(_hdc, pixelFormat, sizeof(pfd), &pfd);
|
||||
}
|
||||
SetPixelFormat(_hdc, pixelFormat, &pfd);
|
||||
{
|
||||
std::vector<int> contextAttribs;
|
||||
uint32_t majorVersion = _version >> 8;
|
||||
uint32_t minorVersion = _version & 0xFF;
|
||||
contextAttribs.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
|
||||
contextAttribs.push_back(majorVersion);
|
||||
contextAttribs.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
|
||||
contextAttribs.push_back(minorVersion);
|
||||
contextAttribs.push_back(WGL_CONTEXT_PROFILE_MASK_ARB);
|
||||
contextAttribs.push_back(WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
|
||||
contextAttribs.push_back(WGL_CONTEXT_FLAGS_ARB);
|
||||
if (enableDebugLogger) {
|
||||
contextAttribs.push_back(WGL_CONTEXT_DEBUG_BIT_ARB);
|
||||
} else {
|
||||
contextAttribs.push_back(0);
|
||||
}
|
||||
contextAttribs.push_back(0);
|
||||
auto shareHglrc = PRIMARY ? PRIMARY->_hglrc : 0;
|
||||
_hglrc = wglCreateContextAttribsARB(_hdc, shareHglrc, &contextAttribs[0]);
|
||||
}
|
||||
|
||||
if (_hglrc == 0) {
|
||||
throw std::runtime_error("Could not create GL context");
|
||||
}
|
||||
|
||||
if (!PRIMARY) {
|
||||
PRIMARY = this;
|
||||
qApp->setProperty(PRIMARY_CONTEXT_PROPERTY_NAME, QVariant::fromValue((void*)PRIMARY));
|
||||
}
|
||||
|
||||
if (enableDebugLogger) {
|
||||
makeCurrent();
|
||||
glDebugMessageCallback(debugMessageCallback, NULL);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
||||
doneCurrent();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Context::clear() {
|
||||
glClearColor(0, 0, 0, 1);
|
||||
QSize windowSize = _window->size() * _window->devicePixelRatio();
|
||||
glViewport(0, 0, windowSize.width(), windowSize.height());
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
|
||||
OffscreenContext::~OffscreenContext() {
|
||||
_window->deleteLater();
|
||||
}
|
||||
|
||||
void OffscreenContext::create() {
|
||||
if (!_window) {
|
||||
_window = new QWindow();
|
||||
_window->setFlags(Qt::MSWindowsOwnDC);
|
||||
_window->setSurfaceType(QSurface::OpenGLSurface);
|
||||
_window->create();
|
||||
setWindow(_window);
|
||||
QGuiApplication::processEvents();
|
||||
}
|
||||
Parent::create();
|
||||
}
|
72
libraries/gl/src/gl/Context.h
Normal file
72
libraries/gl/src/gl/Context.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/08/21
|
||||
// Copyright 2013-2016 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_gl_context_h
|
||||
#define hifi_gl_context_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <QtGlobal>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
class QSurface;
|
||||
class QWindow;
|
||||
class QOpenGLContext;
|
||||
class QThread;
|
||||
|
||||
namespace gl {
|
||||
|
||||
class Context {
|
||||
protected:
|
||||
QWindow* _window { nullptr };
|
||||
static Context* PRIMARY;
|
||||
static void destroyContext(QOpenGLContext* context);
|
||||
#if defined(Q_OS_WIN)
|
||||
uint32_t _version { 0x0401 };
|
||||
HWND _hwnd { 0 };
|
||||
HDC _hdc { 0 };
|
||||
HGLRC _hglrc { 0 };
|
||||
static void destroyWin32Context(HGLRC hglrc);
|
||||
QOpenGLContext* _wrappedContext { nullptr };
|
||||
#else
|
||||
QOpenGLContext* _context { nullptr };
|
||||
#endif
|
||||
|
||||
private:
|
||||
Context(const Context& other);
|
||||
|
||||
public:
|
||||
Context();
|
||||
Context(QWindow* window);
|
||||
void release();
|
||||
virtual ~Context();
|
||||
|
||||
void clear();
|
||||
void setWindow(QWindow* window);
|
||||
bool makeCurrent();
|
||||
static void makeCurrent(QOpenGLContext* context, QSurface* surface);
|
||||
void swapBuffers();
|
||||
void doneCurrent();
|
||||
virtual void create();
|
||||
QOpenGLContext* qglContext();
|
||||
void moveToThread(QThread* thread);
|
||||
};
|
||||
|
||||
class OffscreenContext : public Context {
|
||||
using Parent = Context;
|
||||
protected:
|
||||
QWindow* _window { nullptr };
|
||||
public:
|
||||
virtual ~OffscreenContext();
|
||||
virtual void create();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // hifi_gpu_GPUConfig_h
|
75
libraries/gl/src/gl/ContextQt.cpp
Normal file
75
libraries/gl/src/gl/ContextQt.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/08/21
|
||||
// Copyright 2013-2016 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 "Context.h"
|
||||
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QtPlatformHeaders/QWGLNativeContext>
|
||||
#endif
|
||||
|
||||
using namespace gl;
|
||||
|
||||
void Context::destroyContext(QOpenGLContext* context) {
|
||||
delete context;
|
||||
}
|
||||
|
||||
void Context::makeCurrent(QOpenGLContext* context, QSurface* surface) {
|
||||
context->makeCurrent(surface);
|
||||
}
|
||||
|
||||
QOpenGLContext* Context::qglContext() {
|
||||
#ifdef Q_OS_WIN
|
||||
if (!_wrappedContext) {
|
||||
_wrappedContext = new QOpenGLContext();
|
||||
_wrappedContext->setNativeHandle(QVariant::fromValue(QWGLNativeContext(_hglrc, _hwnd)));
|
||||
_wrappedContext->create();
|
||||
}
|
||||
return _wrappedContext;
|
||||
#else
|
||||
|
||||
return _context;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Context::moveToThread(QThread* thread) {
|
||||
qglContext()->moveToThread(thread);
|
||||
}
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
bool Context::makeCurrent() {
|
||||
return _context->makeCurrent(_window);
|
||||
}
|
||||
|
||||
void Context::swapBuffers() {
|
||||
_context->swapBuffers(_window);
|
||||
}
|
||||
|
||||
void Context::doneCurrent() {
|
||||
if (_context) {
|
||||
_context->doneCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat();
|
||||
|
||||
|
||||
void Context::create() {
|
||||
_context = new QOpenGLContext();
|
||||
if (PRIMARY) {
|
||||
_context->setShareContext(PRIMARY->qglContext());
|
||||
} else {
|
||||
PRIMARY = this;
|
||||
}
|
||||
_context->setFormat(getDefaultOpenGLSurfaceFormat());
|
||||
_context->create();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -21,44 +21,20 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
|
|||
format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS);
|
||||
format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS);
|
||||
setGLFormatVersion(format);
|
||||
if (GLDebug::enabled()) {
|
||||
qDebug() << "Enabling debug context";
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
}
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
|
||||
QSurfaceFormat::setDefaultFormat(format);
|
||||
});
|
||||
return format;
|
||||
}
|
||||
|
||||
const QGLFormat& getDefaultGLFormat() {
|
||||
// Specify an OpenGL 3.3 format using the Core profile.
|
||||
// That is, no old-school fixed pipeline functionality
|
||||
static QGLFormat glFormat;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
setGLFormatVersion(glFormat);
|
||||
glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0
|
||||
glFormat.setSampleBuffers(false);
|
||||
glFormat.setDepth(false);
|
||||
glFormat.setStencil(false);
|
||||
QGLFormat::setDefaultFormat(glFormat);
|
||||
});
|
||||
return glFormat;
|
||||
}
|
||||
|
||||
int glVersionToInteger(QString glVersion) {
|
||||
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
|
||||
int majorNumber = versionParts[0].toInt();
|
||||
int minorNumber = versionParts[1].toInt();
|
||||
return majorNumber * 100 + minorNumber * 10;
|
||||
return (majorNumber << 16) | minorNumber;
|
||||
}
|
||||
|
||||
QJsonObject getGLContextData() {
|
||||
if (!QOpenGLContext::currentContext()) {
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
QString glVersion = QString((const char*)glGetString(GL_VERSION));
|
||||
QString glslVersion = QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
QString glVendor = QString((const char*) glGetString(GL_VENDOR));
|
||||
|
@ -77,31 +53,3 @@ QThread* RENDER_THREAD = nullptr;
|
|||
bool isRenderThread() {
|
||||
return QThread::currentThread() == RENDER_THREAD;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool enableDebugLogger = true;
|
||||
#else
|
||||
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENGL");
|
||||
static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
#endif
|
||||
|
||||
bool GLDebug::enabled() {
|
||||
return enableDebugLogger;
|
||||
}
|
||||
|
||||
void GLDebug::log(const QOpenGLDebugMessage & debugMessage) {
|
||||
qDebug() << debugMessage;
|
||||
}
|
||||
|
||||
void GLDebug::setupLogger(QObject* window) {
|
||||
if (enabled()) {
|
||||
QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(window);
|
||||
logger->initialize(); // initializes in the current context, i.e. ctx
|
||||
logger->enableMessages();
|
||||
QObject::connect(logger, &QOpenGLDebugLogger::messageLogged, window, [&](const QOpenGLDebugMessage & debugMessage) {
|
||||
GLDebug::log(debugMessage);
|
||||
});
|
||||
logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
|
||||
}
|
||||
}
|
|
@ -27,19 +27,9 @@ template<class F>
|
|||
void setGLFormatVersion(F& format, int major = 4, int minor = 5) { format.setVersion(major, minor); }
|
||||
|
||||
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat();
|
||||
const QGLFormat& getDefaultGLFormat();
|
||||
QJsonObject getGLContextData();
|
||||
int glVersionToInteger(QString glVersion);
|
||||
|
||||
bool isRenderThread();
|
||||
|
||||
|
||||
class GLDebug {
|
||||
public:
|
||||
static bool enabled();
|
||||
static void log(const QOpenGLDebugMessage& debugMessage);
|
||||
static void setupLogger(QObject* window = nullptr);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,30 +7,52 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include <QtGlobal>
|
||||
|
||||
#include "GLWidget.h"
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QtCore/QMimeData>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtGui/QPaintEngine>
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
|
||||
#include "Context.h"
|
||||
#include "GLHelpers.h"
|
||||
|
||||
class GLPaintEngine : public QPaintEngine {
|
||||
bool begin(QPaintDevice *pdev) override { return true; }
|
||||
bool end() override { return true; }
|
||||
void updateState(const QPaintEngineState &state) override { }
|
||||
void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override { }
|
||||
Type type() const override { return OpenGL2; }
|
||||
};
|
||||
|
||||
GLWidget::GLWidget() : QGLWidget(getDefaultGLFormat()) {
|
||||
GLWidget::GLWidget() {
|
||||
#ifdef Q_OS_LINUX
|
||||
// Cause GLWidget::eventFilter to be called.
|
||||
// It wouldn't hurt to do this on Mac and PC too; but apparently it's only needed on linux.
|
||||
qApp->installEventFilter(this);
|
||||
#endif
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
setAttribute(Qt::WA_PaintOnScreen);
|
||||
setAttribute(Qt::WA_NoSystemBackground);
|
||||
setAutoFillBackground(false);
|
||||
grabGesture(Qt::PinchGesture);
|
||||
setAcceptDrops(true);
|
||||
_paintEngine = new GLPaintEngine();
|
||||
}
|
||||
|
||||
GLWidget::~GLWidget() {
|
||||
delete _paintEngine;
|
||||
_paintEngine = nullptr;
|
||||
}
|
||||
|
||||
int GLWidget::getDeviceWidth() const {
|
||||
|
@ -41,31 +63,25 @@ int GLWidget::getDeviceHeight() const {
|
|||
return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f);
|
||||
}
|
||||
|
||||
void GLWidget::initializeGL() {
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
grabGesture(Qt::PinchGesture);
|
||||
setAcceptDrops(true);
|
||||
// Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate.
|
||||
setAutoBufferSwap(false);
|
||||
|
||||
makeCurrent();
|
||||
if (isValid() && context() && context()->contextHandle()) {
|
||||
#if defined(Q_OS_WIN)
|
||||
_vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");
|
||||
#elif defined(Q_OS_MAC)
|
||||
_vsyncSupported = true;
|
||||
#else
|
||||
// TODO: write the proper code for linux
|
||||
#endif
|
||||
}
|
||||
void GLWidget::createContext() {
|
||||
_context = new gl::Context();
|
||||
_context->setWindow(windowHandle());
|
||||
_context->create();
|
||||
_context->clear();
|
||||
_context->makeCurrent();
|
||||
}
|
||||
|
||||
void GLWidget::paintEvent(QPaintEvent* event) {
|
||||
QWidget::paintEvent(event);
|
||||
bool GLWidget::makeCurrent() {
|
||||
gl::Context::makeCurrent(_context->qglContext(), windowHandle());
|
||||
return _context->makeCurrent();
|
||||
}
|
||||
|
||||
void GLWidget::resizeEvent(QResizeEvent* event) {
|
||||
QWidget::resizeEvent(event);
|
||||
QOpenGLContext* GLWidget::qglContext() {
|
||||
return _context->qglContext();
|
||||
}
|
||||
|
||||
void GLWidget::doneCurrent() {
|
||||
_context->doneCurrent();
|
||||
}
|
||||
|
||||
bool GLWidget::event(QEvent* event) {
|
||||
|
@ -94,10 +110,9 @@ bool GLWidget::event(QEvent* event) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
return QGLWidget::event(event);
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
|
||||
// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the
|
||||
// SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to
|
||||
// receive keyPress events for the Alt (and Meta) key in a reliable manner.
|
||||
|
@ -119,7 +134,7 @@ bool GLWidget::eventFilter(QObject*, QEvent* event) {
|
|||
} else if (event->type() == QEvent::KeyRelease) {
|
||||
keyReleaseEvent(keyEvent);
|
||||
} else {
|
||||
QGLWidget::event(event);
|
||||
QWidget::event(event);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -130,7 +145,22 @@ bool GLWidget::eventFilter(QObject*, QEvent* event) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool GLWidget::isVsyncSupported() const {
|
||||
return _vsyncSupported;
|
||||
|
||||
bool GLWidget::nativeEvent(const QByteArray &eventType, void *message, long *result) {
|
||||
#ifdef Q_OS_WIN32
|
||||
MSG* win32message = static_cast<MSG*>(message);
|
||||
switch (win32message->message) {
|
||||
case WM_ERASEBKGND:
|
||||
*result = 1L;
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return QWidget::nativeEvent(eventType, message, result);
|
||||
}
|
||||
|
||||
QPaintEngine* GLWidget::paintEngine() const {
|
||||
return _paintEngine;
|
||||
}
|
||||
|
|
|
@ -10,31 +10,43 @@
|
|||
#ifndef hifi_GLWidget_h
|
||||
#define hifi_GLWidget_h
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
namespace gl {
|
||||
class Context;
|
||||
}
|
||||
|
||||
class QOpenGLContext;
|
||||
|
||||
/// customized canvas that simply forwards requests/events to the singleton application
|
||||
class GLWidget : public QGLWidget {
|
||||
class GLWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GLWidget();
|
||||
~GLWidget();
|
||||
int getDeviceWidth() const;
|
||||
int getDeviceHeight() const;
|
||||
QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); }
|
||||
bool isVsyncSupported() const;
|
||||
virtual void initializeGL() override;
|
||||
QPaintEngine* paintEngine() const override;
|
||||
void createContext();
|
||||
bool makeCurrent();
|
||||
void doneCurrent();
|
||||
gl::Context* context() { return _context; }
|
||||
QOpenGLContext* qglContext();
|
||||
|
||||
|
||||
protected:
|
||||
virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
|
||||
virtual bool event(QEvent* event) override;
|
||||
virtual void paintEvent(QPaintEvent* event) override;
|
||||
virtual void resizeEvent(QResizeEvent* event) override;
|
||||
gl::Context* _context { nullptr };
|
||||
|
||||
private slots:
|
||||
virtual bool eventFilter(QObject*, QEvent* event) override;
|
||||
|
||||
private:
|
||||
QPaintEngine* _paintEngine { nullptr };
|
||||
bool _vsyncSupported { false };
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_GLCanvas_h
|
||||
|
|
|
@ -60,7 +60,6 @@ bool OffscreenGLCanvas::makeCurrent() {
|
|||
qDebug() << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
qDebug() << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR));
|
||||
qDebug() << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER));
|
||||
GLDebug::setupLogger(this);
|
||||
});
|
||||
|
||||
return result;
|
||||
|
|
|
@ -10,27 +10,46 @@
|
|||
//
|
||||
|
||||
#include "OpenGLVersionChecker.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QRegularExpression>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Config.h"
|
||||
#include "GLWidget.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtCore/QRegularExpression>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtOpenGL/QGLWidget>
|
||||
|
||||
#include "GLHelpers.h"
|
||||
|
||||
#define MINIMUM_GL_VERSION 410
|
||||
#define MINIMUM_GL_VERSION 0x0401
|
||||
|
||||
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
|
||||
QApplication(argc, argv)
|
||||
{
|
||||
}
|
||||
|
||||
const QGLFormat& getDefaultGLFormat() {
|
||||
// Specify an OpenGL 3.3 format using the Core profile.
|
||||
// That is, no old-school fixed pipeline functionality
|
||||
static QGLFormat glFormat;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
setGLFormatVersion(glFormat);
|
||||
glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0
|
||||
glFormat.setSampleBuffers(false);
|
||||
glFormat.setDepth(false);
|
||||
glFormat.setStencil(false);
|
||||
QGLFormat::setDefaultFormat(glFormat);
|
||||
});
|
||||
return glFormat;
|
||||
}
|
||||
|
||||
|
||||
QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
|
||||
valid = true;
|
||||
override = false;
|
||||
|
||||
GLWidget* glWidget = new GLWidget();
|
||||
QGLWidget* glWidget = new QGLWidget();
|
||||
valid = glWidget->isValid();
|
||||
// Inform user if no OpenGL support
|
||||
if (!valid) {
|
||||
|
@ -46,7 +65,8 @@ QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
|
|||
}
|
||||
|
||||
// Retrieve OpenGL version
|
||||
glWidget->initializeGL();
|
||||
// glWidget->initializeGL();
|
||||
glWidget->makeCurrent();
|
||||
QJsonObject glData = getGLContextData();
|
||||
delete glWidget;
|
||||
|
||||
|
@ -60,8 +80,8 @@ QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
|
|||
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
|
||||
int majorNumber = versionParts[0].toInt();
|
||||
int minorNumber = versionParts[1].toInt();
|
||||
int minimumMajorNumber = MINIMUM_GL_VERSION / 100;
|
||||
int minimumMinorNumber = (MINIMUM_GL_VERSION - minimumMajorNumber * 100) / 10;
|
||||
int minimumMajorNumber = (MINIMUM_GL_VERSION >> 16);
|
||||
int minimumMinorNumber = (MINIMUM_GL_VERSION & 0xFF);
|
||||
valid = (majorNumber > minimumMajorNumber
|
||||
|| (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber));
|
||||
|
||||
|
|
|
@ -3,5 +3,8 @@ setup_hifi_library()
|
|||
link_hifi_libraries(shared gl gpu)
|
||||
GroupSources("src")
|
||||
|
||||
target_glew()
|
||||
target_opengl()
|
||||
target_opengl()
|
||||
|
||||
if (NOT ANDROID)
|
||||
target_glew()
|
||||
endif ()
|
||||
|
|
|
@ -25,6 +25,7 @@ void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) {
|
|||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
glGetInteger64v(GL_TIMESTAMP, (GLint64*)&glquery->_batchElapsedTime);
|
||||
if (timeElapsed) {
|
||||
glBeginQuery(GL_TIME_ELAPSED, glquery->_endqo);
|
||||
} else {
|
||||
|
@ -43,6 +44,10 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
|
|||
} else {
|
||||
glQueryCounter(glquery->_endqo, GL_TIMESTAMP);
|
||||
}
|
||||
GLint64 now;
|
||||
glGetInteger64v(GL_TIMESTAMP, &now);
|
||||
glquery->_batchElapsedTime = now - glquery->_batchElapsedTime;
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +66,7 @@ void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) {
|
|||
glGetQueryObjectui64v(glquery->_endqo, GL_QUERY_RESULT, &end);
|
||||
glquery->_result = end - start;
|
||||
}
|
||||
query->triggerReturnHandler(glquery->_result);
|
||||
query->triggerReturnHandler(glquery->_result, glquery->_batchElapsedTime);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
const GLuint& _endqo = { _id };
|
||||
const GLuint _beginqo = { 0 };
|
||||
GLuint64 _result { (GLuint64)-1 };
|
||||
GLuint64 _batchElapsedTime { (GLuint64) 0 };
|
||||
|
||||
protected:
|
||||
GLQuery(const std::weak_ptr<GLBackend>& backend, const Query& query, GLuint endId, GLuint beginId) : Parent(backend, query, endId), _beginqo(beginId) {}
|
||||
|
|
|
@ -100,7 +100,7 @@ float GLTexture::getMemoryPressure() {
|
|||
|
||||
// If no memory limit has been set, use a percentage of the total dedicated memory
|
||||
if (!availableTextureMemory) {
|
||||
auto totalGpuMemory = gpu::gl::getDedicatedMemory();
|
||||
auto totalGpuMemory = getDedicatedMemory();
|
||||
|
||||
// If no limit has been explicitly set, and the dedicated memory can't be determined,
|
||||
// just use a fallback fixed value of 256 MB
|
||||
|
@ -118,7 +118,7 @@ float GLTexture::getMemoryPressure() {
|
|||
return (float)consumedGpuMemory / (float)availableTextureMemory;
|
||||
}
|
||||
|
||||
GLTexture::DownsampleSource::DownsampleSource(const std::weak_ptr<gl::GLBackend>& backend, GLTexture* oldTexture) :
|
||||
GLTexture::DownsampleSource::DownsampleSource(const std::weak_ptr<GLBackend>& backend, GLTexture* oldTexture) :
|
||||
_backend(backend),
|
||||
_size(oldTexture ? oldTexture->_size : 0),
|
||||
_texture(oldTexture ? oldTexture->takeOwnership() : 0),
|
||||
|
@ -161,7 +161,7 @@ GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture
|
|||
|
||||
|
||||
// Create the texture and allocate storage
|
||||
GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable) :
|
||||
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable) :
|
||||
GLTexture(backend, texture, id, nullptr, transferrable)
|
||||
{
|
||||
// FIXME, do during allocation
|
||||
|
@ -170,7 +170,7 @@ GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture&
|
|||
}
|
||||
|
||||
// Create the texture and copy from the original higher resolution version
|
||||
GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) :
|
||||
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) :
|
||||
GLTexture(backend, texture, id, originalTexture, originalTexture->_transferrable)
|
||||
{
|
||||
Q_ASSERT(_minMip >= originalTexture->_minMip);
|
||||
|
|
|
@ -58,7 +58,6 @@ public:
|
|||
// If we just did a transfer, return the object after doing post-transfer work
|
||||
if (GLSyncState::Transferred == object->getSyncState()) {
|
||||
object->postTransfer();
|
||||
return object;
|
||||
}
|
||||
|
||||
if (object->isOutdated()) {
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
//
|
||||
#include "GLTextureTransfer.h"
|
||||
|
||||
#ifdef THREADED_TEXTURE_TRANSFER
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#endif
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <gl/Context.h>
|
||||
|
||||
#include "GLShared.h"
|
||||
#include "GLTexture.h"
|
||||
|
@ -20,16 +18,9 @@ using namespace gpu::gl;
|
|||
|
||||
GLTextureTransferHelper::GLTextureTransferHelper() {
|
||||
#ifdef THREADED_TEXTURE_TRANSFER
|
||||
_canvas = QSharedPointer<OffscreenGLCanvas>(new OffscreenGLCanvas(), &QObject::deleteLater);
|
||||
_canvas->setObjectName("TextureTransferCanvas");
|
||||
_canvas->create(QOpenGLContextWrapper::currentContext());
|
||||
if (!_canvas->makeCurrent()) {
|
||||
qFatal("Unable to create texture transfer context");
|
||||
}
|
||||
_canvas->doneCurrent();
|
||||
setObjectName("TextureTransferThread");
|
||||
_context.create();
|
||||
initialize(true, QThread::LowPriority);
|
||||
_canvas->moveToThreadWithContext(_thread);
|
||||
|
||||
// Clean shutdown on UNIX, otherwise _canvas is freed early
|
||||
connect(qApp, &QCoreApplication::aboutToQuit, [&] { terminate(); });
|
||||
#endif
|
||||
|
@ -64,17 +55,9 @@ void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texture
|
|||
}
|
||||
|
||||
void GLTextureTransferHelper::setup() {
|
||||
#ifdef THREADED_TEXTURE_TRANSFER
|
||||
_canvas->makeCurrent();
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLTextureTransferHelper::shutdown() {
|
||||
#ifdef THREADED_TEXTURE_TRANSFER
|
||||
_canvas->doneCurrent();
|
||||
_canvas->moveToThreadWithContext(qApp->thread());
|
||||
_canvas.reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLTextureTransferHelper::do_transfer(GLTexture& texture) {
|
||||
|
@ -85,6 +68,9 @@ void GLTextureTransferHelper::do_transfer(GLTexture& texture) {
|
|||
}
|
||||
|
||||
bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
|
||||
#ifdef THREADED_TEXTURE_TRANSFER
|
||||
_context.makeCurrent();
|
||||
#endif
|
||||
for (auto package : messages) {
|
||||
TexturePointer texturePointer = package.texture.lock();
|
||||
// Texture no longer exists, move on to the next
|
||||
|
@ -93,21 +79,39 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
|
|||
}
|
||||
|
||||
if (package.fence) {
|
||||
glClientWaitSync(package.fence, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
auto result = glClientWaitSync(package.fence, 0, 0);
|
||||
while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) {
|
||||
// Minimum sleep
|
||||
QThread::usleep(1);
|
||||
result = glClientWaitSync(package.fence, 0, 0);
|
||||
}
|
||||
assert(GL_CONDITION_SATISFIED == result || GL_ALREADY_SIGNALED == result);
|
||||
glDeleteSync(package.fence);
|
||||
package.fence = 0;
|
||||
}
|
||||
|
||||
GLTexture* object = Backend::getGPUObject<GLTexture>(*texturePointer);
|
||||
|
||||
do_transfer(*object);
|
||||
glBindTexture(object->_target, 0);
|
||||
|
||||
auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
glClientWaitSync(writeSync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(writeSync);
|
||||
{
|
||||
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
assert(fence);
|
||||
auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
|
||||
while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) {
|
||||
// Minimum sleep
|
||||
QThread::usleep(1);
|
||||
result = glClientWaitSync(fence, 0, 0);
|
||||
}
|
||||
glDeleteSync(fence);
|
||||
}
|
||||
|
||||
object->_contentStamp = texturePointer->getDataStamp();
|
||||
object->setSyncState(GLSyncState::Transferred);
|
||||
}
|
||||
#ifdef THREADED_TEXTURE_TRANSFER
|
||||
_context.doneCurrent();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
|
||||
#include <GenericQueueThread.h>
|
||||
|
||||
#include <gl/Context.h>
|
||||
|
||||
#include "GLShared.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#define THREADED_TEXTURE_TRANSFER
|
||||
#endif
|
||||
|
||||
class OffscreenGLCanvas;
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
struct TextureTransferPackage {
|
||||
|
@ -43,7 +43,7 @@ protected:
|
|||
void do_transfer(GLTexture& texturePointer);
|
||||
|
||||
private:
|
||||
QSharedPointer<OffscreenGLCanvas> _canvas;
|
||||
::gl::OffscreenContext _context;
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -27,8 +27,10 @@
|
|||
|
||||
namespace gpu { namespace gl41 {
|
||||
|
||||
class GL41Backend : public gl::GLBackend {
|
||||
using Parent = gl::GLBackend;
|
||||
using namespace gpu::gl;
|
||||
|
||||
class GL41Backend : public GLBackend {
|
||||
using Parent = GLBackend;
|
||||
// Context Backend static interface required
|
||||
friend class Context;
|
||||
|
||||
|
@ -36,12 +38,12 @@ public:
|
|||
explicit GL41Backend(bool syncCache) : Parent(syncCache) {}
|
||||
GL41Backend() : Parent() {}
|
||||
|
||||
class GL41Texture : public gpu::gl::GLTexture {
|
||||
using Parent = gpu::gl::GLTexture;
|
||||
class GL41Texture : public GLTexture {
|
||||
using Parent = GLTexture;
|
||||
GLuint allocate();
|
||||
public:
|
||||
GL41Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& buffer, bool transferrable);
|
||||
GL41Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& buffer, GL41Texture* original);
|
||||
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer, bool transferrable);
|
||||
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer, GL41Texture* original);
|
||||
|
||||
protected:
|
||||
void transferMip(uint16_t mipLevel, uint8_t face = 0) const;
|
||||
|
@ -56,16 +58,16 @@ public:
|
|||
|
||||
protected:
|
||||
GLuint getFramebufferID(const FramebufferPointer& framebuffer) override;
|
||||
gl::GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override;
|
||||
GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override;
|
||||
|
||||
GLuint getBufferID(const Buffer& buffer) override;
|
||||
gl::GLBuffer* syncGPUObject(const Buffer& buffer) override;
|
||||
GLBuffer* syncGPUObject(const Buffer& buffer) override;
|
||||
|
||||
GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) override;
|
||||
gl::GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) override;
|
||||
GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) override;
|
||||
|
||||
GLuint getQueryID(const QueryPointer& query) override;
|
||||
gl::GLQuery* syncGPUObject(const Query& query) override;
|
||||
GLQuery* syncGPUObject(const Query& query) override;
|
||||
|
||||
// Draw Stage
|
||||
void do_draw(const Batch& batch, size_t paramOffset) override;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace gpu {
|
||||
namespace gl41 {
|
||||
class GL41Buffer : public gl::GLBuffer {
|
||||
class GL41Buffer : public gpu::gl::GLBuffer {
|
||||
using Parent = gpu::gl::GLBuffer;
|
||||
static GLuint allocate() {
|
||||
GLuint result;
|
||||
|
@ -55,6 +55,7 @@ namespace gpu {
|
|||
}
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
using namespace gpu::gl41;
|
||||
|
||||
|
||||
|
@ -62,6 +63,6 @@ GLuint GL41Backend::getBufferID(const Buffer& buffer) {
|
|||
return GL41Buffer::getId<GL41Buffer>(*this, buffer);
|
||||
}
|
||||
|
||||
gl::GLBuffer* GL41Backend::syncGPUObject(const Buffer& buffer) {
|
||||
GLBuffer* GL41Backend::syncGPUObject(const Buffer& buffer) {
|
||||
return GL41Buffer::sync<GL41Buffer>(*this, buffer);
|
||||
}
|
||||
|
|
|
@ -13,10 +13,11 @@
|
|||
#include "../gl/GLQuery.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
using namespace gpu::gl41;
|
||||
|
||||
class GL41Query : public gpu::gl::GLQuery {
|
||||
using Parent = gpu::gl::GLQuery;
|
||||
class GL41Query : public GLQuery {
|
||||
using Parent = GLQuery;
|
||||
public:
|
||||
static GLuint allocateQuery() {
|
||||
GLuint result;
|
||||
|
@ -24,11 +25,11 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
GL41Query(const std::weak_ptr<gl::GLBackend>& backend, const Query& query)
|
||||
GL41Query(const std::weak_ptr<GLBackend>& backend, const Query& query)
|
||||
: Parent(backend, query, allocateQuery(), allocateQuery()) { }
|
||||
};
|
||||
|
||||
gl::GLQuery* GL41Backend::syncGPUObject(const Query& query) {
|
||||
GLQuery* GL41Backend::syncGPUObject(const Query& query) {
|
||||
return GL41Query::sync<GL41Query>(*this, query);
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue