mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-10 11:54:54 +02:00
Merge remote-tracking branch 'upstream/master' into breakpad_android
This commit is contained in:
commit
3911a93a38
67 changed files with 1132 additions and 721 deletions
|
@ -66,19 +66,19 @@ ext {
|
|||
def baseFolder = new File(HIFI_ANDROID_PRECOMPILED)
|
||||
def appDir = new File(projectDir, 'app')
|
||||
def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a')
|
||||
def baseUrl = ''
|
||||
def baseUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/android/'
|
||||
|
||||
def qtFile='https://hifi-public.s3.amazonaws.com/austin/android/qt-5.9.3_linux_armv8-libcpp_openssl.tgz'
|
||||
def qtFile='qt-5.9.3_linux_armv8-libcpp_openssl.tgz'
|
||||
def qtChecksum='04599670ccca84bd2b15f6915568eb2d'
|
||||
def qtVersionId='PeoqzN31n.YvLfs9JE2SgHgZ4.IaKAlt'
|
||||
def qtVersionId='8QbCma4ryEPgBYn_8kgYgB10IvNx9I1W'
|
||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||
qtFile = 'https://hifi-public.s3.amazonaws.com/austin/android/qt-5.9.3_osx_armv8-libcpp_openssl.tgz'
|
||||
qtFile = 'qt-5.9.3_osx_armv8-libcpp_openssl.tgz'
|
||||
qtChecksum='4b02de9d67d6bfb202355a808d2d9c59'
|
||||
qtVersionId='HygCmtMLPYioyil0DfXckGVzhw2SXZA9'
|
||||
qtVersionId='2gfgoYCggJGyXxKiazaPGsMs1Gn9j4og'
|
||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
qtFile = 'https://hifi-public.s3.amazonaws.com/austin/android/qt-5.9.3_win_armv8-libcpp_openssl.tgz'
|
||||
qtFile = 'qt-5.9.3_win_armv8-libcpp_openssl.tgz'
|
||||
qtChecksum='c3e25db64002d0f43cf565e0ef708911'
|
||||
qtVersionId='HeVObSVLCBoc7yY7He1oBMvPIH0VkClT'
|
||||
qtVersionId='xKIteC6HO0xrmcWeMmhQcmKyPEsnUrcZ'
|
||||
}
|
||||
|
||||
def packages = [
|
||||
|
@ -88,79 +88,84 @@ def packages = [
|
|||
checksum: qtChecksum,
|
||||
],
|
||||
bullet: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/dependencies/android/bullet-2.88_armv8-libcpp.tgz',
|
||||
file: 'bullet-2.88_armv8-libcpp.tgz',
|
||||
versionId: 'S8YaoED0Cl8sSb8fSV7Q2G1lQJSNDxqg',
|
||||
checksum: '81642779ccb110f8c7338e8739ac38a0',
|
||||
],
|
||||
draco: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/draco_armv8-libcpp.tgz',
|
||||
versionId: 'cA3tVJSmkvb1naA3l6D_Jv2Noh.4yc4m',
|
||||
file: 'draco_armv8-libcpp.tgz',
|
||||
versionId: '3.B.uBj31kWlgND3_R2xwQzT_TP6Dz_8',
|
||||
checksum: '617a80d213a5ec69fbfa21a1f2f738cd',
|
||||
],
|
||||
glad: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/glad_armv8-libcpp.zip',
|
||||
versionId: 'Q9szthzeye8fFyAA.cY26Lgn2B8kezEE',
|
||||
file: 'glad_armv8-libcpp.zip',
|
||||
versionId: 'r5Zran.JSCtvrrB6Q4KaqfIoALPw3lYY',
|
||||
checksum: 'a8ee8584cf1ccd34766c7ddd9d5e5449',
|
||||
],
|
||||
glm: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/dependencies/android/glm-0.9.8.5-patched.tgz',
|
||||
file: 'glm-0.9.8.5-patched.tgz',
|
||||
versionId: 'cskfMoJrFlAeqI3WPxemyO_Cxt7rT9EJ',
|
||||
checksum: '067b5fe16b220b5b1a1039ba51b062ae',
|
||||
],
|
||||
gvr: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/gvrsdk_v1.101.0.tgz',
|
||||
versionId: 'UTberAIFraEfF9IVjoV66u1DTPTopgeY',
|
||||
file: 'gvrsdk_v1.101.0.tgz',
|
||||
versionId: 'nqBV_j81Uc31rC7bKIrlya_Hah4v3y5r',
|
||||
checksum: '57fd02baa069176ba18597a29b6b4fc7',
|
||||
],
|
||||
nvtt: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/nvtt_armv8-libcpp.zip',
|
||||
versionId: 'vLqrqThvpq4gp75BHMAqO6HhfTXaa0An',
|
||||
file: 'nvtt_armv8-libcpp.zip',
|
||||
versionId: 'lmkBVR5t4UF1UUwMwEirnk9H_8Nt90IO',
|
||||
checksum: 'eb46d0b683e66987190ed124aabf8910',
|
||||
sharedLibFolder: 'lib',
|
||||
includeLibs: ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so'],
|
||||
],
|
||||
openssl: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/openssl-1.1.0g_armv8.tgz',
|
||||
versionId: 'DmahmSGFS4ltpHyTdyQvv35WOeUOiib9',
|
||||
file: 'openssl-1.1.0g_armv8.tgz',
|
||||
versionId: 'AiiPjmgUZTgNj7YV1EEx2lL47aDvvvAW',
|
||||
checksum: 'cabb681fbccd79594f65fcc266e02f32',
|
||||
],
|
||||
polyvox: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/polyvox_armv8-libcpp.tgz',
|
||||
versionId: 'LDJtzMTvdm4SAc2KYg8Cg6uwWk4Vq3e3',
|
||||
checksum: '349ad5b72aaf2749ca95d847e60c5314',
|
||||
file: 'polyvox_armv8-libcpp.tgz',
|
||||
versionId: 'A2kbKiNhpIenGq23bKRRzg7IMAI5BI92',
|
||||
checksum: 'dba88b3a098747af4bb169e9eb9af57e',
|
||||
sharedLibFolder: 'lib',
|
||||
includeLibs: ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'],
|
||||
],
|
||||
tbb: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/tbb-2018_U1_armv8_libcpp.tgz',
|
||||
versionId: 'YZliDD8.Menh1IVXKEuLPeO3xAjJ1UdF',
|
||||
file: 'tbb-2018_U1_armv8_libcpp.tgz',
|
||||
versionId: 'mrRbWnv4O4evcM1quRH43RJqimlRtaKB',
|
||||
checksum: '20768f298f53b195e71b414b0ae240c4',
|
||||
sharedLibFolder: 'lib/release',
|
||||
includeLibs: ['libtbb.so', 'libtbbmalloc.so'],
|
||||
],
|
||||
hifiAC: [
|
||||
file: 'https://hifi-public.s3.amazonaws.com/austin/android/libplugins_libhifiCodec.zip',
|
||||
versionId: 'mzKhsRCgVmloqq5bvE.0IwYK1NjGQc_G',
|
||||
file: 'libplugins_libhifiCodec.zip',
|
||||
versionId: 'i31pW.qNbvFOXRxbyiJUxg3sphaFNmZU',
|
||||
checksum: '9412a8e12c88a4096c1fc843bb9fe52d',
|
||||
sharedLibFolder: '',
|
||||
includeLibs: ['libplugins_libhifiCodec.so']
|
||||
],
|
||||
etc2comp: [
|
||||
file: 'etc2comp-patched-armv8-libcpp.tgz',
|
||||
versionId: 'bHhGECRAQR1vkpshBcK6ByNc1BQIM8gU',
|
||||
checksum: '14b02795d774457a33bbc60e00a786bc'
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
def scribeLocalFile='scribe' + EXEC_SUFFIX
|
||||
|
||||
def scribeFile='https://hifi-public.s3.amazonaws.com/austin/android/scribe_linux_x86_64'
|
||||
def scribeFile='scribe_linux_x86_64'
|
||||
def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6'
|
||||
def scribeVersion='wgpf4dB2Ltzg4Lb2jJ4nPFsHoDkmK_OO'
|
||||
def scribeVersion='u_iTrJDaE95i2abTPXOpPZckGBIim53G'
|
||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||
scribeFile = 'https://hifi-public.s3.amazonaws.com/austin/android/scribe_osx_x86_64'
|
||||
scribeFile = 'scribe_osx_x86_64'
|
||||
scribeChecksum='72db9d32d4e1e50add755570ac5eb749'
|
||||
scribeVersion='o_NbPrktzEYtBkQf3Tn7zc1nZWzM52w6'
|
||||
scribeVersion='DAW0DmnjCRib4MD8x93bgc2Z2MpPojZC'
|
||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
scribeFile = 'https://hifi-public.s3.amazonaws.com/austin/android/scribe_win32_x86_64.exe'
|
||||
scribeFile = 'scribe_win32_x86_64.exe'
|
||||
scribeChecksum='678e43d290c90fda670c6fefe038a06d'
|
||||
scribeVersion='GCCJxlmd2irvNOFWfZR0U1UCLHndHQrC'
|
||||
scribeVersion='PuullrA_bPlO9kXZRt8rLe536X1UI.m7'
|
||||
}
|
||||
|
||||
def options = [
|
||||
|
@ -361,6 +366,7 @@ task verifyOpenSSL(type: Verify) { def p = packages['openssl']; src new File(bas
|
|||
task verifyPolyvox(type: Verify) { def p = packages['polyvox']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyTBB(type: Verify) { def p = packages['tbb']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyHifiAC(type: Verify) { def p = packages['hifiAC']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyEtc2Comp(type: Verify) { def p = packages['etc2comp']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
|
||||
task verifyDependencyDownloads(dependsOn: downloadDependencies) { }
|
||||
verifyDependencyDownloads.dependsOn verifyQt
|
||||
|
@ -371,6 +377,7 @@ verifyDependencyDownloads.dependsOn verifyOpenSSL
|
|||
verifyDependencyDownloads.dependsOn verifyPolyvox
|
||||
verifyDependencyDownloads.dependsOn verifyTBB
|
||||
verifyDependencyDownloads.dependsOn verifyHifiAC
|
||||
verifyDependencyDownloads.dependsOn verifyEtc2Comp
|
||||
|
||||
task extractDependencies(dependsOn: verifyDependencyDownloads) {
|
||||
doLast {
|
||||
|
@ -608,4 +615,4 @@ task testElf (dependsOn: 'externalNativeBuildDebug') {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
*/
|
|
@ -233,7 +233,6 @@ OctreeServer::OctreeServer(ReceivedMessage& message) :
|
|||
_argc(0),
|
||||
_argv(NULL),
|
||||
_parsedArgV(NULL),
|
||||
_httpManager(NULL),
|
||||
_statusPort(0),
|
||||
_packetsPerClientPerInterval(10),
|
||||
_packetsTotalPerInterval(DEFAULT_PACKETS_PER_INTERVAL),
|
||||
|
@ -285,7 +284,7 @@ void OctreeServer::initHTTPManager(int port) {
|
|||
QString documentRoot = QString("%1/web").arg(PathUtils::getAppDataPath());
|
||||
|
||||
// setup an httpManager with us as the request handler and the parent
|
||||
_httpManager = new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this, this);
|
||||
_httpManager.reset(new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this));
|
||||
}
|
||||
|
||||
bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||
|
|
|
@ -183,7 +183,7 @@ protected:
|
|||
|
||||
bool _isShuttingDown = false;
|
||||
|
||||
HTTPManager* _httpManager;
|
||||
std::unique_ptr<HTTPManager> _httpManager;
|
||||
int _statusPort;
|
||||
QString _statusHost;
|
||||
|
||||
|
|
4
cmake/externals/LibOVR/CMakeLists.txt
vendored
4
cmake/externals/LibOVR/CMakeLists.txt
vendored
|
@ -17,8 +17,8 @@ if (WIN32)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://static.oculus.com/sdk-downloads/1.11.0/Public/1486063832/ovr_sdk_win_1.11.0_public.zip
|
||||
URL_MD5 ea484403757cbfdfa743b6577fb1f9d2
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.26.0_public.zip
|
||||
URL_MD5 06804ff9727b910dcd04a37c800053b5
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
PATCH_COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/LibOVRCMakeLists.txt" <SOURCE_DIR>/CMakeLists.txt
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
2
cmake/externals/LibOVR/LibOVRCMakeLists.txt
vendored
2
cmake/externals/LibOVR/LibOVRCMakeLists.txt
vendored
|
@ -4,7 +4,7 @@ project(LibOVR)
|
|||
include_directories(LibOVR/Include LibOVR/Src)
|
||||
file(GLOB HEADER_FILES LibOVR/Include/*.h)
|
||||
file(GLOB EXTRA_HEADER_FILES LibOVR/Include/Extras/*.h)
|
||||
file(GLOB_RECURSE SOURCE_FILES LibOVR/Src/*.c LibOVR/Src/*.cpp)
|
||||
file(GLOB_RECURSE SOURCE_FILES LibOVR/Shim/*.c LibOVR/Shim/*.cpp)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DOVR_BUILD_DEBUG")
|
||||
add_library(LibOVR STATIC ${SOURCE_FILES} ${HEADER_FILES} ${EXTRA_HEADER_FILES})
|
||||
set_target_properties(LibOVR PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
|
55
cmake/externals/etc2comp/CMakeLists.txt
vendored
Normal file
55
cmake/externals/etc2comp/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
set(EXTERNAL_NAME etc2comp)
|
||||
|
||||
if (ANDROID)
|
||||
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
set(EXTRA_CMAKE_FLAGS -DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++)
|
||||
endif ()
|
||||
|
||||
include(ExternalProject)
|
||||
# We use a patched version of etc2comp that properly generates all the necessary mips
|
||||
# See https://github.com/google/etc2comp/pull/29
|
||||
# We also use part of https://github.com/google/etc2comp/pull/1, which fixes a bug
|
||||
# that would override CMAKE_CXX_FLAGS
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/etc2comp-patched.zip
|
||||
URL_MD5 4c96153eb179acbe619e3d99d3330595
|
||||
CMAKE_ARGS ${ANDROID_CMAKE_ARGS} ${EXTRA_CMAKE_FLAGS}
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/build/EtcLib/Debug/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp debug library")
|
||||
|
||||
# use generator expression to ensure the correct library is found when building different configurations in VS
|
||||
set(_LIB_FOLDER "$<$<CONFIG:RelWithDebInfo>:build/EtcLib/RelWithDebInfo>")
|
||||
set(_LIB_FOLDER "${_LIB_FOLDER}$<$<CONFIG:MinSizeRel>:build/EtcLib/MinSizeRel>")
|
||||
set(_LIB_FOLDER "${_LIB_FOLDER}$<$<OR:$<CONFIG:Release>,$<CONFIG:Debug>>:build/EtcLib/Release>")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/${_LIB_FOLDER}/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp release library")
|
||||
elseif (APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/build/EtcLib/Debug/libEtcLib.a CACHE FILEPATH "Path to EtcLib debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/build/EtcLib/Release/libEtcLib.a CACHE FILEPATH "Path to EtcLib release library")
|
||||
else ()
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Path to EtcLib debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/build/EtcLib/libEtcLib.a CACHE FILEPATH "Path to EtcLib release library")
|
||||
endif ()
|
||||
|
||||
set(ETC_INCLUDE_DIR ${SOURCE_DIR}/EtcLib/Etc CACHE FILEPATH "Path to Etc2Comp/Etc include directory")
|
||||
set(ETCCODEC_INCLUDE_DIR ${SOURCE_DIR}/EtcLib/EtcCodec CACHE FILEPATH "Path to Etc2Comp/EtcCodec include directory")
|
||||
# ETC2COMP_INCLUDE_DIRS will be set later by FindEtc2Comp
|
22
cmake/macros/TargetEtc2Comp.cmake
Normal file
22
cmake/macros/TargetEtc2Comp.cmake
Normal file
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# Copyright 2018 High Fidelity, Inc.
|
||||
# Created by Sam Gondelman on 5/2/2018
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_ETC2COMP)
|
||||
if (ANDROID)
|
||||
set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/etc2comp)
|
||||
set(ETC2COMP_INCLUDE_DIRS "${INSTALL_DIR}/include/Etc" "${INSTALL_DIR}/include/EtcCodec")
|
||||
set(ETC2COMP_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libEtcLib.a)
|
||||
set(ETC2COMP_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libEtcLib.a)
|
||||
select_library_configurations(ETC2COMP)
|
||||
else()
|
||||
add_dependency_external_projects(etc2comp)
|
||||
find_package(Etc2Comp REQUIRED)
|
||||
endif()
|
||||
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${ETC2COMP_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${ETC2COMP_LIBRARIES})
|
||||
endmacro()
|
37
cmake/modules/FindEtc2Comp.cmake
Normal file
37
cmake/modules/FindEtc2Comp.cmake
Normal file
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
# FindEtc2Comp.cmake
|
||||
#
|
||||
# Try to find the Etc2Comp compression library.
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# ETC2COMP_FOUND - system found Etc2Comp
|
||||
# ETC2COMP_INCLUDE_DIRS - the Etc2Comp include directory
|
||||
# ETC2COMP_LIBRARIES - link to this to use Etc2Comp
|
||||
#
|
||||
# Created on 5/2/2018 by Sam Gondelman
|
||||
# Copyright 2018 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("etc2comp")
|
||||
|
||||
find_path(ETC_INCLUDE_DIR NAMES Etc.h HINTS ${ETC2COMP_SEARCH_DIRS})
|
||||
find_path(ETCCODEC_INCLUDE_DIR NAMES EtcBlock4x4.h HINTS ${ETC2COMP_SEARCH_DIRS})
|
||||
set(ETC2COMP_INCLUDE_DIRS "${ETC_INCLUDE_DIR}" "${ETCCODEC_INCLUDE_DIR}")
|
||||
|
||||
find_library(ETC2COMP_LIBRARY_DEBUG NAMES ETC2COMP ETC2COMP_LIB PATH_SUFFIXES EtcLib/Debug HINTS ${ETC2COMP_SEARCH_DIRS})
|
||||
find_library(ETC2COMP_LIBRARY_RELEASE NAMES ETC2COMP ETC2COMP_LIB PATH_SUFFIXES EtcLib/Release EtcLib HINTS ${ETC2COMP_SEARCH_DIRS})
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(ETC2COMP)
|
||||
|
||||
set(ETC2COMP_LIBRARIES ${ETC2COMP_LIBRARY})
|
||||
|
||||
find_package_handle_standard_args(ETC2COMP "Could NOT find ETC2COMP, try to set the path to ETC2COMP root folder in the system variable ETC2COMP_ROOT_DIR or create a directory etc2comp in HIFI_LIB_DIR and paste the necessary files there"
|
||||
ETC2COMP_INCLUDE_DIRS ETC2COMP_LIBRARIES)
|
||||
|
||||
mark_as_advanced(ETC2COMP_INCLUDE_DIRS ETC2COMP_LIBRARIES ETC2COMP_SEARCH_DIRS)
|
|
@ -16,6 +16,8 @@
|
|||
#include <openssl/x509.h>
|
||||
#include <random>
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <Assignment.h>
|
||||
|
||||
|
|
|
@ -149,7 +149,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
QCoreApplication(argc, argv),
|
||||
_gatekeeper(this),
|
||||
_httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
|
||||
_httpsManager(NULL),
|
||||
_allAssignments(),
|
||||
_unfulfilledAssignments(),
|
||||
_isUsingDTLS(false),
|
||||
|
@ -385,6 +384,8 @@ DomainServer::~DomainServer() {
|
|||
_contentManager->terminate();
|
||||
}
|
||||
|
||||
DependencyManager::destroy<AccountManager>();
|
||||
|
||||
// cleanup the AssetClient thread
|
||||
DependencyManager::destroy<AssetClient>();
|
||||
_assetClientThread.quit();
|
||||
|
@ -439,7 +440,7 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
|||
QSslCertificate sslCertificate(&certFile);
|
||||
QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8());
|
||||
|
||||
_httpsManager = new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this, this);
|
||||
_httpsManager.reset(new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this));
|
||||
|
||||
qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT;
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ private:
|
|||
DomainGatekeeper _gatekeeper;
|
||||
|
||||
HTTPManager _httpManager;
|
||||
HTTPSManager* _httpsManager;
|
||||
std::unique_ptr<HTTPSManager> _httpsManager;
|
||||
|
||||
QHash<QUuid, SharedAssignmentPointer> _allAssignments;
|
||||
QQueue<SharedAssignmentPointer> _unfulfilledAssignments;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <QtCore/QDataStream>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
|
|
@ -133,13 +133,7 @@ if (APPLE)
|
|||
# set where in the bundle to put the resources file
|
||||
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
set(DISCOVERED_RESOURCES "")
|
||||
|
||||
# use the add_resources_to_os_x_bundle macro to recurse into resources
|
||||
add_resources_to_os_x_bundle("${CMAKE_CURRENT_SOURCE_DIR}/resources")
|
||||
|
||||
# append the discovered resources to our list of interface sources
|
||||
list(APPEND INTERFACE_SRCS ${DISCOVERED_RESOURCES})
|
||||
list(APPEND INTERFACE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME})
|
||||
endif()
|
||||
|
||||
|
@ -317,18 +311,27 @@ if (APPLE)
|
|||
set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources")
|
||||
set(RESOURCES_DEV_DIR "$<TARGET_FILE_DIR:${TARGET_NAME}>/../Resources")
|
||||
|
||||
# copy script files beside the executable
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
# copy script files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/scripts"
|
||||
"${RESOURCES_DEV_DIR}/scripts"
|
||||
)
|
||||
|
||||
# copy JSDoc files beside the executable
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
"${CMAKE_SOURCE_DIR}/scripts"
|
||||
"${RESOURCES_DEV_DIR}/scripts"
|
||||
# copy JSDoc files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
"${RESOURCES_DEV_DIR}/jsdoc"
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
"${RESOURCES_DEV_DIR}/jsdoc"
|
||||
# copy the resources files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${RESOURCES_RCC}"
|
||||
"${RESOURCES_DEV_DIR}"
|
||||
# FIXME, the edit script code loads HTML from the scripts folder
|
||||
# which in turn relies on CSS that refers to the fonts. In theory
|
||||
# we should be able to modify the CSS to reference the QRC path to
|
||||
# the ttf files, but doing so generates a CORS policy violation,
|
||||
# so we have to retain a copy of the fonts outside of the resources binary
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/resources/fonts"
|
||||
"${RESOURCES_DEV_DIR}/fonts"
|
||||
)
|
||||
|
||||
# call the fixup_interface macro to add required bundling commands for installation
|
||||
|
@ -357,13 +360,10 @@ else()
|
|||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/tutorial.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/tutorial.json"
|
||||
)
|
||||
|
||||
# copy JSDoc files beside the executable
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
# copy JSDoc files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
"${INTERFACE_EXEC_DIR}/jsdoc"
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
"${INTERFACE_EXEC_DIR}/jsdoc"
|
||||
)
|
||||
|
||||
# link target to external libraries
|
||||
|
|
|
@ -331,6 +331,7 @@ ModalWindow {
|
|||
}
|
||||
|
||||
onFolderChanged: {
|
||||
d.clearSelection();
|
||||
fileTableModel.update(); // Update once the data from the folder change is available.
|
||||
}
|
||||
|
||||
|
@ -450,7 +451,7 @@ ModalWindow {
|
|||
rows = 0,
|
||||
i;
|
||||
|
||||
var newFilesModel = filesModelBuilder.createObject(root);
|
||||
filesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
|
@ -472,7 +473,7 @@ ModalWindow {
|
|||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, newFilesModel.get(middle)[sortField])) {
|
||||
if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
|
@ -481,7 +482,7 @@ ModalWindow {
|
|||
}
|
||||
}
|
||||
|
||||
newFilesModel.insert(lower, {
|
||||
filesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
|
@ -492,9 +493,6 @@ ModalWindow {
|
|||
|
||||
rows++;
|
||||
}
|
||||
filesModel = newFilesModel;
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -332,6 +332,7 @@ ModalWindow {
|
|||
}
|
||||
|
||||
onFolderChanged: {
|
||||
d.clearSelection();
|
||||
fileTableModel.update(); // Update once the data from the folder change is available.
|
||||
}
|
||||
|
||||
|
@ -451,7 +452,7 @@ ModalWindow {
|
|||
rows = 0,
|
||||
i;
|
||||
|
||||
var newFilesModel = filesModelBuilder.createObject(root);
|
||||
filesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
|
@ -473,7 +474,7 @@ ModalWindow {
|
|||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, newFilesModel.get(middle)[sortField])) {
|
||||
if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
|
@ -482,7 +483,7 @@ ModalWindow {
|
|||
}
|
||||
}
|
||||
|
||||
newFilesModel.insert(lower, {
|
||||
filesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
|
@ -493,9 +494,6 @@ ModalWindow {
|
|||
|
||||
rows++;
|
||||
}
|
||||
filesModel = newFilesModel;
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -295,7 +295,8 @@ TabletModalWindow {
|
|||
}
|
||||
|
||||
onFolderChanged: {
|
||||
fileTableModel.update()
|
||||
d.clearSelection();
|
||||
fileTableModel.update();
|
||||
}
|
||||
|
||||
function getItem(index, field) {
|
||||
|
@ -413,7 +414,7 @@ TabletModalWindow {
|
|||
rows = 0,
|
||||
i;
|
||||
|
||||
var newFilesModel = filesModelBuilder.createObject(root);
|
||||
filesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
|
@ -435,7 +436,7 @@ TabletModalWindow {
|
|||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, newFilesModel.get(middle)[sortField])) {
|
||||
if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
|
@ -444,7 +445,7 @@ TabletModalWindow {
|
|||
}
|
||||
}
|
||||
|
||||
newFilesModel.insert(lower, {
|
||||
filesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
|
@ -455,9 +456,6 @@ TabletModalWindow {
|
|||
|
||||
rows++;
|
||||
}
|
||||
filesModel = newFilesModel;
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick 2.7
|
||||
import Qt.labs.folderlistmodel 2.1
|
||||
import Qt.labs.settings 1.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
import QtQuick.Controls 1.4 as QQC1
|
||||
import QtQuick.Controls 2.3
|
||||
|
||||
import ".."
|
||||
import "../../../controls-uit"
|
||||
|
@ -30,6 +30,8 @@ Rectangle {
|
|||
|
||||
color: hifi.colors.baseGray;
|
||||
|
||||
property var filesModel: ListModel { }
|
||||
|
||||
Settings {
|
||||
category: "FileDialog"
|
||||
property alias width: root.width
|
||||
|
@ -149,7 +151,7 @@ Rectangle {
|
|||
|
||||
ComboBox {
|
||||
id: pathSelector
|
||||
anchors {
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: hifi.dimensions.contentMargin.y
|
||||
left: navControls.right
|
||||
|
@ -247,7 +249,9 @@ Rectangle {
|
|||
}
|
||||
|
||||
currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath);
|
||||
currentSelectionIsFolder = fileTableView.model.isFolder(row);
|
||||
currentSelectionIsFolder = fileTableView.model !== filesModel ?
|
||||
fileTableView.model.isFolder(row) :
|
||||
fileTableModel.isFolder(row);
|
||||
if (root.selectDirectory || !currentSelectionIsFolder) {
|
||||
currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl));
|
||||
} else {
|
||||
|
@ -287,6 +291,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onFolderChanged: {
|
||||
d.clearSelection();
|
||||
fileTableModel.update(); // Update once the data from the folder change is available.
|
||||
}
|
||||
|
||||
|
@ -327,7 +332,12 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
Component {
|
||||
id: filesModelBuilder
|
||||
ListModel { }
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: fileTableModel
|
||||
|
||||
// FolderListModel has a couple of problems:
|
||||
|
@ -379,7 +389,11 @@ Rectangle {
|
|||
if (row === -1) {
|
||||
return false;
|
||||
}
|
||||
return get(row).fileIsDir;
|
||||
return filesModel.get(row).fileIsDir;
|
||||
}
|
||||
|
||||
function get(row) {
|
||||
return filesModel.get(row)
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
@ -397,7 +411,7 @@ Rectangle {
|
|||
rows = 0,
|
||||
i;
|
||||
|
||||
clear();
|
||||
filesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
|
@ -419,7 +433,7 @@ Rectangle {
|
|||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, get(middle)[sortField])) {
|
||||
if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
|
@ -428,7 +442,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
insert(lower, {
|
||||
filesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
|
@ -439,8 +453,6 @@ Rectangle {
|
|||
|
||||
rows++;
|
||||
}
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -465,12 +477,12 @@ Rectangle {
|
|||
sortIndicatorOrder: Qt.AscendingOrder
|
||||
sortIndicatorVisible: true
|
||||
|
||||
model: fileTableModel
|
||||
model: filesModel
|
||||
|
||||
function updateSort() {
|
||||
model.sortOrder = sortIndicatorOrder;
|
||||
model.sortColumn = sortIndicatorColumn;
|
||||
model.update();
|
||||
fileTableModel.sortOrder = sortIndicatorOrder;
|
||||
fileTableModel.sortColumn = sortIndicatorColumn;
|
||||
fileTableModel.update();
|
||||
}
|
||||
|
||||
onSortIndicatorColumnChanged: { updateSort(); }
|
||||
|
@ -522,7 +534,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
TableViewColumn {
|
||||
QQC1.TableViewColumn {
|
||||
id: fileNameColumn
|
||||
role: "fileName"
|
||||
title: "Name"
|
||||
|
@ -530,7 +542,7 @@ Rectangle {
|
|||
movable: false
|
||||
resizable: true
|
||||
}
|
||||
TableViewColumn {
|
||||
QQC1.TableViewColumn {
|
||||
id: fileMofifiedColumn
|
||||
role: "fileModified"
|
||||
title: "Date"
|
||||
|
@ -539,7 +551,7 @@ Rectangle {
|
|||
resizable: true
|
||||
visible: !selectDirectory
|
||||
}
|
||||
TableViewColumn {
|
||||
QQC1.TableViewColumn {
|
||||
role: "fileSize"
|
||||
title: "Size"
|
||||
width: fileTableView.width - fileNameColumn.width - fileMofifiedColumn.width
|
||||
|
@ -554,11 +566,12 @@ Rectangle {
|
|||
}
|
||||
|
||||
function navigateToCurrentRow() {
|
||||
var currentModel = fileTableView.model !== filesModel ? fileTableView.model : fileTableModel
|
||||
var row = fileTableView.currentRow
|
||||
var isFolder = model.isFolder(row);
|
||||
var file = model.get(row).filePath;
|
||||
var isFolder = currentModel.isFolder(row);
|
||||
var file = currentModel.get(row).filePath;
|
||||
if (isFolder) {
|
||||
fileTableView.model.folder = helper.pathToUrl(file);
|
||||
currentModel.folder = helper.pathToUrl(file);
|
||||
} else {
|
||||
okAction.trigger();
|
||||
}
|
||||
|
@ -573,7 +586,8 @@ Rectangle {
|
|||
var newPrefix = prefix + event.text.toLowerCase();
|
||||
var matchedIndex = -1;
|
||||
for (var i = 0; i < model.count; ++i) {
|
||||
var name = model.get(i).fileName.toLowerCase();
|
||||
var name = model !== filesModel ? model.get(i).fileName.toLowerCase() :
|
||||
filesModel.get(i).fileName.toLowerCase();
|
||||
if (0 === name.indexOf(newPrefix)) {
|
||||
matchedIndex = i;
|
||||
break;
|
||||
|
|
|
@ -802,15 +802,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir);
|
||||
}
|
||||
|
||||
// FIXME fix the OSX installer to install the resources.rcc binary instead of resource files and remove
|
||||
// this conditional exclusion
|
||||
#if !defined(Q_OS_OSX)
|
||||
{
|
||||
#if defined(Q_OS_ANDROID)
|
||||
const QString resourcesBinaryFile = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/resources.rcc";
|
||||
#else
|
||||
const QString resourcesBinaryFile = QCoreApplication::applicationDirPath() + "/resources.rcc";
|
||||
#endif
|
||||
const QString resourcesBinaryFile = PathUtils::getRccPath();
|
||||
if (!QFile::exists(resourcesBinaryFile)) {
|
||||
throw std::runtime_error("Unable to find primary resources");
|
||||
}
|
||||
|
@ -818,7 +811,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
throw std::runtime_error("Unable to load primary resources");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Tell the plugin manager about our statically linked plugins
|
||||
auto pluginManager = PluginManager::getInstance();
|
||||
|
@ -3674,9 +3666,21 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_1:
|
||||
case Qt::Key_2:
|
||||
case Qt::Key_3:
|
||||
case Qt::Key_1: {
|
||||
Menu* menu = Menu::getInstance();
|
||||
menu->triggerOption(MenuOption::FirstPerson);
|
||||
break;
|
||||
}
|
||||
case Qt::Key_2: {
|
||||
Menu* menu = Menu::getInstance();
|
||||
menu->triggerOption(MenuOption::FullscreenMirror);
|
||||
break;
|
||||
}
|
||||
case Qt::Key_3: {
|
||||
Menu* menu = Menu::getInstance();
|
||||
menu->triggerOption(MenuOption::ThirdPerson);
|
||||
break;
|
||||
}
|
||||
case Qt::Key_4:
|
||||
case Qt::Key_5:
|
||||
case Qt::Key_6:
|
||||
|
@ -4187,7 +4191,7 @@ bool Application::acceptSnapshot(const QString& urlString) {
|
|||
static uint32_t _renderedFrameIndex { INVALID_FRAME };
|
||||
|
||||
bool Application::shouldPaint() const {
|
||||
if (_aboutToQuit) {
|
||||
if (_aboutToQuit || _window->isMinimized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4747,12 +4751,15 @@ void Application::loadSettings() {
|
|||
// DONT CHECK IN
|
||||
//DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false);
|
||||
|
||||
Menu::getInstance()->loadSettings();
|
||||
auto menu = Menu::getInstance();
|
||||
menu->loadSettings();
|
||||
|
||||
// override the menu option show overlays to always be true on startup
|
||||
menu->setIsOptionChecked(MenuOption::Overlays, true);
|
||||
|
||||
// If there is a preferred plugin, we probably messed it up with the menu settings, so fix it.
|
||||
auto pluginManager = PluginManager::getInstance();
|
||||
auto plugins = pluginManager->getPreferredDisplayPlugins();
|
||||
auto menu = Menu::getInstance();
|
||||
if (plugins.size() > 0) {
|
||||
for (auto plugin : plugins) {
|
||||
if (auto action = menu->getActionForOption(plugin->getName())) {
|
||||
|
@ -8041,7 +8048,6 @@ void Application::switchDisplayMode() {
|
|||
setActiveDisplayPlugin(DESKTOP_DISPLAY_PLUGIN_NAME);
|
||||
startHMDStandBySession();
|
||||
}
|
||||
emit activeDisplayPluginChanged();
|
||||
}
|
||||
_previousHMDWornStatus = currentHMDWornStatus;
|
||||
}
|
||||
|
|
|
@ -30,9 +30,6 @@ void Application::editRenderArgs(RenderArgsEditor editor) {
|
|||
|
||||
void Application::paintGL() {
|
||||
// Some plugins process message events, allowing paintGL to be called reentrantly.
|
||||
if (_aboutToQuit || _window->isMinimized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_renderFrameCount++;
|
||||
_lastTimeRendered.start();
|
||||
|
|
|
@ -217,21 +217,21 @@ Menu::Menu() {
|
|||
|
||||
// View > First Person
|
||||
auto firstPersonAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
|
||||
viewMenu, MenuOption::FirstPerson, Qt::Key_1,
|
||||
viewMenu, MenuOption::FirstPerson, 0,
|
||||
true, qApp, SLOT(cameraMenuChanged())));
|
||||
|
||||
firstPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup));
|
||||
|
||||
// View > Third Person
|
||||
auto thirdPersonAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
|
||||
viewMenu, MenuOption::ThirdPerson, Qt::Key_3,
|
||||
viewMenu, MenuOption::ThirdPerson, 0,
|
||||
false, qApp, SLOT(cameraMenuChanged())));
|
||||
|
||||
thirdPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup));
|
||||
|
||||
// View > Mirror
|
||||
auto viewMirrorAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
|
||||
viewMenu, MenuOption::FullscreenMirror, Qt::Key_2,
|
||||
viewMenu, MenuOption::FullscreenMirror, 0,
|
||||
false, qApp, SLOT(cameraMenuChanged())));
|
||||
|
||||
viewMirrorAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup));
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Application.h"
|
||||
#include "SecondaryCamera.h"
|
||||
#include <TextureCache.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
#include <gpu/Context.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
using RenderArgsPointer = std::shared_ptr<RenderArgs>;
|
||||
|
||||
|
|
|
@ -654,8 +654,8 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
if (success) {
|
||||
moveOperator.addEntityToMoveList(entity, newCube);
|
||||
}
|
||||
// send an edit packet to update the entity-server about the queryAABox. If it's an
|
||||
// avatar-entity, don't.
|
||||
// send an edit packet to update the entity-server about the queryAABox
|
||||
// unless it is client-only
|
||||
if (packetSender && !entity->getClientOnly()) {
|
||||
EntityItemProperties properties = entity->getProperties();
|
||||
properties.setQueryAACubeDirty();
|
||||
|
@ -663,6 +663,17 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entity->getID(), properties);
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
|
||||
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
|
||||
if (!entityDescendant->getClientOnly() && descendant->updateQueryAACube()) {
|
||||
EntityItemProperties descendantProperties;
|
||||
descendantProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
descendantProperties.setLastEdited(now);
|
||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entityDescendant->getID(), descendantProperties);
|
||||
entityDescendant->setLastBroadcast(now); // for debug/physics status icons
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -314,6 +314,7 @@ Wallet::Wallet() {
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
_passphrase = new QString("");
|
||||
|
||||
packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket");
|
||||
packetReceiver.registerListener(PacketType::ChallengeOwnershipRequest, this, "handleChallengeOwnershipPacket");
|
||||
|
@ -365,6 +366,10 @@ Wallet::~Wallet() {
|
|||
if (_securityImage) {
|
||||
delete _securityImage;
|
||||
}
|
||||
|
||||
if (_passphrase) {
|
||||
delete _passphrase;
|
||||
}
|
||||
}
|
||||
|
||||
bool Wallet::setPassphrase(const QString& passphrase) {
|
||||
|
|
|
@ -78,7 +78,7 @@ private:
|
|||
QByteArray _salt;
|
||||
QByteArray _iv;
|
||||
QByteArray _ckey;
|
||||
QString* _passphrase { new QString("") };
|
||||
QString* _passphrase { nullptr };
|
||||
bool _isOverridingServer { false };
|
||||
|
||||
bool writeWallet(const QString& newPassphrase = QString(""));
|
||||
|
|
|
@ -105,9 +105,6 @@ class ScriptEngine;
|
|||
* <li>{@link Controller.getValue|getValue}</li>
|
||||
* <li>{@link Controller.getAxisValue|getAxisValue}</li>
|
||||
* <li>{@link Controller.getPoseValue|getgetPoseValue}</li>
|
||||
* <li>{@link Controller.getButtonValue|getButtonValue} for a particular device</li>
|
||||
* <li>{@link Controller.getAxisValue(0)|getAxisValue} for a particular device</li>
|
||||
* <li>{@link Controller.getPoseValue(0)|getPoseValue} for a particular device</li>
|
||||
* <li>{@link Controller.getActionValue|getActionValue}</li>
|
||||
* </ul>
|
||||
*
|
||||
|
|
|
@ -349,3 +349,23 @@ void Base3DOverlay::setVisible(bool visible) {
|
|||
Parent::setVisible(visible);
|
||||
notifyRenderVariableChange();
|
||||
}
|
||||
|
||||
render::ItemKey Base3DOverlay::getKey() {
|
||||
auto builder = render::ItemKey::Builder(Overlay::getKey());
|
||||
|
||||
if (getDrawInFront()) {
|
||||
builder.withLayer(render::hifi::LAYER_3D_FRONT);
|
||||
} else if (getDrawHUDLayer()) {
|
||||
builder.withLayer(render::hifi::LAYER_3D_HUD);
|
||||
} else {
|
||||
builder.withoutLayer();
|
||||
}
|
||||
|
||||
builder.withoutViewSpace();
|
||||
|
||||
if (isTransparent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
|
@ -35,6 +35,7 @@ public:
|
|||
// getters
|
||||
virtual bool is3D() const override { return true; }
|
||||
|
||||
virtual render::ItemKey getKey() override;
|
||||
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override { subItems.push_back(getRenderItemID()); return (uint32_t) subItems.size(); }
|
||||
virtual scriptable::ScriptableModelBase getScriptableModel() override { return scriptable::ScriptableModelBase(); }
|
||||
|
||||
|
|
|
@ -115,6 +115,10 @@ void ModelOverlay::update(float deltatime) {
|
|||
_drawInHUDDirty = false;
|
||||
_model->setLayeredInHUD(getDrawHUDLayer(), scene);
|
||||
}
|
||||
if (_groupCulledDirty) {
|
||||
_groupCulledDirty = false;
|
||||
_model->setGroupCulled(_isGroupCulled);
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
|
||||
if (!_texturesLoaded && _model->getGeometry() && _model->getGeometry()->areTexturesLoaded()) {
|
||||
|
@ -149,13 +153,24 @@ void ModelOverlay::setVisible(bool visible) {
|
|||
}
|
||||
|
||||
void ModelOverlay::setDrawInFront(bool drawInFront) {
|
||||
Base3DOverlay::setDrawInFront(drawInFront);
|
||||
_drawInFrontDirty = true;
|
||||
if (drawInFront != getDrawInFront()) {
|
||||
Base3DOverlay::setDrawInFront(drawInFront);
|
||||
_drawInFrontDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelOverlay::setDrawHUDLayer(bool drawHUDLayer) {
|
||||
Base3DOverlay::setDrawHUDLayer(drawHUDLayer);
|
||||
_drawInHUDDirty = true;
|
||||
if (drawHUDLayer != getDrawHUDLayer()) {
|
||||
Base3DOverlay::setDrawHUDLayer(drawHUDLayer);
|
||||
_drawInHUDDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelOverlay::setGroupCulled(bool groupCulled) {
|
||||
if (groupCulled != _isGroupCulled) {
|
||||
_isGroupCulled = groupCulled;
|
||||
_groupCulledDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelOverlay::setProperties(const QVariantMap& properties) {
|
||||
|
@ -210,6 +225,11 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
|
|||
Q_ARG(const QVariantMap&, textureMap));
|
||||
}
|
||||
|
||||
auto groupCulledValue = properties["isGroupCulled"];
|
||||
if (groupCulledValue.isValid() && groupCulledValue.canConvert(QVariant::Bool)) {
|
||||
setGroupCulled(groupCulledValue.toBool());
|
||||
}
|
||||
|
||||
// jointNames is read-only.
|
||||
// jointPositions is read-only.
|
||||
// jointOrientations is read-only.
|
||||
|
@ -347,6 +367,8 @@ vectorType ModelOverlay::mapJoints(mapFunction<itemType> function) const {
|
|||
* {@link Overlays.findRayIntersection|findRayIntersection} ignores the overlay.
|
||||
* @property {boolean} drawInFront=false - If <code>true</code>, the overlay is rendered in front of other overlays that don't
|
||||
* have <code>drawInFront</code> set to <code>true</code>, and in front of entities.
|
||||
* @property {boolean} isGroupCulled=false - If <code>true</code>, the mesh parts of the model are LOD culled as a group.
|
||||
* If <code>false</code>, separate mesh parts will be LOD culled individually.
|
||||
* @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed.
|
||||
* @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to.
|
||||
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
|
||||
|
@ -711,3 +733,11 @@ scriptable::ScriptableModelBase ModelOverlay::getScriptableModel() {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
render::ItemKey ModelOverlay::getKey() {
|
||||
auto builder = render::ItemKey::Builder(Base3DOverlay::getKey());
|
||||
if (_isGroupCulled) {
|
||||
builder.withMetaCullGroup();
|
||||
}
|
||||
return builder.build();
|
||||
}
|
|
@ -33,6 +33,7 @@ public:
|
|||
|
||||
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override;
|
||||
|
||||
render::ItemKey getKey() override;
|
||||
void clearSubRenderItemIDs();
|
||||
void setSubRenderItemIDs(const render::ItemIDs& ids);
|
||||
|
||||
|
@ -63,6 +64,7 @@ public:
|
|||
void setVisible(bool visible) override;
|
||||
void setDrawInFront(bool drawInFront) override;
|
||||
void setDrawHUDLayer(bool drawHUDLayer) override;
|
||||
void setGroupCulled(bool groupCulled);
|
||||
|
||||
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override;
|
||||
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override;
|
||||
|
@ -121,6 +123,8 @@ private:
|
|||
bool _visibleDirty { true };
|
||||
bool _drawInFrontDirty { false };
|
||||
bool _drawInHUDDirty { false };
|
||||
bool _isGroupCulled { false };
|
||||
bool _groupCulledDirty { false };
|
||||
|
||||
void processMaterials();
|
||||
|
||||
|
|
|
@ -244,4 +244,21 @@ void Overlay::addMaterial(graphics::MaterialLayer material, const std::string& p
|
|||
void Overlay::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||
_materials[parentMaterialName].remove(material);
|
||||
}
|
||||
|
||||
render::ItemKey Overlay::getKey() {
|
||||
auto builder = render::ItemKey::Builder().withTypeShape();
|
||||
|
||||
builder.withViewSpace();
|
||||
builder.withLayer(render::hifi::LAYER_2D);
|
||||
|
||||
if (!getVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
// always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view
|
||||
render::hifi::Tag viewTagBits = getIsVisibleInSecondaryCamera() ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW;
|
||||
builder.withTagBits(viewTagBits);
|
||||
|
||||
return builder.build();
|
||||
}
|
|
@ -40,6 +40,7 @@ public:
|
|||
virtual void update(float deltatime) {}
|
||||
virtual void render(RenderArgs* args) = 0;
|
||||
|
||||
virtual render::ItemKey getKey();
|
||||
virtual AABox getBounds() const = 0;
|
||||
virtual bool supportsGetProperty() const { return true; }
|
||||
|
||||
|
|
|
@ -32,32 +32,7 @@
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay) {
|
||||
auto builder = ItemKey::Builder().withTypeShape();
|
||||
if (overlay->is3D()) {
|
||||
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
|
||||
if (overlay3D->getDrawInFront()) {
|
||||
builder.withLayer(render::hifi::LAYER_3D_FRONT);
|
||||
} else if (overlay3D->getDrawHUDLayer()) {
|
||||
builder.withLayer(render::hifi::LAYER_3D_HUD);
|
||||
}
|
||||
|
||||
if (overlay->isTransparent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
} else {
|
||||
builder.withViewSpace();
|
||||
builder.withLayer(render::hifi::LAYER_2D);
|
||||
}
|
||||
|
||||
if (!overlay->getVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
// always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view
|
||||
render::hifi::Tag viewTagBits = overlay->getIsVisibleInSecondaryCamera() ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW;
|
||||
builder.withTagBits(viewTagBits);
|
||||
|
||||
return builder.build();
|
||||
return overlay->getKey();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
|
||||
return overlay->getBounds();
|
||||
|
|
|
@ -92,28 +92,16 @@ namespace controller {
|
|||
return userInputMapper->getValue(Input((uint32_t)source));
|
||||
}
|
||||
|
||||
float ScriptingInterface::getButtonValue(StandardButtonChannel source, uint16_t device) const {
|
||||
return getValue(Input(device, source, ChannelType::BUTTON).getID());
|
||||
}
|
||||
|
||||
float ScriptingInterface::getAxisValue(int source) const {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
return userInputMapper->getValue(Input((uint32_t)source));
|
||||
}
|
||||
|
||||
float ScriptingInterface::getAxisValue(StandardAxisChannel source, uint16_t device) const {
|
||||
return getValue(Input(device, source, ChannelType::AXIS).getID());
|
||||
}
|
||||
|
||||
Pose ScriptingInterface::getPoseValue(const int& source) const {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
return userInputMapper->getPose(Input((uint32_t)source));
|
||||
}
|
||||
|
||||
Pose ScriptingInterface::getPoseValue(StandardPoseChannel source, uint16_t device) const {
|
||||
return getPoseValue(Input(device, source, ChannelType::POSE).getID());
|
||||
}
|
||||
|
||||
QVector<Action> ScriptingInterface::getAllActions() {
|
||||
return DependencyManager::get<UserInputMapper>()->getAllActions();
|
||||
}
|
||||
|
|
|
@ -206,43 +206,6 @@ namespace controller {
|
|||
*/
|
||||
Q_INVOKABLE Pose getPoseValue(const int& source) const;
|
||||
|
||||
/**jsdoc
|
||||
* Get the value of a button on a particular device.
|
||||
* @function Controller.getButtonValue
|
||||
* @param {StandardButtonChannel} source - The button to get the value of.
|
||||
* @param {number} [device=0] - The ID of the hardware device to get the value from. The default value of
|
||||
* <code>0</code> corresponds to <code>Standard</code>.
|
||||
* @returns {number} The current value of the button if the parameters are valid, otherwise <code>0</code>.
|
||||
* @deprecated This function no longer works.
|
||||
*/
|
||||
// FIXME: This function causes a JavaScript crash: https://highfidelity.manuscript.com/f/cases/edit/14139
|
||||
Q_INVOKABLE float getButtonValue(StandardButtonChannel source, uint16_t device = 0) const;
|
||||
|
||||
/**jsdoc
|
||||
* Get the value of an axis control on a particular device.
|
||||
* @function Controller.getAxisValue
|
||||
* @variation 0
|
||||
* @param {StandardAxisChannel} source - The axis to get the value of.
|
||||
* @param {number} [device=0] - The ID of the hardware device to get the value from. The default value of
|
||||
* <code>0</code> corresponds to <code>Standard</code>.
|
||||
* @returns {number} The current value of the axis if the parameters are valid, otherwise <code>0</code>.
|
||||
* @deprecated This function no longer works.
|
||||
*/
|
||||
Q_INVOKABLE float getAxisValue(StandardAxisChannel source, uint16_t device = 0) const;
|
||||
|
||||
/**jsdoc
|
||||
* Get the value of an pose control on a particular device.
|
||||
* @function Controller.getPoseValue
|
||||
* @variation 0
|
||||
* @param {StandardPoseChannel} source - The pose to get the value of.
|
||||
* @param {number} [device=0] - The ID of the hardware device to get the value from. The default value of
|
||||
* <code>0</code> corresponds to <code>Standard</code>.
|
||||
* @returns {Pose} The current value of the controller pose output if the parameters are valid, otherwise an invalid
|
||||
* pose with <code>Pose.valid == false</code>.
|
||||
* @deprecated This function no longer works.
|
||||
*/
|
||||
Q_INVOKABLE Pose getPoseValue(StandardPoseChannel source, uint16_t device = 0) const;
|
||||
|
||||
/**jsdoc
|
||||
* Triggers a haptic pulse on connected and enabled devices that have the capability.
|
||||
* @function Controller.triggerHapticPulse
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "HTTPConnection.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QCryptographicHash>
|
||||
#include <QTcpSocket>
|
||||
|
@ -29,11 +31,92 @@ const char* HTTPConnection::StatusCode404 = "404 Not Found";
|
|||
const char* HTTPConnection::StatusCode500 = "500 Internal server error";
|
||||
const char* HTTPConnection::DefaultContentType = "text/plain; charset=ISO-8859-1";
|
||||
|
||||
HTTPConnection::HTTPConnection (QTcpSocket* socket, HTTPManager* parentManager) :
|
||||
|
||||
class MemoryStorage : public HTTPConnection::Storage {
|
||||
public:
|
||||
static std::unique_ptr<MemoryStorage> make(qint64 size);
|
||||
virtual ~MemoryStorage() = default;
|
||||
|
||||
const QByteArray& content() const override { return _array; }
|
||||
qint64 bytesLeftToWrite() const override { return _array.size() - _bytesWritten; }
|
||||
void write(const QByteArray& data) override;
|
||||
|
||||
private:
|
||||
MemoryStorage(qint64 size) { _array.resize(size); }
|
||||
|
||||
QByteArray _array;
|
||||
qint64 _bytesWritten { 0 };
|
||||
};
|
||||
|
||||
std::unique_ptr<MemoryStorage> MemoryStorage::make(qint64 size) {
|
||||
return std::unique_ptr<MemoryStorage>(new MemoryStorage(size));
|
||||
}
|
||||
|
||||
void MemoryStorage::write(const QByteArray& data) {
|
||||
assert(data.size() <= bytesLeftToWrite());
|
||||
memcpy(_array.data() + _bytesWritten, data.data(), data.size());
|
||||
_bytesWritten += data.size();
|
||||
}
|
||||
|
||||
|
||||
class FileStorage : public HTTPConnection::Storage {
|
||||
public:
|
||||
static std::unique_ptr<FileStorage> make(qint64 size);
|
||||
virtual ~FileStorage();
|
||||
|
||||
const QByteArray& content() const override { return _wrapperArray; };
|
||||
qint64 bytesLeftToWrite() const override { return _mappedMemorySize - _bytesWritten; }
|
||||
void write(const QByteArray& data) override;
|
||||
|
||||
private:
|
||||
FileStorage(std::unique_ptr<QTemporaryFile> file, uchar* mapped, qint64 size);
|
||||
|
||||
// Byte array is const because any edit will trigger a deep copy
|
||||
// and pull all the data we want to keep on disk in memory.
|
||||
const QByteArray _wrapperArray;
|
||||
std::unique_ptr<QTemporaryFile> _file;
|
||||
|
||||
uchar* const _mappedMemoryAddress { nullptr };
|
||||
const qint64 _mappedMemorySize { 0 };
|
||||
qint64 _bytesWritten { 0 };
|
||||
};
|
||||
|
||||
std::unique_ptr<FileStorage> FileStorage::make(qint64 size) {
|
||||
auto file = std::unique_ptr<QTemporaryFile>(new QTemporaryFile());
|
||||
file->open(); // Open for resize
|
||||
file->resize(size);
|
||||
auto mapped = file->map(0, size); // map the entire file
|
||||
|
||||
return std::unique_ptr<FileStorage>(new FileStorage(std::move(file), mapped, size));
|
||||
}
|
||||
|
||||
// Use QByteArray::fromRawData to avoid a new allocation and access the already existing
|
||||
// memory directly as long as all operations on the array are const.
|
||||
FileStorage::FileStorage(std::unique_ptr<QTemporaryFile> file, uchar* mapped, qint64 size) :
|
||||
_wrapperArray(QByteArray::fromRawData(reinterpret_cast<char*>(mapped), size)),
|
||||
_file(std::move(file)),
|
||||
_mappedMemoryAddress(mapped),
|
||||
_mappedMemorySize(size)
|
||||
{
|
||||
}
|
||||
|
||||
FileStorage::~FileStorage() {
|
||||
_file->unmap(_mappedMemoryAddress);
|
||||
_file->close();
|
||||
}
|
||||
|
||||
void FileStorage::write(const QByteArray& data) {
|
||||
assert(data.size() <= bytesLeftToWrite());
|
||||
// We write directly to the mapped memory
|
||||
memcpy(_mappedMemoryAddress + _bytesWritten, data.data(), data.size());
|
||||
_bytesWritten += data.size();
|
||||
}
|
||||
|
||||
|
||||
HTTPConnection::HTTPConnection(QTcpSocket* socket, HTTPManager* parentManager) :
|
||||
QObject(parentManager),
|
||||
_parentManager(parentManager),
|
||||
_socket(socket),
|
||||
_stream(socket),
|
||||
_address(socket->peerAddress())
|
||||
{
|
||||
// take over ownership of the socket
|
||||
|
@ -62,7 +145,7 @@ QHash<QString, QString> HTTPConnection::parseUrlEncodedForm() {
|
|||
return QHash<QString, QString>();
|
||||
}
|
||||
|
||||
QUrlQuery form { _requestContent };
|
||||
QUrlQuery form { _requestContent->content() };
|
||||
QHash<QString, QString> pairs;
|
||||
for (auto pair : form.queryItems()) {
|
||||
auto key = QUrl::fromPercentEncoding(pair.first.toLatin1().replace('+', ' '));
|
||||
|
@ -97,7 +180,7 @@ QList<FormData> HTTPConnection::parseFormData() const {
|
|||
QByteArray end = "\r\n--" + boundary + "--\r\n";
|
||||
|
||||
QList<FormData> data;
|
||||
QBuffer buffer(const_cast<QByteArray*>(&_requestContent));
|
||||
QBuffer buffer(const_cast<QByteArray*>(&_requestContent->content()));
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
while (buffer.canReadLine()) {
|
||||
QByteArray line = buffer.readLine().trimmed();
|
||||
|
@ -107,12 +190,13 @@ QList<FormData> HTTPConnection::parseFormData() const {
|
|||
QByteArray line = buffer.readLine().trimmed();
|
||||
if (line.isEmpty()) {
|
||||
// content starts after this line
|
||||
int idx = _requestContent.indexOf(end, buffer.pos());
|
||||
int idx = _requestContent->content().indexOf(end, buffer.pos());
|
||||
if (idx == -1) {
|
||||
qWarning() << "Missing end boundary." << _address;
|
||||
return data;
|
||||
}
|
||||
datum.second = _requestContent.mid(buffer.pos(), idx - buffer.pos());
|
||||
datum.second = QByteArray::fromRawData(_requestContent->content().data() + buffer.pos(),
|
||||
idx - buffer.pos());
|
||||
data.append(datum);
|
||||
buffer.seek(idx + end.length());
|
||||
|
||||
|
@ -256,7 +340,24 @@ void HTTPConnection::readHeaders() {
|
|||
_parentManager->handleHTTPRequest(this, _requestUrl);
|
||||
|
||||
} else {
|
||||
_requestContent.resize(clength.toInt());
|
||||
bool success = false;
|
||||
auto length = clength.toInt(&success);
|
||||
if (!success) {
|
||||
qWarning() << "Invalid header." << _address << trimmed;
|
||||
respond("400 Bad Request", "The header was malformed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Storing big requests in memory gets expensive, especially on servers
|
||||
// with limited memory. So we store big requests in a temporary file on disk
|
||||
// and map it to faster read/write access.
|
||||
static const int MAX_CONTENT_SIZE_IN_MEMORY = 10 * 1000 * 1000;
|
||||
if (length < MAX_CONTENT_SIZE_IN_MEMORY) {
|
||||
_requestContent = MemoryStorage::make(length);
|
||||
} else {
|
||||
_requestContent = FileStorage::make(length);
|
||||
}
|
||||
|
||||
connect(_socket, SIGNAL(readyRead()), SLOT(readContent()));
|
||||
|
||||
// read any content immediately available
|
||||
|
@ -285,12 +386,13 @@ void HTTPConnection::readHeaders() {
|
|||
}
|
||||
|
||||
void HTTPConnection::readContent() {
|
||||
int size = _requestContent.size();
|
||||
if (_socket->bytesAvailable() < size) {
|
||||
return;
|
||||
}
|
||||
_socket->read(_requestContent.data(), size);
|
||||
_socket->disconnect(this, SLOT(readContent()));
|
||||
auto size = std::min(_socket->bytesAvailable(), _requestContent->bytesLeftToWrite());
|
||||
|
||||
_parentManager->handleHTTPRequest(this, _requestUrl.path());
|
||||
_requestContent->write(_socket->read(size));
|
||||
|
||||
if (_requestContent->bytesLeftToWrite() == 0) {
|
||||
_socket->disconnect(this, SLOT(readContent()));
|
||||
|
||||
_parentManager->handleHTTPRequest(this, _requestUrl.path());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,14 @@
|
|||
#ifndef hifi_HTTPConnection_h
|
||||
#define hifi_HTTPConnection_h
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QHash>
|
||||
#include <QtNetwork/QHostAddress>
|
||||
#include <QIODevice>
|
||||
#include <QList>
|
||||
#include <QtNetwork/QHostAddress>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QTemporaryFile>
|
||||
#include <QUrl>
|
||||
|
||||
#include <memory>
|
||||
|
@ -57,52 +57,63 @@ public:
|
|||
/// WebSocket close status codes.
|
||||
enum ReasonCode { NoReason = 0, NormalClosure = 1000, GoingAway = 1001 };
|
||||
|
||||
class Storage {
|
||||
public:
|
||||
Storage() = default;
|
||||
virtual ~Storage() = default;
|
||||
|
||||
virtual const QByteArray& content() const = 0;
|
||||
|
||||
virtual qint64 bytesLeftToWrite() const = 0;
|
||||
virtual void write(const QByteArray& data) = 0;
|
||||
};
|
||||
|
||||
/// Initializes the connection.
|
||||
HTTPConnection (QTcpSocket* socket, HTTPManager* parentManager);
|
||||
HTTPConnection(QTcpSocket* socket, HTTPManager* parentManager);
|
||||
|
||||
/// Destroys the connection.
|
||||
virtual ~HTTPConnection ();
|
||||
virtual ~HTTPConnection();
|
||||
|
||||
/// Returns a pointer to the underlying socket, to which WebSocket message bodies should be written.
|
||||
QTcpSocket* socket () const { return _socket; }
|
||||
QTcpSocket* socket() const { return _socket; }
|
||||
|
||||
/// Returns the request operation.
|
||||
QNetworkAccessManager::Operation requestOperation () const { return _requestOperation; }
|
||||
QNetworkAccessManager::Operation requestOperation() const { return _requestOperation; }
|
||||
|
||||
/// Returns a reference to the request URL.
|
||||
const QUrl& requestUrl () const { return _requestUrl; }
|
||||
const QUrl& requestUrl() const { return _requestUrl; }
|
||||
|
||||
/// Returns a copy of the request header value. If it does not exist, it will return a default constructed QByteArray.
|
||||
QByteArray requestHeader(const QString& key) const { return _requestHeaders.value(key.toLower().toLocal8Bit()); }
|
||||
|
||||
/// Returns a reference to the request content.
|
||||
const QByteArray& requestContent () const { return _requestContent; }
|
||||
const QByteArray& requestContent() const { return _requestContent->content(); }
|
||||
|
||||
/// Parses the request content as form data, returning a list of header/content pairs.
|
||||
QList<FormData> parseFormData () const;
|
||||
QList<FormData> parseFormData() const;
|
||||
|
||||
/// Parses the request content as a url encoded form, returning a hash of key/value pairs.
|
||||
/// Duplicate keys are not supported.
|
||||
QHash<QString, QString> parseUrlEncodedForm();
|
||||
|
||||
/// Sends a response and closes the connection.
|
||||
void respond (const char* code, const QByteArray& content = QByteArray(),
|
||||
void respond(const char* code, const QByteArray& content = QByteArray(),
|
||||
const char* contentType = DefaultContentType,
|
||||
const Headers& headers = Headers());
|
||||
void respond (const char* code, std::unique_ptr<QIODevice> device,
|
||||
void respond(const char* code, std::unique_ptr<QIODevice> device,
|
||||
const char* contentType = DefaultContentType,
|
||||
const Headers& headers = Headers());
|
||||
|
||||
protected slots:
|
||||
|
||||
/// Reads the request line.
|
||||
void readRequest ();
|
||||
void readRequest();
|
||||
|
||||
/// Reads the headers.
|
||||
void readHeaders ();
|
||||
void readHeaders();
|
||||
|
||||
/// Reads the content.
|
||||
void readContent ();
|
||||
void readContent();
|
||||
|
||||
protected:
|
||||
void respondWithStatusAndHeaders(const char* code, const char* contentType, const Headers& headers, qint64 size);
|
||||
|
@ -112,9 +123,6 @@ protected:
|
|||
|
||||
/// The underlying socket.
|
||||
QTcpSocket* _socket;
|
||||
|
||||
/// The data stream for writing to the socket.
|
||||
QDataStream _stream;
|
||||
|
||||
/// The stored address.
|
||||
QHostAddress _address;
|
||||
|
@ -132,7 +140,7 @@ protected:
|
|||
QByteArray _lastRequestHeader;
|
||||
|
||||
/// The content of the request.
|
||||
QByteArray _requestContent;
|
||||
std::unique_ptr<Storage> _requestContent;
|
||||
|
||||
/// Response content
|
||||
std::unique_ptr<QIODevice> _responseDevice;
|
||||
|
|
|
@ -24,8 +24,7 @@
|
|||
const int SOCKET_ERROR_EXIT_CODE = 2;
|
||||
const int SOCKET_CHECK_INTERVAL_IN_MS = 30000;
|
||||
|
||||
HTTPManager::HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) :
|
||||
QTcpServer(parent),
|
||||
HTTPManager::HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler) :
|
||||
_listenAddress(listenAddress),
|
||||
_documentRoot(documentRoot),
|
||||
_requestHandler(requestHandler),
|
||||
|
|
|
@ -33,7 +33,7 @@ class HTTPManager : public QTcpServer, public HTTPRequestHandler {
|
|||
Q_OBJECT
|
||||
public:
|
||||
/// Initializes the manager.
|
||||
HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0);
|
||||
HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = nullptr);
|
||||
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
|
||||
|
||||
|
|
|
@ -23,4 +23,4 @@ protected slots:
|
|||
void handleSSLErrors(const QList<QSslError>& errors);
|
||||
};
|
||||
|
||||
#endif // hifi_HTTPSConnection_h
|
||||
#endif // hifi_HTTPSConnection_h
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
#include "HTTPSConnection.h"
|
||||
|
||||
HTTPSManager::HTTPSManager(QHostAddress listenAddress, quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey,
|
||||
const QString& documentRoot, HTTPSRequestHandler* requestHandler, QObject* parent) :
|
||||
HTTPManager(listenAddress, port, documentRoot, requestHandler, parent),
|
||||
const QString& documentRoot, HTTPSRequestHandler* requestHandler) :
|
||||
HTTPManager(listenAddress, port, documentRoot, requestHandler),
|
||||
_certificate(certificate),
|
||||
_privateKey(privateKey),
|
||||
_sslRequestHandler(requestHandler)
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
const QSslCertificate& certificate,
|
||||
const QSslKey& privateKey,
|
||||
const QString& documentRoot,
|
||||
HTTPSRequestHandler* requestHandler = NULL, QObject* parent = 0);
|
||||
HTTPSRequestHandler* requestHandler = nullptr);
|
||||
|
||||
void setCertificate(const QSslCertificate& certificate) { _certificate = certificate; }
|
||||
void setPrivateKey(const QSslKey& privateKey) { _privateKey = privateKey; }
|
||||
|
@ -48,4 +48,4 @@ private:
|
|||
HTTPSRequestHandler* _sslRequestHandler;
|
||||
};
|
||||
|
||||
#endif // hifi_HTTPSManager_h
|
||||
#endif // hifi_HTTPSManager_h
|
||||
|
|
|
@ -684,9 +684,9 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
|
||||
PROFILE_RANGE(render_gpu, "sphericalHarmonicsFromTexture");
|
||||
|
||||
#ifndef USE_GLES
|
||||
auto mipFormat = cubeTexture.getStoredMipFormat();
|
||||
std::function<glm::vec3(uint32)> unpackFunc;
|
||||
|
||||
switch (mipFormat.getSemantic()) {
|
||||
case gpu::R11G11B10:
|
||||
unpackFunc = glm::unpackF2x11_1x10;
|
||||
|
@ -698,6 +698,7 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
assert(false);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
const uint sqOrder = order*order;
|
||||
|
||||
|
@ -732,7 +733,11 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
|
||||
PROFILE_RANGE(render_gpu, "ProcessFace");
|
||||
|
||||
#ifndef USE_GLES
|
||||
auto data = reinterpret_cast<const uint32*>( cubeTexture.accessStoredMipFace(0, face)->readData() );
|
||||
#else
|
||||
auto data = cubeTexture.accessStoredMipFace(0, face)->readData();
|
||||
#endif
|
||||
if (data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
@ -816,8 +821,15 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
|||
glm::vec3 color{ 0.0f, 0.0f, 0.0f };
|
||||
for (int i = 0; i < stride; ++i) {
|
||||
for (int j = 0; j < stride; ++j) {
|
||||
#ifndef USE_GLES
|
||||
int k = (int)(x + i - halfStride + (y + j - halfStride) * width);
|
||||
color += unpackFunc(data[k]);
|
||||
#else
|
||||
const int NUM_COMPONENTS_PER_PIXEL = 4;
|
||||
int k = NUM_COMPONENTS_PER_PIXEL * (int)(x + i - halfStride + (y + j - halfStride) * width);
|
||||
// BGRA -> RGBA
|
||||
color += glm::pow(glm::vec3(data[k + 2], data[k + 1], data[k]) / 255.0f, glm::vec3(2.2f));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
|
|||
if (!Texture::evalKTXFormat(mipFormat, texelFormat, header)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// Set Dimensions
|
||||
uint32_t numFaces = 1;
|
||||
switch (texture.getType()) {
|
||||
|
|
|
@ -2,3 +2,4 @@ set(TARGET_NAME image)
|
|||
setup_hifi_library()
|
||||
link_hifi_libraries(shared gpu)
|
||||
target_nvtt()
|
||||
target_etc2comp()
|
||||
|
|
|
@ -31,8 +31,17 @@ using namespace gpu;
|
|||
#define CPU_MIPMAPS 1
|
||||
#include <nvtt/nvtt.h>
|
||||
|
||||
#ifdef USE_GLES
|
||||
#include <Etc.h>
|
||||
#include <EtcFilter.h>
|
||||
#endif
|
||||
|
||||
static const glm::uvec2 SPARSE_PAGE_SIZE(128);
|
||||
#ifdef Q_OS_ANDROID
|
||||
static const glm::uvec2 MAX_TEXTURE_SIZE(2048);
|
||||
#else
|
||||
static const glm::uvec2 MAX_TEXTURE_SIZE(4096);
|
||||
#endif
|
||||
bool DEV_DECIMATE_TEXTURES = false;
|
||||
std::atomic<size_t> DECIMATED_TEXTURE_COUNT{ 0 };
|
||||
std::atomic<size_t> RECTIFIED_TEXTURE_COUNT{ 0 };
|
||||
|
@ -75,7 +84,13 @@ const QStringList getSupportedFormats() {
|
|||
return stringFormats;
|
||||
}
|
||||
|
||||
|
||||
// On GLES, we don't use HDR skyboxes
|
||||
#ifndef USE_GLES
|
||||
QImage::Format QIMAGE_HDR_FORMAT = QImage::Format_RGB30;
|
||||
#else
|
||||
QImage::Format QIMAGE_HDR_FORMAT = QImage::Format_RGB32;
|
||||
#endif
|
||||
|
||||
TextureUsage::TextureLoader TextureUsage::getTextureLoaderForType(Type type, const QVariantMap& options) {
|
||||
switch (type) {
|
||||
|
@ -548,13 +563,15 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic<bo
|
|||
// https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f18-for-consume-parameters-pass-by-x-and-stdmove-the-parameter
|
||||
QImage localCopy = std::move(image);
|
||||
|
||||
if (localCopy.format() != QImage::Format_ARGB32) {
|
||||
if (localCopy.format() != QImage::Format_ARGB32 && localCopy.format() != QIMAGE_HDR_FORMAT) {
|
||||
localCopy = localCopy.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
const int width = localCopy.width(), height = localCopy.height();
|
||||
const void* data = static_cast<const void*>(localCopy.constBits());
|
||||
auto mipFormat = texture->getStoredMipFormat();
|
||||
|
||||
#ifndef USE_GLES
|
||||
const void* data = static_cast<const void*>(localCopy.constBits());
|
||||
nvtt::TextureType textureType = nvtt::TextureType_2D;
|
||||
nvtt::InputFormat inputFormat = nvtt::InputFormat_BGRA_8UB;
|
||||
nvtt::WrapMode wrapMode = nvtt::WrapMode_Mirror;
|
||||
|
@ -584,8 +601,6 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic<bo
|
|||
nvtt::CompressionOptions compressionOptions;
|
||||
compressionOptions.setQuality(nvtt::Quality_Production);
|
||||
|
||||
// TODO: gles: generate ETC mips instead?
|
||||
auto mipFormat = texture->getStoredMipFormat();
|
||||
if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGB) {
|
||||
compressionOptions.setFormat(nvtt::Format_BC1);
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_MASK) {
|
||||
|
@ -669,21 +684,94 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic<bo
|
|||
nvtt::Compressor compressor;
|
||||
compressor.setTaskDispatcher(&dispatcher);
|
||||
compressor.process(inputOptions, compressionOptions, outputOptions);
|
||||
|
||||
#else
|
||||
int numMips = 1 + (int)log2(std::max(width, height));
|
||||
Etc::RawImage *mipMaps = new Etc::RawImage[numMips];
|
||||
Etc::Image::Format etcFormat = Etc::Image::Format::DEFAULT;
|
||||
|
||||
if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_RGB) {
|
||||
etcFormat = Etc::Image::Format::RGB8;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_SRGB) {
|
||||
etcFormat = Etc::Image::Format::SRGB8;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA) {
|
||||
etcFormat = Etc::Image::Format::RGB8A1;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA) {
|
||||
etcFormat = Etc::Image::Format::SRGB8A1;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_RGBA) {
|
||||
etcFormat = Etc::Image::Format::RGBA8;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA) {
|
||||
etcFormat = Etc::Image::Format::SRGBA8;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_EAC_RED) {
|
||||
etcFormat = Etc::Image::Format::R11;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_EAC_RED_SIGNED) {
|
||||
etcFormat = Etc::Image::Format::SIGNED_R11;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_EAC_XY) {
|
||||
etcFormat = Etc::Image::Format::RG11;
|
||||
} else if (mipFormat == gpu::Element::COLOR_COMPRESSED_EAC_XY_SIGNED) {
|
||||
etcFormat = Etc::Image::Format::SIGNED_RG11;
|
||||
} else {
|
||||
qCWarning(imagelogging) << "Unknown mip format";
|
||||
Q_UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
const Etc::ErrorMetric errorMetric = Etc::ErrorMetric::RGBA;
|
||||
const float effort = 1.0f;
|
||||
const int numEncodeThreads = 4;
|
||||
int encodingTime;
|
||||
const float MAX_COLOR = 255.0f;
|
||||
|
||||
std::vector<vec4> floatData;
|
||||
floatData.resize(width * height);
|
||||
for (int y = 0; y < height; y++) {
|
||||
QRgb *line = (QRgb *) localCopy.scanLine(y);
|
||||
for (int x = 0; x < width; x++) {
|
||||
QRgb &pixel = line[x];
|
||||
floatData[x + y * width] = vec4(qRed(pixel), qGreen(pixel), qBlue(pixel), qAlpha(pixel)) / MAX_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
// free up the memory afterward to avoid bloating the heap
|
||||
localCopy = QImage(); // QImage doesn't have a clear function, so override it with an empty one.
|
||||
|
||||
Etc::EncodeMipmaps(
|
||||
(float *)floatData.data(), width, height,
|
||||
etcFormat, errorMetric, effort,
|
||||
numEncodeThreads, numEncodeThreads,
|
||||
numMips, Etc::FILTER_WRAP_NONE,
|
||||
mipMaps, &encodingTime
|
||||
);
|
||||
|
||||
for (int i = 0; i < numMips; i++) {
|
||||
if (mipMaps[i].paucEncodingBits.get()) {
|
||||
if (face >= 0) {
|
||||
texture->assignStoredMipFace(i, face, mipMaps[i].uiEncodingBitsBytes, static_cast<const gpu::Byte*>(mipMaps[i].paucEncodingBits.get()));
|
||||
} else {
|
||||
texture->assignStoredMip(i, mipMaps[i].uiEncodingBitsBytes, static_cast<const gpu::Byte*>(mipMaps[i].paucEncodingBits.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] mipMaps;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void generateMips(gpu::Texture* texture, QImage&& image, const std::atomic<bool>& abortProcessing = false, int face = -1) {
|
||||
#if CPU_MIPMAPS
|
||||
PROFILE_RANGE(resource_parse, "generateMips");
|
||||
|
||||
#ifndef USE_GLES
|
||||
if (image.format() == QIMAGE_HDR_FORMAT) {
|
||||
generateHDRMips(texture, std::move(image), abortProcessing, face);
|
||||
} else {
|
||||
generateLDRMips(texture, std::move(image), abortProcessing, face);
|
||||
}
|
||||
#else
|
||||
generateLDRMips(texture, std::move(image), abortProcessing, face);
|
||||
#endif
|
||||
#else
|
||||
texture->setAutoGenerateMips(true);
|
||||
#endif
|
||||
|
@ -738,7 +826,6 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma
|
|||
gpu::Element formatMip;
|
||||
gpu::Element formatGPU;
|
||||
if (isColorTexturesCompressionEnabled()) {
|
||||
#ifndef USE_GLES
|
||||
if (validAlpha) {
|
||||
// NOTE: This disables BC1a compression because it was producing odd artifacts on text textures
|
||||
// for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts).
|
||||
|
@ -746,22 +833,15 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma
|
|||
} else {
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_SRGB;
|
||||
}
|
||||
#else
|
||||
if (validAlpha) {
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA;
|
||||
} else {
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGB;
|
||||
}
|
||||
#endif
|
||||
formatMip = formatGPU;
|
||||
} else {
|
||||
#ifdef USE_GLES
|
||||
// GLES does not support GL_BGRA
|
||||
formatMip = gpu::Element::COLOR_SRGBA_32;
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA;
|
||||
formatMip = formatGPU;
|
||||
#else
|
||||
formatGPU = gpu::Element::COLOR_SRGBA_32;
|
||||
formatMip = gpu::Element::COLOR_SBGRA_32;
|
||||
#endif
|
||||
formatGPU = gpu::Element::COLOR_SRGBA_32;
|
||||
}
|
||||
|
||||
if (isStrict) {
|
||||
|
@ -876,16 +956,18 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr
|
|||
|
||||
gpu::TexturePointer theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
gpu::Element formatMip = gpu::Element::VEC2NU8_XY;
|
||||
gpu::Element formatGPU = gpu::Element::VEC2NU8_XY;
|
||||
gpu::Element formatMip;
|
||||
gpu::Element formatGPU;
|
||||
if (isNormalTexturesCompressionEnabled()) {
|
||||
#ifndef USE_GLES
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_XY;
|
||||
#else
|
||||
} else {
|
||||
#ifdef USE_GLES
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_XY;
|
||||
#else
|
||||
formatGPU = gpu::Element::VEC2NU8_XY;
|
||||
#endif
|
||||
formatMip = formatGPU;
|
||||
}
|
||||
formatMip = formatGPU;
|
||||
|
||||
theTexture = gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
|
||||
theTexture->setSource(srcImageName);
|
||||
|
@ -917,16 +999,15 @@ gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& sr
|
|||
gpu::Element formatMip;
|
||||
gpu::Element formatGPU;
|
||||
if (isGrayscaleTexturesCompressionEnabled()) {
|
||||
#ifndef USE_GLES
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_RED;
|
||||
#else
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED;
|
||||
#endif
|
||||
formatMip = formatGPU;
|
||||
} else {
|
||||
formatMip = gpu::Element::COLOR_R_8;
|
||||
#ifdef USE_GLES
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED;
|
||||
#else
|
||||
formatGPU = gpu::Element::COLOR_R_8;
|
||||
#endif
|
||||
}
|
||||
formatMip = formatGPU;
|
||||
|
||||
theTexture = gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
|
||||
theTexture->setSource(srcImageName);
|
||||
|
@ -1283,19 +1364,25 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI
|
|||
QImage image = processSourceImage(std::move(localCopy), true);
|
||||
|
||||
if (image.format() != QIMAGE_HDR_FORMAT) {
|
||||
#ifndef USE_GLES
|
||||
image = convertToHDRFormat(std::move(image), HDR_FORMAT);
|
||||
#else
|
||||
image = image.convertToFormat(QImage::Format_RGB32);
|
||||
#endif
|
||||
}
|
||||
|
||||
gpu::Element formatMip;
|
||||
gpu::Element formatGPU;
|
||||
if (isCubeTexturesCompressionEnabled()) {
|
||||
// TODO: gles: pick HDR ETC format
|
||||
formatMip = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB;
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB;
|
||||
} else {
|
||||
formatMip = HDR_FORMAT;
|
||||
#ifdef USE_GLES
|
||||
formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGB;
|
||||
#else
|
||||
formatGPU = HDR_FORMAT;
|
||||
#endif
|
||||
}
|
||||
formatMip = formatGPU;
|
||||
|
||||
// Find the layout of the cubemap in the 2D image
|
||||
// Use the original image size since processSourceImage may have altered the size / aspect ratio
|
||||
|
@ -1342,9 +1429,16 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI
|
|||
// Generate irradiance while we are at it
|
||||
if (generateIrradiance) {
|
||||
PROFILE_RANGE(resource_parse, "generateIrradiance");
|
||||
auto irradianceTexture = gpu::Texture::createCube(HDR_FORMAT, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
gpu::Element irradianceFormat;
|
||||
// TODO: we could locally compress the irradiance texture on Android, but we don't need to
|
||||
#ifndef USE_GLES
|
||||
irradianceFormat = HDR_FORMAT;
|
||||
#else
|
||||
irradianceFormat = gpu::Element::COLOR_SRGBA_32;
|
||||
#endif
|
||||
auto irradianceTexture = gpu::Texture::createCube(irradianceFormat, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||
irradianceTexture->setSource(srcImageName);
|
||||
irradianceTexture->setStoredMipFormat(HDR_FORMAT);
|
||||
irradianceTexture->setStoredMipFormat(irradianceFormat);
|
||||
for (uint8 face = 0; face < faces.size(); ++face) {
|
||||
irradianceTexture->assignStoredMipFace(0, face, faces[face].byteCount(), faces[face].constBits());
|
||||
}
|
||||
|
|
|
@ -350,6 +350,8 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) {
|
|||
if (idxMoveStartingPointCandidate != -1) {
|
||||
_moveCurrentTouchId = tPoints[idxMoveStartingPointCandidate].id();
|
||||
_unusedTouches.erase(_moveCurrentTouchId);
|
||||
thisPoint.x = tPoints[idxMoveStartingPointCandidate].pos().x();
|
||||
thisPoint.y = tPoints[idxMoveStartingPointCandidate].pos().y();
|
||||
moveTouchBegin(thisPoint);
|
||||
} else {
|
||||
moveTouchEnd();
|
||||
|
@ -359,6 +361,8 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) {
|
|||
if (idxViewStartingPointCandidate != -1) {
|
||||
_viewCurrentTouchId = tPoints[idxViewStartingPointCandidate].id();
|
||||
_unusedTouches.erase(_viewCurrentTouchId);
|
||||
thisPoint.x = tPoints[idxViewStartingPointCandidate].pos().x();
|
||||
thisPoint.y = tPoints[idxViewStartingPointCandidate].pos().y();
|
||||
viewTouchBegin(thisPoint);
|
||||
} else {
|
||||
viewTouchEnd();
|
||||
|
@ -368,6 +372,8 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) {
|
|||
if (idxJumpStartingPointCandidate != -1) {
|
||||
_jumpCurrentTouchId = tPoints[idxJumpStartingPointCandidate].id();
|
||||
_unusedTouches.erase(_jumpCurrentTouchId);
|
||||
thisPoint.x = tPoints[idxJumpStartingPointCandidate].pos().x();
|
||||
thisPoint.y = tPoints[idxJumpStartingPointCandidate].pos().y();
|
||||
jumpTouchBegin(thisPoint);
|
||||
} else {
|
||||
if (_jumpHasValidTouch) {
|
||||
|
@ -424,6 +430,7 @@ void TouchscreenVirtualPadDevice::moveTouchBegin(glm::vec2 touchPoint) {
|
|||
} else {
|
||||
_moveRefTouchPoint = touchPoint;
|
||||
}
|
||||
_moveCurrentTouchPoint = touchPoint;
|
||||
_moveHasValidTouch = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -446,17 +446,13 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
|||
// this case is prevented by setting _ownershipState to UNOWNABLE in EntityMotionState::ctor
|
||||
assert(!(_entity->getClientOnly() && _entity->getOwningAvatarID() != Physics::getSessionUUID()));
|
||||
|
||||
// shouldSendUpdate() sould NOT be triggering updates to maintain the queryAACube of dynamic entities.
|
||||
// The server is supposed to predict the transform of such moving things. The client performs a "double prediction"
|
||||
// where it predicts what the the server is doing, and only sends updates whent the entity's true transform
|
||||
// differs significantly. That is what the remoteSimulationOutOfSync() logic is all about.
|
||||
if (_entity->dynamicDataNeedsTransmit() ||
|
||||
(!_entity->getDynamic() && _entity->queryAACubeNeedsUpdate())) {
|
||||
if (_entity->dynamicDataNeedsTransmit()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_entity->shouldSuppressLocationEdits()) {
|
||||
return false;
|
||||
// "shouldSuppressLocationEdits" really means: "the entity has a 'Hold' action therefore
|
||||
// we don't need send an update unless the entity is not contained by its queryAACube"
|
||||
return _entity->queryAACubeNeedsUpdate();
|
||||
}
|
||||
|
||||
return remoteSimulationOutOfSync(simulationStep);
|
||||
|
|
|
@ -87,7 +87,8 @@ void CauterizedModel::createVisibleRenderItemSet() {
|
|||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
||||
_modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr);
|
||||
_modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName());
|
||||
auto material = getGeometry()->getShapeMaterial(shapeID);
|
||||
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
|
||||
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
|
||||
shapeID++;
|
||||
}
|
||||
|
|
|
@ -149,6 +149,7 @@ public:
|
|||
Builder& withTypeMeta() { _flags.set(TYPE_META); return (*this); }
|
||||
Builder& withTransparent() { _flags.set(TRANSLUCENT); return (*this); }
|
||||
Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); }
|
||||
Builder& withoutViewSpace() { _flags.reset(VIEW_SPACE); return (*this); }
|
||||
Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); }
|
||||
Builder& withDeformed() { _flags.set(DEFORMED); return (*this); }
|
||||
Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); }
|
||||
|
|
|
@ -419,7 +419,7 @@ void ScriptEngine::waitTillDoneRunning() {
|
|||
// Wait for the scripting thread to stop running, as
|
||||
// flooding it with aborts/exceptions will persist it longer
|
||||
static const auto MAX_SCRIPT_QUITTING_TIME = 0.5 * MSECS_PER_SECOND;
|
||||
if (workerThread->wait(MAX_SCRIPT_QUITTING_TIME)) {
|
||||
if (!workerThread->wait(MAX_SCRIPT_QUITTING_TIME)) {
|
||||
workerThread->terminate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,15 +32,13 @@
|
|||
#include "shared/GlobalAppProperties.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
|
||||
// Format: AppName-PID-Timestamp
|
||||
// Example: ...
|
||||
QString TEMP_DIR_FORMAT { "%1-%2-%3" };
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && defined(DEV_BUILD)
|
||||
static bool USE_SOURCE_TREE_RESOURCES() {
|
||||
#if defined(Q_OS_OSX)
|
||||
return true;
|
||||
#else
|
||||
static bool result = false;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
|
@ -48,10 +46,28 @@ static bool USE_SOURCE_TREE_RESOURCES() {
|
|||
result = QProcessEnvironment::systemEnvironment().contains(USE_SOURCE_TREE_RESOURCES_FLAG);
|
||||
});
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
const QString& PathUtils::getRccPath() {
|
||||
static QString rccLocation;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
static const QString rccName{ "/resources.rcc" };
|
||||
#if defined(Q_OS_OSX)
|
||||
char buffer[8192];
|
||||
uint32_t bufferSize = sizeof(buffer);
|
||||
_NSGetExecutablePath(buffer, &bufferSize);
|
||||
rccLocation = QDir::cleanPath(QFileInfo(buffer).dir().absoluteFilePath("../Resources")) + rccName;
|
||||
#elif defined(Q_OS_ANDROID)
|
||||
rccLocation = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + rccName;
|
||||
#else
|
||||
rccLocation = QCoreApplication::applicationDirPath() + rccName;
|
||||
#endif
|
||||
});
|
||||
return rccLocation;
|
||||
}
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
const QString& PathUtils::projectRootPath() {
|
||||
static QString sourceFolder;
|
||||
|
@ -65,23 +81,9 @@ const QString& PathUtils::projectRootPath() {
|
|||
#endif
|
||||
|
||||
const QString& PathUtils::resourcesPath() {
|
||||
static QString staticResourcePath;
|
||||
static QString staticResourcePath{ ":/" };
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]{
|
||||
|
||||
#if defined(Q_OS_OSX)
|
||||
// FIXME fix the OSX installer to install the resources.rcc instead of the
|
||||
// individual resource files
|
||||
// FIXME the first call to fetch the resources location seems to return
|
||||
// nothing for QCoreApplication::applicationDirPath()
|
||||
char buffer[8192];
|
||||
uint32_t bufferSize = sizeof(buffer);
|
||||
_NSGetExecutablePath(buffer, &bufferSize);
|
||||
staticResourcePath = QDir::cleanPath(QFileInfo(buffer).dir().absoluteFilePath("../Resources")) + "/";
|
||||
#else
|
||||
staticResourcePath = ":/";
|
||||
#endif
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && defined(DEV_BUILD)
|
||||
if (USE_SOURCE_TREE_RESOURCES()) {
|
||||
// For dev builds, optionally load content from the Git source tree
|
||||
|
@ -90,21 +92,13 @@ const QString& PathUtils::resourcesPath() {
|
|||
#endif
|
||||
qDebug() << "Resource path resolved to " << staticResourcePath;
|
||||
});
|
||||
|
||||
return staticResourcePath;
|
||||
}
|
||||
|
||||
const QString& PathUtils::resourcesUrl() {
|
||||
static QString staticResourcePath;
|
||||
static QString staticResourcePath{ "qrc:///" };
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]{
|
||||
|
||||
#if defined(Q_OS_OSX)
|
||||
staticResourcePath = QUrl::fromLocalFile(resourcesPath()).toString();
|
||||
#else
|
||||
staticResourcePath = "qrc:///";
|
||||
#endif
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && defined(DEV_BUILD)
|
||||
if (USE_SOURCE_TREE_RESOURCES()) {
|
||||
// For dev builds, optionally load content from the Git source tree
|
||||
|
|
|
@ -37,6 +37,7 @@ class PathUtils : public QObject, public Dependency {
|
|||
Q_PROPERTY(QString resources READ resourcesPath CONSTANT)
|
||||
Q_PROPERTY(QUrl defaultScripts READ defaultScriptsLocation CONSTANT)
|
||||
public:
|
||||
static const QString& getRccPath();
|
||||
static const QString& resourcesUrl();
|
||||
static QUrl resourcesUrl(const QString& relative);
|
||||
static const QString& resourcesPath();
|
||||
|
|
|
@ -47,7 +47,7 @@ static_assert(
|
|||
const char* SDL2Manager::NAME = "SDL2";
|
||||
const char* SDL2Manager::SDL2_ID_STRING = "SDL2";
|
||||
|
||||
const bool DEFAULT_ENABLED = false;
|
||||
const bool DEFAULT_ENABLED = true;
|
||||
|
||||
SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) {
|
||||
SDL_Joystick* joystick = SDL_GameControllerGetJoystick(controller);
|
||||
|
|
|
@ -15,19 +15,25 @@
|
|||
|
||||
#include "OculusHelpers.h"
|
||||
|
||||
using namespace hifi;
|
||||
|
||||
void OculusBaseDisplayPlugin::resetSensors() {
|
||||
ovr_RecenterTrackingOrigin(_session);
|
||||
|
||||
_currentRenderFrameInfo.renderPose = glm::mat4(); // identity
|
||||
}
|
||||
|
||||
bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
||||
handleOVREvents();
|
||||
if (quitRequested()) {
|
||||
ovrSessionStatus status{};
|
||||
if (!OVR_SUCCESS(ovr_GetSessionStatus(_session, &status))) {
|
||||
qCWarning(oculusLog) << "Unable to fetch Oculus session status" << ovr::getError();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ovr::quitRequested(status)) {
|
||||
QMetaObject::invokeMethod(qApp, "quit");
|
||||
return false;
|
||||
}
|
||||
if (reorientRequested()) {
|
||||
if (ovr::reorientRequested(status)) {
|
||||
emit resetSensorsRequested();
|
||||
}
|
||||
|
||||
|
@ -35,18 +41,18 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
|||
_currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
|
||||
_currentRenderFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex);
|
||||
auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrTrue);
|
||||
_currentRenderFrameInfo.renderPose = toGlm(trackingState.HeadPose.ThePose);
|
||||
_currentRenderFrameInfo.renderPose = ovr::toGlm(trackingState.HeadPose.ThePose);
|
||||
_currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose;
|
||||
|
||||
std::array<glm::mat4, 2> handPoses;
|
||||
// Make controller poses available to the presentation thread
|
||||
ovr_for_each_hand([&](ovrHandType hand) {
|
||||
ovr::for_each_hand([&](ovrHandType hand) {
|
||||
static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked | ovrStatus_PositionTracked;
|
||||
if (REQUIRED_HAND_STATUS != (trackingState.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto correctedPose = ovrControllerPoseToHandPose(hand, trackingState.HandPoses[hand]);
|
||||
auto correctedPose = ovr::toControllerPose(hand, trackingState.HandPoses[hand]);
|
||||
static const glm::quat HAND_TO_LASER_ROTATION = glm::rotation(Vectors::UNIT_Z, Vectors::UNIT_NEG_Y);
|
||||
handPoses[hand] = glm::translate(glm::mat4(), correctedPose.translation) * glm::mat4_cast(correctedPose.rotation * HAND_TO_LASER_ROTATION);
|
||||
});
|
||||
|
@ -58,7 +64,7 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
|||
}
|
||||
|
||||
bool OculusBaseDisplayPlugin::isSupported() const {
|
||||
return oculusAvailable();
|
||||
return ovr::available();
|
||||
}
|
||||
|
||||
glm::mat4 OculusBaseDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& baseProjection) const {
|
||||
|
@ -71,7 +77,7 @@ glm::mat4 OculusBaseDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& ba
|
|||
ovrFovPort fovPort = _hmdDesc.DefaultEyeFov[eye];
|
||||
ovrEyeRenderDesc& erd = ovr_GetRenderDesc(_session, ovrEye, fovPort);
|
||||
ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(erd.Fov, baseNearClip, baseFarClip, ovrProjection_ClipRangeOpenGL);
|
||||
return toGlm(ovrPerspectiveProjection);
|
||||
return ovr::toGlm(ovrPerspectiveProjection);
|
||||
} else {
|
||||
return baseProjection;
|
||||
}
|
||||
|
@ -85,7 +91,7 @@ glm::mat4 OculusBaseDisplayPlugin::getCullingProjection(const glm::mat4& basePro
|
|||
float baseFarClip = baseFrustum.getFarClip();
|
||||
auto combinedFov = _eyeFovs[0];
|
||||
combinedFov.LeftTan = combinedFov.RightTan = std::max(combinedFov.LeftTan, combinedFov.RightTan);
|
||||
return toGlm(ovrMatrix4f_Projection(combinedFov, baseNearClip, baseFarClip, ovrProjection_ClipRangeOpenGL));
|
||||
return ovr::toGlm(ovrMatrix4f_Projection(combinedFov, baseNearClip, baseFarClip, ovrProjection_ClipRangeOpenGL));
|
||||
} else {
|
||||
return baseProjection;
|
||||
}
|
||||
|
@ -102,7 +108,7 @@ void OculusBaseDisplayPlugin::uncustomizeContext() {
|
|||
}
|
||||
|
||||
bool OculusBaseDisplayPlugin::internalActivate() {
|
||||
_session = acquireOculusSession();
|
||||
_session = ovr::acquireRenderSession();
|
||||
if (!_session) {
|
||||
return false;
|
||||
}
|
||||
|
@ -113,21 +119,21 @@ bool OculusBaseDisplayPlugin::internalActivate() {
|
|||
_viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f;
|
||||
|
||||
_ipd = 0;
|
||||
ovr_for_each_eye([&](ovrEyeType eye) {
|
||||
ovr::for_each_eye([&](ovrEyeType eye) {
|
||||
_eyeFovs[eye] = _hmdDesc.DefaultEyeFov[eye];
|
||||
ovrEyeRenderDesc& erd = _eyeRenderDescs[eye] = ovr_GetRenderDesc(_session, eye, _eyeFovs[eye]);
|
||||
ovrMatrix4f ovrPerspectiveProjection =
|
||||
ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL);
|
||||
_eyeProjections[eye] = toGlm(ovrPerspectiveProjection);
|
||||
_eyeOffsets[eye] = glm::translate(mat4(), toGlm(erd.HmdToEyeOffset));
|
||||
eyeSizes[eye] = toGlm(ovr_GetFovTextureSize(_session, eye, erd.Fov, 1.0f));
|
||||
_viewScaleDesc.HmdToEyeOffset[eye] = erd.HmdToEyeOffset;
|
||||
_ipd += glm::abs(glm::length(toGlm(erd.HmdToEyeOffset)));
|
||||
_eyeProjections[eye] = ovr::toGlm(ovrPerspectiveProjection);
|
||||
_eyeOffsets[eye] = ovr::toGlm(erd.HmdToEyePose);
|
||||
eyeSizes[eye] = ovr::toGlm(ovr_GetFovTextureSize(_session, eye, erd.Fov, 1.0f));
|
||||
_viewScaleDesc.HmdToEyePose[eye] = erd.HmdToEyePose;
|
||||
_ipd += glm::abs(glm::length(ovr::toGlm(erd.HmdToEyePose.Position)));
|
||||
});
|
||||
|
||||
auto combinedFov = _eyeFovs[0];
|
||||
combinedFov.LeftTan = combinedFov.RightTan = std::max(combinedFov.LeftTan, combinedFov.RightTan);
|
||||
_cullingProjection = toGlm(ovrMatrix4f_Projection(combinedFov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL));
|
||||
_cullingProjection = ovr::toGlm(ovrMatrix4f_Projection(combinedFov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_ClipRangeOpenGL));
|
||||
|
||||
_renderTargetSize = uvec2(
|
||||
eyeSizes[0].x + eyeSizes[1].x,
|
||||
|
@ -136,7 +142,7 @@ bool OculusBaseDisplayPlugin::internalActivate() {
|
|||
memset(&_sceneLayer, 0, sizeof(ovrLayerEyeFov));
|
||||
_sceneLayer.Header.Type = ovrLayerType_EyeFov;
|
||||
_sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
|
||||
ovr_for_each_eye([&](ovrEyeType eye) {
|
||||
ovr::for_each_eye([&](ovrEyeType eye) {
|
||||
ovrFovPort & fov = _sceneLayer.Fov[eye] = _eyeRenderDescs[eye].Fov;
|
||||
ovrSizei & size = _sceneLayer.Viewport[eye].Size = ovr_GetFovTextureSize(_session, eye, fov, 1.0f);
|
||||
_sceneLayer.Viewport[eye].Pos = { eye == ovrEye_Left ? 0 : size.w, 0 };
|
||||
|
@ -150,28 +156,14 @@ bool OculusBaseDisplayPlugin::internalActivate() {
|
|||
|
||||
void OculusBaseDisplayPlugin::internalDeactivate() {
|
||||
Parent::internalDeactivate();
|
||||
ovr::releaseRenderSession(_session);
|
||||
}
|
||||
|
||||
bool OculusBaseDisplayPlugin::activateStandBySession() {
|
||||
if (!_session) {
|
||||
_session = acquireOculusSession();
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
void OculusBaseDisplayPlugin::deactivateSession() {
|
||||
// FIXME
|
||||
// Switching to Qt 5.9 exposed a race condition or similar issue that caused a crash when putting on an Rift
|
||||
// while already in VR mode. Commenting these out is a workaround.
|
||||
//releaseOculusSession();
|
||||
//_session = nullptr;
|
||||
}
|
||||
void OculusBaseDisplayPlugin::updatePresentPose() {
|
||||
ovrTrackingState trackingState;
|
||||
_currentPresentFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
|
||||
_currentPresentFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, 0);
|
||||
auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrFalse);
|
||||
_currentPresentFrameInfo.presentPose = toGlm(trackingState.HeadPose.ThePose);
|
||||
trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrFalse);
|
||||
_currentPresentFrameInfo.presentPose = ovr::toGlm(trackingState.HeadPose.ThePose);
|
||||
_currentPresentFrameInfo.renderPose = _currentPresentFrameInfo.presentPose;
|
||||
}
|
||||
|
||||
OculusBaseDisplayPlugin::~OculusBaseDisplayPlugin() {
|
||||
}
|
||||
|
|
|
@ -16,37 +16,32 @@
|
|||
class OculusBaseDisplayPlugin : public HmdDisplayPlugin {
|
||||
using Parent = HmdDisplayPlugin;
|
||||
public:
|
||||
~OculusBaseDisplayPlugin();
|
||||
bool isSupported() const override;
|
||||
bool hasAsyncReprojection() const override { return true; }
|
||||
bool getSupportsAutoSwitch() override final { return true; }
|
||||
|
||||
glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override;
|
||||
glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override;
|
||||
|
||||
bool hasAsyncReprojection() const override { return true; }
|
||||
|
||||
|
||||
// Stereo specific methods
|
||||
void resetSensors() override final;
|
||||
bool beginFrameRender(uint32_t frameIndex) override;
|
||||
float getTargetFrameRate() const override { return _hmdDesc.DisplayRefreshRate; }
|
||||
bool getSupportsAutoSwitch() override final { return true; }
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
void customizeContext() override;
|
||||
void uncustomizeContext() override;
|
||||
bool internalActivate() override;
|
||||
void internalDeactivate() override;
|
||||
bool activateStandBySession() override;
|
||||
void deactivateSession() override;
|
||||
void updatePresentPose() override;
|
||||
|
||||
protected:
|
||||
ovrSession _session { nullptr };
|
||||
ovrSession _session{ nullptr };
|
||||
ovrGraphicsLuid _luid;
|
||||
ovrEyeRenderDesc _eyeRenderDescs[2];
|
||||
ovrFovPort _eyeFovs[2];
|
||||
std::array<ovrEyeRenderDesc, 2> _eyeRenderDescs;
|
||||
std::array<ovrFovPort, 2> _eyeFovs;
|
||||
ovrHmdDesc _hmdDesc;
|
||||
ovrLayerEyeFov _sceneLayer;
|
||||
ovrViewScaleDesc _viewScaleDesc;
|
||||
// ovrLayerEyeFovDepth _depthLayer;
|
||||
};
|
||||
|
|
|
@ -22,34 +22,23 @@
|
|||
#include <NumericalConstants.h>
|
||||
#include <StreamUtils.h>
|
||||
|
||||
#include <OVR_CAPI.h>
|
||||
#include <ovr_capi.h>
|
||||
|
||||
#include "OculusHelpers.h"
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(oculus)
|
||||
|
||||
|
||||
static const char* MENU_PARENT = "Avatar";
|
||||
static const char* MENU_NAME = "Oculus Touch Controllers";
|
||||
static const char* MENU_PATH = "Avatar" ">" "Oculus Touch Controllers";
|
||||
using namespace hifi;
|
||||
|
||||
const char* OculusControllerManager::NAME = "Oculus";
|
||||
|
||||
const quint64 LOST_TRACKING_DELAY = 3000000;
|
||||
|
||||
bool OculusControllerManager::isSupported() const {
|
||||
return oculusAvailable();
|
||||
return hifi::ovr::available();
|
||||
}
|
||||
|
||||
bool OculusControllerManager::activate() {
|
||||
InputPlugin::activate();
|
||||
if (!_session) {
|
||||
_session = acquireOculusSession();
|
||||
}
|
||||
Q_ASSERT(_session);
|
||||
|
||||
checkForConnectedDevices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -58,33 +47,30 @@ void OculusControllerManager::checkForConnectedDevices() {
|
|||
return;
|
||||
}
|
||||
|
||||
unsigned int controllerConnected = ovr_GetConnectedControllerTypes(_session);
|
||||
ovr::withSession([&] (ovrSession session) {
|
||||
unsigned int controllerConnected = ovr_GetConnectedControllerTypes(session);
|
||||
|
||||
if (!_remote && (controllerConnected & ovrControllerType_Remote) == ovrControllerType_Remote) {
|
||||
if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Remote, &_inputState))) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
_remote = std::make_shared<RemoteDevice>(*this);
|
||||
userInputMapper->registerDevice(_remote);
|
||||
if (!_remote && (controllerConnected & ovrControllerType_Remote) == ovrControllerType_Remote) {
|
||||
if (OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Remote, &_inputState))) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
_remote = std::make_shared<RemoteDevice>(*this);
|
||||
userInputMapper->registerDevice(_remote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_touch && (controllerConnected & ovrControllerType_Touch) != 0) {
|
||||
if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
_touch = std::make_shared<TouchDevice>(*this);
|
||||
userInputMapper->registerDevice(_touch);
|
||||
if (!_touch && (controllerConnected & ovrControllerType_Touch) != 0) {
|
||||
if (OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Touch, &_inputState))) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
_touch = std::make_shared<TouchDevice>(*this);
|
||||
userInputMapper->registerDevice(_touch);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void OculusControllerManager::deactivate() {
|
||||
InputPlugin::deactivate();
|
||||
|
||||
if (_session) {
|
||||
releaseOculusSession();
|
||||
_session = nullptr;
|
||||
}
|
||||
|
||||
// unregister with UserInputMapper
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
if (_touch) {
|
||||
|
@ -100,20 +86,30 @@ void OculusControllerManager::pluginUpdate(float deltaTime, const controller::In
|
|||
|
||||
checkForConnectedDevices();
|
||||
|
||||
if (_touch) {
|
||||
if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) {
|
||||
_touch->update(deltaTime, inputCalibrationData);
|
||||
} else {
|
||||
qCWarning(oculus) << "Unable to read Oculus touch input state";
|
||||
bool updateRemote = false, updateTouch = false;
|
||||
|
||||
ovr::withSession([&](ovrSession session) {
|
||||
if (_touch) {
|
||||
updateTouch = OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Touch, &_inputState));
|
||||
if (!updateTouch) {
|
||||
qCWarning(oculusLog) << "Unable to read Oculus touch input state" << ovr::getError();
|
||||
}
|
||||
}
|
||||
if (_remote) {
|
||||
updateRemote = OVR_SUCCESS(ovr_GetInputState(session, ovrControllerType_Remote, &_inputState));
|
||||
if (!updateRemote) {
|
||||
qCWarning(oculusLog) << "Unable to read Oculus remote input state" << ovr::getError();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (_touch && updateTouch) {
|
||||
_touch->update(deltaTime, inputCalibrationData);
|
||||
}
|
||||
|
||||
if (_remote) {
|
||||
if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Remote, &_inputState))) {
|
||||
_remote->update(deltaTime, inputCalibrationData);
|
||||
} else {
|
||||
qCWarning(oculus) << "Unable to read Oculus remote input state";
|
||||
}
|
||||
if (_remote && updateRemote) {
|
||||
_remote->update(deltaTime, inputCalibrationData);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,15 +206,6 @@ void OculusControllerManager::RemoteDevice::focusOutEvent() {
|
|||
_buttonPressedMap.clear();
|
||||
}
|
||||
|
||||
bool OculusControllerManager::isHeadControllerMounted() const {
|
||||
ovrSessionStatus status;
|
||||
bool success = OVR_SUCCESS(ovr_GetSessionStatus(_session, &status));
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
return status.HmdMounted == ovrTrue;
|
||||
}
|
||||
|
||||
void OculusControllerManager::TouchDevice::update(float deltaTime,
|
||||
const controller::InputCalibrationData& inputCalibrationData) {
|
||||
_buttonPressedMap.clear();
|
||||
|
@ -226,10 +213,19 @@ void OculusControllerManager::TouchDevice::update(float deltaTime,
|
|||
int numTrackedControllers = 0;
|
||||
quint64 currentTime = usecTimestampNow();
|
||||
static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked | ovrStatus_PositionTracked;
|
||||
auto tracking = ovr_GetTrackingState(_parent._session, 0, false);
|
||||
ovr_for_each_hand([&](ovrHandType hand) {
|
||||
bool hasInputFocus = ovr::hasInputFocus();
|
||||
auto tracking = ovr::getTrackingState(); // ovr_GetTrackingState(_parent._session, 0, false);
|
||||
ovr::for_each_hand([&](ovrHandType hand) {
|
||||
++numTrackedControllers;
|
||||
int controller = (hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND);
|
||||
|
||||
// Disable hand tracking while in Oculus Dash (Dash renders it's own hands)
|
||||
if (!hasInputFocus) {
|
||||
_poseStateMap.erase(controller);
|
||||
_poseStateMap[controller].valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (REQUIRED_HAND_STATUS == (tracking.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) {
|
||||
_poseStateMap.erase(controller);
|
||||
handlePose(deltaTime, inputCalibrationData, hand, tracking.HandPoses[hand]);
|
||||
|
@ -253,7 +249,7 @@ void OculusControllerManager::TouchDevice::update(float deltaTime,
|
|||
handleRotationForUntrackedHand(inputCalibrationData, hand, tracking.HandPoses[hand]);
|
||||
});
|
||||
|
||||
if (_parent.isHeadControllerMounted()) {
|
||||
if (ovr::hmdMounted()) {
|
||||
handleHeadPose(deltaTime, inputCalibrationData, tracking.HeadPose);
|
||||
} else {
|
||||
_poseStateMap[controller::HEAD].valid = false;
|
||||
|
@ -311,7 +307,7 @@ void OculusControllerManager::TouchDevice::handlePose(float deltaTime,
|
|||
ovrHandType hand, const ovrPoseStatef& handPose) {
|
||||
auto poseId = hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND;
|
||||
auto& pose = _poseStateMap[poseId];
|
||||
pose = ovrControllerPoseToHandPose(hand, handPose);
|
||||
pose = ovr::toControllerPose(hand, handPose);
|
||||
// transform into avatar frame
|
||||
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
|
||||
pose = pose.transform(controllerToAvatar);
|
||||
|
@ -320,15 +316,15 @@ void OculusControllerManager::TouchDevice::handlePose(float deltaTime,
|
|||
void OculusControllerManager::TouchDevice::handleHeadPose(float deltaTime,
|
||||
const controller::InputCalibrationData& inputCalibrationData,
|
||||
const ovrPoseStatef& headPose) {
|
||||
glm::mat4 mat = createMatFromQuatAndPos(toGlm(headPose.ThePose.Orientation),
|
||||
toGlm(headPose.ThePose.Position));
|
||||
glm::mat4 mat = createMatFromQuatAndPos(ovr::toGlm(headPose.ThePose.Orientation),
|
||||
ovr::toGlm(headPose.ThePose.Position));
|
||||
|
||||
//perform a 180 flip to make the HMD face the +z instead of -z, beacuse the head faces +z
|
||||
glm::mat4 matYFlip = mat * Matrices::Y_180;
|
||||
controller::Pose pose(extractTranslation(matYFlip),
|
||||
glmExtractRotation(matYFlip),
|
||||
toGlm(headPose.LinearVelocity), // XXX * matYFlip ?
|
||||
toGlm(headPose.AngularVelocity));
|
||||
ovr::toGlm(headPose.LinearVelocity), // XXX * matYFlip ?
|
||||
ovr::toGlm(headPose.AngularVelocity));
|
||||
|
||||
glm::mat4 sensorToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
|
||||
glm::mat4 defaultHeadOffset = glm::inverse(inputCalibrationData.defaultCenterEyeMat) *
|
||||
|
@ -343,7 +339,7 @@ void OculusControllerManager::TouchDevice::handleRotationForUntrackedHand(const
|
|||
auto poseId = (hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND);
|
||||
auto& pose = _poseStateMap[poseId];
|
||||
auto lastHandPose = _lastControllerPose[poseId];
|
||||
pose = ovrControllerRotationToHandRotation(hand, handPose, lastHandPose);
|
||||
pose = ovr::toControllerPose(hand, handPose, lastHandPose);
|
||||
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
|
||||
pose = pose.transform(controllerToAvatar);
|
||||
}
|
||||
|
@ -351,36 +347,40 @@ void OculusControllerManager::TouchDevice::handleRotationForUntrackedHand(const
|
|||
bool OculusControllerManager::TouchDevice::triggerHapticPulse(float strength, float duration, controller::Hand hand) {
|
||||
Locker locker(_lock);
|
||||
bool toReturn = true;
|
||||
if (hand == controller::BOTH || hand == controller::LEFT) {
|
||||
if (strength == 0.0f) {
|
||||
_leftHapticStrength = 0.0f;
|
||||
_leftHapticDuration = 0.0f;
|
||||
} else {
|
||||
_leftHapticStrength = (duration > _leftHapticDuration) ? strength : _leftHapticStrength;
|
||||
if (ovr_SetControllerVibration(_parent._session, ovrControllerType_LTouch, 1.0f, _leftHapticStrength) != ovrSuccess) {
|
||||
toReturn = false;
|
||||
ovr::withSession([&](ovrSession session) {
|
||||
if (hand == controller::BOTH || hand == controller::LEFT) {
|
||||
if (strength == 0.0f) {
|
||||
_leftHapticStrength = 0.0f;
|
||||
_leftHapticDuration = 0.0f;
|
||||
} else {
|
||||
_leftHapticStrength = (duration > _leftHapticDuration) ? strength : _leftHapticStrength;
|
||||
if (ovr_SetControllerVibration(session, ovrControllerType_LTouch, 1.0f, _leftHapticStrength) != ovrSuccess) {
|
||||
toReturn = false;
|
||||
}
|
||||
_leftHapticDuration = std::max(duration, _leftHapticDuration);
|
||||
}
|
||||
_leftHapticDuration = std::max(duration, _leftHapticDuration);
|
||||
}
|
||||
}
|
||||
if (hand == controller::BOTH || hand == controller::RIGHT) {
|
||||
if (strength == 0.0f) {
|
||||
_rightHapticStrength = 0.0f;
|
||||
_rightHapticDuration = 0.0f;
|
||||
} else {
|
||||
_rightHapticStrength = (duration > _rightHapticDuration) ? strength : _rightHapticStrength;
|
||||
if (ovr_SetControllerVibration(_parent._session, ovrControllerType_RTouch, 1.0f, _rightHapticStrength) != ovrSuccess) {
|
||||
toReturn = false;
|
||||
if (hand == controller::BOTH || hand == controller::RIGHT) {
|
||||
if (strength == 0.0f) {
|
||||
_rightHapticStrength = 0.0f;
|
||||
_rightHapticDuration = 0.0f;
|
||||
} else {
|
||||
_rightHapticStrength = (duration > _rightHapticDuration) ? strength : _rightHapticStrength;
|
||||
if (ovr_SetControllerVibration(session, ovrControllerType_RTouch, 1.0f, _rightHapticStrength) != ovrSuccess) {
|
||||
toReturn = false;
|
||||
}
|
||||
_rightHapticDuration = std::max(duration, _rightHapticDuration);
|
||||
}
|
||||
_rightHapticDuration = std::max(duration, _rightHapticDuration);
|
||||
}
|
||||
}
|
||||
});
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
void OculusControllerManager::TouchDevice::stopHapticPulse(bool leftHand) {
|
||||
auto handType = (leftHand ? ovrControllerType_LTouch : ovrControllerType_RTouch);
|
||||
ovr_SetControllerVibration(_parent._session, handType, 0.0f, 0.0f);
|
||||
ovr::withSession([&](ovrSession session) {
|
||||
ovr_SetControllerVibration(session, handType, 0.0f, 0.0f);
|
||||
});
|
||||
}
|
||||
|
||||
/**jsdoc
|
||||
|
|
|
@ -26,10 +26,8 @@ public:
|
|||
// Plugin functions
|
||||
bool isSupported() const override;
|
||||
const QString getName() const override { return NAME; }
|
||||
|
||||
bool isHandController() const override { return _touch != nullptr; }
|
||||
bool isHeadController() const override { return true; }
|
||||
bool isHeadControllerMounted() const;
|
||||
QStringList getSubdeviceNames() override;
|
||||
|
||||
bool activate() override;
|
||||
|
@ -105,7 +103,6 @@ private:
|
|||
|
||||
void checkForConnectedDevices();
|
||||
|
||||
ovrSession _session { nullptr };
|
||||
ovrInputState _inputState {};
|
||||
RemoteDevice::Pointer _remote;
|
||||
TouchDevice::Pointer _touch;
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "OculusHelpers.h"
|
||||
|
||||
using namespace hifi;
|
||||
|
||||
const char* OculusDisplayPlugin::NAME { "Oculus Rift" };
|
||||
static ovrPerfHudMode currentDebugMode = ovrPerfHud_Off;
|
||||
|
||||
|
@ -63,7 +65,7 @@ void OculusDisplayPlugin::cycleDebugOutput() {
|
|||
|
||||
void OculusDisplayPlugin::customizeContext() {
|
||||
Parent::customizeContext();
|
||||
_outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OculusOutput", gpu::Element::COLOR_SRGBA_32, _renderTargetSize.x, _renderTargetSize.y));
|
||||
_outputFramebuffer.reset(gpu::Framebuffer::create("OculusOutput", gpu::Element::COLOR_SRGBA_32, _renderTargetSize.x, _renderTargetSize.y));
|
||||
ovrTextureSwapChainDesc desc = { };
|
||||
desc.Type = ovrTexture_2D;
|
||||
desc.ArraySize = 1;
|
||||
|
@ -76,14 +78,14 @@ void OculusDisplayPlugin::customizeContext() {
|
|||
|
||||
ovrResult result = ovr_CreateTextureSwapChainGL(_session, &desc, &_textureSwapChain);
|
||||
if (!OVR_SUCCESS(result)) {
|
||||
logCritical("Failed to create swap textures");
|
||||
qCritical(oculusLog) << "Failed to create swap textures" << ovr::getError();
|
||||
return;
|
||||
}
|
||||
|
||||
int length = 0;
|
||||
result = ovr_GetTextureSwapChainLength(_session, _textureSwapChain, &length);
|
||||
if (!OVR_SUCCESS(result) || !length) {
|
||||
logCritical("Unable to count swap chain textures");
|
||||
qCritical(oculusLog) << "Unable to count swap chain textures" << ovr::getError();
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < length; ++i) {
|
||||
|
@ -164,8 +166,8 @@ void OculusDisplayPlugin::hmdPresent() {
|
|||
auto result = ovr_CommitTextureSwapChain(_session, _textureSwapChain);
|
||||
Q_ASSERT(OVR_SUCCESS(result));
|
||||
_sceneLayer.SensorSampleTime = _currentPresentFrameInfo.sensorSampleTime;
|
||||
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose);
|
||||
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose);
|
||||
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovr::poseFromGlm(_currentPresentFrameInfo.renderPose);
|
||||
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovr::poseFromGlm(_currentPresentFrameInfo.renderPose);
|
||||
|
||||
auto submitStart = usecTimestampNow();
|
||||
uint64_t nonSubmitInterval = 0;
|
||||
|
@ -192,7 +194,7 @@ void OculusDisplayPlugin::hmdPresent() {
|
|||
}
|
||||
|
||||
if (!OVR_SUCCESS(result)) {
|
||||
logWarning("Failed to present");
|
||||
qWarning(oculusLog) << "Failed to present" << ovr::getError();
|
||||
}
|
||||
|
||||
static int compositorDroppedFrames = 0;
|
||||
|
@ -234,9 +236,7 @@ QJsonObject OculusDisplayPlugin::getHardwareStats() const {
|
|||
}
|
||||
|
||||
bool OculusDisplayPlugin::isHmdMounted() const {
|
||||
ovrSessionStatus status;
|
||||
return (OVR_SUCCESS(ovr_GetSessionStatus(_session, &status)) &&
|
||||
(ovrFalse != status.HmdMounted));
|
||||
return ovr::hmdMounted();
|
||||
}
|
||||
|
||||
QString OculusDisplayPlugin::getPreferredAudioInDevice() const {
|
||||
|
|
|
@ -24,41 +24,17 @@
|
|||
#include <NumericalConstants.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display")
|
||||
Q_LOGGING_CATEGORY(oculus, "hifi.plugins.display.oculus")
|
||||
|
||||
static std::atomic<uint32_t> refCount { 0 };
|
||||
static ovrSession session { nullptr };
|
||||
|
||||
static bool _quitRequested { false };
|
||||
static bool _reorientRequested { false };
|
||||
|
||||
inline ovrErrorInfo getError() {
|
||||
ovrErrorInfo error;
|
||||
ovr_GetLastErrorInfo(&error);
|
||||
return error;
|
||||
}
|
||||
|
||||
void logWarning(const char* what) {
|
||||
qWarning(oculus) << what << ":" << getError().ErrorString;
|
||||
}
|
||||
|
||||
void logCritical(const char* what) {
|
||||
std::string error("[oculus] ");
|
||||
error += what;
|
||||
error += ": ";
|
||||
error += getError().ErrorString;
|
||||
qCritical(error.c_str());
|
||||
}
|
||||
Q_LOGGING_CATEGORY(oculusLog, "hifi.plugins.display.oculus")
|
||||
|
||||
using namespace hifi;
|
||||
|
||||
static wchar_t* REQUIRED_OCULUS_DLL = L"LibOVRRT64_1.dll";
|
||||
static wchar_t FOUND_PATH[MAX_PATH];
|
||||
|
||||
bool oculusAvailable() {
|
||||
bool ovr::available() {
|
||||
static std::once_flag once;
|
||||
static bool result { false };
|
||||
static bool result{ false };
|
||||
std::call_once(once, [&] {
|
||||
|
||||
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENVR");
|
||||
static bool enableDebugOpenVR = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
if (enableDebugOpenVR) {
|
||||
|
@ -81,113 +57,107 @@ bool oculusAvailable() {
|
|||
return result;
|
||||
}
|
||||
|
||||
ovrSession acquireOculusSession() {
|
||||
if (!session && !oculusAvailable()) {
|
||||
qCDebug(oculus) << "oculus: no runtime or HMD present";
|
||||
class ovrImpl {
|
||||
using Mutex = std::mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
std::mutex mutex;
|
||||
ovrSession session{ nullptr };
|
||||
size_t renderCount{ 0 };
|
||||
|
||||
private:
|
||||
void setupSession(bool render) {
|
||||
if (session) {
|
||||
return;
|
||||
}
|
||||
ovrInitParams initParams{ ovrInit_RequestVersion | ovrInit_FocusAware, OVR_MINOR_VERSION, nullptr, 0, 0 };
|
||||
if (render) {
|
||||
initParams.Flags |= ovrInit_MixedRendering;
|
||||
} else {
|
||||
initParams.Flags |= ovrInit_Invisible;
|
||||
}
|
||||
|
||||
if (!OVR_SUCCESS(ovr_Initialize(&initParams))) {
|
||||
qCWarning(oculusLog) << "Failed to initialze Oculus SDK" << ovr::getError();
|
||||
return;
|
||||
}
|
||||
|
||||
ovrGraphicsLuid luid;
|
||||
if (!OVR_SUCCESS(ovr_Create(&session, &luid))) {
|
||||
qCWarning(oculusLog) << "Failed to acquire Oculus session" << ovr::getError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void releaseSession() {
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
ovr_Destroy(session);
|
||||
session = nullptr;
|
||||
ovr_Shutdown();
|
||||
}
|
||||
|
||||
public:
|
||||
void withSession(const std::function<void(ovrSession)>& f) {
|
||||
Lock lock(mutex);
|
||||
if (!session) {
|
||||
setupSession(false);
|
||||
}
|
||||
f(session);
|
||||
}
|
||||
|
||||
ovrSession acquireRenderSession() {
|
||||
Lock lock(mutex);
|
||||
if (renderCount++ == 0) {
|
||||
releaseSession();
|
||||
setupSession(true);
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
ovrInitParams initParams {
|
||||
ovrInit_RequestVersion | ovrInit_MixedRendering, OVR_MINOR_VERSION, nullptr, 0, 0
|
||||
};
|
||||
|
||||
if (!OVR_SUCCESS(ovr_Initialize(&initParams))) {
|
||||
logWarning("Failed to initialize Oculus SDK");
|
||||
return session;
|
||||
}
|
||||
|
||||
#ifdef OCULUS_APP_ID
|
||||
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
|
||||
if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) {
|
||||
// we were unable to initialize the platform for entitlement check - fail the check
|
||||
_quitRequested = true;
|
||||
} else {
|
||||
qCDebug(oculus) << "Performing Oculus Platform entitlement check";
|
||||
ovr_Entitlement_GetIsViewerEntitled();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Q_ASSERT(0 == refCount);
|
||||
ovrGraphicsLuid luid;
|
||||
if (!OVR_SUCCESS(ovr_Create(&session, &luid))) {
|
||||
logWarning("Failed to acquire Oculus session");
|
||||
return session;
|
||||
void releaseRenderSession(ovrSession session) {
|
||||
Lock lock(mutex);
|
||||
if (--renderCount == 0) {
|
||||
releaseSession();
|
||||
}
|
||||
}
|
||||
} _ovr;
|
||||
|
||||
++refCount;
|
||||
return session;
|
||||
ovrSession ovr::acquireRenderSession() {
|
||||
return _ovr.acquireRenderSession();
|
||||
}
|
||||
|
||||
void releaseOculusSession() {
|
||||
Q_ASSERT(refCount > 0 && session);
|
||||
// HACK the Oculus runtime doesn't seem to play well with repeated shutdown / restart.
|
||||
// So for now we'll just hold on to the session
|
||||
#if 0
|
||||
if (!--refCount) {
|
||||
qCDebug(oculus) << "oculus: zero refcount, shutdown SDK and session";
|
||||
ovr_Destroy(session);
|
||||
ovr_Shutdown();
|
||||
session = nullptr;
|
||||
}
|
||||
#endif
|
||||
void ovr::releaseRenderSession(ovrSession session) {
|
||||
_ovr.releaseRenderSession(session);
|
||||
}
|
||||
|
||||
void handleOVREvents() {
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
void ovr::withSession(const std::function<void(ovrSession)>& f) {
|
||||
_ovr.withSession(f);
|
||||
}
|
||||
|
||||
ovrSessionStatus status;
|
||||
if (!OVR_SUCCESS(ovr_GetSessionStatus(session, &status))) {
|
||||
return;
|
||||
}
|
||||
|
||||
_quitRequested = status.ShouldQuit;
|
||||
_reorientRequested = status.ShouldRecenter;
|
||||
|
||||
#ifdef OCULUS_APP_ID
|
||||
|
||||
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
|
||||
// pop messages to see if we got a return for an entitlement check
|
||||
ovrMessageHandle message = ovr_PopMessage();
|
||||
|
||||
while (message) {
|
||||
switch (ovr_Message_GetType(message)) {
|
||||
case ovrMessage_Entitlement_GetIsViewerEntitled: {
|
||||
if (!ovr_Message_IsError(message)) {
|
||||
// this viewer is entitled, no need to flag anything
|
||||
qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally";
|
||||
} else {
|
||||
// we failed the entitlement check, set our flag so the app can stop
|
||||
qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID;
|
||||
_quitRequested = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// free the message handle to cleanup and not leak
|
||||
ovr_FreeMessage(message);
|
||||
|
||||
// pop the next message to check, if there is one
|
||||
message = ovr_PopMessage();
|
||||
ovrSessionStatus ovr::getStatus() {
|
||||
ovrSessionStatus status{};
|
||||
withSession([&](ovrSession session) {
|
||||
if (!OVR_SUCCESS(ovr_GetSessionStatus(session, &status))) {
|
||||
qCWarning(oculusLog) << "Failed to get session status" << ovr::getError();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
});
|
||||
return status;
|
||||
}
|
||||
|
||||
bool quitRequested() {
|
||||
return _quitRequested;
|
||||
}
|
||||
bool reorientRequested() {
|
||||
return _reorientRequested;
|
||||
ovrTrackingState ovr::getTrackingState() {
|
||||
ovrTrackingState result{};
|
||||
withSession([&](ovrSession session) { result = ovr_GetTrackingState(session, 0, ovrFalse); });
|
||||
return result;
|
||||
}
|
||||
|
||||
controller::Pose ovrControllerPoseToHandPose(
|
||||
ovrHandType hand,
|
||||
const ovrPoseStatef& handPose) {
|
||||
QString ovr::getError() {
|
||||
static ovrErrorInfo error;
|
||||
ovr_GetLastErrorInfo(&error);
|
||||
return QString(error.ErrorString);
|
||||
}
|
||||
|
||||
controller::Pose hifi::ovr::toControllerPose(ovrHandType hand, const ovrPoseStatef& handPose) {
|
||||
// When the sensor-to-world rotation is identity the coordinate axes look like this:
|
||||
//
|
||||
// user
|
||||
|
@ -247,9 +217,8 @@ controller::Pose ovrControllerPoseToHandPose(
|
|||
static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ) * touchToHand;
|
||||
|
||||
static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
|
||||
static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f,
|
||||
-CONTROLLER_LENGTH_OFFSET / 2.0f,
|
||||
CONTROLLER_LENGTH_OFFSET * 1.5f);
|
||||
static const glm::vec3 CONTROLLER_OFFSET =
|
||||
glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, -CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET * 1.5f);
|
||||
static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET;
|
||||
static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET;
|
||||
|
||||
|
@ -268,12 +237,13 @@ controller::Pose ovrControllerPoseToHandPose(
|
|||
return pose;
|
||||
}
|
||||
|
||||
controller::Pose ovrControllerRotationToHandRotation(ovrHandType hand, const ovrPoseStatef& handPose,
|
||||
const ovrPoseStatef& lastHandPose) {
|
||||
controller::Pose hifi::ovr::toControllerPose(ovrHandType hand,
|
||||
const ovrPoseStatef& handPose,
|
||||
const ovrPoseStatef& lastHandPose) {
|
||||
static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y);
|
||||
static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X);
|
||||
static const glm::quat touchToHand = yFlip * quarterX;
|
||||
|
||||
|
||||
static const glm::quat leftQuarterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z);
|
||||
static const glm::quat rightQuarterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z);
|
||||
|
||||
|
@ -281,9 +251,8 @@ controller::Pose ovrControllerRotationToHandRotation(ovrHandType hand, const ovr
|
|||
static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ) * touchToHand;
|
||||
|
||||
static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
|
||||
static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f,
|
||||
-CONTROLLER_LENGTH_OFFSET / 2.0f,
|
||||
CONTROLLER_LENGTH_OFFSET * 1.5f);
|
||||
static const glm::vec3 CONTROLLER_OFFSET =
|
||||
glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, -CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET * 1.5f);
|
||||
static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET;
|
||||
static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET;
|
||||
|
||||
|
@ -301,3 +270,52 @@ controller::Pose ovrControllerRotationToHandRotation(ovrHandType hand, const ovr
|
|||
pose.valid = true;
|
||||
return pose;
|
||||
}
|
||||
|
||||
// FIXME These should be moved to an oculusPlatform plugin, they don't interact with the controller or session state
|
||||
#if 0
|
||||
void handleOVREvents() {
|
||||
updateSessionStatus(true);
|
||||
|
||||
#ifdef OCULUS_APP_ID
|
||||
|
||||
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
|
||||
// pop messages to see if we got a return for an entitlement check
|
||||
ovrMessageHandle message = ovr_PopMessage();
|
||||
|
||||
while (message) {
|
||||
switch (ovr_Message_GetType(message)) {
|
||||
case ovrMessage_Entitlement_GetIsViewerEntitled:
|
||||
{
|
||||
if (!ovr_Message_IsError(message)) {
|
||||
// this viewer is entitled, no need to flag anything
|
||||
qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally";
|
||||
} else {
|
||||
// we failed the entitlement check, set our flag so the app can stop
|
||||
qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID;
|
||||
_quitRequested = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// free the message handle to cleanup and not leak
|
||||
ovr_FreeMessage(message);
|
||||
|
||||
// pop the next message to check, if there is one
|
||||
message = ovr_PopMessage();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef OCULUS_APP_ID
|
||||
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
|
||||
if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) {
|
||||
// we were unable to initialize the platform for entitlement check - fail the check
|
||||
_quitRequested = true;
|
||||
} else {
|
||||
qCDebug(oculusLog) << "Performing Oculus Platform entitlement check";
|
||||
ovr_Entitlement_GetIsViewerEntitled();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#include <OVR_CAPI_GL.h>
|
||||
#include <ovr_capi.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
@ -18,106 +17,107 @@
|
|||
#include <controllers/Forward.h>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(displayplugins)
|
||||
Q_DECLARE_LOGGING_CATEGORY(oculus)
|
||||
Q_DECLARE_LOGGING_CATEGORY(oculusLog)
|
||||
|
||||
void logWarning(const char* what);
|
||||
void logCritical(const char* what);
|
||||
bool oculusAvailable();
|
||||
ovrSession acquireOculusSession();
|
||||
void releaseOculusSession();
|
||||
namespace hifi {
|
||||
|
||||
struct ovr {
|
||||
static bool available();
|
||||
static ovrSession acquireRenderSession();
|
||||
static void releaseRenderSession(ovrSession session);
|
||||
static void withSession(const std::function<void(ovrSession)>& f);
|
||||
static ovrSessionStatus getStatus();
|
||||
static ovrTrackingState getTrackingState();
|
||||
static QString getError();
|
||||
|
||||
void handleOVREvents();
|
||||
bool quitRequested();
|
||||
bool reorientRequested();
|
||||
static inline bool quitRequested() { return quitRequested(getStatus()); }
|
||||
static inline bool reorientRequested() { return reorientRequested(getStatus()); }
|
||||
static inline bool hmdMounted() { return hmdMounted(getStatus()); }
|
||||
static inline bool hasInputFocus() { return hasInputFocus(getStatus()); }
|
||||
|
||||
// Convenience method for looping over each eye with a lambda
|
||||
template <typename Function>
|
||||
inline void ovr_for_each_eye(Function function) {
|
||||
for (ovrEyeType eye = ovrEyeType::ovrEye_Left;
|
||||
eye < ovrEyeType::ovrEye_Count;
|
||||
eye = static_cast<ovrEyeType>(eye + 1)) {
|
||||
function(eye);
|
||||
static inline bool quitRequested(const ovrSessionStatus& status) { return status.ShouldQuit != ovrFalse; }
|
||||
static inline bool reorientRequested(const ovrSessionStatus& status) { return status.ShouldRecenter != ovrFalse; }
|
||||
static inline bool hmdMounted(const ovrSessionStatus& status) { return status.HmdMounted != ovrFalse; }
|
||||
static inline bool hasInputFocus(const ovrSessionStatus& status) { return status.HasInputFocus != ovrFalse; }
|
||||
|
||||
// Convenience method for looping over each eye with a lambda
|
||||
static inline void for_each_eye(const std::function<void(ovrEyeType eye)>& f) {
|
||||
for (ovrEyeType eye = ovrEye_Left; eye < ovrEye_Count; eye = static_cast<ovrEyeType>(eye + 1)) {
|
||||
f(eye);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
inline void ovr_for_each_hand(Function function) {
|
||||
for (ovrHandType hand = ovrHandType::ovrHand_Left;
|
||||
hand <= ovrHandType::ovrHand_Right;
|
||||
hand = static_cast<ovrHandType>(hand + 1)) {
|
||||
function(hand);
|
||||
static inline void for_each_hand(const std::function<void(ovrHandType eye)>& f) {
|
||||
for (ovrHandType hand = ovrHand_Left; hand < ovrHand_Count; hand = static_cast<ovrHandType>(hand + 1)) {
|
||||
f(hand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline glm::mat4 toGlm(const ovrMatrix4f& om) {
|
||||
return glm::transpose(glm::make_mat4(&om.M[0][0]));
|
||||
}
|
||||
|
||||
static inline glm::mat4 toGlm(const ovrFovPort& fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
|
||||
return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
|
||||
}
|
||||
|
||||
static inline glm::vec3 toGlm(const ovrVector3f& ov) {
|
||||
return glm::make_vec3(&ov.x);
|
||||
}
|
||||
|
||||
static inline glm::vec2 toGlm(const ovrVector2f& ov) {
|
||||
return glm::make_vec2(&ov.x);
|
||||
}
|
||||
|
||||
inline glm::mat4 toGlm(const ovrMatrix4f & om) {
|
||||
return glm::transpose(glm::make_mat4(&om.M[0][0]));
|
||||
}
|
||||
static inline glm::uvec2 toGlm(const ovrSizei& ov) {
|
||||
return glm::uvec2(ov.w, ov.h);
|
||||
}
|
||||
|
||||
inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
|
||||
return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
|
||||
}
|
||||
static inline glm::quat toGlm(const ovrQuatf& oq) {
|
||||
return glm::make_quat(&oq.x);
|
||||
}
|
||||
|
||||
inline glm::vec3 toGlm(const ovrVector3f & ov) {
|
||||
return glm::make_vec3(&ov.x);
|
||||
}
|
||||
static inline glm::mat4 toGlm(const ovrPosef& op) {
|
||||
glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
|
||||
glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
|
||||
return translation * orientation;
|
||||
}
|
||||
|
||||
inline glm::vec2 toGlm(const ovrVector2f & ov) {
|
||||
return glm::make_vec2(&ov.x);
|
||||
}
|
||||
static inline ovrMatrix4f fromGlm(const glm::mat4& m) {
|
||||
ovrMatrix4f result;
|
||||
glm::mat4 transposed(glm::transpose(m));
|
||||
memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline glm::uvec2 toGlm(const ovrSizei & ov) {
|
||||
return glm::uvec2(ov.w, ov.h);
|
||||
}
|
||||
static inline ovrVector3f fromGlm(const glm::vec3& v) {
|
||||
return { v.x, v.y, v.z };
|
||||
}
|
||||
|
||||
inline glm::quat toGlm(const ovrQuatf & oq) {
|
||||
return glm::make_quat(&oq.x);
|
||||
}
|
||||
static inline ovrVector2f fromGlm(const glm::vec2& v) {
|
||||
return { v.x, v.y };
|
||||
}
|
||||
|
||||
inline glm::mat4 toGlm(const ovrPosef & op) {
|
||||
glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
|
||||
glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
|
||||
return translation * orientation;
|
||||
}
|
||||
static inline ovrSizei fromGlm(const glm::uvec2& v) {
|
||||
return { (int)v.x, (int)v.y };
|
||||
}
|
||||
|
||||
inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
|
||||
ovrMatrix4f result;
|
||||
glm::mat4 transposed(glm::transpose(m));
|
||||
memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
|
||||
return result;
|
||||
}
|
||||
static inline ovrQuatf fromGlm(const glm::quat& q) {
|
||||
return { q.x, q.y, q.z, q.w };
|
||||
}
|
||||
|
||||
inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
|
||||
return{ v.x, v.y, v.z };
|
||||
}
|
||||
static inline ovrPosef poseFromGlm(const glm::mat4& m) {
|
||||
glm::vec3 translation = glm::vec3(m[3]) / m[3].w;
|
||||
glm::quat orientation = glm::quat_cast(m);
|
||||
ovrPosef result;
|
||||
result.Orientation = fromGlm(orientation);
|
||||
result.Position = fromGlm(translation);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
|
||||
return{ v.x, v.y };
|
||||
}
|
||||
static controller::Pose toControllerPose(ovrHandType hand, const ovrPoseStatef& handPose);
|
||||
static controller::Pose toControllerPose(ovrHandType hand, const ovrPoseStatef& handPose, const ovrPoseStatef& lastHandPose);
|
||||
|
||||
inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
|
||||
return{ (int)v.x, (int)v.y };
|
||||
}
|
||||
};
|
||||
|
||||
inline ovrQuatf ovrFromGlm(const glm::quat & q) {
|
||||
return{ q.x, q.y, q.z, q.w };
|
||||
}
|
||||
|
||||
inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) {
|
||||
glm::vec3 translation = glm::vec3(m[3]) / m[3].w;
|
||||
glm::quat orientation = glm::quat_cast(m);
|
||||
ovrPosef result;
|
||||
result.Orientation = ovrFromGlm(orientation);
|
||||
result.Position = ovrFromGlm(translation);
|
||||
return result;
|
||||
}
|
||||
|
||||
controller::Pose ovrControllerPoseToHandPose(
|
||||
ovrHandType hand,
|
||||
const ovrPoseStatef& handPose);
|
||||
|
||||
controller::Pose ovrControllerRotationToHandRotation(ovrHandType hand,
|
||||
const ovrPoseStatef& handPose, const ovrPoseStatef& lastHandPose);
|
||||
} // namespace hifi
|
||||
|
|
|
@ -57,7 +57,6 @@ if (Menu.menuExists(MENU_CATEGORY) && !Menu.menuItemExists(MENU_CATEGORY, MENU_I
|
|||
menuItemName: MENU_ITEM,
|
||||
isCheckable: true,
|
||||
isChecked: previousSetting,
|
||||
grouping: "Advanced"
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -2362,26 +2362,21 @@ var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace");
|
|||
|
||||
var propertiesTool = new PropertiesTool();
|
||||
var particleExplorerTool = new ParticleExplorerTool();
|
||||
var selectedParticleEntity = 0;
|
||||
var selectedParticleEntityID = null;
|
||||
|
||||
function selectParticleEntity(entityID) {
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
selectedParticleEntityID = entityID;
|
||||
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
if (properties.emitOrientation) {
|
||||
properties.emitOrientation = Quat.safeEulerAngles(properties.emitOrientation);
|
||||
}
|
||||
var particleData = {
|
||||
messageType: "particle_settings",
|
||||
currentProperties: properties
|
||||
};
|
||||
|
||||
particleExplorerTool.destroyWebView();
|
||||
particleExplorerTool.createWebView();
|
||||
|
||||
selectedParticleEntity = entityID;
|
||||
particleExplorerTool.setActiveParticleEntity(entityID);
|
||||
|
||||
particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
|
||||
particleExplorerTool.setActiveParticleProperties(properties);
|
||||
|
||||
// Switch to particle explorer
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
|
@ -2404,13 +2399,13 @@ entityListTool.webView.webEventReceived.connect(function (data) {
|
|||
var ids = data.entityIds;
|
||||
if (ids.length === 1) {
|
||||
if (Entities.getEntityProperties(ids[0], "type").type === "ParticleEffect") {
|
||||
if (JSON.stringify(selectedParticleEntity) === JSON.stringify(ids[0])) {
|
||||
if (JSON.stringify(selectedParticleEntityID) === JSON.stringify(ids[0])) {
|
||||
// This particle entity is already selected, so return
|
||||
return;
|
||||
}
|
||||
// Destroy the old particles web view first
|
||||
} else {
|
||||
selectedParticleEntity = 0;
|
||||
selectedParticleEntityID = 0;
|
||||
particleExplorerTool.destroyWebView();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,8 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
|||
}),
|
||||
dimensions: { x: tabletWidth, y: tabletHeight, z: tabletDepth },
|
||||
parentID: MyAvatar.SELF_ID,
|
||||
visible: visible
|
||||
visible: visible,
|
||||
isGroupCulled: true
|
||||
};
|
||||
|
||||
// compute position, rotation & parentJointIndex of the tablet
|
||||
|
|
|
@ -91,7 +91,7 @@ CameraManager = function() {
|
|||
}
|
||||
|
||||
var CAPTURED_KEYS = [];
|
||||
for (key in keyToActionMapping) {
|
||||
for (var key in keyToActionMapping) {
|
||||
CAPTURED_KEYS.push(key);
|
||||
}
|
||||
|
||||
|
@ -99,9 +99,9 @@ CameraManager = function() {
|
|||
var action = keyToActionMapping[event.text];
|
||||
if (action !== undefined) {
|
||||
if (event.isShifted) {
|
||||
if (action == "orbitForward") {
|
||||
if (action === "orbitForward") {
|
||||
action = "orbitUp";
|
||||
} else if (action == "orbitBackward") {
|
||||
} else if (action === "orbitBackward") {
|
||||
action = "orbitDown";
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ CameraManager = function() {
|
|||
};
|
||||
|
||||
that.enable = function() {
|
||||
if (Camera.mode == "independent" || that.enabled || HMD.active) {
|
||||
if (Camera.mode === "independent" || that.enabled || HMD.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ CameraManager = function() {
|
|||
}
|
||||
|
||||
that.setFocalPoint = function(pos) {
|
||||
that.targetFocalPoint = pos
|
||||
that.targetFocalPoint = pos;
|
||||
that.updateCamera();
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ CameraManager = function() {
|
|||
}
|
||||
|
||||
that.mouseMoveEvent = function(event) {
|
||||
if (that.enabled && that.mode != MODE_INACTIVE) {
|
||||
if (that.enabled && that.mode !== MODE_INACTIVE) {
|
||||
var x = Reticle.getPosition().x;
|
||||
var y = Reticle.getPosition().y;
|
||||
if (!hasDragged) {
|
||||
|
@ -284,11 +284,11 @@ CameraManager = function() {
|
|||
that.lastMousePosition.y = y;
|
||||
hasDragged = true;
|
||||
}
|
||||
if (that.mode == MODE_ORBIT) {
|
||||
if (that.mode === MODE_ORBIT) {
|
||||
var diffX = x - that.lastMousePosition.x;
|
||||
var diffY = y - that.lastMousePosition.y;
|
||||
that.targetYaw -= MOUSE_SENSITIVITY * (diffX / 5.0)
|
||||
that.targetPitch += MOUSE_SENSITIVITY * (diffY / 10.0)
|
||||
that.targetYaw -= MOUSE_SENSITIVITY * (diffX / 5.0);
|
||||
that.targetPitch += MOUSE_SENSITIVITY * (diffY / 10.0);
|
||||
|
||||
while (that.targetYaw > 180.0) that.targetYaw -= 360;
|
||||
while (that.targetYaw < -180.0) that.targetYaw += 360;
|
||||
|
@ -297,7 +297,7 @@ CameraManager = function() {
|
|||
if (that.targetPitch < -90) that.targetPitch = -90;
|
||||
|
||||
that.updateCamera();
|
||||
} else if (that.mode == MODE_PAN) {
|
||||
} else if (that.mode === MODE_PAN) {
|
||||
var diffX = x - that.lastMousePosition.x;
|
||||
var diffY = y - that.lastMousePosition.y;
|
||||
|
||||
|
@ -316,19 +316,19 @@ CameraManager = function() {
|
|||
var newY = y;
|
||||
var updatePosition = false;
|
||||
|
||||
if (x <= Window.x) {
|
||||
newX = Window.x + Window.innerWidth;
|
||||
if (x <= 0) {
|
||||
newX = Window.innerWidth;
|
||||
updatePosition = true;
|
||||
} else if (x >= (Window.x + Window.innerWidth)) {
|
||||
newX = Window.x;
|
||||
} else if (x >= Window.innerWidth) {
|
||||
newX = 0;
|
||||
updatePosition = true;
|
||||
}
|
||||
|
||||
if (y <= Window.y) {
|
||||
newY = Window.y + Window.innerHeight;
|
||||
if (y <= 0) {
|
||||
newY = Window.innerHeight;
|
||||
updatePosition = true;
|
||||
} else if (y >= (Window.y + Window.innerHeight)) {
|
||||
newY = Window.y;
|
||||
} else if (y >= Window.innerHeight) {
|
||||
newY = 0;
|
||||
updatePosition = true;
|
||||
}
|
||||
|
||||
|
@ -410,7 +410,7 @@ CameraManager = function() {
|
|||
}
|
||||
|
||||
that.updateCamera = function() {
|
||||
if (!that.enabled || Camera.mode != "independent") {
|
||||
if (!that.enabled || Camera.mode !== "independent") {
|
||||
cameraTool.update();
|
||||
return;
|
||||
}
|
||||
|
@ -464,7 +464,7 @@ CameraManager = function() {
|
|||
|
||||
// Ease the position and orbit of the camera
|
||||
that.update = function(dt) {
|
||||
if (Camera.mode != "independent") {
|
||||
if (Camera.mode !== "independent") {
|
||||
that.updateCamera();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1036,6 +1036,29 @@ SelectionDisplay = (function() {
|
|||
}
|
||||
};
|
||||
|
||||
// FUNCTION: TOGGLE SPACE MODE
|
||||
that.toggleSpaceMode = function() {
|
||||
var wantDebug = false;
|
||||
if (wantDebug) {
|
||||
print("========> ToggleSpaceMode called. =========");
|
||||
}
|
||||
if ((spaceMode === SPACE_WORLD) && (SelectionManager.selections.length > 1)) {
|
||||
if (wantDebug) {
|
||||
print("Local space editing is not available with multiple selections");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (wantDebug) {
|
||||
print("PreToggle: " + spaceMode);
|
||||
}
|
||||
spaceMode = (spaceMode === SPACE_LOCAL) ? SPACE_WORLD : SPACE_LOCAL;
|
||||
that.updateHandles();
|
||||
if (wantDebug) {
|
||||
print("PostToggle: " + spaceMode);
|
||||
print("======== ToggleSpaceMode called. <=========");
|
||||
}
|
||||
};
|
||||
|
||||
function addHandleTool(overlay, tool) {
|
||||
handleTools[overlay] = tool;
|
||||
return tool;
|
||||
|
|
|
@ -16,37 +16,62 @@ var PARTICLE_EXPLORER_HTML_URL = Script.resolvePath('particleExplorer.html');
|
|||
|
||||
ParticleExplorerTool = function() {
|
||||
var that = {};
|
||||
that.activeParticleEntity = 0;
|
||||
that.activeParticleProperties = {};
|
||||
|
||||
that.createWebView = function() {
|
||||
that.webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
that.webView.setVisible = function(value) {};
|
||||
that.webView.webEventReceived.connect(that.webEventReceived);
|
||||
}
|
||||
};
|
||||
|
||||
that.destroyWebView = function() {
|
||||
if (!that.webView) {
|
||||
return;
|
||||
}
|
||||
that.activeParticleEntity = 0;
|
||||
that.activeParticleProperties = {};
|
||||
|
||||
var messageData = {
|
||||
messageType: "particle_close"
|
||||
};
|
||||
that.webView.emitScriptEvent(JSON.stringify(messageData));
|
||||
};
|
||||
|
||||
function sendActiveParticleProperties() {
|
||||
that.webView.emitScriptEvent(JSON.stringify({
|
||||
messageType: "particle_settings",
|
||||
currentProperties: that.activeParticleProperties
|
||||
}));
|
||||
}
|
||||
|
||||
that.webEventReceived = function(data) {
|
||||
var data = JSON.parse(data);
|
||||
that.webEventReceived = function(message) {
|
||||
var data = JSON.parse(message);
|
||||
if (data.messageType === "settings_update") {
|
||||
if (data.updatedSettings.emitOrientation) {
|
||||
data.updatedSettings.emitOrientation = Quat.fromVec3Degrees(data.updatedSettings.emitOrientation);
|
||||
}
|
||||
Entities.editEntity(that.activeParticleEntity, data.updatedSettings);
|
||||
|
||||
for (var key in data.updatedSettings) {
|
||||
if (that.activeParticleProperties.hasOwnProperty(key)) {
|
||||
that.activeParticleProperties[key] = data.updatedSettings[key];
|
||||
}
|
||||
}
|
||||
|
||||
} else if (data.messageType === "page_loaded") {
|
||||
sendActiveParticleProperties();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
that.setActiveParticleEntity = function(id) {
|
||||
that.activeParticleEntity = id;
|
||||
}
|
||||
};
|
||||
|
||||
that.setActiveParticleProperties = function(properties) {
|
||||
that.activeParticleProperties = properties;
|
||||
sendActiveParticleProperties();
|
||||
};
|
||||
|
||||
return that;
|
||||
};
|
||||
|
|
|
@ -295,6 +295,7 @@ function printToPolaroid(image_url) {
|
|||
"description": "Printed from Snaps",
|
||||
"modelURL": POLAROID_MODEL_URL,
|
||||
|
||||
"dimensions": { "x": 0.5667, "y": 0.0212, "z": 0.4176 },
|
||||
"position": model_pos,
|
||||
"rotation": model_rot,
|
||||
|
||||
|
|
Loading…
Reference in a new issue