Merge branch 'master' of https://github.com/highfidelity/hifi into low-latency-audio

This commit is contained in:
Ken Cooke 2016-09-06 20:56:20 -07:00
commit 9457d49103
191 changed files with 4669 additions and 2658 deletions

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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})

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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")

View file

@ -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()

View file

@ -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)

View file

@ -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")

View file

@ -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()

View file

@ -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()

View file

@ -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}
)

View file

@ -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}
)

View file

@ -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)

View file

@ -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")

View 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>

View file

@ -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@
;--------------------------------

View file

@ -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.

View file

@ -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);
}

View file

@ -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)

View file

@ -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;

View file

@ -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 ()

View file

@ -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

View file

@ -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: "
}
}

View 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
}
}
}

View file

@ -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

View 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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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;

View file

@ -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;

View file

@ -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
}
}

View file

@ -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);
}

View file

@ -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();

View file

@ -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);

View file

@ -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) {

View file

@ -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");

View file

@ -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;
}

View file

@ -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());
}
}

View file

@ -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);
}
}
}

View file

@ -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.

View file

@ -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());
}
}
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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();
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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()));

View file

@ -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;

View file

@ -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);

View file

@ -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();

View file

@ -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)

View file

@ -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) {

View file

@ -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();

View file

@ -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

View file

@ -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),

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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})

View file

@ -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;

View file

@ -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; }

View file

@ -7,4 +7,6 @@ target_opengl()
GroupSources("src/display-plugins")
target_oglplus()
if (NOT ANDROID)
target_oglplus()
endif ()

View file

@ -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 {

View file

@ -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;

View file

@ -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);
}
});
});
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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";

View file

@ -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
};

View file

@ -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()));

View file

@ -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
};

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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 ()

View 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();
}

View 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

View 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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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));

View file

@ -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 ()

View file

@ -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();
}

View file

@ -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) {}

View file

@ -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);

View file

@ -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()) {

View file

@ -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;
}

View file

@ -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;
};
} }

View file

@ -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;

View file

@ -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);
}

View file

@ -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