mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-18 00:47:30 +02:00
Merge branch 'master' into feature/tablet-ui-foundation
This commit is contained in:
commit
0128d7c61b
86 changed files with 1602 additions and 1312 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Android CMake toolchain file, for use with the Android NDK r5-r10c
|
||||
# Requires cmake 2.6.3 or newer (2.8.5 or newer is recommended).
|
||||
# Android CMake toolchain file, for use with the Android NDK r5-r10d
|
||||
# Requires cmake 2.6.3 or newer (2.8.9 or newer is recommended).
|
||||
# See home page: https://github.com/taka-no-me/android-cmake
|
||||
#
|
||||
# Usage Linux:
|
||||
|
@ -39,12 +39,6 @@
|
|||
# $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake ..
|
||||
# $ make -j8
|
||||
#
|
||||
# Usage Linux (using standalone toolchain):
|
||||
# $ export ANDROID_STANDALONE_TOOLCHAIN=/absolute/path/to/android-toolchain
|
||||
# $ mkdir build && cd build
|
||||
# $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake ..
|
||||
# $ make -j8
|
||||
#
|
||||
# Usage Windows:
|
||||
# You need native port of make to build your project.
|
||||
# Android NDK r7 (and newer) already has make.exe on board.
|
||||
|
@ -63,11 +57,6 @@
|
|||
# ANDROID_NDK=/opt/android-ndk - path to the NDK root.
|
||||
# Can be set as environment variable. Can be set only at first cmake run.
|
||||
#
|
||||
# ANDROID_STANDALONE_TOOLCHAIN=/opt/android-toolchain - path to the
|
||||
# standalone toolchain. This option is not used if full NDK is found
|
||||
# (ignored if ANDROID_NDK is set).
|
||||
# Can be set as environment variable. Can be set only at first cmake run.
|
||||
#
|
||||
# ANDROID_ABI=armeabi-v7a - specifies the target Application Binary
|
||||
# Interface (ABI). This option nearly matches to the APP_ABI variable
|
||||
# used by ndk-build tool from Android NDK.
|
||||
|
@ -123,8 +112,8 @@
|
|||
# * x86_64-clang3.5
|
||||
#
|
||||
# ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions
|
||||
# instead of Thumb. Is not available for "x86" (inapplicable) and
|
||||
# "armeabi-v6 with VFP" (is forced to be ON) ABIs.
|
||||
# instead of Thumb. Is not available for "armeabi-v6 with VFP"
|
||||
# (is forced to be ON) ABI.
|
||||
#
|
||||
# ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker
|
||||
# errors even if they are not used.
|
||||
|
@ -133,13 +122,6 @@
|
|||
# libraries. Automatically turned for NDK r5x and r6x due to GLESv2
|
||||
# problems.
|
||||
#
|
||||
# LIBRARY_OUTPUT_PATH_ROOT=${CMAKE_SOURCE_DIR} - where to output binary
|
||||
# files. See additional details below.
|
||||
#
|
||||
# ANDROID_SET_OBSOLETE_VARIABLES=ON - if set, then toolchain defines some
|
||||
# obsolete variables which were used by previous versions of this file for
|
||||
# backward compatibility.
|
||||
#
|
||||
# ANDROID_STL=gnustl_static - specify the runtime to use.
|
||||
#
|
||||
# Possible values are:
|
||||
|
@ -172,6 +154,8 @@
|
|||
# Implies -frtti -fno-exceptions.
|
||||
# Available for NDK r7b and newer.
|
||||
# Silently degrades to gnustl_static if not available.
|
||||
# c++_static -> Use the LLVM libc++ runtime as a static library.
|
||||
# c++_shared -> Use the LLVM libc++ runtime as a shared library.
|
||||
#
|
||||
# ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on
|
||||
# chosen runtime. If disabled, then the user is responsible for settings
|
||||
|
@ -200,12 +184,6 @@
|
|||
# will be set true, mutually exclusive. NEON option will be set true
|
||||
# if VFP is set to NEON.
|
||||
#
|
||||
# LIBRARY_OUTPUT_PATH_ROOT should be set in cache to determine where Android
|
||||
# libraries will be installed.
|
||||
# Default is ${CMAKE_SOURCE_DIR}, and the android libs will always be
|
||||
# under the ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}
|
||||
# (depending on the target ABI). This is convenient for Android packaging.
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
cmake_minimum_required( VERSION 2.6.3 )
|
||||
|
@ -235,22 +213,22 @@ endif()
|
|||
# this one not so much
|
||||
set( CMAKE_SYSTEM_VERSION 1 )
|
||||
|
||||
# rpath makes low sence for Android
|
||||
# rpath makes low sense for Android
|
||||
set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" )
|
||||
set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." )
|
||||
|
||||
# NDK search paths
|
||||
set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
|
||||
if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS)
|
||||
set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10d -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
|
||||
if( NOT DEFINED ANDROID_NDK_SEARCH_PATHS )
|
||||
if( CMAKE_HOST_WIN32 )
|
||||
file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS )
|
||||
set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}/android-ndk" "$ENV{SystemDrive}/NVPACK/android-ndk" )
|
||||
set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}" "$ENV{SystemDrive}/NVPACK" )
|
||||
else()
|
||||
file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS )
|
||||
set( ANDROID_NDK_SEARCH_PATHS /opt/android-ndk "${ANDROID_NDK_SEARCH_PATHS}/NVPACK/android-ndk" )
|
||||
set( ANDROID_NDK_SEARCH_PATHS /opt "${ANDROID_NDK_SEARCH_PATHS}/NVPACK" )
|
||||
endif()
|
||||
endif()
|
||||
if(NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH)
|
||||
if( NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH )
|
||||
set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain )
|
||||
endif()
|
||||
|
||||
|
@ -272,106 +250,90 @@ set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 )
|
|||
|
||||
|
||||
macro( __LIST_FILTER listvar regex )
|
||||
if( ${listvar} )
|
||||
foreach( __val ${${listvar}} )
|
||||
if( __val MATCHES "${regex}" )
|
||||
list( REMOVE_ITEM ${listvar} "${__val}" )
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
if( ${listvar} )
|
||||
foreach( __val ${${listvar}} )
|
||||
if( __val MATCHES "${regex}" )
|
||||
list( REMOVE_ITEM ${listvar} "${__val}" )
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro( __INIT_VARIABLE var_name )
|
||||
set( __test_path 0 )
|
||||
foreach( __var ${ARGN} )
|
||||
if( __var STREQUAL "PATH" )
|
||||
set( __test_path 1 )
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
if( __test_path AND NOT EXISTS "${${var_name}}" )
|
||||
unset( ${var_name} CACHE )
|
||||
endif()
|
||||
if( "${${var_name}}" STREQUAL "" )
|
||||
set( __values 0 )
|
||||
set( __test_path 0 )
|
||||
foreach( __var ${ARGN} )
|
||||
if( __var STREQUAL "VALUES" )
|
||||
set( __values 1 )
|
||||
elseif( NOT __var STREQUAL "PATH" )
|
||||
set( __obsolete 0 )
|
||||
if( __var MATCHES "^OBSOLETE_.*$" )
|
||||
string( REPLACE "OBSOLETE_" "" __var "${__var}" )
|
||||
set( __obsolete 1 )
|
||||
endif()
|
||||
if( __var MATCHES "^ENV_.*$" )
|
||||
string( REPLACE "ENV_" "" __var "${__var}" )
|
||||
set( __value "$ENV{${__var}}" )
|
||||
elseif( DEFINED ${__var} )
|
||||
set( __value "${${__var}}" )
|
||||
else()
|
||||
if( __values )
|
||||
set( __value "${__var}" )
|
||||
else()
|
||||
set( __value "" )
|
||||
endif()
|
||||
endif()
|
||||
if( NOT "${__value}" STREQUAL "" )
|
||||
if( __test_path )
|
||||
if( EXISTS "${__value}" )
|
||||
file( TO_CMAKE_PATH "${__value}" ${var_name} )
|
||||
if( __obsolete AND NOT _CMAKE_IN_TRY_COMPILE )
|
||||
message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." )
|
||||
endif()
|
||||
break()
|
||||
endif()
|
||||
else()
|
||||
set( ${var_name} "${__value}" )
|
||||
if( __obsolete AND NOT _CMAKE_IN_TRY_COMPILE )
|
||||
message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." )
|
||||
endif()
|
||||
if( __var STREQUAL "PATH" )
|
||||
set( __test_path 1 )
|
||||
break()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
unset( __value )
|
||||
unset( __values )
|
||||
unset( __obsolete )
|
||||
elseif( __test_path )
|
||||
file( TO_CMAKE_PATH "${${var_name}}" ${var_name} )
|
||||
endif()
|
||||
unset( __test_path )
|
||||
|
||||
if( __test_path AND NOT EXISTS "${${var_name}}" )
|
||||
unset( ${var_name} CACHE )
|
||||
endif()
|
||||
|
||||
if( " ${${var_name}}" STREQUAL " " )
|
||||
set( __values 0 )
|
||||
foreach( __var ${ARGN} )
|
||||
if( __var STREQUAL "VALUES" )
|
||||
set( __values 1 )
|
||||
elseif( NOT __var STREQUAL "PATH" )
|
||||
if( __var MATCHES "^ENV_.*$" )
|
||||
string( REPLACE "ENV_" "" __var "${__var}" )
|
||||
set( __value "$ENV{${__var}}" )
|
||||
elseif( DEFINED ${__var} )
|
||||
set( __value "${${__var}}" )
|
||||
elseif( __values )
|
||||
set( __value "${__var}" )
|
||||
else()
|
||||
set( __value "" )
|
||||
endif()
|
||||
|
||||
if( NOT " ${__value}" STREQUAL " " AND (NOT __test_path OR EXISTS "${__value}") )
|
||||
set( ${var_name} "${__value}" )
|
||||
break()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
unset( __value )
|
||||
unset( __values )
|
||||
endif()
|
||||
|
||||
if( __test_path )
|
||||
file( TO_CMAKE_PATH "${${var_name}}" ${var_name} )
|
||||
endif()
|
||||
unset( __test_path )
|
||||
endmacro()
|
||||
|
||||
macro( __DETECT_NATIVE_API_LEVEL _var _path )
|
||||
SET( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" )
|
||||
FILE( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" )
|
||||
if( NOT __apiFileContent )
|
||||
message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." )
|
||||
endif()
|
||||
string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" )
|
||||
unset( __apiFileContent )
|
||||
unset( __ndkApiLevelRegex )
|
||||
set( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" )
|
||||
file( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" )
|
||||
if( NOT __apiFileContent )
|
||||
message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." )
|
||||
endif()
|
||||
string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" )
|
||||
unset( __apiFileContent )
|
||||
unset( __ndkApiLevelRegex )
|
||||
endmacro()
|
||||
|
||||
macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root )
|
||||
if( EXISTS "${_root}" )
|
||||
file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" )
|
||||
__LIST_FILTER( __gccExePath "^[.].*" )
|
||||
list( LENGTH __gccExePath __gccExePathsCount )
|
||||
if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE )
|
||||
message( WARNING "Could not determine machine name for compiler from ${_root}" )
|
||||
set( ${_var} "" )
|
||||
file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" )
|
||||
__LIST_FILTER( __gccExePath "^[.].*" )
|
||||
list( LENGTH __gccExePath __gccExePathsCount )
|
||||
if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE )
|
||||
message( WARNING "Could not determine machine name for compiler from ${_root}" )
|
||||
set( ${_var} "" )
|
||||
else()
|
||||
get_filename_component( __gccExeName "${__gccExePath}" NAME_WE )
|
||||
string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" )
|
||||
endif()
|
||||
unset( __gccExePath )
|
||||
unset( __gccExePathsCount )
|
||||
unset( __gccExeName )
|
||||
else()
|
||||
get_filename_component( __gccExeName "${__gccExePath}" NAME_WE )
|
||||
string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" )
|
||||
set( ${_var} "" )
|
||||
endif()
|
||||
unset( __gccExePath )
|
||||
unset( __gccExePathsCount )
|
||||
unset( __gccExeName )
|
||||
else()
|
||||
set( ${_var} "" )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
|
@ -419,17 +381,19 @@ if( NOT ANDROID_NDK_HOST_X64 )
|
|||
endif()
|
||||
|
||||
# see if we have path to Android NDK
|
||||
__INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK )
|
||||
if( NOT ANDROID_NDK AND NOT ANDROID_STANDALONE_TOOLCHAIN )
|
||||
__INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK )
|
||||
endif()
|
||||
if( NOT ANDROID_NDK )
|
||||
# see if we have path to Android standalone toolchain
|
||||
__INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN OBSOLETE_ANDROID_NDK_TOOLCHAIN_ROOT OBSOLETE_ENV_ANDROID_NDK_TOOLCHAIN_ROOT )
|
||||
__INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN )
|
||||
|
||||
if( NOT ANDROID_STANDALONE_TOOLCHAIN )
|
||||
#try to find Android NDK in one of the the default locations
|
||||
set( __ndkSearchPaths )
|
||||
foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} )
|
||||
foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} )
|
||||
list( APPEND __ndkSearchPaths "${__ndkSearchPath}${suffix}" )
|
||||
list( APPEND __ndkSearchPaths "${__ndkSearchPath}/android-ndk${suffix}" )
|
||||
endforeach()
|
||||
endforeach()
|
||||
__INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} )
|
||||
|
@ -487,7 +451,7 @@ else()
|
|||
or
|
||||
export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain
|
||||
or put the toolchain or NDK in the default path:
|
||||
sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}
|
||||
sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}/android-ndk
|
||||
sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" )
|
||||
endif()
|
||||
|
||||
|
@ -636,7 +600,7 @@ if( BUILD_WITH_ANDROID_NDK )
|
|||
endif()
|
||||
if( NOT __availableToolchains )
|
||||
file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" )
|
||||
if( __availableToolchains )
|
||||
if( __availableToolchainsLst )
|
||||
list(SORT __availableToolchainsLst) # we need clang to go after gcc
|
||||
endif()
|
||||
__LIST_FILTER( __availableToolchainsLst "^[.]" )
|
||||
|
@ -669,7 +633,7 @@ if( NOT ANDROID_SUPPORTED_ABIS )
|
|||
endif()
|
||||
|
||||
# choose target ABI
|
||||
__INIT_VARIABLE( ANDROID_ABI OBSOLETE_ARM_TARGET OBSOLETE_ARM_TARGETS VALUES ${ANDROID_SUPPORTED_ABIS} )
|
||||
__INIT_VARIABLE( ANDROID_ABI VALUES ${ANDROID_SUPPORTED_ABIS} )
|
||||
# verify that target ABI is supported
|
||||
list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx )
|
||||
if( __androidAbiIdx EQUAL -1 )
|
||||
|
@ -760,7 +724,7 @@ if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMa
|
|||
endif()
|
||||
|
||||
if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 )
|
||||
__INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD OBSOLETE_FORCE_ARM VALUES OFF )
|
||||
__INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD VALUES OFF )
|
||||
set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE )
|
||||
mark_as_advanced( ANDROID_FORCE_ARM_BUILD )
|
||||
else()
|
||||
|
@ -845,6 +809,7 @@ else()
|
|||
unset( __realApiLevel )
|
||||
endif()
|
||||
set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE )
|
||||
set( CMAKE_ANDROID_API ${ANDROID_NATIVE_API_LEVEL} )
|
||||
if( CMAKE_VERSION VERSION_GREATER "2.8" )
|
||||
list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS )
|
||||
set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
|
||||
|
@ -863,23 +828,14 @@ endif()
|
|||
|
||||
# runtime choice (STL, rtti, exceptions)
|
||||
if( NOT ANDROID_STL )
|
||||
# honor legacy ANDROID_USE_STLPORT
|
||||
if( DEFINED ANDROID_USE_STLPORT )
|
||||
if( ANDROID_USE_STLPORT )
|
||||
set( ANDROID_STL stlport_static )
|
||||
endif()
|
||||
message( WARNING "You are using an obsolete variable ANDROID_USE_STLPORT to select the STL variant. Use -DANDROID_STL=stlport_static instead." )
|
||||
endif()
|
||||
if( NOT ANDROID_STL )
|
||||
set( ANDROID_STL gnustl_static )
|
||||
endif()
|
||||
endif()
|
||||
set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" )
|
||||
set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" )
|
||||
mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES )
|
||||
|
||||
if( BUILD_WITH_ANDROID_NDK )
|
||||
if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$")
|
||||
if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared|c\\+\\+_static|c\\+\\+_shared)$")
|
||||
message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\".
|
||||
The possible values are:
|
||||
none -> Do not configure the runtime.
|
||||
|
@ -891,6 +847,8 @@ The possible values are:
|
|||
stlport_shared -> Use the STLport runtime as a shared library.
|
||||
gnustl_static -> (default) Use the GNU STL as a static library.
|
||||
gnustl_shared -> Use the GNU STL as a shared library.
|
||||
c++_static -> Use the LLVM libc++ runtime as a static library.
|
||||
c++_shared -> Use the LLVM libc++ runtime as a shared library.
|
||||
" )
|
||||
endif()
|
||||
elseif( BUILD_WITH_STANDALONE_TOOLCHAIN )
|
||||
|
@ -1033,7 +991,7 @@ if( BUILD_WITH_ANDROID_NDK )
|
|||
set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" )
|
||||
elseif( ANDROID_STL MATCHES "gabi" )
|
||||
if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
|
||||
message( FATAL_ERROR "gabi++ is not awailable in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.")
|
||||
message( FATAL_ERROR "gabi++ is not available in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.")
|
||||
endif()
|
||||
set( ANDROID_RTTI ON )
|
||||
set( ANDROID_EXCEPTIONS OFF )
|
||||
|
@ -1066,12 +1024,40 @@ if( BUILD_WITH_ANDROID_NDK )
|
|||
else()
|
||||
set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" )
|
||||
endif()
|
||||
set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" )
|
||||
set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" "${__libstl}/include/backward" )
|
||||
if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" )
|
||||
set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" )
|
||||
else()
|
||||
set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" )
|
||||
endif()
|
||||
elseif( ANDROID_STL MATCHES "c\\+\\+_shared" OR ANDROID_STL MATCHES "c\\+\\+_static" )
|
||||
set( ANDROID_EXCEPTIONS ON )
|
||||
set( ANDROID_RTTI ON )
|
||||
set( ANDROID_CXX_ROOT "${ANDROID_NDK}/sources/cxx-stl/" )
|
||||
set( ANDROID_LLVM_ROOT "${ANDROID_CXX_ROOT}/llvm-libc++" )
|
||||
|
||||
if( X86 )
|
||||
set( ANDROID_ABI_INCLUDE_DIRS "${ANDROID_CXX_ROOT}/gabi++/include" )
|
||||
else()
|
||||
set( ANDROID_ABI_INCLUDE_DIRS "${ANDROID_CXX_ROOT}/llvm-libc++abi/include" )
|
||||
endif()
|
||||
|
||||
set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_LLVM_ROOT}/libcxx/include" "${ANDROID_ABI_INCLUDE_DIRS}" )
|
||||
|
||||
# android support sfiles
|
||||
include_directories ( SYSTEM ${ANDROID_NDK}/sources/android/support/include )
|
||||
|
||||
if(ANDROID_STL MATCHES "c\\+\\+_shared")
|
||||
set ( LLVM_LIBRARY_NAME "libc++_shared.so")
|
||||
else()
|
||||
set ( LLVM_LIBRARY_NAME "libc++_static.a" )
|
||||
endif ()
|
||||
|
||||
if( EXISTS "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/${LLVM_LIBRARY_NAME}" )
|
||||
set( __libstl "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/${LLVM_LIBRARY_NAME}" )
|
||||
else()
|
||||
message( FATAL_ERROR "Could not find libc++ library" )
|
||||
endif()
|
||||
else()
|
||||
message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" )
|
||||
endif()
|
||||
|
@ -1144,7 +1130,12 @@ if( NOT CMAKE_C_COMPILER )
|
|||
endif()
|
||||
set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" )
|
||||
set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" )
|
||||
set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
|
||||
if( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" )
|
||||
# Use gcc-ar if we have it for better LTO support.
|
||||
set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
|
||||
else()
|
||||
set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
|
||||
endif()
|
||||
set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" )
|
||||
set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" )
|
||||
set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" )
|
||||
|
@ -1168,7 +1159,7 @@ endif()
|
|||
include( CMakeForceCompiler )
|
||||
CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU )
|
||||
if( ANDROID_COMPILER_IS_CLANG )
|
||||
set( CMAKE_C_COMPILER_ID Clang)
|
||||
set( CMAKE_C_COMPILER_ID Clang )
|
||||
endif()
|
||||
set( CMAKE_C_PLATFORM_ID Linux )
|
||||
if( X86_64 OR MIPS64 OR ARM64_V8A )
|
||||
|
@ -1195,6 +1186,14 @@ set( CMAKE_ASM_COMPILER_FORCED TRUE )
|
|||
set( CMAKE_COMPILER_IS_GNUASM 1)
|
||||
set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm )
|
||||
|
||||
foreach( lang C CXX ASM )
|
||||
if( ANDROID_COMPILER_IS_CLANG )
|
||||
set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_CLANG_VERSION} )
|
||||
else()
|
||||
set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_COMPILER_VERSION} )
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# flags and definitions
|
||||
remove_definitions( -DANDROID )
|
||||
add_definitions( -DANDROID )
|
||||
|
@ -1225,14 +1224,14 @@ endif()
|
|||
|
||||
# NDK flags
|
||||
if (ARM64_V8A )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -ffunction-sections -funwind-tables" )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
|
||||
set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" )
|
||||
set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" )
|
||||
if( NOT ANDROID_COMPILER_IS_CLANG )
|
||||
set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" )
|
||||
endif()
|
||||
elseif( ARMEABI OR ARMEABI_V7A)
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -funwind-tables" )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
|
||||
if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 )
|
||||
set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" )
|
||||
set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" )
|
||||
|
@ -1251,13 +1250,11 @@ elseif( X86 OR X86_64 )
|
|||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
|
||||
if( NOT ANDROID_COMPILER_IS_CLANG )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" )
|
||||
else()
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fPIC" )
|
||||
endif()
|
||||
set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" )
|
||||
set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" )
|
||||
elseif( MIPS OR MIPS64 )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0" )
|
||||
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-strict-aliasing -finline-functions -funwind-tables -fmessage-length=0" )
|
||||
set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" )
|
||||
set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" )
|
||||
if( NOT ANDROID_COMPILER_IS_CLANG )
|
||||
|
@ -1342,7 +1339,7 @@ if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
|
|||
else()
|
||||
__INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF )
|
||||
endif()
|
||||
__INIT_VARIABLE( ANDROID_NO_UNDEFINED OBSOLETE_NO_UNDEFINED VALUES ON )
|
||||
__INIT_VARIABLE( ANDROID_NO_UNDEFINED VALUES ON )
|
||||
__INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON )
|
||||
__INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON )
|
||||
__INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON )
|
||||
|
@ -1350,7 +1347,7 @@ __INIT_VARIABLE( ANDROID_RELRO VALUES ON )
|
|||
|
||||
set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" )
|
||||
set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
|
||||
set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
|
||||
set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Put each function in separate section and enable garbage collection of unused input sections at link time" )
|
||||
set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker" )
|
||||
set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
|
||||
set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" )
|
||||
|
@ -1452,6 +1449,16 @@ if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" )
|
|||
set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" )
|
||||
endif()
|
||||
|
||||
# pie/pic
|
||||
if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE) AND (CMAKE_VERSION VERSION_GREATER 2.8.8) )
|
||||
set( CMAKE_POSITION_INDEPENDENT_CODE TRUE )
|
||||
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie")
|
||||
else()
|
||||
set( CMAKE_POSITION_INDEPENDENT_CODE FALSE )
|
||||
set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" )
|
||||
set( CMAKE_C_FLAGS "-fpic ${CMAKE_C_FLAGS}" )
|
||||
endif()
|
||||
|
||||
# configure rtti
|
||||
if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES )
|
||||
if( ANDROID_RTTI )
|
||||
|
@ -1515,27 +1522,31 @@ if( ANDROID_EXPLICIT_CRT_LINK )
|
|||
endif()
|
||||
|
||||
# setup output directories
|
||||
set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library output, set this to change where android libs are installed to" )
|
||||
set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" )
|
||||
|
||||
if(NOT _CMAKE_IN_TRY_COMPILE)
|
||||
if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" )
|
||||
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" )
|
||||
else()
|
||||
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" )
|
||||
endif()
|
||||
set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" )
|
||||
if( DEFINED LIBRARY_OUTPUT_PATH_ROOT
|
||||
OR EXISTS "${CMAKE_SOURCE_DIR}/AndroidManifest.xml"
|
||||
OR (EXISTS "${CMAKE_SOURCE_DIR}/../AndroidManifest.xml" AND EXISTS "${CMAKE_SOURCE_DIR}/../jni/") )
|
||||
set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "Root for binaries output, set this to change where Android libs are installed to" )
|
||||
if( NOT _CMAKE_IN_TRY_COMPILE )
|
||||
if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" )
|
||||
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" )
|
||||
else()
|
||||
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" )
|
||||
endif()
|
||||
set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for Android libs" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# copy shaed stl library to build directory
|
||||
if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" )
|
||||
get_filename_component( __libstlname "${__libstl}" NAME )
|
||||
execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess )
|
||||
if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}")
|
||||
message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" )
|
||||
endif()
|
||||
unset( __fileCopyProcess )
|
||||
unset( __libstlname )
|
||||
if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" AND DEFINED LIBRARY_OUTPUT_PATH )
|
||||
get_filename_component( __libstlname "${__libstl}" NAME )
|
||||
execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess )
|
||||
if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}")
|
||||
message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" )
|
||||
endif()
|
||||
unset( __fileCopyProcess )
|
||||
unset( __libstlname )
|
||||
endif()
|
||||
|
||||
|
||||
|
@ -1596,28 +1607,10 @@ macro( find_host_program )
|
|||
endmacro()
|
||||
|
||||
|
||||
macro( ANDROID_GET_ABI_RAWNAME TOOLCHAIN_FLAG VAR )
|
||||
if( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI" )
|
||||
set( ${VAR} "armeabi" )
|
||||
elseif( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI_V7A" )
|
||||
set( ${VAR} "armeabi-v7a" )
|
||||
elseif( "${TOOLCHAIN_FLAG}" STREQUAL "X86" )
|
||||
set( ${VAR} "x86" )
|
||||
elseif( "${TOOLCHAIN_FLAG}" STREQUAL "MIPS" )
|
||||
set( ${VAR} "mips" )
|
||||
else()
|
||||
set( ${VAR} "unknown" )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
if (POLICY CMP0054)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif ()
|
||||
|
||||
# export toolchain settings for the try_compile() command
|
||||
if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" )
|
||||
if( NOT _CMAKE_IN_TRY_COMPILE )
|
||||
set( __toolchain_config "")
|
||||
foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN ANDROID_SET_OBSOLETE_VARIABLES
|
||||
foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN
|
||||
ANDROID_NDK_HOST_X64
|
||||
ANDROID_NDK
|
||||
ANDROID_NDK_LAYOUT
|
||||
|
@ -1636,9 +1629,10 @@ if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" )
|
|||
ANDROID_RELRO
|
||||
ANDROID_LIBM_PATH
|
||||
ANDROID_EXPLICIT_CRT_LINK
|
||||
ANDROID_APP_PIE
|
||||
)
|
||||
if( DEFINED ${__var} )
|
||||
if( "${__var}" MATCHES " ")
|
||||
if( ${__var} MATCHES " ")
|
||||
set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" )
|
||||
else()
|
||||
set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" )
|
||||
|
@ -1663,16 +1657,6 @@ if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 )
|
|||
endif()
|
||||
|
||||
|
||||
# set some obsolete variables for backward compatibility
|
||||
set( ANDROID_SET_OBSOLETE_VARIABLES ON CACHE BOOL "Define obsolete Andrid-specific cmake variables" )
|
||||
mark_as_advanced( ANDROID_SET_OBSOLETE_VARIABLES )
|
||||
if( ANDROID_SET_OBSOLETE_VARIABLES )
|
||||
set( ANDROID_API_LEVEL ${ANDROID_NATIVE_API_LEVEL} )
|
||||
set( ARM_TARGET "${ANDROID_ABI}" )
|
||||
set( ARMEABI_NDK_NAME "${ANDROID_NDK_ABI_NAME}" )
|
||||
endif()
|
||||
|
||||
|
||||
# Variables controlling behavior or set by cmake toolchain:
|
||||
# ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64"
|
||||
# ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version)
|
||||
|
@ -1686,22 +1670,15 @@ endif()
|
|||
# ANDROID_RELRO : ON/OFF
|
||||
# ANDROID_FORCE_ARM_BUILD : ON/OFF
|
||||
# ANDROID_STL_FORCE_FEATURES : ON/OFF
|
||||
# ANDROID_SET_OBSOLETE_VARIABLES : ON/OFF
|
||||
# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product/<product_name>/obj/lib/libm.so) to workaround unresolved `sincos`
|
||||
# Can be set only at the first run:
|
||||
# ANDROID_NDK
|
||||
# ANDROID_STANDALONE_TOOLCHAIN
|
||||
# ANDROID_NDK : path to your NDK install
|
||||
# NDK_CCACHE : path to your ccache executable
|
||||
# ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain
|
||||
# ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems)
|
||||
# ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID)
|
||||
# LIBRARY_OUTPUT_PATH_ROOT : <any valid path>
|
||||
# NDK_CCACHE : <path to your ccache executable>
|
||||
# Obsolete:
|
||||
# ANDROID_API_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL
|
||||
# ARM_TARGET : superseded by ANDROID_ABI
|
||||
# ARM_TARGETS : superseded by ANDROID_ABI (can be set only)
|
||||
# ANDROID_NDK_TOOLCHAIN_ROOT : superseded by ANDROID_STANDALONE_TOOLCHAIN (can be set only)
|
||||
# ANDROID_USE_STLPORT : superseded by ANDROID_STL=stlport_static
|
||||
# ANDROID_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL (completely removed)
|
||||
# ANDROID_STANDALONE_TOOLCHAIN
|
||||
#
|
||||
# Primary read-only variables:
|
||||
# ANDROID : always TRUE
|
||||
|
@ -1715,19 +1692,16 @@ endif()
|
|||
# X86_64 : TRUE if configured for x86_64
|
||||
# MIPS : TRUE if configured for mips
|
||||
# MIPS64 : TRUE if configured for mips64
|
||||
# BUILD_ANDROID : always TRUE
|
||||
# BUILD_WITH_ANDROID_NDK : TRUE if NDK is used
|
||||
# BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used
|
||||
# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform
|
||||
# ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI
|
||||
# ANDROID_NDK_RELEASE : from r5 to r10c; set only for NDK
|
||||
# ANDROID_NDK_RELEASE : from r5 to r10d; set only for NDK
|
||||
# ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor)
|
||||
# ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI
|
||||
# ANDROID_SYSROOT : path to the compiler sysroot
|
||||
# TOOL_OS_SUFFIX : "" or ".exe" depending on host platform
|
||||
# ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used
|
||||
# Obsolete:
|
||||
# ARMEABI_NDK_NAME : superseded by ANDROID_NDK_ABI_NAME
|
||||
#
|
||||
# Secondary (less stable) read-only variables:
|
||||
# ANDROID_COMPILER_VERSION : GCC version used (not Clang version)
|
||||
|
@ -1742,12 +1716,10 @@ endif()
|
|||
# ANDROID_RTTI : if rtti is enabled by the runtime
|
||||
# ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime
|
||||
# ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used
|
||||
# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product/<product_name>/obj/lib/libm.so) to workaround unresolved `sincos`
|
||||
#
|
||||
# Defaults:
|
||||
# ANDROID_DEFAULT_NDK_API_LEVEL
|
||||
# ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH}
|
||||
# ANDROID_NDK_SEARCH_PATHS
|
||||
# ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH
|
||||
# ANDROID_SUPPORTED_ABIS_${ARCH}
|
||||
# ANDROID_SUPPORTED_NDK_VERSIONS
|
||||
# ANDROID_SUPPORTED_NDK_VERSIONS
|
||||
|
|
3
cmake/externals/glew/CMakeLists.txt
vendored
3
cmake/externals/glew/CMakeLists.txt
vendored
|
@ -15,7 +15,6 @@ ExternalProject_Add(
|
|||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
|
@ -32,4 +31,4 @@ elseif (WIN32)
|
|||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/${LIB_PREFIX}glew_d.${LIB_EXT} CACHE FILEPATH "Path to glew debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/${LIB_PREFIX}glew.${LIB_EXT} CACHE FILEPATH "Path to glew release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/${LIB_PREFIX}glew.${LIB_EXT} CACHE FILEPATH "Path to glew release library")
|
||||
|
|
74
cmake/externals/hifiAudioCodec/CMakeLists.txt
vendored
74
cmake/externals/hifiAudioCodec/CMakeLists.txt
vendored
|
@ -5,39 +5,43 @@ set(EXTERNAL_NAME hifiAudioCodec)
|
|||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (WIN32 OR APPLE)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-1.zip
|
||||
URL_MD5 23ec3fe51eaa155ea159a4971856fc13
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
elseif(NOT ANDROID)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux.zip
|
||||
URL_MD5 7d37914a18aa4de971d2f45dd3043bde
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
endif()
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL)
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL)
|
||||
elseif(APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
|
||||
elseif(NOT ANDROID)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
|
||||
if (NOT ANDROID)
|
||||
|
||||
if (WIN32 OR APPLE)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-1.zip
|
||||
URL_MD5 23ec3fe51eaa155ea159a4971856fc13
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
else ()
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux.zip
|
||||
URL_MD5 7d37914a18aa4de971d2f45dd3043bde
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
endif()
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL)
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL)
|
||||
elseif(APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
|
||||
elseif(NOT ANDROID)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
|
7
cmake/externals/sdl2/CMakeLists.txt
vendored
7
cmake/externals/sdl2/CMakeLists.txt
vendored
|
@ -46,7 +46,7 @@ else ()
|
|||
if (ANDROID)
|
||||
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
|
||||
endif ()
|
||||
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://www.libsdl.org/release/SDL2-2.0.3.tar.gz
|
||||
|
@ -61,7 +61,6 @@ endif ()
|
|||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
|
||||
if (APPLE)
|
||||
|
||||
# NOOP
|
||||
|
@ -78,9 +77,9 @@ elseif (WIN32)
|
|||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${SOURCE_DIR}/lib/x86/SDL2.lib CACHE FILEPATH "Path to SDL2 library")
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/lib/x86 CACHE PATH "Location of SDL2 DLL")
|
||||
endif()
|
||||
|
||||
|
||||
add_paths_to_fixup_libs(${${EXTERNAL_NAME_UPPER}_DLL_PATH})
|
||||
|
||||
|
||||
else ()
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
|
28
cmake/externals/tbb/CMakeLists.txt
vendored
28
cmake/externals/tbb/CMakeLists.txt
vendored
|
@ -3,9 +3,9 @@ set(EXTERNAL_NAME tbb)
|
|||
include(ExternalProject)
|
||||
|
||||
if (ANDROID)
|
||||
|
||||
|
||||
find_program(NDK_BUILD_COMMAND NAMES ndk-build DOC "Path to the ndk-build command")
|
||||
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_src.tgz
|
||||
|
@ -20,7 +20,7 @@ if (ANDROID)
|
|||
)
|
||||
elseif (APPLE)
|
||||
find_program(MAKE_COMMAND NAMES make DOC "Path to the make command")
|
||||
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_src.tgz
|
||||
|
@ -37,11 +37,11 @@ else ()
|
|||
if (WIN32)
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_win.zip)
|
||||
set(DOWNLOAD_MD5 d250d40bb93b255f75bcbb19e976a440)
|
||||
else ()
|
||||
else ()
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_lin.tgz)
|
||||
set(DOWNLOAD_MD5 7830ba2bc62438325fba2ec0c95367a5)
|
||||
endif ()
|
||||
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL ${DOWNLOAD_URL}
|
||||
|
@ -60,11 +60,11 @@ ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
|||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (APPLE)
|
||||
if (APPLE)
|
||||
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib")
|
||||
set(_LIB_PREFIX "lib")
|
||||
set(_LIB_EXT "dylib")
|
||||
|
||||
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
change-install-name
|
||||
|
@ -74,7 +74,7 @@ if (APPLE)
|
|||
WORKING_DIRECTORY <SOURCE_DIR>
|
||||
LOG 1
|
||||
)
|
||||
|
||||
|
||||
elseif (WIN32)
|
||||
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/intel64/vc12")
|
||||
|
@ -91,18 +91,18 @@ elseif (ANDROID)
|
|||
elseif (UNIX)
|
||||
set(_LIB_PREFIX "lib")
|
||||
set(_LIB_EXT "so")
|
||||
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(_TBB_ARCH_DIR "intel64")
|
||||
else()
|
||||
set(_TBB_ARCH_DIR "ia32")
|
||||
endif()
|
||||
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE GCC_VERSION
|
||||
)
|
||||
|
||||
|
||||
if (GCC_VERSION VERSION_GREATER 4.4 OR GCC_VERSION VERSION_EQUAL 4.4)
|
||||
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/${_TBB_ARCH_DIR}/gcc4.4")
|
||||
elseif (GCC_VERSION VERSION_GREATER 4.1 OR GCC_VERSION VERSION_EQUAL 4.1)
|
||||
|
@ -110,9 +110,9 @@ elseif (UNIX)
|
|||
else ()
|
||||
message(STATUS "Could not find a compatible version of Threading Building Blocks library for your compiler.")
|
||||
endif ()
|
||||
|
||||
|
||||
endif ()
|
||||
|
||||
|
||||
endif ()
|
||||
|
||||
if (DEFINED _TBB_LIB_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbb_debug.${_LIB_EXT} CACHE FILEPATH "TBB debug library location")
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
#
|
||||
# AutoMTC.cmake
|
||||
#
|
||||
# Created by Andrzej Kapolka on 12/31/13.
|
||||
# Copyright 2013 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(AUTO_MTC)
|
||||
set(AUTOMTC_SRC ${TARGET_NAME}_automtc.cpp)
|
||||
|
||||
file(GLOB INCLUDE_FILES src/*.h)
|
||||
|
||||
if (NOT ANDROID)
|
||||
set(MTC_EXECUTABLE mtc)
|
||||
else ()
|
||||
set(MTC_EXECUTABLE $ENV{MTC_PATH}/mtc)
|
||||
endif ()
|
||||
|
||||
add_custom_command(OUTPUT ${AUTOMTC_SRC} COMMAND ${MTC_EXECUTABLE} -o ${AUTOMTC_SRC} ${INCLUDE_FILES} DEPENDS ${MTC_EXECUTABLE} ${INCLUDE_FILES})
|
||||
endmacro()
|
|
@ -1,77 +1,92 @@
|
|||
#
|
||||
#
|
||||
# AutoScribeShader.cmake
|
||||
#
|
||||
#
|
||||
# Created by Sam Gateau on 12/17/14.
|
||||
# Copyright 2014 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
#
|
||||
|
||||
function(AUTOSCRIBE_SHADER SHADER_FILE)
|
||||
|
||||
# Grab include files
|
||||
foreach(includeFile ${ARGN})
|
||||
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
|
||||
endforeach()
|
||||
# Grab include files
|
||||
foreach(includeFile ${ARGN})
|
||||
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
|
||||
endforeach()
|
||||
|
||||
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
|
||||
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
|
||||
endforeach()
|
||||
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
|
||||
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
|
||||
endforeach()
|
||||
|
||||
#Extract the unique include shader paths
|
||||
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
|
||||
#message(${TARGET_NAME} Hifi for includes ${INCLUDES})
|
||||
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
|
||||
endforeach()
|
||||
|
||||
#Extract the unique include shader paths
|
||||
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
|
||||
#message(${TARGET_NAME} Hifi for includes ${INCLUDES})
|
||||
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
|
||||
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
|
||||
endforeach()
|
||||
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
|
||||
#message(ready for includes ${SHADER_INCLUDES_PATHS})
|
||||
|
||||
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
|
||||
#message(ready for includes ${SHADER_INCLUDES_PATHS})
|
||||
# make the scribe include arguments
|
||||
set(SCRIBE_INCLUDES)
|
||||
foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS})
|
||||
set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/)
|
||||
endforeach()
|
||||
|
||||
# make the scribe include arguments
|
||||
set(SCRIBE_INCLUDES)
|
||||
foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS})
|
||||
set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/)
|
||||
endforeach()
|
||||
# Define the final name of the generated shader file
|
||||
get_filename_component(SHADER_TARGET ${SHADER_FILE} NAME_WE)
|
||||
get_filename_component(SHADER_EXT ${SHADER_FILE} EXT)
|
||||
if(SHADER_EXT STREQUAL .slv)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_vert.h)
|
||||
elseif(${SHADER_EXT} STREQUAL .slf)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_frag.h)
|
||||
elseif(${SHADER_EXT} STREQUAL .slg)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_geom.h)
|
||||
endif()
|
||||
|
||||
# Define the final name of the generated shader file
|
||||
get_filename_component(SHADER_TARGET ${SHADER_FILE} NAME_WE)
|
||||
get_filename_component(SHADER_EXT ${SHADER_FILE} EXT)
|
||||
if(SHADER_EXT STREQUAL .slv)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_vert.h)
|
||||
elseif(${SHADER_EXT} STREQUAL .slf)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_frag.h)
|
||||
elseif(${SHADER_EXT} STREQUAL .slg)
|
||||
set(SHADER_TARGET ${SHADER_TARGET}_geom.h)
|
||||
endif()
|
||||
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_TARGET}")
|
||||
|
||||
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_TARGET}")
|
||||
# Target dependant Custom rule on the SHADER_FILE
|
||||
if (APPLE)
|
||||
set(GLPROFILE MAC_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
|
||||
# Target dependant Custom rule on the SHADER_FILE
|
||||
if (APPLE)
|
||||
set(GLPROFILE MAC_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
elseif (ANDROID)
|
||||
set(GLPROFILE LINUX_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
elseif (UNIX)
|
||||
set(GLPROFILE LINUX_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
# for an android build, we can't use the scribe that cmake would normally produce as a target,
|
||||
# since it's unrunnable by the cross-compiling build machine
|
||||
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
else ()
|
||||
set(GLPROFILE PC_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
# so, we require the compiling user to point us at a compiled executable version for their native toolchain
|
||||
find_program(NATIVE_SCRIBE scribe PATHS ${SCRIBE_PATH} ENV SCRIBE_PATH)
|
||||
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
endif()
|
||||
if (NOT NATIVE_SCRIBE)
|
||||
message(FATAL_ERROR "The High Fidelity scribe tool is required for shader pre-processing. \
|
||||
Please compile scribe using your native toolchain and set SCRIBE_PATH to the path containing the scribe executable in your ENV.\
|
||||
")
|
||||
endif ()
|
||||
|
||||
#output the generated file name
|
||||
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE)
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND ${NATIVE_SCRIBE} ${SCRIBE_ARGS} DEPENDS ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
elseif (UNIX)
|
||||
set(GLPROFILE LINUX_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
|
||||
file(GLOB INCLUDE_FILES ${SHADER_TARGET})
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
else ()
|
||||
set(GLPROFILE PC_GL)
|
||||
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||
|
||||
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
|
||||
endif()
|
||||
|
||||
#output the generated file name
|
||||
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE)
|
||||
|
||||
file(GLOB INCLUDE_FILES ${SHADER_TARGET})
|
||||
|
||||
endfunction()
|
||||
|
||||
|
@ -79,11 +94,11 @@ endfunction()
|
|||
macro(AUTOSCRIBE_SHADER_LIB)
|
||||
set(HIFI_LIBRARIES_SHADER_INCLUDE_FILES "")
|
||||
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
|
||||
foreach(HIFI_LIBRARY ${ARGN})
|
||||
foreach(HIFI_LIBRARY ${ARGN})
|
||||
#if (NOT TARGET ${HIFI_LIBRARY})
|
||||
# file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}/src/)
|
||||
#endif ()
|
||||
|
||||
|
||||
#file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src/*.slh)
|
||||
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src)
|
||||
endforeach()
|
||||
|
@ -99,9 +114,9 @@ macro(AUTOSCRIBE_SHADER_LIB)
|
|||
#message("${TARGET_NAME} ${SHADER_INCLUDE_FILES}")
|
||||
set(AUTOSCRIBE_SHADER_SRC "")
|
||||
foreach(SHADER_FILE ${SHADER_SOURCE_FILES})
|
||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
||||
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
|
||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
||||
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
|
||||
endforeach()
|
||||
#message(${TARGET_NAME} ${AUTOSCRIBE_SHADER_SRC})
|
||||
|
||||
|
@ -118,4 +133,4 @@ macro(AUTOSCRIBE_SHADER_LIB)
|
|||
# Link library shaders, if they exist
|
||||
include_directories("${SHADERS_DIR}")
|
||||
|
||||
endmacro()
|
||||
endmacro()
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#
|
||||
#
|
||||
# SetupHifiLibrary.cmake
|
||||
#
|
||||
#
|
||||
# Copyright 2013 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
#
|
||||
|
||||
macro(SETUP_HIFI_LIBRARY)
|
||||
|
||||
|
||||
project(${TARGET_NAME})
|
||||
|
||||
|
||||
# grab the implementation and header files
|
||||
file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c")
|
||||
list(APPEND ${TARGET_NAME}_SRCS ${LIB_SRCS})
|
||||
|
@ -34,19 +34,19 @@ macro(SETUP_HIFI_LIBRARY)
|
|||
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS "-mavx2 -mfma")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
|
||||
setup_memory_debugger()
|
||||
|
||||
# create a library and set the property so it can be referenced later
|
||||
if (${${TARGET_NAME}_SHARED})
|
||||
add_library(${TARGET_NAME} SHARED ${LIB_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
|
||||
add_library(${TARGET_NAME} SHARED ${LIB_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
|
||||
else ()
|
||||
add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
|
||||
add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
|
||||
endif ()
|
||||
|
||||
|
||||
set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN})
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
|
||||
|
||||
|
||||
# find these Qt modules and link them to our own target
|
||||
find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED)
|
||||
|
||||
|
@ -59,7 +59,7 @@ macro(SETUP_HIFI_LIBRARY)
|
|||
set(QT_RESOURCES_FILE "")
|
||||
|
||||
target_glm()
|
||||
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Libraries")
|
||||
|
||||
endmacro(SETUP_HIFI_LIBRARY)
|
||||
|
||||
endmacro(SETUP_HIFI_LIBRARY)
|
||||
|
|
|
@ -22,7 +22,7 @@ macro(SETUP_HIFI_PROJECT)
|
|||
endif ()
|
||||
endforeach()
|
||||
|
||||
add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC})
|
||||
add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC})
|
||||
|
||||
# include the generated application version header
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")
|
||||
|
|
|
@ -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@
|
||||
|
||||
;--------------------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 WebKitWidgets)
|
||||
endif ()
|
||||
|
||||
find_package(
|
||||
Qt5 COMPONENTS
|
||||
Gui Multimedia Network OpenGL Qml Quick Script ScriptTools 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
|
||||
|
@ -95,7 +124,7 @@ if (APPLE)
|
|||
|
||||
# make sure the output name for the .app bundle is correct
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${INTERFACE_BUNDLE_NAME})
|
||||
elseif(WIN32)
|
||||
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 +133,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 +142,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")
|
||||
|
||||
|
@ -135,21 +167,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()
|
||||
|
@ -291,3 +334,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 ()
|
||||
|
|
|
@ -28,7 +28,7 @@ Rectangle {
|
|||
color: hifi.colors.baseGrayShadow
|
||||
property var currentUrl: "https://metaverse.highfidelity.com/marketplace"
|
||||
|
||||
Controls.WebView {
|
||||
Controls.BaseWebView {
|
||||
id: webview
|
||||
url: currentUrl
|
||||
anchors.top: switchMarketView.bottom
|
||||
|
|
68
interface/resources/qml/controls-uit/BaseWebView.qml
Normal file
68
interface/resources/qml/controls-uit/BaseWebView.qml
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// WebView.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 12 Jan 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtWebEngine 1.1
|
||||
|
||||
WebEngineView {
|
||||
id: root
|
||||
property var newUrl;
|
||||
|
||||
profile.httpUserAgent: "Mozilla/5.0 Chrome/38.0 (HighFidelityInterface)"
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging")
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
|
||||
Timer {
|
||||
id: urlReplacementTimer
|
||||
running: false
|
||||
repeat: false
|
||||
interval: 50
|
||||
onTriggered: url = newUrl;
|
||||
}
|
||||
|
||||
onUrlChanged: {
|
||||
var originalUrl = url.toString();
|
||||
newUrl = urlHandler.fixupUrl(originalUrl).toString();
|
||||
if (newUrl !== originalUrl) {
|
||||
root.stop();
|
||||
if (urlReplacementTimer.running) {
|
||||
console.warn("Replacement timer already running");
|
||||
return;
|
||||
}
|
||||
urlReplacementTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
onLoadingChanged: {
|
||||
// Required to support clicking on "hifi://" links
|
||||
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
|
||||
var url = loadRequest.url.toString();
|
||||
if (urlHandler.canHandleUrl(url)) {
|
||||
if (urlHandler.handleUrl(url)) {
|
||||
root.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6
|
||||
// See https://bugreports.qt.io/browse/QTBUG-49521
|
||||
//profile: desktop.browserProfile
|
||||
}
|
|
@ -9,60 +9,12 @@
|
|||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtWebEngine 1.1
|
||||
import "."
|
||||
|
||||
WebEngineView {
|
||||
id: root
|
||||
property var newUrl;
|
||||
|
||||
profile.httpUserAgent: "Mozilla/5.0 Chrome/38.0 (HighFidelityInterface)"
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging")
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
BaseWebView {
|
||||
onNewViewRequested: {
|
||||
var component = Qt.createComponent("../Browser.qml");
|
||||
var newWindow = component.createObject(desktop);
|
||||
request.openIn(newWindow.webView)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
|
||||
Timer {
|
||||
id: urlReplacementTimer
|
||||
running: false
|
||||
repeat: false
|
||||
interval: 50
|
||||
onTriggered: url = newUrl;
|
||||
}
|
||||
|
||||
onUrlChanged: {
|
||||
var originalUrl = url.toString();
|
||||
newUrl = urlHandler.fixupUrl(originalUrl).toString();
|
||||
if (newUrl !== originalUrl) {
|
||||
root.stop();
|
||||
if (urlReplacementTimer.running) {
|
||||
console.warn("Replacement timer already running");
|
||||
return;
|
||||
}
|
||||
urlReplacementTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
onLoadingChanged: {
|
||||
// Required to support clicking on "hifi://" links
|
||||
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
|
||||
var url = loadRequest.url.toString();
|
||||
if (urlHandler.canHandleUrl(url)) {
|
||||
if (urlHandler.handleUrl(url)) {
|
||||
root.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6
|
||||
// See https://bugreports.qt.io/browse/QTBUG-49521
|
||||
//profile: desktop.browserProfile
|
||||
}
|
||||
|
|
|
@ -4318,18 +4318,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)
|
||||
}
|
||||
|
||||
|
@ -4348,8 +4344,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 {
|
||||
|
|
|
@ -29,7 +29,9 @@ void ConnectionMonitor::init() {
|
|||
|
||||
_timer.setSingleShot(true);
|
||||
_timer.setInterval(DISPLAY_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
_timer.start();
|
||||
if (!domainHandler.isConnected()) {
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||
connect(&_timer, &QTimer::timeout, dialogsManager.data(), &DialogsManager::showAddressBar);
|
||||
|
|
|
@ -111,7 +111,7 @@ void DiscoverabilityManager::updateLocation() {
|
|||
}
|
||||
|
||||
// Update Steam
|
||||
SteamClient::updateLocation(domainHandler.getHostname(), addressManager->currentFacingAddress());
|
||||
SteamClient::updateLocation(domainHandler.getHostname(), addressManager->currentFacingShareableAddress());
|
||||
}
|
||||
|
||||
void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply) {
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// InterfaceActivity.java
|
||||
// gvr-interface/java
|
||||
//
|
||||
// Created by Stephen Birarda on 1/26/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
package io.highfidelity.gvrinterface;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
import android.util.Log;
|
||||
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||
|
||||
public class InterfaceActivity extends QtActivity {
|
||||
|
||||
public static native void handleHifiURL(String hifiURLString);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
||||
// Get the intent that started this activity in case we have a hifi:// URL to parse
|
||||
Intent intent = getIntent();
|
||||
if (intent.getAction() == Intent.ACTION_VIEW) {
|
||||
Uri data = intent.getData();
|
||||
|
||||
if (data.getScheme().equals("hifi")) {
|
||||
handleHifiURL(data.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,3 +1,8 @@
|
|||
set(TARGET_NAME audio)
|
||||
setup_hifi_library(Network)
|
||||
|
||||
if (ANDROID)
|
||||
add_definitions("-D__STDC_CONSTANT_MACROS")
|
||||
endif ()
|
||||
|
||||
link_hifi_libraries(networking shared plugins)
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AudioInjector.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDataStream>
|
||||
|
||||
|
@ -24,8 +26,6 @@
|
|||
#include "SoundCache.h"
|
||||
#include "AudioSRC.h"
|
||||
|
||||
#include "AudioInjector.h"
|
||||
|
||||
int audioInjectorPtrMetaTypeId = qRegisterMetaType<AudioInjector*>();
|
||||
|
||||
AudioInjectorState operator& (AudioInjectorState lhs, AudioInjectorState rhs) {
|
||||
|
@ -52,7 +52,7 @@ AudioInjector::AudioInjector(const Sound& sound, const AudioInjectorOptions& inj
|
|||
|
||||
AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions) :
|
||||
_audioData(audioData),
|
||||
_options(injectorOptions)
|
||||
_options(injectorOptions)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ bool AudioInjector::stateHas(AudioInjectorState state) const {
|
|||
}
|
||||
|
||||
void AudioInjector::setOptions(const AudioInjectorOptions& options) {
|
||||
// since options.stereo is computed from the audio stream,
|
||||
// since options.stereo is computed from the audio stream,
|
||||
// we need to copy it from existing options just in case.
|
||||
bool currentlyStereo = _options.stereo;
|
||||
_options = options;
|
||||
|
@ -71,7 +71,7 @@ void AudioInjector::setOptions(const AudioInjectorOptions& options) {
|
|||
|
||||
void AudioInjector::finishNetworkInjection() {
|
||||
_state |= AudioInjectorState::NetworkInjectionFinished;
|
||||
|
||||
|
||||
// if we are already finished with local
|
||||
// injection, then we are finished
|
||||
if(stateHas(AudioInjectorState::LocalInjectionFinished)) {
|
||||
|
@ -154,13 +154,13 @@ void AudioInjector::restart() {
|
|||
_hasSetup = false;
|
||||
_shouldStop = false;
|
||||
_state = AudioInjectorState::NotFinished;
|
||||
|
||||
|
||||
// call inject audio to start injection over again
|
||||
setupInjection();
|
||||
|
||||
// inject locally
|
||||
if(injectLocally()) {
|
||||
|
||||
|
||||
// if not localOnly, wake the AudioInjectorManager back up if it is stuck waiting
|
||||
if (!_options.localOnly) {
|
||||
|
||||
|
@ -221,7 +221,7 @@ qint64 writeStringToStream(const QString& string, QDataStream& stream) {
|
|||
stream << static_cast<quint32>(length);
|
||||
} else {
|
||||
// http://doc.qt.io/qt-5/datastreamformat.html
|
||||
// QDataStream << QByteArray -
|
||||
// QDataStream << QByteArray -
|
||||
// If the byte array is null : 0xFFFFFFFF (quint32)
|
||||
// Otherwise : the array size(quint32) followed by the array bytes, i.e.size bytes
|
||||
stream << data;
|
||||
|
@ -239,7 +239,7 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
static int positionOptionOffset = -1;
|
||||
static int volumeOptionOffset = -1;
|
||||
static int audioDataOffset = -1;
|
||||
|
||||
|
||||
if (!_currentPacket) {
|
||||
if (_currentSendOffset < 0 ||
|
||||
_currentSendOffset >= _audioData.size()) {
|
||||
|
@ -277,7 +277,7 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
|
||||
// current injectors don't use codecs, so pack in the unknown codec name
|
||||
QString noCodecForInjectors("");
|
||||
writeStringToStream(noCodecForInjectors, audioPacketStream);
|
||||
writeStringToStream(noCodecForInjectors, audioPacketStream);
|
||||
|
||||
// pack stream identifier (a generated UUID)
|
||||
audioPacketStream << QUuid::createUuid();
|
||||
|
@ -286,7 +286,7 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
audioPacketStream << _options.stereo;
|
||||
|
||||
// pack the flag for loopback. Now, we don't loopback
|
||||
// and _always_ play locally, so loopbackFlag should be
|
||||
// and _always_ play locally, so loopbackFlag should be
|
||||
// false always.
|
||||
uchar loopbackFlag = (uchar)false;
|
||||
audioPacketStream << loopbackFlag;
|
||||
|
@ -365,7 +365,7 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
_currentSendOffset = 0;
|
||||
}
|
||||
}
|
||||
// FIXME -- good place to call codec encode here. We need to figure out how to tell the AudioInjector which
|
||||
// FIXME -- good place to call codec encode here. We need to figure out how to tell the AudioInjector which
|
||||
// codec to use... possible through AbstractAudioInterface.
|
||||
QByteArray encodedAudio = decodedAudio;
|
||||
_currentPacket->write(encodedAudio.data(), encodedAudio.size());
|
||||
|
@ -407,7 +407,7 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
}
|
||||
|
||||
int64_t playNextFrameAt = ++_nextFrame * AudioConstants::NETWORK_FRAME_USECS;
|
||||
|
||||
|
||||
return std::max(INT64_C(0), playNextFrameAt - currentTime);
|
||||
}
|
||||
|
||||
|
@ -491,7 +491,7 @@ AudioInjector* AudioInjector::playSound(const QByteArray& buffer, const AudioInj
|
|||
|
||||
// we always inject locally, except when there is no localInterface
|
||||
injector->injectLocally();
|
||||
|
||||
|
||||
// if localOnly, we are done, just return injector.
|
||||
if (!options.localOnly) {
|
||||
|
||||
|
|
|
@ -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})
|
||||
|
||||
|
|
|
@ -7,4 +7,6 @@ target_opengl()
|
|||
|
||||
GroupSources("src/display-plugins")
|
||||
|
||||
target_oglplus()
|
||||
if (NOT ANDROID)
|
||||
target_oglplus()
|
||||
endif ()
|
||||
|
|
|
@ -52,7 +52,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
_viewState(viewState),
|
||||
_scriptingServices(scriptingServices),
|
||||
_displayModelBounds(false),
|
||||
_dontDoPrecisionPicking(false)
|
||||
_dontDoPrecisionPicking(false),
|
||||
_layeredZones(this)
|
||||
{
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
|
||||
|
@ -135,8 +136,8 @@ void EntityTreeRenderer::clear() {
|
|||
_entitiesInScene.clear();
|
||||
|
||||
// reset the zone to the default (while we load the next scene)
|
||||
_bestZone = nullptr;
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
_layeredZones.clear();
|
||||
applyZoneAndHasSkybox(nullptr);
|
||||
|
||||
OctreeRenderer::clear();
|
||||
}
|
||||
|
@ -192,10 +193,10 @@ void EntityTreeRenderer::update() {
|
|||
|
||||
// If we haven't already updated and previously attempted to load a texture,
|
||||
// check if the texture loaded and apply it
|
||||
if (!updated && (
|
||||
(_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())) ||
|
||||
(_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())))) {
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
if (!updated &&
|
||||
((_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())) ||
|
||||
(_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())))) {
|
||||
applySkyboxAndHasAmbient();
|
||||
}
|
||||
|
||||
// Even if we're not moving the mouse, if we started clicking on an entity and we have
|
||||
|
@ -210,7 +211,7 @@ void EntityTreeRenderer::update() {
|
|||
deleteReleasedModels();
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar) {
|
||||
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar) {
|
||||
bool didUpdate = false;
|
||||
float radius = 0.01f; // for now, assume 0.01 meter radius, because we actually check the point inside later
|
||||
QVector<EntityItemPointer> foundEntities;
|
||||
|
@ -220,12 +221,10 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3&
|
|||
_tree->withReadLock([&] {
|
||||
|
||||
// FIXME - if EntityTree had a findEntitiesContainingPoint() this could theoretically be a little faster
|
||||
std::static_pointer_cast<EntityTree>(_tree)->findEntities(avatarPosition, radius, foundEntities);
|
||||
std::static_pointer_cast<EntityTree>(_tree)->findEntities(_avatarPosition, radius, foundEntities);
|
||||
|
||||
// Whenever you're in an intersection between zones, we will always choose the smallest zone.
|
||||
auto oldBestZone = _bestZone;
|
||||
_bestZone = nullptr; // NOTE: Is this what we want?
|
||||
_bestZoneVolume = std::numeric_limits<float>::max();
|
||||
LayeredZones oldLayeredZones(std::move(_layeredZones));
|
||||
_layeredZones.clear();
|
||||
|
||||
// create a list of entities that actually contain the avatar's position
|
||||
for (auto& entity : foundEntities) {
|
||||
|
@ -239,38 +238,34 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3&
|
|||
if (isZone || hasScript) {
|
||||
// now check to see if the point contains our entity, this can be expensive if
|
||||
// the entity has a collision hull
|
||||
if (entity->contains(avatarPosition)) {
|
||||
if (entity->contains(_avatarPosition)) {
|
||||
if (entitiesContainingAvatar) {
|
||||
*entitiesContainingAvatar << entity->getEntityItemID();
|
||||
}
|
||||
|
||||
// if this entity is a zone and visible, determine if it is the bestZone
|
||||
if (isZone && entity->getVisible()) {
|
||||
float entityVolumeEstimate = entity->getVolumeEstimate();
|
||||
if (entityVolumeEstimate < _bestZoneVolume) {
|
||||
_bestZoneVolume = entityVolumeEstimate;
|
||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
} else if (entityVolumeEstimate == _bestZoneVolume) {
|
||||
// in the case of the volume being equal, we will use the
|
||||
// EntityItemID to deterministically pick one entity over the other
|
||||
if (!_bestZone) {
|
||||
_bestZoneVolume = entityVolumeEstimate;
|
||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
} else if (entity->getEntityItemID() < _bestZone->getEntityItemID()) {
|
||||
_bestZoneVolume = entityVolumeEstimate;
|
||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
}
|
||||
}
|
||||
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
|
||||
_layeredZones.insert(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_bestZone != oldBestZone) {
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
didUpdate = true;
|
||||
// check if our layered zones have changed
|
||||
if (_layeredZones.empty()) {
|
||||
if (oldLayeredZones.empty()) {
|
||||
return;
|
||||
}
|
||||
} else if (!oldLayeredZones.empty()) {
|
||||
if (_layeredZones.contains(oldLayeredZones)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_layeredZones.apply();
|
||||
didUpdate = true;
|
||||
});
|
||||
|
||||
return didUpdate;
|
||||
}
|
||||
|
||||
|
@ -286,13 +281,14 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
// if some amount of time has elapsed since we last checked. We check the time
|
||||
// elapsed because zones or entities might have been created "around us" while we've
|
||||
// been stationary
|
||||
auto movedEnough = glm::distance(avatarPosition, _lastAvatarPosition) > ZONE_CHECK_DISTANCE;
|
||||
auto movedEnough = glm::distance(avatarPosition, _avatarPosition) > ZONE_CHECK_DISTANCE;
|
||||
auto enoughTimeElapsed = (now - _lastZoneCheck) > ZONE_CHECK_INTERVAL;
|
||||
|
||||
if (movedEnough || enoughTimeElapsed) {
|
||||
_avatarPosition = avatarPosition;
|
||||
_lastZoneCheck = now;
|
||||
QVector<EntityItemID> entitiesContainingAvatar;
|
||||
didUpdate = findBestZoneAndMaybeContainingEntities(avatarPosition, &entitiesContainingAvatar);
|
||||
didUpdate = findBestZoneAndMaybeContainingEntities(&entitiesContainingAvatar);
|
||||
|
||||
// Note: at this point we don't need to worry about the tree being locked, because we only deal with
|
||||
// EntityItemIDs from here. The callEntityScriptMethod() method is robust against attempting to call scripts
|
||||
|
@ -318,7 +314,6 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
}
|
||||
}
|
||||
_currentEntitiesInside = entitiesContainingAvatar;
|
||||
_lastAvatarPosition = avatarPosition;
|
||||
}
|
||||
}
|
||||
return didUpdate;
|
||||
|
@ -342,24 +337,20 @@ void EntityTreeRenderer::leaveAllEntities() {
|
|||
void EntityTreeRenderer::forceRecheckEntities() {
|
||||
// make sure our "last avatar position" is something other than our current position,
|
||||
// so that on our next chance, we'll check for enter/leave entity events.
|
||||
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||
_avatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||
}
|
||||
|
||||
|
||||
void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone) {
|
||||
bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto sceneStage = scene->getStage();
|
||||
auto skyStage = scene->getSkyStage();
|
||||
auto sceneKeyLight = sceneStage->getKeyLight();
|
||||
|
||||
// Skybox and procedural skybox data
|
||||
auto skybox = std::dynamic_pointer_cast<ProceduralSkybox>(skyStage->getSkybox());
|
||||
|
||||
// If there is no zone, use the default background
|
||||
if (!zone) {
|
||||
_zoneUserData = QString();
|
||||
skybox->clear();
|
||||
skyStage->getSkybox()->clear();
|
||||
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
|
@ -371,7 +362,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
sceneKeyLight->setAmbientMap(nullptr);
|
||||
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the keylight
|
||||
|
@ -394,90 +385,127 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
}
|
||||
|
||||
// Set the ambient texture
|
||||
bool isAmbientTextureSet = false;
|
||||
if (zone->getKeyLightProperties().getAmbientURL().isEmpty()) {
|
||||
_ambientTextureURL = zone->getKeyLightProperties().getAmbientURL();
|
||||
if (_ambientTextureURL.isEmpty()) {
|
||||
_pendingAmbientTexture = false;
|
||||
_ambientTexture.clear();
|
||||
} else {
|
||||
_ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), NetworkTexture::CUBE_TEXTURE);
|
||||
_pendingAmbientTexture = true;
|
||||
|
||||
if (_ambientTexture && _ambientTexture->isLoaded()) {
|
||||
_pendingAmbientTexture = false;
|
||||
|
||||
auto texture = _ambientTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
isAmbientTextureSet = true;
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << zone->getKeyLightProperties().getAmbientURL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the skybox texture
|
||||
return layerZoneAndHasSkybox(zone);
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
|
||||
assert(zone);
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto skyStage = scene->getSkyStage();
|
||||
auto skybox = skyStage->getSkybox();
|
||||
|
||||
bool hasSkybox = false;
|
||||
|
||||
switch (zone->getBackgroundMode()) {
|
||||
case BACKGROUND_MODE_SKYBOX: {
|
||||
case BACKGROUND_MODE_SKYBOX:
|
||||
hasSkybox = true;
|
||||
|
||||
skybox->setColor(zone->getSkyboxProperties().getColorVec3());
|
||||
|
||||
if (_zoneUserData != zone->getUserData()) {
|
||||
_zoneUserData = zone->getUserData();
|
||||
skybox->parse(_zoneUserData);
|
||||
std::dynamic_pointer_cast<ProceduralSkybox>(skybox)->parse(_zoneUserData);
|
||||
}
|
||||
if (zone->getSkyboxProperties().getURL().isEmpty()) {
|
||||
skybox->setCubemap(nullptr);
|
||||
|
||||
_skyboxTextureURL = zone->getSkyboxProperties().getURL();
|
||||
if (_skyboxTextureURL.isEmpty()) {
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
} else {
|
||||
// Update the Texture of the Skybox with the one pointed by this zone
|
||||
_skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), NetworkTexture::CUBE_TEXTURE);
|
||||
_pendingSkyboxTexture = true;
|
||||
|
||||
if (_skyboxTexture && _skyboxTexture->isLoaded()) {
|
||||
_pendingSkyboxTexture = false;
|
||||
|
||||
auto texture = _skyboxTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
skybox->setCubemap(texture);
|
||||
if (!isAmbientTextureSet) {
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
isAmbientTextureSet = true;
|
||||
}
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load skybox texture:" << zone->getSkyboxProperties().getURL();
|
||||
skybox->setCubemap(nullptr);
|
||||
}
|
||||
} else {
|
||||
skybox->setCubemap(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
applySkyboxAndHasAmbient();
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BACKGROUND_MODE_INHERIT:
|
||||
default:
|
||||
// Clear the skybox to release its textures
|
||||
_zoneUserData = QString();
|
||||
skybox->clear();
|
||||
_zoneUserData = QString();
|
||||
|
||||
_skyboxTexture.clear();
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
|
||||
// Let the application background through
|
||||
if (isAmbientTextureSet) {
|
||||
if (applySkyboxAndHasAmbient()) {
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_TEXTURE);
|
||||
} else {
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isAmbientTextureSet) {
|
||||
return hasSkybox;
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::applySkyboxAndHasAmbient() {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto sceneStage = scene->getStage();
|
||||
auto skyStage = scene->getSkyStage();
|
||||
auto sceneKeyLight = sceneStage->getKeyLight();
|
||||
auto skybox = skyStage->getSkybox();
|
||||
|
||||
bool isAmbientSet = false;
|
||||
if (_pendingAmbientTexture && !_ambientTexture) {
|
||||
_ambientTexture = textureCache->getTexture(_ambientTextureURL, NetworkTexture::CUBE_TEXTURE);
|
||||
}
|
||||
if (_ambientTexture && _ambientTexture->isLoaded()) {
|
||||
_pendingAmbientTexture = false;
|
||||
|
||||
auto texture = _ambientTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
isAmbientSet = true;
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << _ambientTexture->getURL();
|
||||
}
|
||||
}
|
||||
|
||||
if (_pendingSkyboxTexture && !_skyboxTexture) {
|
||||
_skyboxTexture = textureCache->getTexture(_skyboxTextureURL, NetworkTexture::CUBE_TEXTURE);
|
||||
}
|
||||
if (_skyboxTexture && _skyboxTexture->isLoaded()) {
|
||||
_pendingSkyboxTexture = false;
|
||||
|
||||
auto texture = _skyboxTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
skybox->setCubemap(texture);
|
||||
if (!isAmbientSet) {
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
isAmbientSet = true;
|
||||
}
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load skybox texture:" << _skyboxTexture->getURL();
|
||||
skybox->setCubemap(nullptr);
|
||||
}
|
||||
} else {
|
||||
skybox->setCubemap(nullptr);
|
||||
}
|
||||
|
||||
if (!isAmbientSet) {
|
||||
sceneKeyLight->resetAmbientSphere();
|
||||
sceneKeyLight->setAmbientMap(nullptr);
|
||||
}
|
||||
|
||||
return isAmbientSet;
|
||||
}
|
||||
|
||||
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) {
|
||||
|
@ -528,14 +556,13 @@ ModelPointer EntityTreeRenderer::allocateModel(const QString& url, float loading
|
|||
return model;
|
||||
}
|
||||
|
||||
ModelPointer EntityTreeRenderer::updateModel(ModelPointer model, const QString& newUrl, const QString& collisionUrl) {
|
||||
ModelPointer EntityTreeRenderer::updateModel(ModelPointer model, const QString& newUrl) {
|
||||
// Only create and delete models on the thread that owns the EntityTreeRenderer
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateModel", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(ModelPointer, model),
|
||||
Q_ARG(ModelPointer, model),
|
||||
Q_ARG(const QString&, newUrl),
|
||||
Q_ARG(const QString&, collisionUrl));
|
||||
Q_ARG(const QString&, newUrl));
|
||||
|
||||
return model;
|
||||
}
|
||||
|
@ -1046,21 +1073,128 @@ void EntityTreeRenderer::updateEntityRenderStatus(bool shouldRenderEntities) {
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::updateZone(const EntityItemID& id) {
|
||||
if (!_bestZone) {
|
||||
// Get in the zone!
|
||||
auto zone = getTree()->findEntityByEntityItemID(id);
|
||||
if (zone && zone->contains(_lastAvatarPosition)) {
|
||||
_currentEntitiesInside << id;
|
||||
emit enterEntity(id);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(id, "enterEntity");
|
||||
}
|
||||
if (zone->getVisible()) {
|
||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_bestZone && _bestZone->getID() == id) {
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
// Get in the zone!
|
||||
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(getTree()->findEntityByEntityItemID(id));
|
||||
if (zone && zone->contains(_avatarPosition)) {
|
||||
_layeredZones.update(zone);
|
||||
}
|
||||
}
|
||||
|
||||
EntityTreeRenderer::LayeredZones::LayeredZones(LayeredZones&& other) {
|
||||
// In a swap:
|
||||
// > All iterators and references remain valid. The past-the-end iterator is invalidated.
|
||||
bool isSkyboxLayerValid = (other._skyboxLayer != other.end());
|
||||
|
||||
swap(other);
|
||||
_map.swap(other._map);
|
||||
_skyboxLayer = other._skyboxLayer;
|
||||
|
||||
if (!isSkyboxLayerValid) {
|
||||
_skyboxLayer = end();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::clear() {
|
||||
std::set<LayeredZone>::clear();
|
||||
_map.clear();
|
||||
_skyboxLayer = end();
|
||||
}
|
||||
|
||||
std::pair<EntityTreeRenderer::LayeredZones::iterator, bool> EntityTreeRenderer::LayeredZones::insert(const LayeredZone& layer) {
|
||||
iterator it;
|
||||
bool success;
|
||||
std::tie(it, success) = std::set<LayeredZone>::insert(layer);
|
||||
|
||||
if (success) {
|
||||
_map.emplace(it->id, it);
|
||||
}
|
||||
|
||||
return { it, success };
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::apply() {
|
||||
assert(_entityTreeRenderer);
|
||||
|
||||
applyPartial(begin());
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::update(std::shared_ptr<ZoneEntityItem> zone) {
|
||||
assert(_entityTreeRenderer);
|
||||
bool isVisible = zone->isVisible();
|
||||
|
||||
if (empty() && isVisible) {
|
||||
// there are no zones: set this one
|
||||
insert(zone);
|
||||
apply();
|
||||
return;
|
||||
} else {
|
||||
LayeredZone zoneLayer(zone);
|
||||
|
||||
// should we update? only if this zone is tighter than the current skybox zone
|
||||
bool shouldUpdate = false;
|
||||
if (_skyboxLayer == end() || zoneLayer <= *_skyboxLayer) {
|
||||
shouldUpdate = true;
|
||||
}
|
||||
|
||||
// find this zone's layer, if it exists
|
||||
iterator layer = end();
|
||||
auto it = _map.find(zoneLayer.id);
|
||||
if (it != _map.end()) {
|
||||
layer = it->second;
|
||||
// if the volume changed, we need to resort the layer (reinsertion)
|
||||
// if the visibility changed, we need to erase the layer
|
||||
if (zoneLayer.volume != layer->volume || !isVisible) {
|
||||
erase(layer);
|
||||
_map.erase(it);
|
||||
layer = end();
|
||||
}
|
||||
}
|
||||
|
||||
// (re)insert this zone's layer if necessary
|
||||
if (layer == end() && isVisible) {
|
||||
std::tie(layer, std::ignore) = insert(zoneLayer);
|
||||
_map.emplace(layer->id, layer);
|
||||
}
|
||||
|
||||
if (shouldUpdate) {
|
||||
applyPartial(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::applyPartial(iterator layer) {
|
||||
bool hasSkybox = false;
|
||||
_skyboxLayer = end();
|
||||
|
||||
if (layer == end()) {
|
||||
if (empty()) {
|
||||
_entityTreeRenderer->applyZoneAndHasSkybox(nullptr);
|
||||
return;
|
||||
} else { // a layer was removed - reapply from beginning
|
||||
layer = begin();
|
||||
}
|
||||
}
|
||||
|
||||
if (layer == begin()) {
|
||||
hasSkybox = _entityTreeRenderer->applyZoneAndHasSkybox(layer->zone);
|
||||
} else {
|
||||
hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone);
|
||||
}
|
||||
|
||||
if (layer != end()) {
|
||||
while (!hasSkybox && ++layer != end()) {
|
||||
hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone);
|
||||
}
|
||||
}
|
||||
|
||||
_skyboxLayer = layer;
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::LayeredZones::contains(const LayeredZones& other) {
|
||||
bool result = std::equal(other.begin(), other._skyboxLayer, begin());
|
||||
if (result) {
|
||||
// if valid, set the _skyboxLayer from the other LayeredZones
|
||||
_skyboxLayer = std::next(begin(), std::distance(other.begin(), other._skyboxLayer));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
Q_INVOKABLE ModelPointer allocateModel(const QString& url, float loadingPriority = 0.0f);
|
||||
|
||||
/// if a renderable entity item needs to update the URL of a model, we will handle that for the entity
|
||||
Q_INVOKABLE ModelPointer updateModel(ModelPointer original, const QString& newUrl, const QString& collisionUrl);
|
||||
Q_INVOKABLE ModelPointer updateModel(ModelPointer original, const QString& newUrl);
|
||||
|
||||
/// if a renderable entity item is done with a model, it should return it to us
|
||||
void releaseModel(ModelPointer model);
|
||||
|
@ -95,7 +95,7 @@ public:
|
|||
// For Scene.shouldRenderEntities
|
||||
QList<EntityItemID>& getEntitiesLastInScene() { return _entityIDsLastInScene; }
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _bestZone; }
|
||||
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _layeredZones.getZone(); }
|
||||
|
||||
signals:
|
||||
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
|
@ -138,9 +138,12 @@ private:
|
|||
void resetEntitiesScriptEngine();
|
||||
|
||||
void addEntityToScene(EntityItemPointer entity);
|
||||
bool findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar);
|
||||
bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr);
|
||||
|
||||
bool applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||
bool layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||
bool applySkyboxAndHasAmbient();
|
||||
|
||||
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
|
||||
void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false);
|
||||
|
||||
QList<ModelPointer> _releasedModels;
|
||||
|
@ -156,15 +159,9 @@ private:
|
|||
void leaveAllEntities();
|
||||
void forceRecheckEntities();
|
||||
|
||||
glm::vec3 _lastAvatarPosition { 0.0f };
|
||||
glm::vec3 _avatarPosition { 0.0f };
|
||||
QVector<EntityItemID> _currentEntitiesInside;
|
||||
|
||||
bool _pendingSkyboxTexture { false };
|
||||
NetworkTexturePointer _skyboxTexture;
|
||||
|
||||
bool _pendingAmbientTexture { false };
|
||||
NetworkTexturePointer _ambientTexture;
|
||||
|
||||
bool _wantScripts;
|
||||
QSharedPointer<ScriptEngine> _entitiesScriptEngine;
|
||||
|
||||
|
@ -185,26 +182,62 @@ private:
|
|||
|
||||
QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> _bestZone;
|
||||
float _bestZoneVolume;
|
||||
class LayeredZone {
|
||||
public:
|
||||
LayeredZone(std::shared_ptr<ZoneEntityItem> zone, QUuid id, float volume) : zone(zone), id(id), volume(volume) {}
|
||||
LayeredZone(std::shared_ptr<ZoneEntityItem> zone) : LayeredZone(zone, zone->getID(), zone->getVolumeEstimate()) {}
|
||||
|
||||
bool operator<(const LayeredZone& r) const { return std::tie(volume, id) < std::tie(r.volume, r.id); }
|
||||
bool operator==(const LayeredZone& r) const { return id == r.id; }
|
||||
bool operator<=(const LayeredZone& r) const { return (*this < r) || (*this == r); }
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> zone;
|
||||
QUuid id;
|
||||
float volume;
|
||||
};
|
||||
|
||||
class LayeredZones : public std::set<LayeredZone> {
|
||||
public:
|
||||
LayeredZones(EntityTreeRenderer* parent) : _entityTreeRenderer(parent) {}
|
||||
LayeredZones(LayeredZones&& other);
|
||||
|
||||
// avoid accidental misconstruction
|
||||
LayeredZones() = delete;
|
||||
LayeredZones(const LayeredZones&) = delete;
|
||||
LayeredZones& operator=(const LayeredZones&) = delete;
|
||||
LayeredZones& operator=(LayeredZones&&) = delete;
|
||||
|
||||
void clear();
|
||||
std::pair<iterator, bool> insert(const LayeredZone& layer);
|
||||
|
||||
void apply();
|
||||
void update(std::shared_ptr<ZoneEntityItem> zone);
|
||||
|
||||
bool contains(const LayeredZones& other);
|
||||
|
||||
std::shared_ptr<ZoneEntityItem> getZone() { return empty() ? nullptr : begin()->zone; }
|
||||
|
||||
private:
|
||||
void applyPartial(iterator layer);
|
||||
|
||||
std::map<QUuid, iterator> _map;
|
||||
iterator _skyboxLayer{ end() };
|
||||
EntityTreeRenderer* _entityTreeRenderer;
|
||||
};
|
||||
|
||||
LayeredZones _layeredZones;
|
||||
QString _zoneUserData;
|
||||
NetworkTexturePointer _ambientTexture;
|
||||
NetworkTexturePointer _skyboxTexture;
|
||||
QString _ambientTextureURL;
|
||||
QString _skyboxTextureURL;
|
||||
bool _pendingAmbientTexture { false };
|
||||
bool _pendingSkyboxTexture { false };
|
||||
|
||||
quint64 _lastZoneCheck { 0 };
|
||||
const quint64 ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz
|
||||
const float ZONE_CHECK_DISTANCE = 0.001f;
|
||||
|
||||
glm::vec3 _previousKeyLightColor;
|
||||
float _previousKeyLightIntensity;
|
||||
float _previousKeyLightAmbientIntensity;
|
||||
glm::vec3 _previousKeyLightDirection;
|
||||
bool _previousStageSunModelEnabled;
|
||||
float _previousStageLongitude;
|
||||
float _previousStageLatitude;
|
||||
float _previousStageAltitude;
|
||||
float _previousStageHour;
|
||||
int _previousStageDay;
|
||||
|
||||
QHash<EntityItemID, EntityItemPointer> _entitiesInScene;
|
||||
// For Scene.shouldRenderEntities
|
||||
QList<EntityItemID> _entityIDsLastInScene;
|
||||
|
|
|
@ -548,6 +548,15 @@ EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlag
|
|||
if (_originalTexturesRead) {
|
||||
properties.setTextureNames(_originalTextures);
|
||||
}
|
||||
|
||||
if (_model) {
|
||||
properties.setRenderInfoVertexCount(_model->getRenderInfoVertexCount());
|
||||
properties.setRenderInfoTextureCount(_model->getRenderInfoTextureCount());
|
||||
properties.setRenderInfoTextureSize(_model->getRenderInfoTextureSize());
|
||||
properties.setRenderInfoDrawCalls(_model->getRenderInfoDrawCalls());
|
||||
properties.setRenderInfoHasTransparent(_model->getRenderInfoHasTransparent());
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -580,6 +580,24 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID);
|
||||
|
||||
// Rendering info
|
||||
if (!skipDefaults) {
|
||||
QScriptValue renderInfo = engine->newObject();
|
||||
|
||||
// currently only supported by models
|
||||
if (_type == EntityTypes::Model) {
|
||||
renderInfo.setProperty("verticesCount", (int)getRenderInfoVertexCount()); // FIXME - theoretically the number of vertex could be > max int
|
||||
renderInfo.setProperty("texturesSize", (int)getRenderInfoTextureSize()); // FIXME - theoretically the size of textures could be > max int
|
||||
renderInfo.setProperty("hasTransparent", getRenderInfoHasTransparent());
|
||||
renderInfo.setProperty("drawCalls", getRenderInfoDrawCalls());
|
||||
}
|
||||
|
||||
if (_type == EntityTypes::Model || _type == EntityTypes::PolyLine || _type == EntityTypes::ParticleEffect) {
|
||||
renderInfo.setProperty("texturesCount", QScriptValue(_textureNames.count()));
|
||||
}
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(renderInfo, renderInfo); // Gettable but not settable
|
||||
}
|
||||
|
||||
properties.setProperty("clientOnly", convertScriptValue(engine, getClientOnly()));
|
||||
properties.setProperty("owningAvatarID", convertScriptValue(engine, getOwningAvatarID()));
|
||||
|
||||
|
|
|
@ -285,6 +285,19 @@ public:
|
|||
void setJointRotationsDirty() { _jointRotationsSetChanged = true; _jointRotationsChanged = true; }
|
||||
void setJointTranslationsDirty() { _jointTranslationsSetChanged = true; _jointTranslationsChanged = true; }
|
||||
|
||||
// render info related items
|
||||
size_t getRenderInfoVertexCount() const { return _renderInfoVertexCount; }
|
||||
void setRenderInfoVertexCount(size_t value) { _renderInfoVertexCount = value; }
|
||||
int getRenderInfoTextureCount() const { return _renderInfoTextureCount; }
|
||||
void setRenderInfoTextureCount(int value) { _renderInfoTextureCount = value; }
|
||||
size_t getRenderInfoTextureSize() const { return _renderInfoTextureSize; }
|
||||
void setRenderInfoTextureSize(size_t value) { _renderInfoTextureSize = value; }
|
||||
int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; }
|
||||
void setRenderInfoDrawCalls(int value) { _renderInfoDrawCalls = value; }
|
||||
bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; }
|
||||
void setRenderInfoHasTransparent(bool value) { _renderInfoHasTransparent = value; }
|
||||
|
||||
|
||||
protected:
|
||||
QString getCollisionMaskAsString() const;
|
||||
void setCollisionMaskFromString(const QString& maskString);
|
||||
|
@ -308,6 +321,12 @@ private:
|
|||
glm::vec3 _naturalDimensions;
|
||||
glm::vec3 _naturalPosition;
|
||||
|
||||
size_t _renderInfoVertexCount { 0 };
|
||||
int _renderInfoTextureCount { 0 };
|
||||
size_t _renderInfoTextureSize { 0 };
|
||||
int _renderInfoDrawCalls { 0 };
|
||||
bool _renderInfoHasTransparent { false };
|
||||
|
||||
EntityPropertyFlags _desiredProperties; // if set will narrow scopes of copy/to/from to just these properties
|
||||
};
|
||||
|
||||
|
|
|
@ -140,17 +140,35 @@ QVariant parseBinaryFBXProperty(QDataStream& in, int& position) {
|
|||
}
|
||||
}
|
||||
|
||||
FBXNode parseBinaryFBXNode(QDataStream& in, int& position) {
|
||||
qint32 endOffset;
|
||||
quint32 propertyCount;
|
||||
quint32 propertyListLength;
|
||||
FBXNode parseBinaryFBXNode(QDataStream& in, int& position, bool has64BitPositions = false) {
|
||||
qint64 endOffset;
|
||||
quint64 propertyCount;
|
||||
quint64 propertyListLength;
|
||||
quint8 nameLength;
|
||||
|
||||
in >> endOffset;
|
||||
in >> propertyCount;
|
||||
in >> propertyListLength;
|
||||
// FBX 2016 and beyond uses 64bit positions in the node headers, pre-2016 used 32bit values
|
||||
// our code generally doesn't care about the size that much, so we will use 64bit values
|
||||
// from here on out, but if the file is an older format we read the stream into temp 32bit
|
||||
// values and then assign to our actual 64bit values.
|
||||
if (has64BitPositions) {
|
||||
in >> endOffset;
|
||||
in >> propertyCount;
|
||||
in >> propertyListLength;
|
||||
position += sizeof(quint64) * 3;
|
||||
} else {
|
||||
qint32 tempEndOffset;
|
||||
quint32 tempPropertyCount;
|
||||
quint32 tempPropertyListLength;
|
||||
in >> tempEndOffset;
|
||||
in >> tempPropertyCount;
|
||||
in >> tempPropertyListLength;
|
||||
position += sizeof(quint32) * 3;
|
||||
endOffset = tempEndOffset;
|
||||
propertyCount = tempPropertyCount;
|
||||
propertyListLength = tempPropertyListLength;
|
||||
}
|
||||
in >> nameLength;
|
||||
position += sizeof(quint32) * 3 + sizeof(quint8);
|
||||
position += sizeof(quint8);
|
||||
|
||||
FBXNode node;
|
||||
const int MIN_VALID_OFFSET = 40;
|
||||
|
@ -166,7 +184,7 @@ FBXNode parseBinaryFBXNode(QDataStream& in, int& position) {
|
|||
}
|
||||
|
||||
while (endOffset > position) {
|
||||
FBXNode child = parseBinaryFBXNode(in, position);
|
||||
FBXNode child = parseBinaryFBXNode(in, position, has64BitPositions);
|
||||
if (child.name.isNull()) {
|
||||
return node;
|
||||
|
||||
|
@ -327,15 +345,24 @@ FBXNode FBXReader::parseFBX(QIODevice* device) {
|
|||
// see http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ for an explanation
|
||||
// of the FBX binary format
|
||||
|
||||
// skip the rest of the header
|
||||
const int HEADER_SIZE = 27;
|
||||
in.skipRawData(HEADER_SIZE);
|
||||
int position = HEADER_SIZE;
|
||||
// The first 27 bytes contain the header.
|
||||
// Bytes 0 - 20: Kaydara FBX Binary \x00(file - magic, with 2 spaces at the end, then a NULL terminator).
|
||||
// Bytes 21 - 22: [0x1A, 0x00](unknown but all observed files show these bytes).
|
||||
// Bytes 23 - 26 : unsigned int, the version number. 7300 for version 7.3 for example.
|
||||
const int HEADER_BEFORE_VERSION = 23;
|
||||
const quint32 VERSION_FBX2016 = 7500;
|
||||
in.skipRawData(HEADER_BEFORE_VERSION);
|
||||
int position = HEADER_BEFORE_VERSION;
|
||||
quint32 fileVersion;
|
||||
in >> fileVersion;
|
||||
position += sizeof(fileVersion);
|
||||
qDebug() << "fileVersion:" << fileVersion;
|
||||
bool has64BitPositions = (fileVersion >= VERSION_FBX2016);
|
||||
|
||||
// parse the top-level node
|
||||
FBXNode top;
|
||||
while (device->bytesAvailable()) {
|
||||
FBXNode next = parseBinaryFBXNode(in, position);
|
||||
FBXNode next = parseBinaryFBXNode(in, position, has64BitPositions);
|
||||
if (next.name.isNull()) {
|
||||
return top;
|
||||
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -3,5 +3,8 @@ setup_hifi_library()
|
|||
link_hifi_libraries(shared gl gpu)
|
||||
GroupSources("src")
|
||||
|
||||
target_glew()
|
||||
target_opengl()
|
||||
target_opengl()
|
||||
|
||||
if (NOT ANDROID)
|
||||
target_glew()
|
||||
endif ()
|
||||
|
|
|
@ -25,6 +25,7 @@ void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) {
|
|||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
glGetInteger64v(GL_TIMESTAMP, (GLint64*)&glquery->_batchElapsedTime);
|
||||
if (timeElapsed) {
|
||||
glBeginQuery(GL_TIME_ELAPSED, glquery->_endqo);
|
||||
} else {
|
||||
|
@ -43,6 +44,10 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
|
|||
} else {
|
||||
glQueryCounter(glquery->_endqo, GL_TIMESTAMP);
|
||||
}
|
||||
GLint64 now;
|
||||
glGetInteger64v(GL_TIMESTAMP, &now);
|
||||
glquery->_batchElapsedTime = now - glquery->_batchElapsedTime;
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +66,7 @@ void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) {
|
|||
glGetQueryObjectui64v(glquery->_endqo, GL_QUERY_RESULT, &end);
|
||||
glquery->_result = end - start;
|
||||
}
|
||||
query->triggerReturnHandler(glquery->_result);
|
||||
query->triggerReturnHandler(glquery->_result, glquery->_batchElapsedTime);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
const GLuint& _endqo = { _id };
|
||||
const GLuint _beginqo = { 0 };
|
||||
GLuint64 _result { (GLuint64)-1 };
|
||||
GLuint64 _batchElapsedTime { (GLuint64) 0 };
|
||||
|
||||
protected:
|
||||
GLQuery(const std::weak_ptr<GLBackend>& backend, const Query& query, GLuint endId, GLuint beginId) : Parent(backend, query, endId), _beginqo(beginId) {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
set(TARGET_NAME gpu)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu)
|
||||
autoscribe_shader_lib(gpu)
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
|
|
|
@ -24,12 +24,16 @@ Query::~Query()
|
|||
{
|
||||
}
|
||||
|
||||
double Query::getElapsedTime() const {
|
||||
double Query::getGPUElapsedTime() const {
|
||||
return ((double)_queryResult) / 1000000.0;
|
||||
}
|
||||
double Query::getBatchElapsedTime() const {
|
||||
return ((double)_usecBatchElapsedTime) / 1000000.0;
|
||||
}
|
||||
|
||||
void Query::triggerReturnHandler(uint64_t queryResult) {
|
||||
void Query::triggerReturnHandler(uint64_t queryResult, uint64_t batchElapsedTime) {
|
||||
_queryResult = queryResult;
|
||||
_usecBatchElapsedTime = batchElapsedTime;
|
||||
if (_returnHandler) {
|
||||
_returnHandler(*this);
|
||||
}
|
||||
|
@ -40,8 +44,8 @@ RangeTimer::RangeTimer() {
|
|||
for (int i = 0; i < QUERY_QUEUE_SIZE; i++) {
|
||||
_timerQueries.push_back(std::make_shared<gpu::Query>([&, i] (const Query& query) {
|
||||
_tailIndex ++;
|
||||
auto elapsedTime = query.getElapsedTime();
|
||||
_movingAverage.addSample(elapsedTime);
|
||||
_movingAverageGPU.addSample(query.getGPUElapsedTime());
|
||||
_movingAverageBatch.addSample(query.getBatchElapsedTime());
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +70,10 @@ void RangeTimer::end(gpu::Batch& batch) {
|
|||
}
|
||||
}
|
||||
|
||||
double RangeTimer::getAverage() const {
|
||||
return _movingAverage.average;
|
||||
double RangeTimer::getGPUAverage() const {
|
||||
return _movingAverageGPU.average;
|
||||
}
|
||||
|
||||
double RangeTimer::getBatchAverage() const {
|
||||
return _movingAverageBatch.average;
|
||||
}
|
|
@ -30,14 +30,17 @@ namespace gpu {
|
|||
Query(const Handler& returnHandler);
|
||||
~Query();
|
||||
|
||||
double getElapsedTime() const;
|
||||
double getGPUElapsedTime() const;
|
||||
double getBatchElapsedTime() const;
|
||||
|
||||
// Only for gpu::Context
|
||||
const GPUObjectPointer gpuObject {};
|
||||
void triggerReturnHandler(uint64_t queryResult);
|
||||
void triggerReturnHandler(uint64_t queryResult, uint64_t batchElapsedTime);
|
||||
protected:
|
||||
Handler _returnHandler;
|
||||
|
||||
uint64_t _queryResult = 0;
|
||||
uint64_t _queryResult { 0 };
|
||||
uint64_t _usecBatchElapsedTime { 0 };
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Query> QueryPointer;
|
||||
|
@ -53,7 +56,8 @@ namespace gpu {
|
|||
void begin(gpu::Batch& batch);
|
||||
void end(gpu::Batch& batch);
|
||||
|
||||
double getAverage() const;
|
||||
double getGPUAverage() const;
|
||||
double getBatchAverage() const;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -62,7 +66,8 @@ namespace gpu {
|
|||
gpu::Queries _timerQueries;
|
||||
int _headIndex = -1;
|
||||
int _tailIndex = -1;
|
||||
MovingAverage<double, QUERY_QUEUE_SIZE * 2> _movingAverage;
|
||||
MovingAverage<double, QUERY_QUEUE_SIZE * 2> _movingAverageGPU;
|
||||
MovingAverage<double, QUERY_QUEUE_SIZE * 2> _movingAverageBatch;
|
||||
|
||||
int rangeIndex(int index) const { return (index % QUERY_QUEUE_SIZE); }
|
||||
};
|
||||
|
|
|
@ -26,13 +26,15 @@ Skybox::Skybox() {
|
|||
}
|
||||
|
||||
void Skybox::setColor(const Color& color) {
|
||||
_empty = false;
|
||||
_schemaBuffer.edit<Schema>().color = color;
|
||||
_empty = false;
|
||||
}
|
||||
|
||||
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
|
||||
_empty = false;
|
||||
_cubemap = cubemap;
|
||||
if (cubemap) {
|
||||
_empty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Skybox::updateSchemaBuffer() const {
|
||||
|
@ -52,9 +54,9 @@ void Skybox::updateSchemaBuffer() const {
|
|||
}
|
||||
|
||||
void Skybox::clear() {
|
||||
_empty = true;
|
||||
_schemaBuffer.edit<Schema>().color = vec3(0);
|
||||
setCubemap(nullptr);
|
||||
_cubemap = nullptr;
|
||||
_empty = true;
|
||||
}
|
||||
|
||||
void Skybox::prepare(gpu::Batch& batch, int textureSlot, int bufferSlot) const {
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
TextureMap() {}
|
||||
|
||||
void setTextureSource(gpu::TextureSourcePointer& textureSource);
|
||||
gpu::TextureSourcePointer getTextureSource() const { return _textureSource; }
|
||||
|
||||
bool isDefined() const;
|
||||
gpu::TextureView getTextureView() const;
|
||||
|
|
|
@ -56,7 +56,7 @@ JSONCallbackParameters::JSONCallbackParameters(QObject* jsonCallbackReceiver, co
|
|||
updateReciever(updateReceiver),
|
||||
updateSlot(updateSlot)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
QJsonObject AccountManager::dataObjectFromResponse(QNetworkReply &requestReply) {
|
||||
|
@ -85,7 +85,7 @@ AccountManager::AccountManager(UserAgentGetter userAgentGetter) :
|
|||
|
||||
qRegisterMetaType<QNetworkAccessManager::Operation>("QNetworkAccessManager::Operation");
|
||||
qRegisterMetaType<JSONCallbackParameters>("JSONCallbackParameters");
|
||||
|
||||
|
||||
qRegisterMetaType<QHttpMultiPart*>("QHttpMultiPart*");
|
||||
|
||||
qRegisterMetaType<AccountManagerAuth::Type>();
|
||||
|
@ -143,7 +143,7 @@ void AccountManager::setAuthURL(const QUrl& authURL) {
|
|||
_authURL = authURL;
|
||||
|
||||
qCDebug(networking) << "AccountManager URL for authenticated requests has been changed to" << qPrintable(_authURL.toString());
|
||||
|
||||
|
||||
// check if there are existing access tokens to load from settings
|
||||
QFile accountsFile { accountFilePath() };
|
||||
bool loadedMap = false;
|
||||
|
@ -434,9 +434,9 @@ void AccountManager::removeAccountFromFile() {
|
|||
}
|
||||
|
||||
bool AccountManager::hasValidAccessToken() {
|
||||
|
||||
|
||||
if (_accountInfo.getAccessToken().token.isEmpty() || _accountInfo.getAccessToken().isExpired()) {
|
||||
|
||||
|
||||
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
|
||||
qCDebug(networking) << "An access token is required for requests to" << qPrintable(_authURL.toString());
|
||||
}
|
||||
|
@ -468,7 +468,7 @@ void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken)
|
|||
} else if (!_accountInfo.getAccessToken().token.isEmpty()) {
|
||||
qCDebug(networking) << "Clearing AccountManager OAuth token.";
|
||||
}
|
||||
|
||||
|
||||
_accountInfo.setAccessToken(newOAuthToken);
|
||||
|
||||
persistAccountToFile();
|
||||
|
@ -553,7 +553,7 @@ void AccountManager::requestAccessTokenFinished() {
|
|||
_accountInfo.setAccessTokenFromJSON(rootObject);
|
||||
|
||||
emit loginComplete(rootURL);
|
||||
|
||||
|
||||
persistAccountToFile();
|
||||
|
||||
requestProfile();
|
||||
|
@ -576,7 +576,7 @@ void AccountManager::requestProfile() {
|
|||
|
||||
QUrl profileURL = _authURL;
|
||||
profileURL.setPath("/api/v1/user/profile");
|
||||
|
||||
|
||||
QNetworkRequest profileRequest(profileURL);
|
||||
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter());
|
||||
profileRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, _accountInfo.getAccessToken().authorizationHeaderValue());
|
||||
|
@ -602,7 +602,7 @@ void AccountManager::requestProfileFinished() {
|
|||
|
||||
// store the whole profile into the local settings
|
||||
persistAccountToFile();
|
||||
|
||||
|
||||
} else {
|
||||
// TODO: error handling
|
||||
qCDebug(networking) << "Error in response for profile";
|
||||
|
@ -658,14 +658,14 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI
|
|||
connect(generateThread, &QThread::finished, generateThread, &QThread::deleteLater);
|
||||
|
||||
keypairGenerator->moveToThread(generateThread);
|
||||
|
||||
|
||||
qCDebug(networking) << "Starting worker thread to generate 2048-bit RSA keypair.";
|
||||
generateThread->start();
|
||||
}
|
||||
}
|
||||
|
||||
void AccountManager::processGeneratedKeypair() {
|
||||
|
||||
|
||||
qCDebug(networking) << "Generated 2048-bit RSA keypair. Uploading public key now.";
|
||||
|
||||
RSAKeypairGenerator* keypairGenerator = qobject_cast<RSAKeypairGenerator*>(sender());
|
||||
|
@ -716,7 +716,7 @@ void AccountManager::processGeneratedKeypair() {
|
|||
|
||||
sendRequest(uploadPath, AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation,
|
||||
callbackParameters, QByteArray(), requestMultiPart);
|
||||
|
||||
|
||||
keypairGenerator->deleteLater();
|
||||
} else {
|
||||
qCWarning(networking) << "Expected processGeneratedKeypair to be called by a live RSAKeypairGenerator"
|
||||
|
|
|
@ -63,15 +63,31 @@ QUrl AddressManager::currentAddress() const {
|
|||
}
|
||||
|
||||
QUrl AddressManager::currentFacingAddress() const {
|
||||
QUrl hifiURL;
|
||||
auto hifiURL = currentAddress();
|
||||
hifiURL.setPath(currentFacingPath());
|
||||
|
||||
hifiURL.setScheme(HIFI_URL_SCHEME);
|
||||
hifiURL.setHost(_host);
|
||||
return hifiURL;
|
||||
}
|
||||
|
||||
if (_port != 0 && _port != DEFAULT_DOMAIN_SERVER_PORT) {
|
||||
hifiURL.setPort(_port);
|
||||
|
||||
QUrl AddressManager::currentShareableAddress() const {
|
||||
if (!_shareablePlaceName.isEmpty()) {
|
||||
// if we have a shareable place name use that instead of whatever the current host is
|
||||
QUrl hifiURL;
|
||||
|
||||
hifiURL.setScheme(HIFI_URL_SCHEME);
|
||||
hifiURL.setHost(_shareablePlaceName);
|
||||
|
||||
hifiURL.setPath(currentPath());
|
||||
|
||||
return hifiURL;
|
||||
} else {
|
||||
return currentAddress();
|
||||
}
|
||||
}
|
||||
|
||||
QUrl AddressManager::currentFacingShareableAddress() const {
|
||||
auto hifiURL = currentShareableAddress();
|
||||
hifiURL.setPath(currentFacingPath());
|
||||
|
||||
return hifiURL;
|
||||
|
@ -360,6 +376,7 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
|
|||
|
||||
LookupTrigger trigger = (LookupTrigger) reply.property(LOOKUP_TRIGGER_KEY).toInt();
|
||||
|
||||
|
||||
// set our current root place id to the ID that came back
|
||||
const QString PLACE_ID_KEY = "id";
|
||||
_rootPlaceID = rootMap[PLACE_ID_KEY].toUuid();
|
||||
|
@ -368,6 +385,18 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
|
|||
const QString PLACE_NAME_KEY = "name";
|
||||
QString placeName = rootMap[PLACE_NAME_KEY].toString();
|
||||
|
||||
if (placeName.isEmpty()) {
|
||||
// we didn't get a set place name, check if there is a default or temporary domain name to use
|
||||
const QString TEMPORARY_DOMAIN_NAME_KEY = "name";
|
||||
const QString DEFAULT_DOMAIN_NAME_KEY = "default_place_name";
|
||||
|
||||
if (domainObject.contains(TEMPORARY_DOMAIN_NAME_KEY)) {
|
||||
placeName = domainObject[TEMPORARY_DOMAIN_NAME_KEY].toString();
|
||||
} else if (domainObject.contains(DEFAULT_DOMAIN_NAME_KEY)) {
|
||||
placeName = domainObject[DEFAULT_DOMAIN_NAME_KEY].toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (!placeName.isEmpty()) {
|
||||
if (setHost(placeName, trigger)) {
|
||||
trigger = LookupTrigger::Internal;
|
||||
|
@ -651,6 +680,9 @@ bool AddressManager::setHost(const QString& host, LookupTrigger trigger, quint16
|
|||
|
||||
_port = port;
|
||||
|
||||
// any host change should clear the shareable place name
|
||||
_shareablePlaceName.clear();
|
||||
|
||||
if (host != _host) {
|
||||
_host = host;
|
||||
emit hostChanged(_host);
|
||||
|
@ -701,13 +733,67 @@ void AddressManager::refreshPreviousLookup() {
|
|||
}
|
||||
|
||||
void AddressManager::copyAddress() {
|
||||
QApplication::clipboard()->setText(currentAddress().toString());
|
||||
// assume that the address is being copied because the user wants a shareable address
|
||||
QApplication::clipboard()->setText(currentShareableAddress().toString());
|
||||
}
|
||||
|
||||
void AddressManager::copyPath() {
|
||||
QApplication::clipboard()->setText(currentPath());
|
||||
}
|
||||
|
||||
void AddressManager::handleShareableNameAPIResponse(QNetworkReply& requestReply) {
|
||||
// make sure that this response is for the domain we're currently connected to
|
||||
auto domainID = DependencyManager::get<NodeList>()->getDomainHandler().getUUID();
|
||||
|
||||
if (requestReply.url().toString().contains(uuidStringWithoutCurlyBraces(domainID))) {
|
||||
// check for a name or default name in the API response
|
||||
|
||||
QJsonObject responseObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||
QJsonObject domainObject = responseObject["domain"].toObject();
|
||||
|
||||
const QString DOMAIN_NAME_KEY = "name";
|
||||
const QString DOMAIN_DEFAULT_PLACE_NAME_KEY = "default_place_name";
|
||||
|
||||
bool shareableNameChanged { false };
|
||||
|
||||
if (domainObject[DOMAIN_NAME_KEY].isString()) {
|
||||
_shareablePlaceName = domainObject[DOMAIN_NAME_KEY].toString();
|
||||
shareableNameChanged = true;
|
||||
} else if (domainObject[DOMAIN_DEFAULT_PLACE_NAME_KEY].isString()) {
|
||||
_shareablePlaceName = domainObject[DOMAIN_DEFAULT_PLACE_NAME_KEY].toString();
|
||||
shareableNameChanged = true;
|
||||
}
|
||||
|
||||
if (shareableNameChanged) {
|
||||
qDebug() << "AddressManager shareable name changed to" << _shareablePlaceName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddressManager::lookupShareableNameForDomainID(const QUuid& domainID) {
|
||||
|
||||
// if we get to a domain via IP/hostname, often the address is only reachable by this client
|
||||
// and not by other clients on the LAN or Internet
|
||||
|
||||
// to work around this we use the ID to lookup the default place name, and if it exists we
|
||||
// then use that for Steam join/invite or copiable address
|
||||
|
||||
// it only makes sense to lookup a shareable default name if we don't have a place name
|
||||
if (_placeName.isEmpty()) {
|
||||
JSONCallbackParameters callbackParams;
|
||||
|
||||
// no error callback handling
|
||||
// in the case of an error we simply assume there is no default place name
|
||||
callbackParams.jsonCallbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "handleShareableNameAPIResponse";
|
||||
|
||||
DependencyManager::get<AccountManager>()->sendRequest(GET_DOMAIN_ID.arg(uuidStringWithoutCurlyBraces(domainID)),
|
||||
AccountManagerAuth::None,
|
||||
QNetworkAccessManager::GetOperation,
|
||||
callbackParams);
|
||||
}
|
||||
}
|
||||
|
||||
void AddressManager::addCurrentAddressToHistory(LookupTrigger trigger) {
|
||||
|
||||
// if we're cold starting and this is called for the first address (from settings) we don't do anything
|
||||
|
|
|
@ -60,6 +60,8 @@ public:
|
|||
|
||||
QUrl currentAddress() const;
|
||||
QUrl currentFacingAddress() const;
|
||||
QUrl currentShareableAddress() const;
|
||||
QUrl currentFacingShareableAddress() const;
|
||||
QString currentPath(bool withOrientation = true) const;
|
||||
QString currentFacingPath() const;
|
||||
|
||||
|
@ -102,6 +104,8 @@ public slots:
|
|||
void copyAddress();
|
||||
void copyPath();
|
||||
|
||||
void lookupShareableNameForDomainID(const QUuid& domainID);
|
||||
|
||||
signals:
|
||||
void lookupResultsFinished();
|
||||
void lookupResultIsOffline();
|
||||
|
@ -125,6 +129,8 @@ private slots:
|
|||
void handleAPIResponse(QNetworkReply& requestReply);
|
||||
void handleAPIError(QNetworkReply& errorReply);
|
||||
|
||||
void handleShareableNameAPIResponse(QNetworkReply& requestReply);
|
||||
|
||||
private:
|
||||
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply& reply);
|
||||
|
||||
|
@ -155,6 +161,8 @@ private:
|
|||
PositionGetter _positionGetter;
|
||||
OrientationGetter _orientationGetter;
|
||||
|
||||
QString _shareablePlaceName;
|
||||
|
||||
QStack<QUrl> _backStack;
|
||||
QStack<QUrl> _forwardStack;
|
||||
quint64 _lastBackPush = 0;
|
||||
|
|
|
@ -539,6 +539,10 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
|||
if (!_domainHandler.isConnected()) {
|
||||
_domainHandler.setUUID(domainUUID);
|
||||
_domainHandler.setIsConnected(true);
|
||||
|
||||
// in case we didn't use a place name to get to this domain,
|
||||
// give the address manager a chance to lookup a default one now
|
||||
DependencyManager::get<AddressManager>()->lookupShareableNameForDomainID(domainUUID);
|
||||
} else if (_domainHandler.getUUID() != domainUUID) {
|
||||
// Recieved packet from different domain.
|
||||
qWarning() << "IGNORING DomainList packet from" << domainUUID << "while connected to" << _domainHandler.getUUID();
|
||||
|
|
|
@ -32,25 +32,25 @@ PacketQueue::PacketPointer PacketQueue::takePacket() {
|
|||
if (isEmpty()) {
|
||||
return PacketPointer();
|
||||
}
|
||||
|
||||
|
||||
// Find next non empty channel
|
||||
if (_channels[nextIndex()].empty()) {
|
||||
nextIndex();
|
||||
}
|
||||
auto& channel = _channels[_currentIndex];
|
||||
Q_ASSERT(!channel.empty());
|
||||
|
||||
|
||||
// Take front packet
|
||||
auto packet = std::move(channel.front());
|
||||
channel.pop_front();
|
||||
|
||||
|
||||
// Remove now empty channel (Don't remove the main channel)
|
||||
if (channel.empty() && _currentIndex != 0) {
|
||||
channel.swap(_channels.back());
|
||||
_channels.pop_back();
|
||||
--_currentIndex;
|
||||
}
|
||||
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ void PacketQueue::queuePacketList(PacketListPointer packetList) {
|
|||
if (packetList->isOrdered()) {
|
||||
packetList->preparePackets(getNextMessageNumber());
|
||||
}
|
||||
|
||||
|
||||
LockGuard locker(_packetsLock);
|
||||
_channels.push_back(std::move(packetList->_packets));
|
||||
}
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
|
||||
#include "Socket.h"
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <LogHandler.h>
|
||||
|
@ -30,10 +34,10 @@ Socket::Socket(QObject* parent) :
|
|||
_synTimer(new QTimer(this))
|
||||
{
|
||||
connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams);
|
||||
|
||||
|
||||
// make sure our synchronization method is called every SYN interval
|
||||
connect(_synTimer, &QTimer::timeout, this, &Socket::rateControlSync);
|
||||
|
||||
|
||||
// start our timer for the synchronization time interval
|
||||
_synTimer->start(_synInterval);
|
||||
|
||||
|
@ -60,7 +64,7 @@ void Socket::bind(const QHostAddress& address, quint16 port) {
|
|||
|
||||
void Socket::rebind() {
|
||||
quint16 oldPort = _udpSocket.localPort();
|
||||
|
||||
|
||||
_udpSocket.close();
|
||||
bind(QHostAddress::AnyIPv4, oldPort);
|
||||
}
|
||||
|
@ -69,26 +73,26 @@ void Socket::setSystemBufferSizes() {
|
|||
for (int i = 0; i < 2; i++) {
|
||||
QAbstractSocket::SocketOption bufferOpt;
|
||||
QString bufferTypeString;
|
||||
|
||||
|
||||
int numBytes = 0;
|
||||
|
||||
|
||||
if (i == 0) {
|
||||
bufferOpt = QAbstractSocket::SendBufferSizeSocketOption;
|
||||
numBytes = udt::UDP_SEND_BUFFER_SIZE_BYTES;
|
||||
bufferTypeString = "send";
|
||||
|
||||
|
||||
} else {
|
||||
bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption;
|
||||
numBytes = udt::UDP_RECEIVE_BUFFER_SIZE_BYTES;
|
||||
bufferTypeString = "receive";
|
||||
}
|
||||
|
||||
|
||||
int oldBufferSize = _udpSocket.socketOption(bufferOpt).toInt();
|
||||
|
||||
|
||||
if (oldBufferSize < numBytes) {
|
||||
_udpSocket.setSocketOption(bufferOpt, QVariant(numBytes));
|
||||
int newBufferSize = _udpSocket.socketOption(bufferOpt).toInt();
|
||||
|
||||
|
||||
qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to"
|
||||
<< newBufferSize << "bytes";
|
||||
} else {
|
||||
|
@ -101,29 +105,29 @@ void Socket::setSystemBufferSizes() {
|
|||
|
||||
qint64 Socket::writeBasePacket(const udt::BasePacket& packet, const HifiSockAddr &sockAddr) {
|
||||
// Since this is a base packet we have no way to know if this is reliable or not - we just fire it off
|
||||
|
||||
|
||||
// this should not be called with an instance of Packet
|
||||
Q_ASSERT_X(!dynamic_cast<const Packet*>(&packet),
|
||||
"Socket::writeBasePacket", "Cannot send a Packet/NLPacket via writeBasePacket");
|
||||
|
||||
|
||||
return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr);
|
||||
}
|
||||
|
||||
qint64 Socket::writePacket(const Packet& packet, const HifiSockAddr& sockAddr) {
|
||||
Q_ASSERT_X(!packet.isReliable(), "Socket::writePacket", "Cannot send a reliable packet unreliably");
|
||||
|
||||
|
||||
// write the correct sequence number to the Packet here
|
||||
packet.writeSequenceNumber(++_unreliableSequenceNumbers[sockAddr]);
|
||||
|
||||
|
||||
return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr);
|
||||
}
|
||||
|
||||
qint64 Socket::writePacket(std::unique_ptr<Packet> packet, const HifiSockAddr& sockAddr) {
|
||||
|
||||
|
||||
if (packet->isReliable()) {
|
||||
// hand this packet off to writeReliablePacket
|
||||
// because Qt can't invoke with the unique_ptr we have to release it here and re-construct in writeReliablePacket
|
||||
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "writeReliablePacket", Qt::QueuedConnection,
|
||||
Q_ARG(Packet*, packet.release()),
|
||||
|
@ -131,10 +135,10 @@ qint64 Socket::writePacket(std::unique_ptr<Packet> packet, const HifiSockAddr& s
|
|||
} else {
|
||||
writeReliablePacket(packet.release(), sockAddr);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return writePacket(*packet, sockAddr);
|
||||
}
|
||||
|
||||
|
@ -142,7 +146,7 @@ qint64 Socket::writePacketList(std::unique_ptr<PacketList> packetList, const Hif
|
|||
if (packetList->isReliable()) {
|
||||
// hand this packetList off to writeReliablePacketList
|
||||
// because Qt can't invoke with the unique_ptr we have to release it here and re-construct in writeReliablePacketList
|
||||
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
auto ptr = packetList.release();
|
||||
QMetaObject::invokeMethod(this, "writeReliablePacketList", Qt::AutoConnection,
|
||||
|
@ -151,7 +155,7 @@ qint64 Socket::writePacketList(std::unique_ptr<PacketList> packetList, const Hif
|
|||
} else {
|
||||
writeReliablePacketList(packetList.release(), sockAddr);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -177,18 +181,18 @@ qint64 Socket::writeDatagram(const char* data, qint64 size, const HifiSockAddr&
|
|||
}
|
||||
|
||||
qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr) {
|
||||
|
||||
|
||||
qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort());
|
||||
|
||||
|
||||
if (bytesWritten < 0) {
|
||||
// when saturating a link this isn't an uncommon message - suppress it so it doesn't bomb the debug
|
||||
static const QString WRITE_ERROR_REGEX = "Socket::writeDatagram QAbstractSocket::NetworkError - Unable to send a message";
|
||||
static QString repeatedMessage
|
||||
= LogHandler::getInstance().addRepeatedMessageRegex(WRITE_ERROR_REGEX);
|
||||
|
||||
|
||||
qCDebug(networking) << "Socket::writeDatagram" << _udpSocket.error() << "-" << qPrintable(_udpSocket.errorString());
|
||||
}
|
||||
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
|
@ -199,17 +203,17 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) {
|
|||
auto congestionControl = _ccFactory->create();
|
||||
congestionControl->setMaxBandwidth(_maxBandwidth);
|
||||
auto connection = std::unique_ptr<Connection>(new Connection(this, sockAddr, std::move(congestionControl)));
|
||||
|
||||
|
||||
// we queue the connection to cleanup connection in case it asks for it during its own rate control sync
|
||||
QObject::connect(connection.get(), &Connection::connectionInactive, this, &Socket::cleanupConnection);
|
||||
|
||||
|
||||
#ifdef UDT_CONNECTION_DEBUG
|
||||
qCDebug(networking) << "Creating new connection to" << sockAddr;
|
||||
#endif
|
||||
|
||||
|
||||
it = _connectionsHash.insert(it, std::make_pair(sockAddr, std::move(connection)));
|
||||
}
|
||||
|
||||
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
|
@ -228,7 +232,7 @@ void Socket::clearConnections() {
|
|||
|
||||
void Socket::cleanupConnection(HifiSockAddr sockAddr) {
|
||||
auto numErased = _connectionsHash.erase(sockAddr);
|
||||
|
||||
|
||||
if (numErased > 0) {
|
||||
#ifdef UDT_CONNECTION_DEBUG
|
||||
qCDebug(networking) << "Socket::cleanupConnection called for UDT connection to" << sockAddr;
|
||||
|
@ -253,10 +257,10 @@ void Socket::readPendingDatagrams() {
|
|||
while ((packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1) {
|
||||
// setup a HifiSockAddr to read into
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
|
||||
// setup a buffer to read the packet into
|
||||
auto buffer = std::unique_ptr<char[]>(new char[packetSizeWithHeader]);
|
||||
|
||||
|
||||
// pull the datagram
|
||||
auto sizeRead = _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader,
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
|
@ -266,34 +270,34 @@ void Socket::readPendingDatagrams() {
|
|||
// on windows even if there's not a packet available)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
auto it = _unfilteredHandlers.find(senderSockAddr);
|
||||
|
||||
|
||||
if (it != _unfilteredHandlers.end()) {
|
||||
// we have a registered unfiltered handler for this HifiSockAddr - call that and return
|
||||
if (it->second) {
|
||||
auto basePacket = BasePacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr);
|
||||
it->second(std::move(basePacket));
|
||||
}
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// check if this was a control packet or a data packet
|
||||
bool isControlPacket = *reinterpret_cast<uint32_t*>(buffer.get()) & CONTROL_BIT_MASK;
|
||||
|
||||
|
||||
if (isControlPacket) {
|
||||
// setup a control packet from the data we just read
|
||||
auto controlPacket = ControlPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr);
|
||||
|
||||
|
||||
// move this control packet to the matching connection
|
||||
auto& connection = findOrCreateConnection(senderSockAddr);
|
||||
connection.processControl(move(controlPacket));
|
||||
|
||||
|
||||
} else {
|
||||
// setup a Packet from the data we just read
|
||||
auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr);
|
||||
|
||||
|
||||
// call our verification operator to see if this packet is verified
|
||||
if (!_packetFilterOperator || _packetFilterOperator(*packet)) {
|
||||
if (packet->isReliable()) {
|
||||
|
@ -328,27 +332,27 @@ void Socket::connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* r
|
|||
}
|
||||
|
||||
void Socket::rateControlSync() {
|
||||
|
||||
|
||||
// enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control
|
||||
|
||||
|
||||
// the way we do this is a little funny looking - we need to avoid the case where we call sync and
|
||||
// (because of our Qt direct connection to the Connection's signal that it has been deactivated)
|
||||
// an iterator on _connectionsHash would be invalidated by our own call to cleanupConnection
|
||||
|
||||
|
||||
// collect the sockets for all connections in a vector
|
||||
|
||||
|
||||
std::vector<HifiSockAddr> sockAddrVector;
|
||||
sockAddrVector.reserve(_connectionsHash.size());
|
||||
|
||||
|
||||
for (auto& connection : _connectionsHash) {
|
||||
sockAddrVector.emplace_back(connection.first);
|
||||
}
|
||||
|
||||
|
||||
// enumerate that vector of HifiSockAddr objects
|
||||
for (auto& sockAddr : sockAddrVector) {
|
||||
// pull out the respective connection via a quick find on the unordered_map
|
||||
auto it = _connectionsHash.find(sockAddr);
|
||||
|
||||
|
||||
if (it != _connectionsHash.end()) {
|
||||
// if the connection is erased while calling sync since we are re-using the iterator that was invalidated
|
||||
// we're good to go
|
||||
|
@ -356,7 +360,7 @@ void Socket::rateControlSync() {
|
|||
connection->sync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_synTimer->interval() != _synInterval) {
|
||||
// if the _synTimer interval doesn't match the current _synInterval (changes when the CC factory is changed)
|
||||
// then restart it now with the right interval
|
||||
|
@ -367,7 +371,7 @@ void Socket::rateControlSync() {
|
|||
void Socket::setCongestionControlFactory(std::unique_ptr<CongestionControlVirtualFactory> ccFactory) {
|
||||
// swap the current unique_ptr for the new factory
|
||||
_ccFactory.swap(ccFactory);
|
||||
|
||||
|
||||
// update the _synInterval to the value from the factory
|
||||
_synInterval = _ccFactory->synInterval();
|
||||
}
|
||||
|
@ -402,10 +406,10 @@ Socket::StatsVector Socket::sampleStatsForAllConnections() {
|
|||
}
|
||||
|
||||
|
||||
std::vector<HifiSockAddr> Socket::getConnectionSockAddrs() {
|
||||
std::vector<HifiSockAddr> Socket::getConnectionSockAddrs() {
|
||||
std::vector<HifiSockAddr> addr;
|
||||
addr.reserve(_connectionsHash.size());
|
||||
|
||||
|
||||
for (const auto& connectionPair : _connectionsHash) {
|
||||
addr.push_back(connectionPair.first);
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@ btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info) {
|
|||
btIndexedMesh mesh;
|
||||
const int32_t VERTICES_PER_TRIANGLE = 3;
|
||||
mesh.m_numTriangles = numIndices / VERTICES_PER_TRIANGLE;
|
||||
if (numIndices < INT16_MAX) {
|
||||
if (numIndices < std::numeric_limits<int16_t>::max()) {
|
||||
// small number of points so we can use 16-bit indices
|
||||
mesh.m_triangleIndexBase = new unsigned char[sizeof(int16_t) * (size_t)numIndices];
|
||||
mesh.m_indexType = PHY_SHORT;
|
||||
|
@ -211,7 +211,7 @@ btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info) {
|
|||
vertexData[j + 1] = point.y;
|
||||
vertexData[j + 2] = point.z;
|
||||
}
|
||||
if (numIndices < INT16_MAX) {
|
||||
if (numIndices < std::numeric_limits<int16_t>::max()) {
|
||||
int16_t* indices = static_cast<int16_t*>((void*)(mesh.m_triangleIndexBase));
|
||||
for (int32_t i = 0; i < numIndices; ++i) {
|
||||
indices[i] = (int16_t)triangleIndices[i];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
set(TARGET_NAME plugins)
|
||||
setup_hifi_library(OpenGL)
|
||||
link_hifi_libraries(shared)
|
||||
link_hifi_libraries(shared networking)
|
||||
include_hifi_library_headers(gpu)
|
||||
|
|
|
@ -115,10 +115,42 @@ const LoaderList& getLoadedPlugins() {
|
|||
PluginManager::PluginManager() {
|
||||
}
|
||||
|
||||
extern CodecPluginList getCodecPlugins();
|
||||
|
||||
const CodecPluginList& PluginManager::getCodecPlugins() {
|
||||
static CodecPluginList codecPlugins;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
//codecPlugins = ::getCodecPlugins();
|
||||
|
||||
// Now grab the dynamic plugins
|
||||
for (auto loader : getLoadedPlugins()) {
|
||||
CodecProvider* codecProvider = qobject_cast<CodecProvider*>(loader->instance());
|
||||
if (codecProvider) {
|
||||
for (auto codecPlugin : codecProvider->getCodecPlugins()) {
|
||||
if (codecPlugin->isSupported()) {
|
||||
codecPlugins.push_back(codecPlugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto plugin : codecPlugins) {
|
||||
plugin->setContainer(_container);
|
||||
plugin->init();
|
||||
|
||||
qDebug() << "init codec:" << plugin->getName();
|
||||
}
|
||||
});
|
||||
return codecPlugins;
|
||||
}
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
|
||||
// TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class
|
||||
extern DisplayPluginList getDisplayPlugins();
|
||||
extern InputPluginList getInputPlugins();
|
||||
extern CodecPluginList getCodecPlugins();
|
||||
|
||||
extern void saveInputPluginSettings(const InputPluginList& plugins);
|
||||
static DisplayPluginList displayPlugins;
|
||||
|
||||
|
@ -137,6 +169,7 @@ const DisplayPluginList& PluginManager::getDisplayPlugins() {
|
|||
// Grab the built in plugins
|
||||
displayPlugins = ::getDisplayPlugins();
|
||||
|
||||
|
||||
// Now grab the dynamic plugins
|
||||
for (auto loader : getLoadedPlugins()) {
|
||||
DisplayProvider* displayProvider = qobject_cast<DisplayProvider*>(loader->instance());
|
||||
|
@ -204,35 +237,6 @@ const InputPluginList& PluginManager::getInputPlugins() {
|
|||
return inputPlugins;
|
||||
}
|
||||
|
||||
const CodecPluginList& PluginManager::getCodecPlugins() {
|
||||
static CodecPluginList codecPlugins;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
//codecPlugins = ::getCodecPlugins();
|
||||
|
||||
// Now grab the dynamic plugins
|
||||
for (auto loader : getLoadedPlugins()) {
|
||||
CodecProvider* codecProvider = qobject_cast<CodecProvider*>(loader->instance());
|
||||
if (codecProvider) {
|
||||
for (auto codecPlugin : codecProvider->getCodecPlugins()) {
|
||||
if (codecPlugin->isSupported()) {
|
||||
codecPlugins.push_back(codecPlugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto plugin : codecPlugins) {
|
||||
plugin->setContainer(_container);
|
||||
plugin->init();
|
||||
|
||||
qDebug() << "init codec:" << plugin->getName();
|
||||
}
|
||||
});
|
||||
return codecPlugins;
|
||||
}
|
||||
|
||||
|
||||
void PluginManager::setPreferredDisplayPlugins(const QStringList& displays) {
|
||||
preferredDisplayPlugins = displays;
|
||||
}
|
||||
|
@ -270,3 +274,5 @@ void PluginManager::disableInputs(const QStringList& inputs) {
|
|||
void PluginManager::saveSettings() {
|
||||
saveInputPluginSettings(getInputPlugins());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -100,7 +100,9 @@ bool Procedural::parseVersion(const QJsonValue& version) {
|
|||
return (_version == 1 || _version == 2);
|
||||
}
|
||||
|
||||
bool Procedural::parseUrl(const QUrl& shaderUrl) {
|
||||
bool Procedural::parseShader(const QUrl& shaderPath) {
|
||||
auto shaderUrl = ResourceManager::normalizeURL(shaderPath);
|
||||
|
||||
if (!shaderUrl.isValid()) {
|
||||
if (!shaderUrl.isEmpty()) {
|
||||
qWarning() << "Invalid shader URL: " << shaderUrl;
|
||||
|
@ -168,7 +170,6 @@ void Procedural::parse(const QJsonObject& proceduralData) {
|
|||
|
||||
auto version = proceduralData[VERSION_KEY];
|
||||
auto shaderUrl = proceduralData[URL_KEY].toString();
|
||||
shaderUrl = ResourceManager::normalizeURL(shaderUrl);
|
||||
auto uniforms = proceduralData[UNIFORMS_KEY].toObject();
|
||||
auto channels = proceduralData[CHANNELS_KEY].toArray();
|
||||
|
||||
|
@ -176,7 +177,7 @@ void Procedural::parse(const QJsonObject& proceduralData) {
|
|||
|
||||
// Run through parsing regardless of validity to clear old cached resources
|
||||
isValid = parseVersion(version) && isValid;
|
||||
isValid = parseUrl(shaderUrl) && isValid;
|
||||
isValid = parseShader(shaderUrl) && isValid;
|
||||
isValid = parseUniforms(uniforms) && isValid;
|
||||
isValid = parseTextures(channels) && isValid;
|
||||
|
||||
|
@ -221,6 +222,7 @@ bool Procedural::ready() {
|
|||
_hasStartedFade = true;
|
||||
_isFading = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ private:
|
|||
// This should only be called from the render thread, as it shares data with Procedural::prepare
|
||||
void parse(const QJsonObject&);
|
||||
bool parseVersion(const QJsonValue& version);
|
||||
bool parseUrl(const QUrl& url);
|
||||
bool parseShader(const QUrl& shaderPath);
|
||||
bool parseUniforms(const QJsonObject& uniforms);
|
||||
bool parseTextures(const QJsonArray& channels);
|
||||
|
||||
|
|
|
@ -13,7 +13,12 @@
|
|||
#include "Forward.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include <limits>
|
||||
#endif
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
|
@ -22,7 +27,13 @@ namespace recording {
|
|||
struct FrameHeader {
|
||||
using Time = uint32_t;
|
||||
|
||||
// until we use a version of visual studio that has constexpr support, we can't use numeric_limits at compile time
|
||||
#ifdef Q_OS_WIN
|
||||
static const Time INVALID_TIME = UINT32_MAX;
|
||||
#else
|
||||
static const Time INVALID_TIME = std::numeric_limits<uint32_t>::max();
|
||||
#endif
|
||||
|
||||
static const FrameType TYPE_INVALID = 0xFFFF;
|
||||
static const FrameType TYPE_HEADER = 0x0;
|
||||
|
||||
|
@ -51,7 +62,7 @@ public:
|
|||
QByteArray data;
|
||||
|
||||
Frame() {}
|
||||
Frame(FrameType type, float timeOffset, const QByteArray& data)
|
||||
Frame(FrameType type, float timeOffset, const QByteArray& data)
|
||||
: FrameHeader(type, timeOffset), data(data) { }
|
||||
|
||||
static FrameType registerFrameType(const QString& frameTypeName);
|
||||
|
|
|
@ -3,7 +3,9 @@ AUTOSCRIBE_SHADER_LIB(gpu model render)
|
|||
# pull in the resources.qrc file
|
||||
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
|
||||
setup_hifi_library(Widgets OpenGL Network Qml Quick Script)
|
||||
link_hifi_libraries(shared gpu model model-networking render animation fbx)
|
||||
link_hifi_libraries(shared gpu model model-networking render animation fbx entities)
|
||||
|
||||
target_nsight()
|
||||
target_oglplus()
|
||||
if (NOT ANDROID)
|
||||
target_nsight()
|
||||
target_oglplus()
|
||||
endif ()
|
||||
|
|
|
@ -432,7 +432,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext
|
|||
});
|
||||
|
||||
// Update the timer
|
||||
std::static_pointer_cast<Config>(renderContext->jobConfig)->gpuTime = _gpuTimer.getAverage();
|
||||
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
|
||||
config->setGPUBatchRunTime(_gpuTimer.getGPUAverage(), _gpuTimer.getBatchAverage());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ protected:
|
|||
|
||||
using AmbientOcclusionFramebufferPointer = std::shared_ptr<AmbientOcclusionFramebuffer>;
|
||||
|
||||
class AmbientOcclusionEffectConfig : public render::Job::Config::Persistent {
|
||||
class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
|
||||
Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty)
|
||||
|
@ -68,9 +68,9 @@ class AmbientOcclusionEffectConfig : public render::Job::Config::Persistent {
|
|||
Q_PROPERTY(int numSamples MEMBER numSamples WRITE setNumSamples)
|
||||
Q_PROPERTY(int resolutionLevel MEMBER resolutionLevel WRITE setResolutionLevel)
|
||||
Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius)
|
||||
Q_PROPERTY(double gpuTime READ getGpuTime)
|
||||
|
||||
public:
|
||||
AmbientOcclusionEffectConfig() : render::Job::Config::Persistent("Ambient Occlusion", false) {}
|
||||
AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent("Ambient Occlusion", false) {}
|
||||
|
||||
const int MAX_RESOLUTION_LEVEL = 4;
|
||||
const int MAX_BLUR_RADIUS = 6;
|
||||
|
@ -84,7 +84,6 @@ public:
|
|||
void setNumSamples(int samples) { numSamples = std::max(1.0f, (float)samples); emit dirty(); }
|
||||
void setResolutionLevel(int level) { resolutionLevel = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL)); emit dirty(); }
|
||||
void setBlurRadius(int radius) { blurRadius = std::max(0, std::min(MAX_BLUR_RADIUS, radius)); emit dirty(); }
|
||||
double getGpuTime() { return gpuTime; }
|
||||
|
||||
float radius{ 0.5f };
|
||||
float perspectiveScale{ 1.0f };
|
||||
|
@ -99,7 +98,6 @@ public:
|
|||
bool ditheringEnabled{ true }; // randomize the distribution of taps per pixel, should always be true
|
||||
bool borderingEnabled{ true }; // avoid evaluating information from non existing pixels out of the frame, should always be true
|
||||
bool fetchMipsEnabled{ true }; // fetch taps in sub mips to otpimize cache, should always be true
|
||||
double gpuTime{ 0.0 };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
|
|
|
@ -714,5 +714,5 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo
|
|||
});
|
||||
|
||||
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
|
||||
config->gpuTime = _gpuTimer.getAverage();
|
||||
config->setGPUBatchRunTime(_gpuTimer.getGPUAverage(), _gpuTimer.getBatchAverage());
|
||||
}
|
||||
|
|
|
@ -161,21 +161,7 @@ public:
|
|||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
};
|
||||
|
||||
|
||||
class RenderDeferredConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuTime READ getGpuTime)
|
||||
public:
|
||||
RenderDeferredConfig() : render::Job::Config(true) {}
|
||||
|
||||
double getGpuTime() { return gpuTime; }
|
||||
|
||||
double gpuTime{ 0.0 };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
using RenderDeferredConfig = render::GPUJobConfig;
|
||||
|
||||
class RenderDeferred {
|
||||
public:
|
||||
|
|
|
@ -71,8 +71,37 @@ void MeshPartPayload::updateTransform(const Transform& transform, const Transfor
|
|||
|
||||
void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) {
|
||||
_drawMaterial = drawMaterial;
|
||||
calculateMaterialSize();
|
||||
}
|
||||
|
||||
bool MeshPartPayload::calculateMaterialSize() {
|
||||
bool allTextures = true; // assume we got this...
|
||||
_materialTextureSize = 0;
|
||||
auto textureMaps = _drawMaterial->getTextureMaps();
|
||||
for (auto const &textureMapItem : textureMaps) {
|
||||
auto textureMap = textureMapItem.second;
|
||||
if (textureMap) {
|
||||
auto textureSoure = textureMap->getTextureSource();
|
||||
if (textureSoure) {
|
||||
auto texture = textureSoure->getGPUTexture();
|
||||
if (texture) {
|
||||
//auto storedSize = texture->getStoredSize();
|
||||
auto size = texture->getSize();
|
||||
_materialTextureSize += size;
|
||||
} else {
|
||||
allTextures = false;
|
||||
}
|
||||
} else {
|
||||
allTextures = false;
|
||||
}
|
||||
} else {
|
||||
allTextures = false;
|
||||
}
|
||||
}
|
||||
return allTextures;
|
||||
}
|
||||
|
||||
|
||||
ItemKey MeshPartPayload::getKey() const {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape();
|
||||
|
@ -347,8 +376,8 @@ void ModelMeshPartPayload::initCache() {
|
|||
auto networkMaterial = _model->getGeometry()->getShapeMaterial(_shapeID);
|
||||
if (networkMaterial) {
|
||||
_drawMaterial = networkMaterial;
|
||||
};
|
||||
|
||||
calculateMaterialSize();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::notifyLocationChanged() {
|
||||
|
|
|
@ -64,6 +64,13 @@ public:
|
|||
mutable model::Box _worldBound;
|
||||
|
||||
bool _hasColorAttrib = false;
|
||||
|
||||
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
|
||||
size_t getMaterialTextureSize() { return _materialTextureSize; }
|
||||
bool calculateMaterialSize();
|
||||
|
||||
protected:
|
||||
size_t _materialTextureSize { 0 };
|
||||
};
|
||||
|
||||
namespace render {
|
||||
|
|
|
@ -161,6 +161,23 @@ void Model::setOffset(const glm::vec3& offset) {
|
|||
_snappedToRegistrationPoint = false;
|
||||
}
|
||||
|
||||
size_t Model::getRenderInfoTextureSize() {
|
||||
if (!_hasCalculatedTextureSize && isLoaded() && getGeometry()->areTexturesLoaded()) {
|
||||
size_t textureSize = 0;
|
||||
bool allTexturesLoaded = true;
|
||||
foreach(auto renderItem, _modelMeshRenderItemsSet) {
|
||||
auto meshPart = renderItem.get();
|
||||
bool allTexturesForThisMesh = meshPart->calculateMaterialSize();
|
||||
allTexturesLoaded = allTexturesLoaded & allTexturesForThisMesh;
|
||||
textureSize += meshPart->getMaterialTextureSize();
|
||||
}
|
||||
_renderInfoTextureSize = textureSize;
|
||||
_hasCalculatedTextureSize = allTexturesLoaded; // only do this once
|
||||
}
|
||||
return _renderInfoTextureSize;
|
||||
}
|
||||
|
||||
|
||||
void Model::updateRenderItems() {
|
||||
if (!_addedToScene) {
|
||||
return;
|
||||
|
@ -615,16 +632,26 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
|||
}
|
||||
} else {
|
||||
if (_modelMeshRenderItems.empty()) {
|
||||
foreach (auto renderItem, _modelMeshRenderItemsSet) {
|
||||
|
||||
bool hasTransparent = false;
|
||||
size_t verticesCount = 0;
|
||||
foreach(auto renderItem, _modelMeshRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
if (statusGetters.size()) {
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
}
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
|
||||
hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent();
|
||||
verticesCount += renderItem.get()->getVerticesCount();
|
||||
_modelMeshRenderItems.insert(item, renderPayload);
|
||||
}
|
||||
somethingAdded = !_modelMeshRenderItems.empty();
|
||||
|
||||
_renderInfoVertexCount = verticesCount;
|
||||
_renderInfoDrawCalls = _modelMeshRenderItems.count();
|
||||
_renderInfoHasTransparent = hasTransparent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -650,6 +677,11 @@ void Model::removeFromScene(std::shared_ptr<render::Scene> scene, render::Pendin
|
|||
_collisionRenderItems.clear();
|
||||
_collisionRenderItemsSet.clear();
|
||||
_addedToScene = false;
|
||||
|
||||
_renderInfoVertexCount = 0;
|
||||
_renderInfoDrawCalls = 0;
|
||||
_renderInfoTextureSize = 0;
|
||||
_renderInfoHasTransparent = false;
|
||||
}
|
||||
|
||||
void Model::renderDebugMeshBoxes(gpu::Batch& batch) {
|
||||
|
@ -1332,13 +1364,21 @@ bool Model::initWhenReady(render::ScenePointer scene) {
|
|||
}
|
||||
addedPendingChanges = !_collisionRenderItems.empty();
|
||||
} else {
|
||||
bool hasTransparent = false;
|
||||
size_t verticesCount = 0;
|
||||
foreach (auto renderItem, _modelMeshRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
|
||||
hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent();
|
||||
verticesCount += renderItem.get()->getVerticesCount();
|
||||
_modelMeshRenderItems.insert(item, renderPayload);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
}
|
||||
addedPendingChanges = !_modelMeshRenderItems.empty();
|
||||
_renderInfoVertexCount = verticesCount;
|
||||
_renderInfoDrawCalls = _modelMeshRenderItems.count();
|
||||
_renderInfoHasTransparent = hasTransparent;
|
||||
}
|
||||
_addedToScene = addedPendingChanges;
|
||||
if (addedPendingChanges) {
|
||||
|
|
|
@ -232,6 +232,12 @@ public:
|
|||
|
||||
void setLoadingPriority(float priority) { _loadingPriority = priority; }
|
||||
|
||||
size_t getRenderInfoVertexCount() const { return _renderInfoVertexCount; }
|
||||
int getRenderInfoTextureCount() const { return _renderInfoTextureCount; }
|
||||
size_t getRenderInfoTextureSize();
|
||||
int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; }
|
||||
bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; }
|
||||
|
||||
public slots:
|
||||
void loadURLFinished(bool success);
|
||||
|
||||
|
@ -400,6 +406,13 @@ protected:
|
|||
|
||||
bool _renderItemsNeedUpdate { false };
|
||||
|
||||
size_t _renderInfoVertexCount { 0 };
|
||||
int _renderInfoTextureCount { 0 };
|
||||
size_t _renderInfoTextureSize { 0 };
|
||||
bool _hasCalculatedTextureSize { false };
|
||||
int _renderInfoDrawCalls { 0 };
|
||||
int _renderInfoHasTransparent { false };
|
||||
|
||||
private:
|
||||
float _loadingPriority { 0.0f };
|
||||
|
||||
|
|
|
@ -245,7 +245,7 @@ void EndGPURangeTimer::run(const render::SceneContextPointer& sceneContext, cons
|
|||
});
|
||||
|
||||
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
|
||||
config->gpuTime = timer->getAverage();
|
||||
config->setGPUBatchRunTime(timer->getGPUAverage(), timer->getBatchAverage());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,18 +29,8 @@ protected:
|
|||
gpu::RangeTimerPointer _gpuTimer;
|
||||
};
|
||||
|
||||
using GPURangeTimerConfig = render::GPUJobConfig;
|
||||
|
||||
class GPURangeTimerConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuTime READ getGpuTime)
|
||||
public:
|
||||
double getGpuTime() { return gpuTime; }
|
||||
|
||||
protected:
|
||||
friend class EndGPURangeTimer;
|
||||
double gpuTime;
|
||||
};
|
||||
|
||||
class EndGPURangeTimer {
|
||||
public:
|
||||
using Config = GPURangeTimerConfig;
|
||||
|
@ -143,16 +133,7 @@ protected:
|
|||
gpu::PipelinePointer getOpaquePipeline();
|
||||
};
|
||||
|
||||
class DrawBackgroundDeferredConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuTime READ getGpuTime)
|
||||
public:
|
||||
double getGpuTime() { return gpuTime; }
|
||||
|
||||
protected:
|
||||
friend class DrawBackgroundDeferred;
|
||||
double gpuTime;
|
||||
};
|
||||
using DrawBackgroundDeferredConfig = render::GPUJobConfig;
|
||||
|
||||
class DrawBackgroundDeferred {
|
||||
public:
|
||||
|
@ -211,16 +192,7 @@ public:
|
|||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer);
|
||||
};
|
||||
|
||||
class RenderDeferredTaskConfig : public render::Task::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuTime READ getGpuTime)
|
||||
public:
|
||||
double getGpuTime() { return gpuTime; }
|
||||
|
||||
protected:
|
||||
friend class RenderDeferredTask;
|
||||
double gpuTime;
|
||||
};
|
||||
using RenderDeferredTaskConfig = render::GPUTaskConfig;
|
||||
|
||||
class RenderDeferredTask : public render::Task {
|
||||
public:
|
||||
|
|
|
@ -201,7 +201,7 @@ void LinearDepthPass::run(const render::SceneContextPointer& sceneContext, const
|
|||
});
|
||||
|
||||
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
|
||||
config->gpuTime = _gpuTimer.getAverage();
|
||||
config->setGPUBatchRunTime(_gpuTimer.getGPUAverage(), _gpuTimer.getBatchAverage());
|
||||
}
|
||||
|
||||
|
||||
|
@ -524,7 +524,7 @@ void SurfaceGeometryPass::run(const render::SceneContextPointer& sceneContext, c
|
|||
|
||||
|
||||
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
|
||||
config->gpuTime = _gpuTimer.getAverage();
|
||||
config->setGPUBatchRunTime(_gpuTimer.getGPUAverage(), _gpuTimer.getBatchAverage());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -62,20 +62,7 @@ protected:
|
|||
|
||||
using LinearDepthFramebufferPointer = std::shared_ptr<LinearDepthFramebuffer>;
|
||||
|
||||
|
||||
class LinearDepthPassConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuTime READ getGpuTime)
|
||||
public:
|
||||
LinearDepthPassConfig() : render::Job::Config(true) {}
|
||||
|
||||
double getGpuTime() { return gpuTime; }
|
||||
|
||||
double gpuTime{ 0.0 };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
using LinearDepthPassConfig = render::GPUJobConfig;
|
||||
|
||||
class LinearDepthPass {
|
||||
public:
|
||||
|
@ -148,7 +135,7 @@ protected:
|
|||
|
||||
using SurfaceGeometryFramebufferPointer = std::shared_ptr<SurfaceGeometryFramebuffer>;
|
||||
|
||||
class SurfaceGeometryPassConfig : public render::Job::Config {
|
||||
class SurfaceGeometryPassConfig : public render::GPUJobConfig {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float depthThreshold MEMBER depthThreshold NOTIFY dirty)
|
||||
Q_PROPERTY(float basisScale MEMBER basisScale NOTIFY dirty)
|
||||
|
@ -158,9 +145,8 @@ class SurfaceGeometryPassConfig : public render::Job::Config {
|
|||
Q_PROPERTY(float diffuseFilterScale MEMBER diffuseFilterScale NOTIFY dirty)
|
||||
Q_PROPERTY(float diffuseDepthThreshold MEMBER diffuseDepthThreshold NOTIFY dirty)
|
||||
|
||||
Q_PROPERTY(double gpuTime READ getGpuTime)
|
||||
public:
|
||||
SurfaceGeometryPassConfig() : render::Job::Config(true) {}
|
||||
SurfaceGeometryPassConfig() : render::GPUJobConfig(true) {}
|
||||
|
||||
float depthThreshold{ 5.0f }; // centimeters
|
||||
float basisScale{ 1.0f };
|
||||
|
@ -169,10 +155,6 @@ public:
|
|||
float diffuseFilterScale{ 0.2f };
|
||||
float diffuseDepthThreshold{ 1.0f };
|
||||
|
||||
double getGpuTime() { return gpuTime; }
|
||||
|
||||
double gpuTime{ 0.0 };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
set(TARGET_NAME render)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model)
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries(shared gpu model)
|
||||
|
||||
# render needs octree only for getAccuracyAngle(float, int)
|
||||
link_hifi_libraries(shared gpu model octree)
|
||||
|
||||
target_nsight()
|
||||
|
|
|
@ -334,9 +334,9 @@ protected:
|
|||
// A default Config is always on; to create an enableable Config, use the ctor JobConfig(bool enabled)
|
||||
class JobConfig : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(quint64 cpuRunTime READ getCPUTRunTime NOTIFY newStats())
|
||||
Q_PROPERTY(double cpuRunTime READ getCPURunTime NOTIFY newStats()) //ms
|
||||
|
||||
quint64 _CPURunTime{ 0 };
|
||||
double _msCPURunTime{ 0.0 };
|
||||
public:
|
||||
using Persistent = PersistentConfig<JobConfig>;
|
||||
|
||||
|
@ -364,8 +364,8 @@ public:
|
|||
|
||||
// Running Time measurement
|
||||
// The new stats signal is emitted once per run time of a job when stats (cpu runtime) are updated
|
||||
void setCPURunTime(quint64 ustime) { _CPURunTime = ustime; emit newStats(); }
|
||||
quint64 getCPUTRunTime() const { return _CPURunTime; }
|
||||
void setCPURunTime(double mstime) { _msCPURunTime = mstime; emit newStats(); }
|
||||
double getCPURunTime() const { return _msCPURunTime; }
|
||||
|
||||
public slots:
|
||||
void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); emit loaded(); }
|
||||
|
@ -418,6 +418,46 @@ template <class T, class I, class O> void jobRun(T& data, const SceneContextPoin
|
|||
data.run(sceneContext, renderContext, input, output);
|
||||
}
|
||||
|
||||
class GPUJobConfig : public JobConfig {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuRunTime READ getGPURunTime)
|
||||
Q_PROPERTY(double batchRunTime READ getBatchRunTime)
|
||||
|
||||
double _msGPURunTime { 0.0 };
|
||||
double _msBatchRunTime { 0.0 };
|
||||
public:
|
||||
using Persistent = PersistentConfig<GPUJobConfig>;
|
||||
|
||||
GPUJobConfig() = default;
|
||||
GPUJobConfig(bool enabled) : JobConfig(enabled) {}
|
||||
|
||||
// Running Time measurement on GPU and for Batch execution
|
||||
void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; }
|
||||
double getGPURunTime() const { return _msGPURunTime; }
|
||||
double getBatchRunTime() const { return _msBatchRunTime; }
|
||||
};
|
||||
|
||||
class GPUTaskConfig : public TaskConfig {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double gpuRunTime READ getGPURunTime)
|
||||
Q_PROPERTY(double batchRunTime READ getBatchRunTime)
|
||||
|
||||
double _msGPURunTime { 0.0 };
|
||||
double _msBatchRunTime { 0.0 };
|
||||
public:
|
||||
|
||||
using Persistent = PersistentConfig<GPUTaskConfig>;
|
||||
|
||||
|
||||
GPUTaskConfig() = default;
|
||||
GPUTaskConfig(bool enabled) : TaskConfig(enabled) {}
|
||||
|
||||
// Running Time measurement on GPU and for Batch execution
|
||||
void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; }
|
||||
double getGPURunTime() const { return _msGPURunTime; }
|
||||
double getBatchRunTime() const { return _msBatchRunTime; }
|
||||
};
|
||||
|
||||
class Job {
|
||||
public:
|
||||
using Config = JobConfig;
|
||||
|
@ -439,7 +479,7 @@ public:
|
|||
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0;
|
||||
|
||||
protected:
|
||||
void setCPURunTime(quint64 ustime) { std::static_pointer_cast<Config>(_config)->setCPURunTime(ustime); }
|
||||
void setCPURunTime(double mstime) { std::static_pointer_cast<Config>(_config)->setCPURunTime(mstime); }
|
||||
|
||||
QConfigPointer _config;
|
||||
|
||||
|
@ -502,7 +542,7 @@ public:
|
|||
|
||||
_concept->run(sceneContext, renderContext);
|
||||
|
||||
_concept->setCPURunTime(usecTimestampNow() - start);
|
||||
_concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -3,13 +3,17 @@ setup_hifi_library(Gui Network Script ScriptTools WebSockets Widgets)
|
|||
|
||||
target_zlib()
|
||||
|
||||
add_dependency_external_projects(quazip)
|
||||
find_package(QuaZip REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${QUAZIP_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES})
|
||||
if (NOT ANDROID)
|
||||
|
||||
if (WIN32)
|
||||
add_dependency_external_projects(quazip)
|
||||
find_package(QuaZip REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${QUAZIP_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES})
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${QUAZIP_DLL_PATH})
|
||||
endif ()
|
||||
|
||||
endif ()
|
||||
|
||||
link_hifi_libraries(shared networking octree gpu ui procedural model model-networking recording avatars fbx entities controllers animation audio physics)
|
||||
|
|
|
@ -81,28 +81,43 @@ QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEve
|
|||
direction.setProperty("z", event._direction.z);
|
||||
obj.setProperty("pos3D", direction);
|
||||
|
||||
bool isPrimaryButton = false;
|
||||
bool isSecondaryButton = false;
|
||||
bool isTertiaryButton = false;
|
||||
switch (event._button) {
|
||||
case NoButtons:
|
||||
obj.setProperty("button", "None");
|
||||
break;
|
||||
case PrimaryButton:
|
||||
obj.setProperty("button", "Primary");
|
||||
isPrimaryButton = true;
|
||||
break;
|
||||
case SecondaryButton:
|
||||
obj.setProperty("button", "Secondary");
|
||||
isSecondaryButton = true;
|
||||
break;
|
||||
case TertiaryButton:
|
||||
obj.setProperty("button", "Tertiary");
|
||||
isTertiaryButton = true;
|
||||
break;
|
||||
}
|
||||
|
||||
obj.setProperty("isLeftButton", areFlagsSet(event._buttons, PrimaryButton));
|
||||
obj.setProperty("isRightButton", areFlagsSet(event._buttons, SecondaryButton));
|
||||
obj.setProperty("isMiddleButton", areFlagsSet(event._buttons, TertiaryButton));
|
||||
if (isPrimaryButton) {
|
||||
obj.setProperty("isPrimaryButton", isPrimaryButton);
|
||||
obj.setProperty("isLeftButton", isPrimaryButton);
|
||||
}
|
||||
if (isSecondaryButton) {
|
||||
obj.setProperty("isSecondaryButton", isSecondaryButton);
|
||||
obj.setProperty("isRightButton", isSecondaryButton);
|
||||
}
|
||||
if (isTertiaryButton) {
|
||||
obj.setProperty("isTertiaryButton", isTertiaryButton);
|
||||
obj.setProperty("isMiddleButton", isTertiaryButton);
|
||||
}
|
||||
|
||||
obj.setProperty("isPrimaryButton", areFlagsSet(event._buttons, PrimaryButton));
|
||||
obj.setProperty("isSecondaryButton", areFlagsSet(event._buttons, SecondaryButton));
|
||||
obj.setProperty("isTertiaryButton", areFlagsSet(event._buttons, TertiaryButton));
|
||||
obj.setProperty("isPrimaryHeld", areFlagsSet(event._buttons, PrimaryButton));
|
||||
obj.setProperty("isSecondaryHeld", areFlagsSet(event._buttons, SecondaryButton));
|
||||
obj.setProperty("isTertiaryHeld", areFlagsSet(event._buttons, TertiaryButton));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
@ -146,9 +161,9 @@ void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& eve
|
|||
event._button = NoButtons;
|
||||
}
|
||||
|
||||
bool primary = object.property("isPrimary").toBool() || object.property("isLeftButton").toBool();
|
||||
bool secondary = object.property("isSecondary").toBool() || object.property("isRightButton").toBool();
|
||||
bool tertiary = object.property("isTertiary").toBool() || object.property("isMiddleButton").toBool();
|
||||
bool primary = object.property("isPrimaryHeld").toBool();
|
||||
bool secondary = object.property("isSecondaryHeld").toBool();
|
||||
bool tertiary = object.property("isTertiaryHeld").toBool();
|
||||
event._buttons = 0;
|
||||
if (primary) {
|
||||
event._buttons |= PrimaryButton;
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace bilateral {
|
|||
case Side::Right:
|
||||
return 0x02;
|
||||
}
|
||||
return UINT8_MAX;
|
||||
return std::numeric_limits<uint8_t>::max();
|
||||
}
|
||||
|
||||
inline uint8_t index(Side side) {
|
||||
|
@ -38,7 +38,7 @@ namespace bilateral {
|
|||
case Side::Right:
|
||||
return 1;
|
||||
}
|
||||
return UINT8_MAX;
|
||||
return std::numeric_limits<uint8_t>::max();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
|
|
|
@ -11,7 +11,7 @@ file(GLOB PLUGIN_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT
|
|||
list(REMOVE_ITEM PLUGIN_SUBDIRS "CMakeFiles")
|
||||
|
||||
# client-side plugins
|
||||
if (NOT SERVER_ONLY)
|
||||
if (NOT SERVER_ONLY AND NOT ANDROID)
|
||||
set(DIR "oculus")
|
||||
add_subdirectory(${DIR})
|
||||
set(DIR "hifiSdl2")
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
set(TARGET_NAME hifiSixense)
|
||||
setup_hifi_plugin(Script Qml Widgets)
|
||||
link_hifi_libraries(shared controllers ui plugins ui-plugins input-plugins)
|
||||
target_sixense()
|
||||
if (NOT ANDROID)
|
||||
set(TARGET_NAME hifiSixense)
|
||||
setup_hifi_plugin(Script Qml Widgets)
|
||||
link_hifi_libraries(shared controllers ui plugins ui-plugins input-plugins)
|
||||
target_sixense()
|
||||
endif ()
|
||||
|
|
|
@ -75,10 +75,10 @@ Column {
|
|||
object: Render.getConfig("AmbientOcclusion")
|
||||
valueUnit: "ms"
|
||||
valueScale: 1
|
||||
valueNumDigits: "4"
|
||||
valueNumDigits: "3"
|
||||
plots: [
|
||||
{
|
||||
prop: "gpuTime",
|
||||
prop: "gpuRunTime",
|
||||
label: "gpu",
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
|
|
@ -213,8 +213,8 @@ Item {
|
|||
height: parent.evalEvenHeight()
|
||||
object: parent.drawOpaqueConfig
|
||||
valueUnit: "ms"
|
||||
valueScale: 1000
|
||||
valueNumDigits: "1"
|
||||
valueScale: 1
|
||||
valueNumDigits: "2"
|
||||
plots: [
|
||||
{
|
||||
object: Render.getConfig("DrawOpaqueDeferred"),
|
||||
|
|
|
@ -30,7 +30,7 @@ Item {
|
|||
|
||||
|
||||
PlotPerf {
|
||||
title: "Timing"
|
||||
title: "GPU Timing"
|
||||
height: parent.evalEvenHeight()
|
||||
object: parent.drawOpaqueConfig
|
||||
valueUnit: "ms"
|
||||
|
@ -39,31 +39,71 @@ Item {
|
|||
plots: [
|
||||
{
|
||||
object: Render.getConfig("OpaqueRangeTimer"),
|
||||
prop: "gpuTime",
|
||||
prop: "gpuRunTime",
|
||||
label: "Opaque",
|
||||
color: "#FFFFFF"
|
||||
},
|
||||
{
|
||||
object: Render.getConfig("LinearDepth"),
|
||||
prop: "gpuTime",
|
||||
prop: "gpuRunTime",
|
||||
label: "LinearDepth",
|
||||
color: "#00FF00"
|
||||
},{
|
||||
object: Render.getConfig("SurfaceGeometry"),
|
||||
prop: "gpuTime",
|
||||
prop: "gpuRunTime",
|
||||
label: "SurfaceGeometry",
|
||||
color: "#00FFFF"
|
||||
},
|
||||
{
|
||||
object: Render.getConfig("RenderDeferred"),
|
||||
prop: "gpuTime",
|
||||
prop: "gpuRunTime",
|
||||
label: "DeferredLighting",
|
||||
color: "#FF00FF"
|
||||
}
|
||||
,
|
||||
{
|
||||
object: Render.getConfig("ToneAndPostRangeTimer"),
|
||||
prop: "gpuTime",
|
||||
prop: "gpuRunTime",
|
||||
label: "tone and post",
|
||||
color: "#FF0000"
|
||||
}
|
||||
]
|
||||
}
|
||||
PlotPerf {
|
||||
title: "Batch Timing"
|
||||
height: parent.evalEvenHeight()
|
||||
object: parent.drawOpaqueConfig
|
||||
valueUnit: "ms"
|
||||
valueScale: 1
|
||||
valueNumDigits: "3"
|
||||
plots: [
|
||||
{
|
||||
object: Render.getConfig("OpaqueRangeTimer"),
|
||||
prop: "batchRunTime",
|
||||
label: "Opaque",
|
||||
color: "#FFFFFF"
|
||||
},
|
||||
{
|
||||
object: Render.getConfig("LinearDepth"),
|
||||
prop: "batchRunTime",
|
||||
label: "LinearDepth",
|
||||
color: "#00FF00"
|
||||
},{
|
||||
object: Render.getConfig("SurfaceGeometry"),
|
||||
prop: "batchRunTime",
|
||||
label: "SurfaceGeometry",
|
||||
color: "#00FFFF"
|
||||
},
|
||||
{
|
||||
object: Render.getConfig("RenderDeferred"),
|
||||
prop: "batchRunTime",
|
||||
label: "DeferredLighting",
|
||||
color: "#FF00FF"
|
||||
}
|
||||
,
|
||||
{
|
||||
object: Render.getConfig("ToneAndPostRangeTimer"),
|
||||
prop: "batchRunTime",
|
||||
label: "tone and post",
|
||||
color: "#FF0000"
|
||||
}
|
||||
|
|
|
@ -125,6 +125,12 @@ var ZERO_VEC = {
|
|||
z: 0
|
||||
};
|
||||
|
||||
var ONE_VEC = {
|
||||
x: 1,
|
||||
y: 1,
|
||||
z: 1
|
||||
};
|
||||
|
||||
var NULL_UUID = "{00000000-0000-0000-0000-000000000000}";
|
||||
|
||||
// these control how long an abandoned pointer line or action will hang around
|
||||
|
@ -232,6 +238,25 @@ CONTROLLER_STATE_MACHINE[STATE_ENTITY_TOUCHING] = {
|
|||
updateMethod: "entityTouching"
|
||||
};
|
||||
|
||||
function distanceBetweenPointAndEntityBoundingBox(point, entityProps) {
|
||||
var entityXform = new Xform(entityProps.rotation, entityProps.position);
|
||||
var localPoint = entityXform.inv().xformPoint(point);
|
||||
var minOffset = Vec3.multiplyVbyV(entityProps.registrationPoint, entityProps.dimensions);
|
||||
var maxOffset = Vec3.multiplyVbyV(Vec3.subtract(ONE_VEC, entityProps.registrationPoint), entityProps.dimensions);
|
||||
var localMin = Vec3.subtract(entityXform.trans, minOffset);
|
||||
var localMax = Vec3.sum(entityXform.trans, maxOffset);
|
||||
|
||||
var v = {x: localPoint.x, y: localPoint.y, z: localPoint.z};
|
||||
v.x = Math.max(v.x, localMin.x);
|
||||
v.x = Math.min(v.x, localMax.x);
|
||||
v.y = Math.max(v.y, localMin.y);
|
||||
v.y = Math.min(v.y, localMax.y);
|
||||
v.z = Math.max(v.z, localMin.z);
|
||||
v.z = Math.min(v.z, localMax.z);
|
||||
|
||||
return Vec3.distance(v, localPoint);
|
||||
}
|
||||
|
||||
function angleBetween(a, b) {
|
||||
return Math.acos(Vec3.dot(Vec3.normalize(a), Vec3.normalize(b)));
|
||||
}
|
||||
|
@ -1319,6 +1344,11 @@ function MyController(hand) {
|
|||
|
||||
this.searchEnter = function() {
|
||||
mostRecentSearchingHand = this.hand;
|
||||
var rayPickInfo = this.calcRayPickInfo(this.hand);
|
||||
if (rayPickInfo.entityID || rayPickInfo.overlayID) {
|
||||
this.intersectionDistance = rayPickInfo.distance;
|
||||
this.searchSphereDistance = this.intersectionDistance;
|
||||
}
|
||||
};
|
||||
|
||||
this.search = function(deltaTime, timestamp) {
|
||||
|
@ -1426,10 +1456,7 @@ function MyController(hand) {
|
|||
pos3D: rayPickInfo.intersection,
|
||||
normal: rayPickInfo.normal,
|
||||
direction: rayPickInfo.searchRay.direction,
|
||||
button: "None",
|
||||
isPrimaryButton: false,
|
||||
isSecondaryButton: false,
|
||||
isTertiaryButton: false
|
||||
button: "None"
|
||||
};
|
||||
|
||||
this.hoverEntity = entity;
|
||||
|
@ -1449,10 +1476,7 @@ function MyController(hand) {
|
|||
pos3D: rayPickInfo.intersection,
|
||||
normal: rayPickInfo.normal,
|
||||
direction: rayPickInfo.searchRay.direction,
|
||||
button: "None",
|
||||
isPrimaryButton: false,
|
||||
isSecondaryButton: false,
|
||||
isTertiaryButton: false
|
||||
button: "None"
|
||||
};
|
||||
|
||||
Entities.sendMouseMoveOnEntity(entity, pointerEvent);
|
||||
|
@ -1961,7 +1985,8 @@ function MyController(hand) {
|
|||
this.heartBeat(this.grabbedEntity);
|
||||
|
||||
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID",
|
||||
"position", "rotation", "dimensions"]);
|
||||
"position", "rotation", "dimensions",
|
||||
"registrationPoint"]);
|
||||
if (!props.position) {
|
||||
// server may have reset, taking our equipped entity with it. move back to "off" stte
|
||||
this.callEntityMethodOnGrabbed("releaseGrab");
|
||||
|
@ -1975,14 +2000,12 @@ function MyController(hand) {
|
|||
|
||||
if (props.parentID == MyAvatar.sessionUUID) {
|
||||
var handPosition = this.getHandPosition();
|
||||
// the center of the equipped object being far from the hand isn't enough to auto-unequip -- we also
|
||||
// need to fail the findEntities test.
|
||||
var TEAR_AWAY_DISTANCE = 0.04;
|
||||
var nearPickedCandidateEntities = Entities.findEntities(handPosition, NEAR_GRAB_RADIUS + TEAR_AWAY_DISTANCE);
|
||||
if (nearPickedCandidateEntities.indexOf(this.grabbedEntity) == -1) {
|
||||
// for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip.
|
||||
|
||||
var TEAR_AWAY_DISTANCE = 0.1;
|
||||
var dist = distanceBetweenPointAndEntityBoundingBox(handPosition, props);
|
||||
if (dist > TEAR_AWAY_DISTANCE) {
|
||||
print("handControllerGrab -- autoreleasing held or equipped item because it is far from hand." +
|
||||
props.parentID + " " + vec3toStr(props.position));
|
||||
props.parentID + ", dist = " + dist);
|
||||
|
||||
if (this.state == STATE_NEAR_GRABBING) {
|
||||
this.callEntityMethodOnGrabbed("releaseGrab");
|
||||
|
@ -2124,9 +2147,7 @@ function MyController(hand) {
|
|||
normal: intersectInfo.normal,
|
||||
direction: intersectInfo.searchRay.direction,
|
||||
button: "Primary",
|
||||
isPrimaryButton: true,
|
||||
isSecondaryButton: false,
|
||||
isTertiaryButton: false
|
||||
isPrimaryHeld: true
|
||||
};
|
||||
|
||||
Entities.sendMousePressOnEntity(this.grabbedEntity, pointerEvent);
|
||||
|
@ -2152,16 +2173,13 @@ function MyController(hand) {
|
|||
pos3D: intersectInfo.point,
|
||||
normal: intersectInfo.normal,
|
||||
direction: intersectInfo.searchRay.direction,
|
||||
button: "Primary",
|
||||
isPrimaryButton: false,
|
||||
isSecondaryButton: false,
|
||||
isTertiaryButton: false
|
||||
button: "Primary"
|
||||
};
|
||||
} else {
|
||||
pointerEvent = this.touchingEnterPointerEvent;
|
||||
pointerEvent.type = "Release";
|
||||
pointerEvent.button = "Primary";
|
||||
pointerEvent.isPrimaryButton = false;
|
||||
pointerEvent.isPrimaryHeld = false;
|
||||
}
|
||||
|
||||
Entities.sendMouseReleaseOnEntity(this.grabbedEntity, pointerEvent);
|
||||
|
@ -2198,9 +2216,7 @@ function MyController(hand) {
|
|||
normal: intersectInfo.normal,
|
||||
direction: intersectInfo.searchRay.direction,
|
||||
button: "NoButtons",
|
||||
isPrimaryButton: true,
|
||||
isSecondaryButton: false,
|
||||
isTertiaryButton: false
|
||||
isPrimaryHeld: true
|
||||
};
|
||||
|
||||
var POINTER_PRESS_TO_MOVE_DELAY = 0.15; // seconds
|
||||
|
|
|
@ -164,9 +164,10 @@ function toggleMarketplace() {
|
|||
}
|
||||
}
|
||||
|
||||
var TOOLS_PATH = Script.resolvePath("assets/images/tools/");
|
||||
|
||||
var toolBar = (function () {
|
||||
var EDIT_SETTING = "io.highfidelity.isEditting"; // for communication with other scripts
|
||||
var TOOL_ICON_URL = Script.resolvePath("assets/images/tools/");
|
||||
var that = {},
|
||||
toolBar,
|
||||
systemToolbar,
|
||||
|
@ -199,7 +200,7 @@ var toolBar = (function () {
|
|||
}
|
||||
|
||||
function addButton(name, image, handler) {
|
||||
var imageUrl = TOOL_ICON_URL + image;
|
||||
var imageUrl = TOOLS_PATH + image;
|
||||
var button = toolBar.addButton({
|
||||
objectName: name,
|
||||
imageURL: imageUrl,
|
||||
|
@ -232,7 +233,7 @@ var toolBar = (function () {
|
|||
systemToolbar = Toolbars.getToolbar(SYSTEM_TOOLBAR);
|
||||
activeButton = systemToolbar.addButton({
|
||||
objectName: EDIT_TOGGLE_BUTTON,
|
||||
imageURL: TOOL_ICON_URL + "edit.svg",
|
||||
imageURL: TOOLS_PATH + "edit.svg",
|
||||
visible: true,
|
||||
alpha: 0.9,
|
||||
buttonState: 1,
|
||||
|
@ -803,7 +804,7 @@ function setupModelMenus() {
|
|||
menuName: "Edit",
|
||||
menuItemName: "Delete",
|
||||
shortcutKeyEvent: {
|
||||
text: "backspace"
|
||||
text: "delete"
|
||||
},
|
||||
afterItem: "Entities",
|
||||
grouping: "Advanced"
|
||||
|
@ -1215,7 +1216,7 @@ Controller.keyReleaseEvent.connect(function (event) {
|
|||
cameraManager.keyReleaseEvent(event);
|
||||
}
|
||||
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
|
||||
if (event.text === "BACKSPACE" || event.text === "DELETE") {
|
||||
if (event.text === "DELETE") {
|
||||
deleteSelectedEntities();
|
||||
} else if (event.text === "ESC") {
|
||||
selectionManager.clearSelections();
|
||||
|
@ -1326,13 +1327,14 @@ function pushCommandForSelections(createdEntityData, deletedEntityData) {
|
|||
UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
|
||||
}
|
||||
|
||||
var ENTITY_PROPERTIES_URL = Script.resolvePath('html/entityProperties.html');
|
||||
|
||||
var PropertiesTool = function (opts) {
|
||||
var that = {};
|
||||
|
||||
var url = Script.resolvePath('html/entityProperties.html');
|
||||
var webView = new OverlayWebWindow({
|
||||
title: 'Entity Properties',
|
||||
source: url,
|
||||
source: ENTITY_PROPERTIES_URL,
|
||||
toolWindow: true
|
||||
});
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
var RAD_TO_DEG = 180 / Math.PI;
|
||||
var X_AXIS = {x: 1, y: 0, z: 0};
|
||||
var Y_AXIS = {x: 0, y: 1, z: 0};
|
||||
var DEFAULT_DPI = 30;
|
||||
var DEFAULT_WIDTH = 0.5;
|
||||
|
||||
var TABLET_URL = "https://s3.amazonaws.com/hifi-public/tony/tablet.fbx";
|
||||
|
||||
|
@ -37,12 +39,13 @@ function calcSpawnInfo() {
|
|||
}
|
||||
|
||||
// ctor
|
||||
WebTablet = function (url) {
|
||||
WebTablet = function (url, width, dpi) {
|
||||
|
||||
var ASPECT = 4.0 / 3.0;
|
||||
var WIDTH = 0.4;
|
||||
var WIDTH = width || DEFAULT_WIDTH;
|
||||
var HEIGHT = WIDTH * ASPECT;
|
||||
var DEPTH = 0.025;
|
||||
var DPI = dpi || DEFAULT_DPI;
|
||||
|
||||
var spawnInfo = calcSpawnInfo();
|
||||
|
||||
|
@ -78,7 +81,7 @@ WebTablet = function (url) {
|
|||
position: webEntityPosition,
|
||||
rotation: webEntityRotation,
|
||||
shapeType: "box",
|
||||
dpi: 45,
|
||||
dpi: DPI,
|
||||
parentID: this.tabletEntityID,
|
||||
parentJointIndex: -1
|
||||
});
|
||||
|
|
|
@ -16,8 +16,11 @@
|
|||
// grab the toolbar
|
||||
var toolbar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
|
||||
var ASSETS_PATH = Script.resolvePath("assets");
|
||||
var TOOLS_PATH = Script.resolvePath("assets/images/tools/");
|
||||
|
||||
function buttonImageURL() {
|
||||
return Script.resolvePath("assets/images/tools/" + (Users.canKick ? 'kick.svg' : 'ignore.svg'));
|
||||
return TOOLS_PATH + (Users.canKick ? 'kick.svg' : 'ignore.svg');
|
||||
}
|
||||
|
||||
// setup the mod button and add it to the toolbar
|
||||
|
@ -68,7 +71,7 @@ function buttonClicked(){
|
|||
button.clicked.connect(buttonClicked);
|
||||
|
||||
function overlayURL() {
|
||||
return Script.resolvePath("assets") + "/images/" + (Users.canKick ? "kick-target.svg" : "ignore-target.svg");
|
||||
return ASSETS_PATH + "/images/" + (Users.canKick ? "kick-target.svg" : "ignore-target.svg");
|
||||
}
|
||||
|
||||
function updateOverlays() {
|
||||
|
|
|
@ -124,7 +124,6 @@ var NotificationType = {
|
|||
var randomSounds = new SoundArray({ localOnly: true }, true);
|
||||
var numberOfSounds = 2;
|
||||
for (var i = 1; i <= numberOfSounds; i++) {
|
||||
|
||||
randomSounds.addSound(Script.resolvePath("assets/sounds/notification-general"+ i + ".raw"));
|
||||
}
|
||||
|
||||
|
@ -317,6 +316,8 @@ function notify(notice, button, height, imageProperties, image) {
|
|||
return notificationText;
|
||||
}
|
||||
|
||||
var CLOSE_NOTIFICATION_ICON = Script.resolvePath("assets/images/close-small-light.svg");
|
||||
|
||||
// This function creates and sizes the overlays
|
||||
function createNotification(text, notificationType, imageProperties) {
|
||||
var count = (text.match(/\n/g) || []).length,
|
||||
|
@ -363,7 +364,7 @@ function createNotification(text, notificationType, imageProperties) {
|
|||
width: 10.0,
|
||||
height: 10.0,
|
||||
subImage: { x: 0, y: 0, width: 10, height: 10 },
|
||||
imageURL: Script.resolvePath("assets/images/close-small-light.svg"),
|
||||
imageURL: CLOSE_NOTIFICATION_ICON,
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
visible: true,
|
||||
alpha: backgroundAlpha
|
||||
|
@ -534,7 +535,7 @@ function onDomainConnectionRefused(reason) {
|
|||
function onSnapshotTaken(path, notify) {
|
||||
if (notify) {
|
||||
var imageProperties = {
|
||||
path: Script.resolvePath("file:///" + path),
|
||||
path: "file:///" + path,
|
||||
aspectRatio: Window.innerWidth / Window.innerHeight
|
||||
}
|
||||
createNotification(wordWrap("Snapshot saved to " + path), NotificationType.SNAPSHOT, imageProperties);
|
||||
|
|
|
@ -32,9 +32,11 @@ function showFeedWindow() {
|
|||
DialogsManager.showFeed();
|
||||
}
|
||||
|
||||
var SNAPSHOT_REVIEW_URL = Script.resolvePath("html/SnapshotReview.html");
|
||||
|
||||
var outstanding;
|
||||
function confirmShare(data) {
|
||||
var dialog = new OverlayWebWindow('Snapshot Review', Script.resolvePath("html/SnapshotReview.html"), 800, 320);
|
||||
var dialog = new OverlayWebWindow('Snapshot Review', SNAPSHOT_REVIEW_URL, 800, 320);
|
||||
function onMessage(message) {
|
||||
// Receives message from the html dialog via the qwebchannel EventBridge. This is complicated by the following:
|
||||
// 1. Although we can send POJOs, we cannot receive a toplevel object. (Arrays of POJOs are fine, though.)
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
// resolve these paths immediately
|
||||
var MIN_MAX_BUTTON_SVG = Script.resolvePath("assets/images/tools/min-max-toggle.svg");
|
||||
var BASE_URL = Script.resolvePath("assets/images/tools/");
|
||||
|
||||
var PopUpMenu = function (properties) {
|
||||
var value = properties.value,
|
||||
promptOverlay,
|
||||
|
@ -25,8 +29,7 @@ var PopUpMenu = function (properties) {
|
|||
MIN_MAX_BUTTON_SVG_WIDTH = 17.1,
|
||||
MIN_MAX_BUTTON_SVG_HEIGHT = 32.5,
|
||||
MIN_MAX_BUTTON_WIDTH = 14,
|
||||
MIN_MAX_BUTTON_HEIGHT = MIN_MAX_BUTTON_WIDTH,
|
||||
MIN_MAX_BUTTON_SVG = Script.resolvePath("assets/images/tools/min-max-toggle.svg");
|
||||
MIN_MAX_BUTTON_HEIGHT = MIN_MAX_BUTTON_WIDTH;
|
||||
|
||||
function positionDisplayOptions() {
|
||||
var y,
|
||||
|
@ -223,8 +226,7 @@ var PopUpMenu = function (properties) {
|
|||
|
||||
var usersWindow = (function () {
|
||||
|
||||
var baseURL = Script.resolvePath("assets/images/tools/"),
|
||||
WINDOW_WIDTH = 260,
|
||||
var WINDOW_WIDTH = 260,
|
||||
WINDOW_MARGIN = 12,
|
||||
WINDOW_BASE_MARGIN = 6, // A little less is needed in order look correct
|
||||
WINDOW_FONT = {
|
||||
|
@ -261,7 +263,7 @@ var usersWindow = (function () {
|
|||
WINDOW_BORDER_ALPHA = 0.5,
|
||||
windowBorder,
|
||||
|
||||
MIN_MAX_BUTTON_SVG = baseURL + "min-max-toggle.svg",
|
||||
MIN_MAX_BUTTON_SVG = BASE_URL + "min-max-toggle.svg",
|
||||
MIN_MAX_BUTTON_SVG_WIDTH = 17.1,
|
||||
MIN_MAX_BUTTON_SVG_HEIGHT = 32.5,
|
||||
MIN_MAX_BUTTON_WIDTH = 14,
|
||||
|
@ -293,7 +295,7 @@ var usersWindow = (function () {
|
|||
scrollbarBackgroundHeight,
|
||||
scrollbarBarHeight,
|
||||
FRIENDS_BUTTON_SPACER = 6, // Space before add/remove friends button
|
||||
FRIENDS_BUTTON_SVG = baseURL + "add-remove-friends.svg",
|
||||
FRIENDS_BUTTON_SVG = BASE_URL + "add-remove-friends.svg",
|
||||
FRIENDS_BUTTON_SVG_WIDTH = 107,
|
||||
FRIENDS_BUTTON_SVG_HEIGHT = 27,
|
||||
FRIENDS_BUTTON_WIDTH = FRIENDS_BUTTON_SVG_WIDTH,
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
# add the tool directories
|
||||
add_subdirectory(mtc)
|
||||
set_target_properties(mtc PROPERTIES FOLDER "Tools")
|
||||
|
||||
add_subdirectory(scribe)
|
||||
set_target_properties(scribe PROPERTIES FOLDER "Tools")
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
set(TARGET_NAME mtc)
|
||||
setup_hifi_project()
|
||||
|
||||
package_libraries_for_deployment()
|
|
@ -1,362 +0,0 @@
|
|||
//
|
||||
// main.cpp
|
||||
// tools/mtc/src
|
||||
//
|
||||
// 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
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QFile>
|
||||
#include <QList>
|
||||
#include <QRegExp>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QtDebug>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Class {
|
||||
public:
|
||||
QString name;
|
||||
QStringList bases;
|
||||
};
|
||||
|
||||
class Field {
|
||||
public:
|
||||
QString type;
|
||||
QString name;
|
||||
};
|
||||
|
||||
class Streamable {
|
||||
public:
|
||||
Class clazz;
|
||||
QList<Field> fields;
|
||||
};
|
||||
|
||||
void processInput(QTextStream& in, QList<Streamable>* streamables) {
|
||||
Class clazz;
|
||||
Streamable currentStreamable;
|
||||
|
||||
QRegExp exp(
|
||||
"(/\\*.*\\*/)|" // multi-line comments
|
||||
"(//.*\n)|" // single-line comments
|
||||
"(\\s*#.*\n)|" // preprocessor definitions
|
||||
"(\\s*STREAMABLE\\s+)|" // STREAMABLE tag for classes
|
||||
"(\\s*STREAM\\s+.*;)|" // STREAM tag for fields
|
||||
"(\\s*class\\s+[^;]+\\{)" // class definition
|
||||
);
|
||||
exp.setMinimal(true);
|
||||
|
||||
QRegExp classExp("class (\\w+) ?:?([^:]*)\\{");
|
||||
|
||||
// read in the entire input and look for matches with our expression
|
||||
QString all = in.readAll();
|
||||
for (int off = 0; (off = exp.indexIn(all, off)) != -1; off += exp.matchedLength()) {
|
||||
QString match = exp.cap().simplified();
|
||||
if (match.startsWith("/*") || match.startsWith("//") || match.startsWith('#')) {
|
||||
continue; // comment, preprocessor definition
|
||||
}
|
||||
if (match.startsWith("STREAMABLE")) {
|
||||
if (clazz.name.isEmpty()) {
|
||||
cerr << "Found STREAMABLE marker before class definition." << endl;
|
||||
continue;
|
||||
}
|
||||
if (!currentStreamable.clazz.name.isEmpty()) {
|
||||
streamables->append(currentStreamable);
|
||||
}
|
||||
currentStreamable.clazz = clazz;
|
||||
currentStreamable.fields.clear();
|
||||
|
||||
} else if (match.startsWith("STREAM")) {
|
||||
match.chop(1); // get rid of the semicolon
|
||||
match = match.mid(match.indexOf(' ') + 1).trimmed(); // and STREAM, and any space before it
|
||||
int index = match.lastIndexOf(' ');
|
||||
Field field = { match.left(index).simplified(), match.mid(index + 1) };
|
||||
currentStreamable.fields.append(field);
|
||||
|
||||
} else { // match.startsWith("class")
|
||||
classExp.exactMatch(match);
|
||||
clazz.name = classExp.cap(1);
|
||||
clazz.bases.clear();
|
||||
foreach (const QString& bstr, classExp.cap(2).split(',')) {
|
||||
QString base = bstr.trimmed();
|
||||
if (!base.isEmpty() && base.startsWith("STREAM")) {
|
||||
clazz.bases.append(base.mid(base.lastIndexOf(' ') + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!currentStreamable.clazz.name.isEmpty()) {
|
||||
streamables->append(currentStreamable);
|
||||
}
|
||||
}
|
||||
|
||||
void generateOutput (QTextStream& out, const QList<Streamable>& streamables) {
|
||||
foreach (const Streamable& str, streamables) {
|
||||
const QString& name = str.clazz.name;
|
||||
|
||||
out << "const int " << name << "::Type = registerStreamableMetaType<" << name << ">();\n";
|
||||
|
||||
out << "const QVector<MetaField>& " << name << "::getMetaFields() {\n";
|
||||
out << " static QVector<MetaField> metaFields = QVector<MetaField>()";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " << " << base << "::getMetaFields()";
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
out << "\n << MetaField(\"" << field.name << "\", Bitstream::getTypeStreamer(qMetaTypeId<" <<
|
||||
field.type << ">()))";
|
||||
}
|
||||
out << ";\n";
|
||||
out << " return metaFields;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "int " << name << "::getFieldIndex(const QByteArray& name) {\n";
|
||||
out << " static QHash<QByteArray, int> fieldIndices = createFieldIndices();\n";
|
||||
out << " return fieldIndices.value(name) - 1;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "QHash<QByteArray, int> " << name << "::createFieldIndices() {\n";
|
||||
out << " QHash<QByteArray, int> indices;\n";
|
||||
out << " int index = 1;\n";
|
||||
out << " foreach (const MetaField& field, getMetaFields()) {\n";
|
||||
out << " indices.insert(field.getName(), index++);\n";
|
||||
out << " }\n";
|
||||
out << " return indices;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "void " << name << "::setField(int index, const QVariant& value) {\n";
|
||||
if (!str.clazz.bases.isEmpty()) {
|
||||
out << " int nextIndex;\n";
|
||||
}
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " if ((nextIndex = index - " << base << "::getMetaFields().size()) < 0) {\n";
|
||||
out << " " << base << "::setField(index, value);\n";
|
||||
out << " return;\n";
|
||||
out << " }\n";
|
||||
out << " index = nextIndex;\n";
|
||||
}
|
||||
if (!str.fields.isEmpty()) {
|
||||
out << " switch (index) {\n";
|
||||
for (int i = 0; i < str.fields.size(); i++) {
|
||||
out << " case " << i << ":\n";
|
||||
out << " this->" << str.fields.at(i).name << " = value.value<" << str.fields.at(i).type << ">();\n";
|
||||
out << " break;\n";
|
||||
}
|
||||
out << " }\n";
|
||||
}
|
||||
out << "}\n";
|
||||
|
||||
out << "QVariant " << name << "::getField(int index) const {\n";
|
||||
if (!str.clazz.bases.isEmpty()) {
|
||||
out << " int nextIndex;\n";
|
||||
}
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " if ((nextIndex = index - " << base << "::getMetaFields().size()) < 0) {\n";
|
||||
out << " return " << base << "::getField(index);\n";
|
||||
out << " }\n";
|
||||
out << " index = nextIndex;\n";
|
||||
}
|
||||
if (!str.fields.isEmpty()) {
|
||||
out << " switch (index) {\n";
|
||||
for (int i = 0; i < str.fields.size(); i++) {
|
||||
out << " case " << i << ":\n";
|
||||
out << " return QVariant::fromValue(this->" << str.fields.at(i).name << ");\n";
|
||||
}
|
||||
out << " }\n";
|
||||
}
|
||||
out << " return QVariant();\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "Bitstream& operator<<(Bitstream& out, const " << name << "& obj) {\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " out << static_cast<const " << base << "&>(obj);\n";
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
out << " out << obj." << field.name << ";\n";
|
||||
}
|
||||
out << " return out;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "Bitstream& operator>>(Bitstream& in, " << name << "& obj) {\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " in >> static_cast<" << base << "&>(obj);\n";
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
out << " in >> obj." << field.name << ";\n";
|
||||
}
|
||||
out << " return in;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "template<> void Bitstream::writeRawDelta(const " << name << "& value, const " << name << "& reference) {\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " writeRawDelta(static_cast<const " << base << "&>(value), static_cast<const " <<
|
||||
base << "&>(reference));\n";
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
out << " writeDelta(value." << field.name << ", reference." << field.name << ");\n";
|
||||
}
|
||||
out << "}\n";
|
||||
|
||||
out << "template<> void Bitstream::readRawDelta(" << name << "& value, const " << name << "& reference) {\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " readRawDelta(static_cast<" << base << "&>(value), static_cast<const " <<
|
||||
base << "&>(reference));\n";
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
out << " readDelta(value." << field.name << ", reference." << field.name << ");\n";
|
||||
}
|
||||
out << "}\n";
|
||||
|
||||
out << "template<> QJsonValue JSONWriter::getData(const " << name << "& value) {\n";
|
||||
out << " QJsonArray array;\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " foreach (const QJsonValue& element, getData(static_cast<const " << base << "&>(value)).toArray()) {\n";
|
||||
out << " array.append(element);\n";
|
||||
out << " }\n";
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
out << " array.append(getData(value." << field.name << "));\n";
|
||||
}
|
||||
out << " return array;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "template<> void JSONReader::putData(const QJsonValue& data, " << name << "& value) {\n";
|
||||
if (!(str.clazz.bases.isEmpty() && str.fields.isEmpty())) {
|
||||
out << " QJsonArray array = data.toArray(), subarray;\n";
|
||||
out << " QJsonArray::const_iterator it = array.constBegin();\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " subarray = QJsonArray();\n";
|
||||
out << " for (int i = 0; i < " << base << "::getMetaFields().size(); i++) {\n";
|
||||
out << " subarray.append(*it++);\n";
|
||||
out << " }\n";
|
||||
out << " putData(subarray, static_cast<" << base << "&>(value));\n";
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
out << " putData(*it++, value." << field.name << ");\n";
|
||||
}
|
||||
}
|
||||
out << "}\n";
|
||||
|
||||
out << "bool operator==(const " << name << "& first, const " << name << "& second) {\n";
|
||||
if (str.clazz.bases.isEmpty() && str.fields.isEmpty()) {
|
||||
out << " return true";
|
||||
} else {
|
||||
out << " return ";
|
||||
bool first = true;
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
if (!first) {
|
||||
out << " &&\n";
|
||||
out << " ";
|
||||
}
|
||||
out << "static_cast<const " << base << "&>(first) == static_cast<const " << base << "&>(second)";
|
||||
first = false;
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
if (!first) {
|
||||
out << " &&\n";
|
||||
out << " ";
|
||||
}
|
||||
out << "first." << field.name << " == second." << field.name;
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
out << ";\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "bool operator!=(const " << name << "& first, const " << name << "& second) {\n";
|
||||
if (str.clazz.bases.isEmpty() && str.fields.isEmpty()) {
|
||||
out << " return false";
|
||||
} else {
|
||||
out << " return ";
|
||||
bool first = true;
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
if (!first) {
|
||||
out << " ||\n";
|
||||
out << " ";
|
||||
}
|
||||
out << "static_cast<const " << base << "&>(first) != static_cast<const " << base << "&>(second)";
|
||||
first = false;
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
if (!first) {
|
||||
out << " ||\n";
|
||||
out << " ";
|
||||
}
|
||||
out << "first." << field.name << " != second." << field.name;
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
out << ";\n";
|
||||
out << "}\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
// process the command line arguments
|
||||
QStringList inputs;
|
||||
QString output;
|
||||
for (int ii = 1; ii < argc; ii++) {
|
||||
QString arg(argv[ii]);
|
||||
if (!arg.startsWith('-')) {
|
||||
inputs.append(arg);
|
||||
continue;
|
||||
}
|
||||
QStringRef name = arg.midRef(1);
|
||||
if (name == "o") {
|
||||
if (++ii == argc) {
|
||||
cerr << "Missing file name argument for -o" << endl;
|
||||
return 1;
|
||||
}
|
||||
output = argv[ii];
|
||||
|
||||
} else {
|
||||
cerr << "Unknown option " << arg.toStdString() << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (inputs.isEmpty()) {
|
||||
cerr << "Usage: mtc [OPTION]... input files" << endl;
|
||||
cerr << "Where options include:" << endl;
|
||||
cerr << " -o filename: Send output to filename rather than standard output." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
QList<Streamable> streamables;
|
||||
foreach (const QString& input, inputs) {
|
||||
QFile ifile(input);
|
||||
if (!ifile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
cerr << ("Couldn't open " + input + ": " + ifile.errorString()).toStdString() << endl;
|
||||
continue;
|
||||
}
|
||||
QTextStream istream(&ifile);
|
||||
int oldSize = streamables.size();
|
||||
processInput(istream, &streamables);
|
||||
if (streamables.size() == oldSize) {
|
||||
// no streamables; remove from list
|
||||
inputs.removeOne(input);
|
||||
}
|
||||
}
|
||||
|
||||
QFile ofile(output);
|
||||
if (output.isNull()) {
|
||||
ofile.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
|
||||
|
||||
} else if (!ofile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
cerr << ("Couldn't open " + output + ": " + ofile.errorString()).toStdString() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
QTextStream ostream(&ofile);
|
||||
ostream << "// generated by mtc\n";
|
||||
foreach (const QString& input, inputs) {
|
||||
ostream << "#include \"" << input << "\"\n";
|
||||
}
|
||||
generateOutput(ostream, streamables);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue