mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 01:24:36 +02:00
merge and update based on sam's changes
This commit is contained in:
commit
86ee5c12d8
216 changed files with 3633 additions and 1789 deletions
14
BUILD_WIN.md
14
BUILD_WIN.md
|
@ -9,15 +9,17 @@ Note: The prerequisites will require about 10 GB of space on your drive. You wil
|
||||||
|
|
||||||
If you don’t have Community or Professional edition of Visual Studio 2017, download [Visual Studio Community 2017](https://www.visualstudio.com/downloads/).
|
If you don’t have Community or Professional edition of Visual Studio 2017, download [Visual Studio Community 2017](https://www.visualstudio.com/downloads/).
|
||||||
|
|
||||||
When selecting components, check "Desktop development with C++." Also check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)" on the Summary toolbar on the right.
|
When selecting components, check "Desktop development with C++." Also on the right on the Summary toolbar, check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)".
|
||||||
|
|
||||||
### Step 2. Installing CMake
|
### Step 2. Installing CMake
|
||||||
|
|
||||||
Download and install the latest version of CMake 3.9. Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). Make sure to check "Add CMake to system PATH for all users" when prompted during installation.
|
Download and install the latest version of CMake 3.9.
|
||||||
|
|
||||||
|
Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.9 Version page](https://cmake.org/files/v3.9/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted.
|
||||||
|
|
||||||
### Step 3. Installing Qt
|
### Step 3. Installing Qt
|
||||||
|
|
||||||
Download and install the [Qt Online Installer](https://www.qt.io/download-open-source/?hsCtaTracking=f977210e-de67-475f-a32b-65cec207fd03%7Cd62710cd-e1db-46aa-8d4d-2f1c1ffdacea). While installing, you only need to have the following components checked under Qt 5.10.1: "msvc2017 64-bit", "Qt WebEngine", and "Qt Script (Deprecated)".
|
Download and install the [Qt Open Source Online Installer](https://www.qt.io/download-open-source/?hsCtaTracking=f977210e-de67-475f-a32b-65cec207fd03%7Cd62710cd-e1db-46aa-8d4d-2f1c1ffdacea). While installing, you only need to have the following components checked under Qt 5.10.1: "msvc2017 64-bit", "Qt WebEngine", and "Qt Script (Deprecated)".
|
||||||
|
|
||||||
Note: Installing the Sources is optional but recommended if you have room for them (~2GB).
|
Note: Installing the Sources is optional but recommended if you have room for them (~2GB).
|
||||||
|
|
||||||
|
@ -56,9 +58,9 @@ Where `%HIFI_DIR%` is the directory for the highfidelity repository.
|
||||||
|
|
||||||
Open `%HIFI_DIR%\build\hifi.sln` using Visual Studio.
|
Open `%HIFI_DIR%\build\hifi.sln` using Visual Studio.
|
||||||
|
|
||||||
Change the Solution Configuration (next to the green play button) from "Debug" to "Release" for best performance.
|
Change the Solution Configuration (menu ribbon under the menu bar, next to the green play button) from "Debug" to "Release" for best performance.
|
||||||
|
|
||||||
Run `Build > Build Solution`.
|
Run from the menu bar `Build > Build Solution`.
|
||||||
|
|
||||||
### Step 9. Testing Interface
|
### Step 9. Testing Interface
|
||||||
|
|
||||||
|
@ -66,7 +68,7 @@ Create another environment variable (see Step #4)
|
||||||
* Set "Variable name": `_NO_DEBUG_HEAP`
|
* Set "Variable name": `_NO_DEBUG_HEAP`
|
||||||
* Set "Variable value": `1`
|
* Set "Variable value": `1`
|
||||||
|
|
||||||
In Visual Studio, right+click "interface" under the Apps folder in Solution Explorer and select "Set as Startup Project". Run `Debug > Start Debugging`.
|
In Visual Studio, right+click "interface" under the Apps folder in Solution Explorer and select "Set as Startup Project". Run from the menu bar `Debug > Start Debugging`.
|
||||||
|
|
||||||
Now, you should have a full build of High Fidelity and be able to run the Interface using Visual Studio. Please check our [Docs](https://wiki.highfidelity.com/wiki/Main_Page) for more information regarding the programming workflow.
|
Now, you should have a full build of High Fidelity and be able to run the Interface using Visual Studio. Please check our [Docs](https://wiki.highfidelity.com/wiki/Main_Page) for more information regarding the programming workflow.
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,14 @@ android {
|
||||||
'-DDISABLE_KTX_CACHE=OFF'
|
'-DDISABLE_KTX_CACHE=OFF'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
signingConfigs {
|
||||||
|
release {
|
||||||
|
storeFile project.hasProperty("HIFI_ANDROID_KEYSTORE") ? file(HIFI_ANDROID_KEYSTORE) : null
|
||||||
|
storePassword project.hasProperty("HIFI_ANDROID_KEYSTORE_PASSWORD") ? HIFI_ANDROID_KEYSTORE_PASSWORD : ''
|
||||||
|
keyAlias project.hasProperty("HIFI_ANDROID_KEY_ALIAS") ? HIFI_ANDROID_KEY_ALIAS : ''
|
||||||
|
keyPassword project.hasProperty("HIFI_ANDROID_KEY_PASSWORD") ? HIFI_ANDROID_KEY_PASSWORD : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
@ -38,6 +46,10 @@ android {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
signingConfig project.hasProperty("HIFI_ANDROID_KEYSTORE") &&
|
||||||
|
project.hasProperty("HIFI_ANDROID_KEYSTORE_PASSWORD") &&
|
||||||
|
project.hasProperty("HIFI_ANDROID_KEY_ALIAS") &&
|
||||||
|
project.hasProperty("HIFI_ANDROID_KEY_PASSWORD")? signingConfigs.release : null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,12 +49,6 @@
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
>
|
>
|
||||||
|
|
||||||
<intent-filter>
|
|
||||||
<category android:name="com.google.intent.category.DAYDREAM"/>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<meta-data android:name="android.app.lib_name" android:value="native-lib"/>
|
<meta-data android:name="android.app.lib_name" android:value="native-lib"/>
|
||||||
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||||
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
|
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
|
||||||
|
|
|
@ -66,17 +66,17 @@ ext {
|
||||||
def baseFolder = new File(HIFI_ANDROID_PRECOMPILED)
|
def baseFolder = new File(HIFI_ANDROID_PRECOMPILED)
|
||||||
def appDir = new File(projectDir, 'app')
|
def appDir = new File(projectDir, 'app')
|
||||||
def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a')
|
def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a')
|
||||||
def baseUrl = 'https://hifi-public.s3.amazonaws.com/austin/android/'
|
def baseUrl = ''
|
||||||
|
|
||||||
def qtFile='qt-5.9.3_linux_armv8-libcpp_openssl.tgz'
|
def qtFile='https://hifi-public.s3.amazonaws.com/austin/android/qt-5.9.3_linux_armv8-libcpp_openssl.tgz'
|
||||||
def qtChecksum='04599670ccca84bd2b15f6915568eb2d'
|
def qtChecksum='04599670ccca84bd2b15f6915568eb2d'
|
||||||
def qtVersionId='PeoqzN31n.YvLfs9JE2SgHgZ4.IaKAlt'
|
def qtVersionId='PeoqzN31n.YvLfs9JE2SgHgZ4.IaKAlt'
|
||||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||||
qtFile = 'qt-5.9.3_osx_armv8-libcpp_openssl.tgz'
|
qtFile = 'https://hifi-public.s3.amazonaws.com/austin/android/qt-5.9.3_osx_armv8-libcpp_openssl.tgz'
|
||||||
qtChecksum='4b02de9d67d6bfb202355a808d2d9c59'
|
qtChecksum='4b02de9d67d6bfb202355a808d2d9c59'
|
||||||
qtVersionId='HygCmtMLPYioyil0DfXckGVzhw2SXZA9'
|
qtVersionId='HygCmtMLPYioyil0DfXckGVzhw2SXZA9'
|
||||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||||
qtFile = 'qt-5.9.3_win_armv8-libcpp_openssl.tgz'
|
qtFile = 'https://hifi-public.s3.amazonaws.com/austin/android/qt-5.9.3_win_armv8-libcpp_openssl.tgz'
|
||||||
qtChecksum='c3e25db64002d0f43cf565e0ef708911'
|
qtChecksum='c3e25db64002d0f43cf565e0ef708911'
|
||||||
qtVersionId='HeVObSVLCBoc7yY7He1oBMvPIH0VkClT'
|
qtVersionId='HeVObSVLCBoc7yY7He1oBMvPIH0VkClT'
|
||||||
}
|
}
|
||||||
|
@ -88,58 +88,58 @@ def packages = [
|
||||||
checksum: qtChecksum,
|
checksum: qtChecksum,
|
||||||
],
|
],
|
||||||
bullet: [
|
bullet: [
|
||||||
file: 'bullet-2.83_armv8-libcpp.tgz',
|
file: 'https://hifi-public.s3.amazonaws.com/dependencies/android/bullet-2.88_armv8-libcpp.tgz',
|
||||||
versionId: 'ljb7v.1IjVRqyopUKVDbVnLA4z88J8Eo',
|
versionId: 'S8YaoED0Cl8sSb8fSV7Q2G1lQJSNDxqg',
|
||||||
checksum: '2c558d604fce337f5eba3eb7ec1252fd',
|
checksum: '81642779ccb110f8c7338e8739ac38a0',
|
||||||
],
|
],
|
||||||
draco: [
|
draco: [
|
||||||
file: 'draco_armv8-libcpp.tgz',
|
file: 'https://hifi-public.s3.amazonaws.com/austin/android/draco_armv8-libcpp.tgz',
|
||||||
versionId: 'cA3tVJSmkvb1naA3l6D_Jv2Noh.4yc4m',
|
versionId: 'cA3tVJSmkvb1naA3l6D_Jv2Noh.4yc4m',
|
||||||
checksum: '617a80d213a5ec69fbfa21a1f2f738cd',
|
checksum: '617a80d213a5ec69fbfa21a1f2f738cd',
|
||||||
],
|
],
|
||||||
glad: [
|
glad: [
|
||||||
file: 'glad_armv8-libcpp.zip',
|
file: 'https://hifi-public.s3.amazonaws.com/austin/android/glad_armv8-libcpp.zip',
|
||||||
versionId: 'Q9szthzeye8fFyAA.cY26Lgn2B8kezEE',
|
versionId: 'Q9szthzeye8fFyAA.cY26Lgn2B8kezEE',
|
||||||
checksum: 'a8ee8584cf1ccd34766c7ddd9d5e5449',
|
checksum: 'a8ee8584cf1ccd34766c7ddd9d5e5449',
|
||||||
],
|
],
|
||||||
glm: [
|
glm: [
|
||||||
file: 'glm-0.9.8.tgz',
|
file: 'https://hifi-public.s3.amazonaws.com/dependencies/android/glm-0.9.8.5-patched.tgz',
|
||||||
versionId: 'BlkJNwaYV2Gfy5XwMeU7K0uzPDRKFMt2',
|
versionId: 'cskfMoJrFlAeqI3WPxemyO_Cxt7rT9EJ',
|
||||||
checksum: 'd2b42cee31d2bc17bab6ce69e6b3f30a',
|
checksum: '067b5fe16b220b5b1a1039ba51b062ae',
|
||||||
],
|
],
|
||||||
gvr: [
|
gvr: [
|
||||||
file: 'gvrsdk_v1.101.0.tgz',
|
file: 'https://hifi-public.s3.amazonaws.com/austin/android/gvrsdk_v1.101.0.tgz',
|
||||||
versionId: 'UTberAIFraEfF9IVjoV66u1DTPTopgeY',
|
versionId: 'UTberAIFraEfF9IVjoV66u1DTPTopgeY',
|
||||||
checksum: '57fd02baa069176ba18597a29b6b4fc7',
|
checksum: '57fd02baa069176ba18597a29b6b4fc7',
|
||||||
],
|
],
|
||||||
nvtt: [
|
nvtt: [
|
||||||
file: 'nvtt_armv8-libcpp.zip',
|
file: 'https://hifi-public.s3.amazonaws.com/austin/android/nvtt_armv8-libcpp.zip',
|
||||||
versionId: 'vLqrqThvpq4gp75BHMAqO6HhfTXaa0An',
|
versionId: 'vLqrqThvpq4gp75BHMAqO6HhfTXaa0An',
|
||||||
checksum: 'eb46d0b683e66987190ed124aabf8910',
|
checksum: 'eb46d0b683e66987190ed124aabf8910',
|
||||||
sharedLibFolder: 'lib',
|
sharedLibFolder: 'lib',
|
||||||
includeLibs: ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so'],
|
includeLibs: ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so'],
|
||||||
],
|
],
|
||||||
openssl: [
|
openssl: [
|
||||||
file: 'openssl-1.1.0g_armv8.tgz',
|
file: 'https://hifi-public.s3.amazonaws.com/austin/android/openssl-1.1.0g_armv8.tgz',
|
||||||
versionId: 'DmahmSGFS4ltpHyTdyQvv35WOeUOiib9',
|
versionId: 'DmahmSGFS4ltpHyTdyQvv35WOeUOiib9',
|
||||||
checksum: 'cabb681fbccd79594f65fcc266e02f32',
|
checksum: 'cabb681fbccd79594f65fcc266e02f32',
|
||||||
],
|
],
|
||||||
polyvox: [
|
polyvox: [
|
||||||
file: 'polyvox_armv8-libcpp.tgz',
|
file: 'https://hifi-public.s3.amazonaws.com/austin/android/polyvox_armv8-libcpp.tgz',
|
||||||
versionId: 'LDJtzMTvdm4SAc2KYg8Cg6uwWk4Vq3e3',
|
versionId: 'LDJtzMTvdm4SAc2KYg8Cg6uwWk4Vq3e3',
|
||||||
checksum: '349ad5b72aaf2749ca95d847e60c5314',
|
checksum: '349ad5b72aaf2749ca95d847e60c5314',
|
||||||
sharedLibFolder: 'lib',
|
sharedLibFolder: 'lib',
|
||||||
includeLibs: ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'],
|
includeLibs: ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'],
|
||||||
],
|
],
|
||||||
tbb: [
|
tbb: [
|
||||||
file: 'tbb-2018_U1_armv8_libcpp.tgz',
|
file: 'https://hifi-public.s3.amazonaws.com/austin/android/tbb-2018_U1_armv8_libcpp.tgz',
|
||||||
versionId: 'YZliDD8.Menh1IVXKEuLPeO3xAjJ1UdF',
|
versionId: 'YZliDD8.Menh1IVXKEuLPeO3xAjJ1UdF',
|
||||||
checksum: '20768f298f53b195e71b414b0ae240c4',
|
checksum: '20768f298f53b195e71b414b0ae240c4',
|
||||||
sharedLibFolder: 'lib/release',
|
sharedLibFolder: 'lib/release',
|
||||||
includeLibs: ['libtbb.so', 'libtbbmalloc.so'],
|
includeLibs: ['libtbb.so', 'libtbbmalloc.so'],
|
||||||
],
|
],
|
||||||
hifiAC: [
|
hifiAC: [
|
||||||
file: 'libplugins_libhifiCodec.zip',
|
file: 'https://hifi-public.s3.amazonaws.com/austin/android/libplugins_libhifiCodec.zip',
|
||||||
versionId: 'mzKhsRCgVmloqq5bvE.0IwYK1NjGQc_G',
|
versionId: 'mzKhsRCgVmloqq5bvE.0IwYK1NjGQc_G',
|
||||||
checksum: '9412a8e12c88a4096c1fc843bb9fe52d',
|
checksum: '9412a8e12c88a4096c1fc843bb9fe52d',
|
||||||
sharedLibFolder: '',
|
sharedLibFolder: '',
|
||||||
|
@ -150,15 +150,15 @@ def packages = [
|
||||||
|
|
||||||
def scribeLocalFile='scribe' + EXEC_SUFFIX
|
def scribeLocalFile='scribe' + EXEC_SUFFIX
|
||||||
|
|
||||||
def scribeFile='scribe_linux_x86_64'
|
def scribeFile='https://hifi-public.s3.amazonaws.com/austin/android/scribe_linux_x86_64'
|
||||||
def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6'
|
def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6'
|
||||||
def scribeVersion='wgpf4dB2Ltzg4Lb2jJ4nPFsHoDkmK_OO'
|
def scribeVersion='wgpf4dB2Ltzg4Lb2jJ4nPFsHoDkmK_OO'
|
||||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||||
scribeFile = 'scribe_osx_x86_64'
|
scribeFile = 'https://hifi-public.s3.amazonaws.com/austin/android/scribe_osx_x86_64'
|
||||||
scribeChecksum='72db9d32d4e1e50add755570ac5eb749'
|
scribeChecksum='72db9d32d4e1e50add755570ac5eb749'
|
||||||
scribeVersion='o_NbPrktzEYtBkQf3Tn7zc1nZWzM52w6'
|
scribeVersion='o_NbPrktzEYtBkQf3Tn7zc1nZWzM52w6'
|
||||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||||
scribeFile = 'scribe_win32_x86_64.exe'
|
scribeFile = 'https://hifi-public.s3.amazonaws.com/austin/android/scribe_win32_x86_64.exe'
|
||||||
scribeChecksum='678e43d290c90fda670c6fefe038a06d'
|
scribeChecksum='678e43d290c90fda670c6fefe038a06d'
|
||||||
scribeVersion='GCCJxlmd2irvNOFWfZR0U1UCLHndHQrC'
|
scribeVersion='GCCJxlmd2irvNOFWfZR0U1UCLHndHQrC'
|
||||||
}
|
}
|
||||||
|
@ -608,4 +608,4 @@ task testElf (dependsOn: 'externalNativeBuildDebug') {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
8
cmake/externals/bullet/CMakeLists.txt
vendored
8
cmake/externals/bullet/CMakeLists.txt
vendored
|
@ -17,8 +17,8 @@ include(ExternalProject)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
ExternalProject_Add(
|
ExternalProject_Add(
|
||||||
${EXTERNAL_NAME}
|
${EXTERNAL_NAME}
|
||||||
URL http://hifi-public.s3.amazonaws.com/dependencies/bullet-2.83-ccd-and-cmake-fixes.tgz
|
URL http://hifi-public.s3.amazonaws.com/dependencies/bullet-2.88.tgz
|
||||||
URL_MD5 03051bf112dcc78ddd296f9cab38fd68
|
URL_MD5 0a6876607ebe83e227427215f15946fd
|
||||||
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DBUILD_EXTRAS=0 -DINSTALL_LIBS=1 -DBUILD_BULLET3=0 -DBUILD_OPENGL3_DEMOS=0 -DBUILD_BULLET2_DEMOS=0 -DBUILD_UNIT_TESTS=0 -DUSE_GLUT=0 -DUSE_DX11=0
|
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DBUILD_EXTRAS=0 -DINSTALL_LIBS=1 -DBUILD_BULLET3=0 -DBUILD_OPENGL3_DEMOS=0 -DBUILD_BULLET2_DEMOS=0 -DBUILD_UNIT_TESTS=0 -DUSE_GLUT=0 -DUSE_DX11=0
|
||||||
LOG_DOWNLOAD 1
|
LOG_DOWNLOAD 1
|
||||||
LOG_CONFIGURE 1
|
LOG_CONFIGURE 1
|
||||||
|
@ -28,8 +28,8 @@ if (WIN32)
|
||||||
else ()
|
else ()
|
||||||
ExternalProject_Add(
|
ExternalProject_Add(
|
||||||
${EXTERNAL_NAME}
|
${EXTERNAL_NAME}
|
||||||
URL http://hifi-public.s3.amazonaws.com/dependencies/bullet-2.83-ccd-and-cmake-fixes.tgz
|
URL http://hifi-public.s3.amazonaws.com/dependencies/bullet-2.88.tgz
|
||||||
URL_MD5 03051bf112dcc78ddd296f9cab38fd68
|
URL_MD5 0a6876607ebe83e227427215f15946fd
|
||||||
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DBUILD_EXTRAS=0 -DINSTALL_LIBS=1 -DBUILD_BULLET3=0 -DBUILD_OPENGL3_DEMOS=0 -DBUILD_BULLET2_DEMOS=0 -DBUILD_UNIT_TESTS=0 -DUSE_GLUT=0
|
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DBUILD_EXTRAS=0 -DINSTALL_LIBS=1 -DBUILD_BULLET3=0 -DBUILD_OPENGL3_DEMOS=0 -DBUILD_BULLET2_DEMOS=0 -DBUILD_UNIT_TESTS=0 -DUSE_GLUT=0
|
||||||
LOG_DOWNLOAD 1
|
LOG_DOWNLOAD 1
|
||||||
LOG_CONFIGURE 1
|
LOG_CONFIGURE 1
|
||||||
|
|
6
cmake/externals/glm/CMakeLists.txt
vendored
6
cmake/externals/glm/CMakeLists.txt
vendored
|
@ -3,8 +3,8 @@ set(EXTERNAL_NAME glm)
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
ExternalProject_Add(
|
ExternalProject_Add(
|
||||||
${EXTERNAL_NAME}
|
${EXTERNAL_NAME}
|
||||||
URL https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.zip
|
URL https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.5-patched.zip
|
||||||
URL_MD5 579ac77a3110befa3244d68c0ceb7281
|
URL_MD5 7d39ecc1cea275427534c3cfd6dd63f0
|
||||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ${EXTERNAL_ARGS}
|
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ${EXTERNAL_ARGS}
|
||||||
LOG_DOWNLOAD 1
|
LOG_DOWNLOAD 1
|
||||||
|
@ -18,4 +18,4 @@ set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||||
|
|
||||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of glm include directories")
|
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of glm include directories")
|
||||||
|
|
|
@ -4,8 +4,8 @@ set(EXTERNAL_NAME serverless-content)
|
||||||
|
|
||||||
ExternalProject_Add(
|
ExternalProject_Add(
|
||||||
${EXTERNAL_NAME}
|
${EXTERNAL_NAME}
|
||||||
URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC67-v4.zip
|
URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC68.zip
|
||||||
URL_MD5 ba32aed18bfeaac4ccaf5ebb8ea3e804
|
URL_MD5 a068f74d4045e257cfa7926fe6e38ad5
|
||||||
CONFIGURE_COMMAND ""
|
CONFIGURE_COMMAND ""
|
||||||
BUILD_COMMAND ""
|
BUILD_COMMAND ""
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
|
|
|
@ -61,16 +61,21 @@ macro(SETUP_HIFI_TESTCASE)
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
|
||||||
# Find test classes to build into test executables.
|
# Find test classes to build into test executables.
|
||||||
# Warn about any .cpp files that are *not* test classes (*Test[s].cpp), since those files will not be used.
|
# Warn about any .cpp files that are *not* test classes (*Test[s].cpp), since those files will not be used.
|
||||||
foreach (SRC_FILE ${TEST_PROJ_SRC_FILES})
|
foreach (SRC_FILE ${TEST_PROJ_SRC_FILES})
|
||||||
string(REGEX MATCH ".+Tests?\\.cpp$" TEST_CPP_FILE ${SRC_FILE})
|
string(REGEX MATCH ".+Tests?\\.cpp$" TEST_CPP_FILE ${SRC_FILE})
|
||||||
string(REGEX MATCH ".+\\.cpp$" NON_TEST_CPP_FILE ${SRC_FILE})
|
string(REGEX MATCH ".+\\.cpp$" NON_TEST_CPP_FILE ${SRC_FILE})
|
||||||
|
string(REGEX MATCH ".+\\.qrc$" QRC_FILE ${SRC_FILE})
|
||||||
if (TEST_CPP_FILE)
|
if (TEST_CPP_FILE)
|
||||||
list(APPEND TEST_CASE_FILES ${TEST_CPP_FILE})
|
list(APPEND TEST_CASE_FILES ${TEST_CPP_FILE})
|
||||||
elseif (NON_TEST_CPP_FILE)
|
elseif (NON_TEST_CPP_FILE)
|
||||||
message(WARNING "ignoring .cpp file (not a test class -- this will not be linked or compiled!): " ${NON_TEST_CPP_FILE})
|
message(WARNING "ignoring .cpp file (not a test class -- this will not be linked or compiled!): " ${NON_TEST_CPP_FILE})
|
||||||
endif ()
|
endif ()
|
||||||
|
if (QRC_FILE)
|
||||||
|
list(APPEND EXTRA_FILES ${QRC_FILE})
|
||||||
|
endif()
|
||||||
endforeach ()
|
endforeach ()
|
||||||
|
|
||||||
if (TEST_CASE_FILES)
|
if (TEST_CASE_FILES)
|
||||||
|
@ -88,7 +93,7 @@ macro(SETUP_HIFI_TESTCASE)
|
||||||
# grab the implemenation and header files
|
# grab the implemenation and header files
|
||||||
set(TARGET_SRCS ${TEST_FILE}) # only one source / .cpp file (the test class)
|
set(TARGET_SRCS ${TEST_FILE}) # only one source / .cpp file (the test class)
|
||||||
|
|
||||||
add_executable(${TARGET_NAME} ${TEST_FILE})
|
add_executable(${TARGET_NAME} ${TEST_FILE} ${EXTRA_FILES})
|
||||||
add_test(${TARGET_NAME}-test ${TARGET_NAME})
|
add_test(${TARGET_NAME}-test ${TARGET_NAME})
|
||||||
set_target_properties(${TARGET_NAME} PROPERTIES
|
set_target_properties(${TARGET_NAME} PROPERTIES
|
||||||
EXCLUDE_FROM_DEFAULT_BUILD TRUE
|
EXCLUDE_FROM_DEFAULT_BUILD TRUE
|
||||||
|
|
|
@ -479,7 +479,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
||||||
limitedNodeList->killNodeWithUUID(existingNodeID);
|
limitedNodeList->killNodeWithUUID(existingNodeID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the connecting node (or re-use the matched one from eachNodeBreakable above)
|
// add the connecting node
|
||||||
SharedNodePointer newNode = addVerifiedNodeFromConnectRequest(nodeConnection);
|
SharedNodePointer newNode = addVerifiedNodeFromConnectRequest(nodeConnection);
|
||||||
|
|
||||||
// set the edit rights for this user
|
// set the edit rights for this user
|
||||||
|
@ -508,26 +508,22 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection,
|
SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection) {
|
||||||
QUuid nodeID) {
|
|
||||||
HifiSockAddr discoveredSocket = nodeConnection.senderSockAddr;
|
HifiSockAddr discoveredSocket = nodeConnection.senderSockAddr;
|
||||||
SharedNetworkPeer connectedPeer = _icePeers.value(nodeConnection.connectUUID);
|
SharedNetworkPeer connectedPeer = _icePeers.value(nodeConnection.connectUUID);
|
||||||
|
|
||||||
if (connectedPeer) {
|
if (connectedPeer && connectedPeer->getActiveSocket()) {
|
||||||
// this user negotiated a connection with us via ICE, so re-use their ICE client ID
|
// set their discovered socket to whatever the activated socket on the network peer object was
|
||||||
nodeID = nodeConnection.connectUUID;
|
discoveredSocket = *connectedPeer->getActiveSocket();
|
||||||
|
|
||||||
if (connectedPeer->getActiveSocket()) {
|
|
||||||
// set their discovered socket to whatever the activated socket on the network peer object was
|
|
||||||
discoveredSocket = *connectedPeer->getActiveSocket();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we got a connectUUID we didn't recognize, either use the hinted node ID or randomly generate a new one
|
|
||||||
if (nodeID.isNull()) {
|
|
||||||
nodeID = QUuid::createUuid();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create a new node ID for the verified connecting node
|
||||||
|
auto nodeID = QUuid::createUuid();
|
||||||
|
|
||||||
|
// add a mapping from connection node ID to ICE peer ID
|
||||||
|
// so that we can remove the ICE peer once we see this node connect
|
||||||
|
_nodeToICEPeerIDs.insert(nodeID, nodeConnection.connectUUID);
|
||||||
|
|
||||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
|
||||||
Node::LocalID newLocalID = findOrCreateLocalID(nodeID);
|
Node::LocalID newLocalID = findOrCreateLocalID(nodeID);
|
||||||
|
@ -541,6 +537,15 @@ SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const Node
|
||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DomainGatekeeper::cleanupICEPeerForNode(const QUuid& nodeID) {
|
||||||
|
// remove this node ID from our node to ICE peer ID map
|
||||||
|
// and the associated ICE peer (if it still exists)
|
||||||
|
auto icePeerID = _nodeToICEPeerIDs.take(nodeID);
|
||||||
|
if (!icePeerID.isNull()) {
|
||||||
|
_icePeers.remove(icePeerID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool DomainGatekeeper::verifyUserSignature(const QString& username,
|
bool DomainGatekeeper::verifyUserSignature(const QString& username,
|
||||||
const QByteArray& usernameSignature,
|
const QByteArray& usernameSignature,
|
||||||
const HifiSockAddr& senderSockAddr) {
|
const HifiSockAddr& senderSockAddr) {
|
||||||
|
|
|
@ -39,8 +39,8 @@ public:
|
||||||
void addPendingAssignedNode(const QUuid& nodeUUID, const QUuid& assignmentUUID,
|
void addPendingAssignedNode(const QUuid& nodeUUID, const QUuid& assignmentUUID,
|
||||||
const QUuid& walletUUID, const QString& nodeVersion);
|
const QUuid& walletUUID, const QString& nodeVersion);
|
||||||
QUuid assignmentUUIDForPendingAssignment(const QUuid& tempUUID);
|
QUuid assignmentUUIDForPendingAssignment(const QUuid& tempUUID);
|
||||||
|
|
||||||
void removeICEPeer(const QUuid& peerUUID) { _icePeers.remove(peerUUID); }
|
void cleanupICEPeerForNode(const QUuid& nodeID);
|
||||||
|
|
||||||
Node::LocalID findOrCreateLocalID(const QUuid& uuid);
|
Node::LocalID findOrCreateLocalID(const QUuid& uuid);
|
||||||
|
|
||||||
|
@ -77,8 +77,7 @@ private:
|
||||||
SharedNodePointer processAgentConnectRequest(const NodeConnectionData& nodeConnection,
|
SharedNodePointer processAgentConnectRequest(const NodeConnectionData& nodeConnection,
|
||||||
const QString& username,
|
const QString& username,
|
||||||
const QByteArray& usernameSignature);
|
const QByteArray& usernameSignature);
|
||||||
SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection,
|
SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection);
|
||||||
QUuid nodeID = QUuid());
|
|
||||||
|
|
||||||
bool verifyUserSignature(const QString& username, const QByteArray& usernameSignature,
|
bool verifyUserSignature(const QString& username, const QByteArray& usernameSignature,
|
||||||
const HifiSockAddr& senderSockAddr);
|
const HifiSockAddr& senderSockAddr);
|
||||||
|
@ -101,6 +100,10 @@ private:
|
||||||
std::unordered_map<QUuid, PendingAssignedNodeData> _pendingAssignedNodes;
|
std::unordered_map<QUuid, PendingAssignedNodeData> _pendingAssignedNodes;
|
||||||
|
|
||||||
QHash<QUuid, SharedNetworkPeer> _icePeers;
|
QHash<QUuid, SharedNetworkPeer> _icePeers;
|
||||||
|
|
||||||
|
using ConnectingNodeID = QUuid;
|
||||||
|
using ICEPeerID = QUuid;
|
||||||
|
QHash<ConnectingNodeID, ICEPeerID> _nodeToICEPeerIDs;
|
||||||
|
|
||||||
QHash<QString, QUuid> _connectionTokenHash;
|
QHash<QString, QUuid> _connectionTokenHash;
|
||||||
|
|
||||||
|
|
|
@ -1017,15 +1017,22 @@ void DomainServer::processListRequestPacket(QSharedPointer<ReceivedMessage> mess
|
||||||
sendingNode->setPublicSocket(nodeRequestData.publicSockAddr);
|
sendingNode->setPublicSocket(nodeRequestData.publicSockAddr);
|
||||||
sendingNode->setLocalSocket(nodeRequestData.localSockAddr);
|
sendingNode->setLocalSocket(nodeRequestData.localSockAddr);
|
||||||
|
|
||||||
// update the NodeInterestSet in case there have been any changes
|
|
||||||
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(sendingNode->getLinkedData());
|
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(sendingNode->getLinkedData());
|
||||||
|
|
||||||
|
if (!nodeData->hasCheckedIn()) {
|
||||||
|
nodeData->setHasCheckedIn(true);
|
||||||
|
|
||||||
|
// on first check in, make sure we've cleaned up any ICE peer for this node
|
||||||
|
_gatekeeper.cleanupICEPeerForNode(sendingNode->getUUID());
|
||||||
|
}
|
||||||
|
|
||||||
// guard against patched agents asking to hear about other agents
|
// guard against patched agents asking to hear about other agents
|
||||||
auto safeInterestSet = nodeRequestData.interestList.toSet();
|
auto safeInterestSet = nodeRequestData.interestList.toSet();
|
||||||
if (sendingNode->getType() == NodeType::Agent) {
|
if (sendingNode->getType() == NodeType::Agent) {
|
||||||
safeInterestSet.remove(NodeType::Agent);
|
safeInterestSet.remove(NodeType::Agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update the NodeInterestSet in case there have been any changes
|
||||||
nodeData->setNodeInterestSet(safeInterestSet);
|
nodeData->setNodeInterestSet(safeInterestSet);
|
||||||
|
|
||||||
// update the connecting hostname in case it has changed
|
// update the connecting hostname in case it has changed
|
||||||
|
@ -2945,7 +2952,7 @@ void DomainServer::nodeAdded(SharedNodePointer node) {
|
||||||
|
|
||||||
void DomainServer::nodeKilled(SharedNodePointer node) {
|
void DomainServer::nodeKilled(SharedNodePointer node) {
|
||||||
// if this peer connected via ICE then remove them from our ICE peers hash
|
// if this peer connected via ICE then remove them from our ICE peers hash
|
||||||
_gatekeeper.removeICEPeer(node->getUUID());
|
_gatekeeper.cleanupICEPeerForNode(node->getUUID());
|
||||||
|
|
||||||
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
|
DomainServerNodeData* nodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||||
|
|
||||||
|
@ -2978,6 +2985,8 @@ void DomainServer::nodeKilled(SharedNodePointer node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
broadcastNodeDisconnect(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedAssignmentPointer DomainServer::dequeueMatchingAssignment(const QUuid& assignmentUUID, NodeType_t nodeType) {
|
SharedAssignmentPointer DomainServer::dequeueMatchingAssignment(const QUuid& assignmentUUID, NodeType_t nodeType) {
|
||||||
|
@ -3163,18 +3172,23 @@ void DomainServer::handleKillNode(SharedNodePointer nodeToKill) {
|
||||||
const QUuid& nodeUUID = nodeToKill->getUUID();
|
const QUuid& nodeUUID = nodeToKill->getUUID();
|
||||||
|
|
||||||
limitedNodeList->killNodeWithUUID(nodeUUID);
|
limitedNodeList->killNodeWithUUID(nodeUUID);
|
||||||
|
}
|
||||||
|
|
||||||
static auto removedNodePacket = NLPacket::create(PacketType::DomainServerRemovedNode, NUM_BYTES_RFC4122_UUID);
|
void DomainServer::broadcastNodeDisconnect(const SharedNodePointer& disconnectedNode) {
|
||||||
|
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
|
||||||
|
static auto removedNodePacket = NLPacket::create(PacketType::DomainServerRemovedNode, NUM_BYTES_RFC4122_UUID, true);
|
||||||
|
|
||||||
removedNodePacket->reset();
|
removedNodePacket->reset();
|
||||||
removedNodePacket->write(nodeUUID.toRfc4122());
|
removedNodePacket->write(disconnectedNode->getUUID().toRfc4122());
|
||||||
|
|
||||||
// broadcast out the DomainServerRemovedNode message
|
// broadcast out the DomainServerRemovedNode message
|
||||||
limitedNodeList->eachMatchingNode([this, &nodeToKill](const SharedNodePointer& otherNode) -> bool {
|
limitedNodeList->eachMatchingNode([this, &disconnectedNode](const SharedNodePointer& otherNode) -> bool {
|
||||||
// only send the removed node packet to nodes that care about the type of node this was
|
// only send the removed node packet to nodes that care about the type of node this was
|
||||||
return isInInterestSet(otherNode, nodeToKill);
|
return isInInterestSet(otherNode, disconnectedNode);
|
||||||
}, [&limitedNodeList](const SharedNodePointer& otherNode){
|
}, [&limitedNodeList](const SharedNodePointer& otherNode){
|
||||||
limitedNodeList->sendUnreliablePacket(*removedNodePacket, *otherNode);
|
auto removedNodePacketCopy = NLPacket::createCopy(*removedNodePacket);
|
||||||
|
limitedNodeList->sendPacket(std::move(removedNodePacketCopy), *otherNode);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,7 @@ private:
|
||||||
unsigned int countConnectedUsers();
|
unsigned int countConnectedUsers();
|
||||||
|
|
||||||
void handleKillNode(SharedNodePointer nodeToKill);
|
void handleKillNode(SharedNodePointer nodeToKill);
|
||||||
|
void broadcastNodeDisconnect(const SharedNodePointer& disconnnectedNode);
|
||||||
|
|
||||||
void sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr& senderSockAddr);
|
void sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr& senderSockAddr);
|
||||||
|
|
||||||
|
|
|
@ -67,8 +67,11 @@ public:
|
||||||
const QString& getPlaceName() { return _placeName; }
|
const QString& getPlaceName() { return _placeName; }
|
||||||
void setPlaceName(const QString& placeName) { _placeName = placeName; }
|
void setPlaceName(const QString& placeName) { _placeName = placeName; }
|
||||||
|
|
||||||
bool wasAssigned() const { return _wasAssigned; };
|
bool wasAssigned() const { return _wasAssigned; }
|
||||||
void setWasAssigned(bool wasAssigned) { _wasAssigned = wasAssigned; }
|
void setWasAssigned(bool wasAssigned) { _wasAssigned = wasAssigned; }
|
||||||
|
|
||||||
|
bool hasCheckedIn() const { return _hasCheckedIn; }
|
||||||
|
void setHasCheckedIn(bool hasCheckedIn) { _hasCheckedIn = hasCheckedIn; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QJsonObject overrideValuesIfNeeded(const QJsonObject& newStats);
|
QJsonObject overrideValuesIfNeeded(const QJsonObject& newStats);
|
||||||
|
@ -94,6 +97,8 @@ private:
|
||||||
QString _placeName;
|
QString _placeName;
|
||||||
|
|
||||||
bool _wasAssigned { false };
|
bool _wasAssigned { false };
|
||||||
|
|
||||||
|
bool _hasCheckedIn { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_DomainServerNodeData_h
|
#endif // hifi_DomainServerNodeData_h
|
||||||
|
|
|
@ -163,10 +163,18 @@ TextField {
|
||||||
text: textField.label
|
text: textField.label
|
||||||
colorScheme: textField.colorScheme
|
colorScheme: textField.colorScheme
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
|
||||||
|
Binding on anchors.right {
|
||||||
|
when: parent.right
|
||||||
|
value: parent.right
|
||||||
|
}
|
||||||
|
Binding on wrapMode {
|
||||||
|
when: parent.right
|
||||||
|
value: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
anchors.bottom: parent.top
|
anchors.bottom: parent.top
|
||||||
anchors.bottomMargin: 3
|
anchors.bottomMargin: 3
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
visible: label != ""
|
visible: label != ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ ModalWindow {
|
||||||
property int iconSize: 40
|
property int iconSize: 40
|
||||||
|
|
||||||
property bool selectDirectory: false;
|
property bool selectDirectory: false;
|
||||||
property bool showHidden: false;
|
property bool showHidden: true;
|
||||||
// FIXME implement
|
// FIXME implement
|
||||||
property bool multiSelect: false;
|
property bool multiSelect: false;
|
||||||
property bool saveDialog: false;
|
property bool saveDialog: false;
|
||||||
|
@ -324,8 +324,10 @@ ModalWindow {
|
||||||
showDirsFirst: true
|
showDirsFirst: true
|
||||||
showDotAndDotDot: false
|
showDotAndDotDot: false
|
||||||
showFiles: !root.selectDirectory
|
showFiles: !root.selectDirectory
|
||||||
|
showHidden: root.showHidden
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
showFiles = !root.selectDirectory
|
showFiles = !root.selectDirectory
|
||||||
|
showHidden = root.showHidden
|
||||||
}
|
}
|
||||||
|
|
||||||
onFolderChanged: {
|
onFolderChanged: {
|
||||||
|
|
|
@ -58,7 +58,7 @@ ModalWindow {
|
||||||
property int iconSize: 40
|
property int iconSize: 40
|
||||||
|
|
||||||
property bool selectDirectory: false;
|
property bool selectDirectory: false;
|
||||||
property bool showHidden: false;
|
property bool showHidden: true;
|
||||||
// FIXME implement
|
// FIXME implement
|
||||||
property bool multiSelect: false;
|
property bool multiSelect: false;
|
||||||
property bool saveDialog: false;
|
property bool saveDialog: false;
|
||||||
|
@ -325,8 +325,10 @@ ModalWindow {
|
||||||
showDirsFirst: true
|
showDirsFirst: true
|
||||||
showDotAndDotDot: false
|
showDotAndDotDot: false
|
||||||
showFiles: !root.selectDirectory
|
showFiles: !root.selectDirectory
|
||||||
|
showHidden: root.showHidden
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
showFiles = !root.selectDirectory
|
showFiles = !root.selectDirectory
|
||||||
|
showHidden = root.showHidden
|
||||||
}
|
}
|
||||||
|
|
||||||
onFolderChanged: {
|
onFolderChanged: {
|
||||||
|
|
|
@ -55,7 +55,7 @@ TabletModalWindow {
|
||||||
property int iconSize: 40
|
property int iconSize: 40
|
||||||
|
|
||||||
property bool selectDirectory: false;
|
property bool selectDirectory: false;
|
||||||
property bool showHidden: false;
|
property bool showHidden: true;
|
||||||
// FIXME implement
|
// FIXME implement
|
||||||
property bool multiSelect: false;
|
property bool multiSelect: false;
|
||||||
property bool saveDialog: false;
|
property bool saveDialog: false;
|
||||||
|
@ -288,8 +288,10 @@ TabletModalWindow {
|
||||||
showDirsFirst: true
|
showDirsFirst: true
|
||||||
showDotAndDotDot: false
|
showDotAndDotDot: false
|
||||||
showFiles: !root.selectDirectory
|
showFiles: !root.selectDirectory
|
||||||
|
showHidden: root.showHidden
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
showFiles = !root.selectDirectory
|
showFiles = !root.selectDirectory
|
||||||
|
showHidden = root.showHidden
|
||||||
}
|
}
|
||||||
|
|
||||||
onFolderChanged: {
|
onFolderChanged: {
|
||||||
|
|
|
@ -52,7 +52,7 @@ Rectangle {
|
||||||
property int iconSize: 40
|
property int iconSize: 40
|
||||||
|
|
||||||
property bool selectDirectory: false;
|
property bool selectDirectory: false;
|
||||||
property bool showHidden: false;
|
property bool showHidden: true;
|
||||||
// FIXME implement
|
// FIXME implement
|
||||||
property bool multiSelect: false;
|
property bool multiSelect: false;
|
||||||
property bool saveDialog: false;
|
property bool saveDialog: false;
|
||||||
|
@ -280,8 +280,10 @@ Rectangle {
|
||||||
showDirsFirst: true
|
showDirsFirst: true
|
||||||
showDotAndDotDot: false
|
showDotAndDotDot: false
|
||||||
showFiles: !root.selectDirectory
|
showFiles: !root.selectDirectory
|
||||||
|
showHidden: root.showHidden
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
showFiles = !root.selectDirectory
|
showFiles = !root.selectDirectory
|
||||||
|
showHidden = root.showHidden
|
||||||
}
|
}
|
||||||
|
|
||||||
onFolderChanged: {
|
onFolderChanged: {
|
||||||
|
|
|
@ -717,7 +717,7 @@ private:
|
||||||
* <tr><td><code>NavigationFocused</code></td><td>number</td><td>number</td><td><em>Not used.</em></td></tr>
|
* <tr><td><code>NavigationFocused</code></td><td>number</td><td>number</td><td><em>Not used.</em></td></tr>
|
||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* @typedef Controller.Hardware-Application
|
* @typedef {object} Controller.Hardware-Application
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const QString STATE_IN_HMD = "InHMD";
|
static const QString STATE_IN_HMD = "InHMD";
|
||||||
|
@ -2492,6 +2492,7 @@ void Application::cleanupBeforeQuit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_window->saveGeometry();
|
_window->saveGeometry();
|
||||||
|
_gpuContext->shutdown();
|
||||||
|
|
||||||
// Destroy third party processes after scripts have finished using them.
|
// Destroy third party processes after scripts have finished using them.
|
||||||
#ifdef HAVE_DDE
|
#ifdef HAVE_DDE
|
||||||
|
@ -3011,9 +3012,11 @@ void Application::onDesktopRootItemCreated(QQuickItem* rootItem) {
|
||||||
auto surfaceContext = DependencyManager::get<OffscreenUi>()->getSurfaceContext();
|
auto surfaceContext = DependencyManager::get<OffscreenUi>()->getSurfaceContext();
|
||||||
surfaceContext->setContextProperty("Stats", Stats::getInstance());
|
surfaceContext->setContextProperty("Stats", Stats::getInstance());
|
||||||
|
|
||||||
|
#if !defined(Q_OS_ANDROID)
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
auto qml = PathUtils::qmlUrl("AvatarInputsBar.qml");
|
auto qml = PathUtils::qmlUrl("AvatarInputsBar.qml");
|
||||||
offscreenUi->show(qml, "AvatarInputsBar");
|
offscreenUi->show(qml, "AvatarInputsBar");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
|
void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
|
||||||
|
@ -4632,12 +4635,6 @@ void Application::idle() {
|
||||||
|
|
||||||
_overlayConductor.update(secondsSinceLastUpdate);
|
_overlayConductor.update(secondsSinceLastUpdate);
|
||||||
|
|
||||||
auto myAvatar = getMyAvatar();
|
|
||||||
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN);
|
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN));
|
|
||||||
cameraMenuChanged();
|
|
||||||
}
|
|
||||||
_gameLoopCounter.increment();
|
_gameLoopCounter.increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5184,6 +5181,21 @@ void Application::cameraModeChanged() {
|
||||||
cameraMenuChanged();
|
cameraMenuChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::changeViewAsNeeded(float boomLength) {
|
||||||
|
// Switch between first and third person views as needed
|
||||||
|
// This is called when the boom length has changed
|
||||||
|
bool boomLengthGreaterThanMinimum = (boomLength > MyAvatar::ZOOM_MIN);
|
||||||
|
|
||||||
|
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON && boomLengthGreaterThanMinimum) {
|
||||||
|
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
|
||||||
|
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true);
|
||||||
|
cameraMenuChanged();
|
||||||
|
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON && !boomLengthGreaterThanMinimum) {
|
||||||
|
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true);
|
||||||
|
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, false);
|
||||||
|
cameraMenuChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::cameraMenuChanged() {
|
void Application::cameraMenuChanged() {
|
||||||
auto menu = Menu::getInstance();
|
auto menu = Menu::getInstance();
|
||||||
|
|
|
@ -417,6 +417,8 @@ public slots:
|
||||||
|
|
||||||
void updateVerboseLogging();
|
void updateVerboseLogging();
|
||||||
|
|
||||||
|
void changeViewAsNeeded(float boomLength);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onDesktopRootItemCreated(QQuickItem* qmlContext);
|
void onDesktopRootItemCreated(QQuickItem* qmlContext);
|
||||||
void onDesktopRootContextCreated(QQmlContext* qmlContext);
|
void onDesktopRootContextCreated(QQmlContext* qmlContext);
|
||||||
|
@ -649,7 +651,7 @@ private:
|
||||||
quint64 _lastFaceTrackerUpdate;
|
quint64 _lastFaceTrackerUpdate;
|
||||||
|
|
||||||
render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) };
|
render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) };
|
||||||
render::EnginePointer _renderEngine{ new render::Engine() };
|
render::EnginePointer _renderEngine{ new render::RenderEngine() };
|
||||||
gpu::ContextPointer _gpuContext; // initialized during window creation
|
gpu::ContextPointer _gpuContext; // initialized during window creation
|
||||||
|
|
||||||
mutable QMutex _renderArgsMutex{ QMutex::Recursive };
|
mutable QMutex _renderArgsMutex{ QMutex::Recursive };
|
||||||
|
|
|
@ -25,7 +25,7 @@ class FancyCamera : public Camera {
|
||||||
|
|
||||||
// FIXME: JSDoc 3.5.5 doesn't augment @property definitions. The following definition is repeated in Camera.h.
|
// FIXME: JSDoc 3.5.5 doesn't augment @property definitions. The following definition is repeated in Camera.h.
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @property cameraEntity {Uuid} The ID of the entity that the camera position and orientation follow when the camera is in
|
* @property {Uuid} cameraEntity The ID of the entity that the camera position and orientation follow when the camera is in
|
||||||
* entity mode.
|
* entity mode.
|
||||||
*/
|
*/
|
||||||
Q_PROPERTY(QUuid cameraEntity READ getCameraEntity WRITE setCameraEntity)
|
Q_PROPERTY(QUuid cameraEntity READ getCameraEntity WRITE setCameraEntity)
|
||||||
|
|
|
@ -104,6 +104,9 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
|
||||||
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
|
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
|
||||||
|
|
||||||
_myAvatar->update(deltaTime);
|
_myAvatar->update(deltaTime);
|
||||||
|
render::Transaction transaction;
|
||||||
|
_myAvatar->updateRenderItem(transaction);
|
||||||
|
qApp->getMain3DScene()->enqueueTransaction(transaction);
|
||||||
|
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
quint64 dt = now - _lastSendAvatarDataTime;
|
quint64 dt = now - _lastSendAvatarDataTime;
|
||||||
|
|
|
@ -160,7 +160,7 @@ QUuid AvatarMotionState::getSimulatorID() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void AvatarMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const {
|
void AvatarMotionState::computeCollisionGroupAndMask(int32_t& group, int32_t& mask) const {
|
||||||
group = BULLET_COLLISION_GROUP_OTHER_AVATAR;
|
group = BULLET_COLLISION_GROUP_OTHER_AVATAR;
|
||||||
mask = Physics::getDefaultCollisionMask(group);
|
mask = Physics::getDefaultCollisionMask(group);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ public:
|
||||||
|
|
||||||
void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; }
|
void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; }
|
||||||
|
|
||||||
virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const override;
|
virtual void computeCollisionGroupAndMask(int32_t& group, int32_t& mask) const override;
|
||||||
|
|
||||||
virtual float getMass() const override;
|
virtual float getMass() const override;
|
||||||
|
|
||||||
|
|
|
@ -1127,7 +1127,11 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setEnableMeshVisible(bool isEnabled) {
|
void MyAvatar::setEnableMeshVisible(bool isEnabled) {
|
||||||
_skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true);
|
return Avatar::setEnableMeshVisible(isEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MyAvatar::getEnableMeshVisible() const {
|
||||||
|
return Avatar::getEnableMeshVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
|
void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
|
||||||
|
@ -1479,7 +1483,10 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
_skeletonModelChangeCount++;
|
_skeletonModelChangeCount++;
|
||||||
int skeletonModelChangeCount = _skeletonModelChangeCount;
|
int skeletonModelChangeCount = _skeletonModelChangeCount;
|
||||||
Avatar::setSkeletonModelURL(skeletonModelURL);
|
Avatar::setSkeletonModelURL(skeletonModelURL);
|
||||||
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true);
|
_skeletonModel->setTagMask(render::hifi::TAG_NONE);
|
||||||
|
_skeletonModel->setGroupCulled(true);
|
||||||
|
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
|
||||||
|
|
||||||
_headBoneSet.clear();
|
_headBoneSet.clear();
|
||||||
_cauterizationNeedsUpdate = true;
|
_cauterizationNeedsUpdate = true;
|
||||||
|
|
||||||
|
@ -2054,14 +2061,12 @@ void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) {
|
||||||
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
|
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
|
||||||
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
|
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
|
||||||
_attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
|
_attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
|
||||||
uint8_t modelRenderTagBits = shouldDrawHead ? render::ItemKey::TAG_BITS_0 : render::ItemKey::TAG_BITS_NONE;
|
uint8_t modelRenderTagBits = shouldDrawHead ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_SECONDARY_VIEW;
|
||||||
modelRenderTagBits |= render::ItemKey::TAG_BITS_1;
|
|
||||||
_attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene(),
|
|
||||||
modelRenderTagBits, false);
|
|
||||||
|
|
||||||
uint8_t castShadowRenderTagBits = render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1;
|
_attachmentModels[i]->setTagMask(modelRenderTagBits);
|
||||||
_attachmentModels[i]->setCanCastShadow(true, qApp->getMain3DScene(),
|
_attachmentModels[i]->setGroupCulled(false);
|
||||||
castShadowRenderTagBits, false);
|
_attachmentModels[i]->setCanCastShadow(true);
|
||||||
|
_attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2245,9 +2250,15 @@ void MyAvatar::updateActionMotor(float deltaTime) {
|
||||||
_actionMotorVelocity = getSensorToWorldScale() * (_walkSpeed.get() * _walkSpeedScalar) * direction;
|
_actionMotorVelocity = getSensorToWorldScale() * (_walkSpeed.get() * _walkSpeedScalar) * direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float previousBoomLength = _boomLength;
|
||||||
float boomChange = getDriveKey(ZOOM);
|
float boomChange = getDriveKey(ZOOM);
|
||||||
_boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange;
|
_boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange;
|
||||||
_boomLength = glm::clamp<float>(_boomLength, ZOOM_MIN, ZOOM_MAX);
|
_boomLength = glm::clamp<float>(_boomLength, ZOOM_MIN, ZOOM_MAX);
|
||||||
|
|
||||||
|
// May need to change view if boom length has changed
|
||||||
|
if (previousBoomLength != _boomLength) {
|
||||||
|
qApp->changeViewAsNeeded(_boomLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::updatePosition(float deltaTime) {
|
void MyAvatar::updatePosition(float deltaTime) {
|
||||||
|
|
|
@ -121,7 +121,7 @@ class MyAvatar : public Avatar {
|
||||||
* while flying.
|
* while flying.
|
||||||
* @property {number} hmdRollControlDeadZone=8 - The amount of HMD roll, in degrees, required before your avatar turns if
|
* @property {number} hmdRollControlDeadZone=8 - The amount of HMD roll, in degrees, required before your avatar turns if
|
||||||
* <code>hmdRollControlEnabled</code> is enabled.
|
* <code>hmdRollControlEnabled</code> is enabled.
|
||||||
* @property hmdRollControlRate {number} If hmdRollControlEnabled is true, this value determines the maximum turn rate of
|
* @property {number} hmdRollControlRate If hmdRollControlEnabled is true, this value determines the maximum turn rate of
|
||||||
* your avatar when rolling your HMD in degrees per second.
|
* your avatar when rolling your HMD in degrees per second.
|
||||||
* @property {number} userHeight=1.75 - The height of the user in sensor space.
|
* @property {number} userHeight=1.75 - The height of the user in sensor space.
|
||||||
* @property {number} userEyeHeight=1.65 - The estimated height of the user's eyes in sensor space. <em>Read-only.</em>
|
* @property {number} userEyeHeight=1.65 - The estimated height of the user's eyes in sensor space. <em>Read-only.</em>
|
||||||
|
@ -1159,7 +1159,7 @@ public slots:
|
||||||
* @function MyAvatar.getEnableMeshVisible
|
* @function MyAvatar.getEnableMeshVisible
|
||||||
* @returns {boolean} <code>true</code> if your avatar's mesh is visible, otherwise <code>false</code>.
|
* @returns {boolean} <code>true</code> if your avatar's mesh is visible, otherwise <code>false</code>.
|
||||||
*/
|
*/
|
||||||
bool getEnableMeshVisible() const { return _skeletonModel->isVisible(); }
|
bool getEnableMeshVisible() const override;
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Set whether or not your avatar mesh is visible.
|
* Set whether or not your avatar mesh is visible.
|
||||||
|
@ -1171,7 +1171,7 @@ public slots:
|
||||||
* MyAvatar.setEnableMeshVisible(true);
|
* MyAvatar.setEnableMeshVisible(true);
|
||||||
* }, 10000);
|
* }, 10000);
|
||||||
*/
|
*/
|
||||||
void setEnableMeshVisible(bool isEnabled);
|
virtual void setEnableMeshVisible(bool isEnabled) override;
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function MyAvatar.setEnableInverseKinematics
|
* @function MyAvatar.setEnableInverseKinematics
|
||||||
|
@ -1402,7 +1402,7 @@ private:
|
||||||
SharedSoundPointer _collisionSound;
|
SharedSoundPointer _collisionSound;
|
||||||
|
|
||||||
MyCharacterController _characterController;
|
MyCharacterController _characterController;
|
||||||
int16_t _previousCollisionGroup { BULLET_COLLISION_GROUP_MY_AVATAR };
|
int32_t _previousCollisionGroup { BULLET_COLLISION_GROUP_MY_AVATAR };
|
||||||
|
|
||||||
AvatarWeakPointer _lookAtTargetAvatar;
|
AvatarWeakPointer _lookAtTargetAvatar;
|
||||||
glm::vec3 _targetAvatarPosition;
|
glm::vec3 _targetAvatarPosition;
|
||||||
|
|
|
@ -22,21 +22,22 @@
|
||||||
* @hifi-interface
|
* @hifi-interface
|
||||||
* @hifi-client-entity
|
* @hifi-client-entity
|
||||||
*
|
*
|
||||||
* @property PICK_NOTHING {number} A filter flag. Don't intersect with anything. <em>Read-only.</em>
|
* @property {number} PICK_NOTHING A filter flag. Don't intersect with anything. <em>Read-only.</em>
|
||||||
* @property PICK_ENTITIES {number} A filter flag. Include entities when intersecting. <em>Read-only.</em>
|
* @property {number} PICK_ENTITIES A filter flag. Include entities when intersecting. <em>Read-only.</em>
|
||||||
* @property PICK_OVERLAYS {number} A filter flag. Include overlays when intersecting. <em>Read-only.</em>
|
* @property {number} PICK_OVERLAYS A filter flag. Include overlays when intersecting. <em>Read-only.</em>
|
||||||
* @property PICK_AVATARS {number} A filter flag. Include avatars when intersecting. <em>Read-only.</em>
|
* @property {number} PICK_AVATARS A filter flag. Include avatars when intersecting. <em>Read-only.</em>
|
||||||
* @property PICK_HUD {number} A filter flag. Include the HUD sphere when intersecting in HMD mode. <em>Read-only.</em>
|
* @property {number} PICK_HUD A filter flag. Include the HUD sphere when intersecting in HMD mode. <em>Read-only.</em>
|
||||||
* @property PICK_COARSE {number} A filter flag. Pick against coarse meshes, instead of exact meshes. <em>Read-only.</em>
|
* @property {number} PICK_COARSE A filter flag. Pick against coarse meshes, instead of exact meshes. <em>Read-only.</em>
|
||||||
* @property PICK_INCLUDE_INVISIBLE {number} A filter flag. Include invisible objects when intersecting. <em>Read-only.</em>
|
* @property {number} PICK_INCLUDE_INVISIBLE A filter flag. Include invisible objects when intersecting. <em>Read-only.</em>
|
||||||
* @property PICK_INCLUDE_NONCOLLIDABLE {number} A filter flag. Include non-collidable objects when intersecting.
|
* @property {number} PICK_INCLUDE_NONCOLLIDABLE A filter flag. Include non-collidable objects when intersecting.
|
||||||
* <em>Read-only.</em>
|
* <em>Read-only.</em>
|
||||||
* @property PICK_ALL_INTERSECTIONS {number} <em>Read-only.</em>
|
* @property {number} PICK_ALL_INTERSECTIONS <em>Read-only.</em>
|
||||||
* @property INTERSECTED_NONE {number} An intersection type. Intersected nothing with the given filter flags. <em>Read-only.</em>
|
* @property {number} INTERSECTED_NONE An intersection type. Intersected nothing with the given filter flags.
|
||||||
* @property INTERSECTED_ENTITY {number} An intersection type. Intersected an entity. <em>Read-only.</em>
|
* <em>Read-only.</em>
|
||||||
* @property INTERSECTED_OVERLAY {number} An intersection type. Intersected an overlay. <em>Read-only.</em>
|
* @property {number} INTERSECTED_ENTITY An intersection type. Intersected an entity. <em>Read-only.</em>
|
||||||
* @property INTERSECTED_AVATAR {number} An intersection type. Intersected an avatar. <em>Read-only.</em>
|
* @property {number} INTERSECTED_OVERLAY An intersection type. Intersected an overlay. <em>Read-only.</em>
|
||||||
* @property INTERSECTED_HUD {number} An intersection type. Intersected the HUD sphere. <em>Read-only.</em>
|
* @property {number} INTERSECTED_AVATAR An intersection type. Intersected an avatar. <em>Read-only.</em>
|
||||||
|
* @property {number} INTERSECTED_HUD An intersection type. Intersected the HUD sphere. <em>Read-only.</em>
|
||||||
* @property {number} perFrameTimeBudget - The max number of usec to spend per frame updating Pick results. <em>Read-only.</em>
|
* @property {number} perFrameTimeBudget - The max number of usec to spend per frame updating Pick results. <em>Read-only.</em>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -99,7 +100,7 @@ public:
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* An intersection result for a Ray Pick.
|
* An intersection result for a Ray Pick.
|
||||||
*
|
*
|
||||||
* @typedef {Object} RayPickResult
|
* @typedef {object} RayPickResult
|
||||||
* @property {number} type The intersection type.
|
* @property {number} type The intersection type.
|
||||||
* @property {boolean} intersects If there was a valid intersection (type != INTERSECTED_NONE)
|
* @property {boolean} intersects If there was a valid intersection (type != INTERSECTED_NONE)
|
||||||
* @property {Uuid} objectID The ID of the intersected object. Uuid.NULL for the HUD or invalid intersections.
|
* @property {Uuid} objectID The ID of the intersected object. Uuid.NULL for the HUD or invalid intersections.
|
||||||
|
@ -113,7 +114,7 @@ public:
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* An intersection result for a Stylus Pick.
|
* An intersection result for a Stylus Pick.
|
||||||
*
|
*
|
||||||
* @typedef {Object} StylusPickResult
|
* @typedef {object} StylusPickResult
|
||||||
* @property {number} type The intersection type.
|
* @property {number} type The intersection type.
|
||||||
* @property {boolean} intersects If there was a valid intersection (type != INTERSECTED_NONE)
|
* @property {boolean} intersects If there was a valid intersection (type != INTERSECTED_NONE)
|
||||||
* @property {Uuid} objectID The ID of the intersected object. Uuid.NULL for the HUD or invalid intersections.
|
* @property {Uuid} objectID The ID of the intersected object. Uuid.NULL for the HUD or invalid intersections.
|
||||||
|
|
|
@ -68,14 +68,14 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties)
|
||||||
* A set of properties used to define the visual aspect of a Ray Pointer in the case that the Pointer is not intersecting something. Same as a {@link Pointers.RayPointerRenderState},
|
* A set of properties used to define the visual aspect of a Ray Pointer in the case that the Pointer is not intersecting something. Same as a {@link Pointers.RayPointerRenderState},
|
||||||
* but with an additional distance field.
|
* but with an additional distance field.
|
||||||
*
|
*
|
||||||
* @typedef {Object} Pointers.DefaultRayPointerRenderState
|
* @typedef {object} Pointers.DefaultRayPointerRenderState
|
||||||
* @augments Pointers.RayPointerRenderState
|
* @augments Pointers.RayPointerRenderState
|
||||||
* @property {number} distance The distance at which to render the end of this Ray Pointer, if one is defined.
|
* @property {number} distance The distance at which to render the end of this Ray Pointer, if one is defined.
|
||||||
*/
|
*/
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* A set of properties used to define the visual aspect of a Ray Pointer in the case that the Pointer is intersecting something.
|
* A set of properties used to define the visual aspect of a Ray Pointer in the case that the Pointer is intersecting something.
|
||||||
*
|
*
|
||||||
* @typedef {Object} Pointers.RayPointerRenderState
|
* @typedef {object} Pointers.RayPointerRenderState
|
||||||
* @property {string} name The name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState}
|
* @property {string} name The name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState}
|
||||||
* @property {Overlays.OverlayProperties} [start] All of the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
|
* @property {Overlays.OverlayProperties} [start] All of the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
|
||||||
* An overlay to represent the beginning of the Ray Pointer, if desired.
|
* An overlay to represent the beginning of the Ray Pointer, if desired.
|
||||||
|
@ -87,7 +87,7 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties)
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* A trigger mechanism for Ray Pointers.
|
* A trigger mechanism for Ray Pointers.
|
||||||
*
|
*
|
||||||
* @typedef {Object} Pointers.Trigger
|
* @typedef {object} Pointers.Trigger
|
||||||
* @property {Controller.Standard|Controller.Actions|function} action This can be a built-in Controller action, like Controller.Standard.LTClick, or a function that evaluates to >= 1.0 when you want to trigger <code>button</code>.
|
* @property {Controller.Standard|Controller.Actions|function} action This can be a built-in Controller action, like Controller.Standard.LTClick, or a function that evaluates to >= 1.0 when you want to trigger <code>button</code>.
|
||||||
* @property {string} button Which button to trigger. "Primary", "Secondary", "Tertiary", and "Focus" are currently supported. Only "Primary" will trigger clicks on web surfaces. If "Focus" is triggered,
|
* @property {string} button Which button to trigger. "Primary", "Secondary", "Tertiary", and "Focus" are currently supported. Only "Primary" will trigger clicks on web surfaces. If "Focus" is triggered,
|
||||||
* it will try to set the entity or overlay focus to the object at which the Pointer is aimed. Buttons besides the first three will still trigger events, but event.button will be "None".
|
* it will try to set the entity or overlay focus to the object at which the Pointer is aimed. Buttons besides the first three will still trigger events, but event.button will be "None".
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <shared/FileUtils.h>
|
#include <shared/FileUtils.h>
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
|
#include <MainWindow.h>
|
||||||
#include <OffscreenUi.h>
|
#include <OffscreenUi.h>
|
||||||
#include <StatTracker.h>
|
#include <StatTracker.h>
|
||||||
#include <Trace.h>
|
#include <Trace.h>
|
||||||
|
@ -186,3 +187,7 @@ void TestScriptingInterface::saveObject(QVariant variant, const QString& filenam
|
||||||
file.write(jsonData);
|
file.write(jsonData);
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestScriptingInterface::showMaximized() {
|
||||||
|
qApp->getWindow()->showMaximized();
|
||||||
|
}
|
|
@ -27,70 +27,128 @@ public slots:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Exits the application
|
* Exits the application
|
||||||
|
* @function Test.quit
|
||||||
*/
|
*/
|
||||||
void quit();
|
void quit();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Waits for all texture transfers to be complete
|
* Waits for all texture transfers to be complete
|
||||||
|
* @function Test.waitForTextureIdle
|
||||||
*/
|
*/
|
||||||
void waitForTextureIdle();
|
void waitForTextureIdle();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Waits for all pending downloads to be complete
|
* Waits for all pending downloads to be complete
|
||||||
|
* @function Test.waitForDownloadIdle
|
||||||
*/
|
*/
|
||||||
void waitForDownloadIdle();
|
void waitForDownloadIdle();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Waits for all file parsing operations to be complete
|
* Waits for all file parsing operations to be complete
|
||||||
|
* @function Test.waitForProcessingIdle
|
||||||
*/
|
*/
|
||||||
void waitForProcessingIdle();
|
void waitForProcessingIdle();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Waits for all pending downloads, parsing and texture transfers to be complete
|
* Waits for all pending downloads, parsing and texture transfers to be complete
|
||||||
|
* @function Test.waitIdle
|
||||||
*/
|
*/
|
||||||
void waitIdle();
|
void waitIdle();
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Waits for establishment of connection to server
|
||||||
|
* @function Test.waitForConnection
|
||||||
|
* @param {int} maxWaitMs [default=10000] - Number of milliseconds to wait
|
||||||
|
*/
|
||||||
bool waitForConnection(qint64 maxWaitMs = 10000);
|
bool waitForConnection(qint64 maxWaitMs = 10000);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Waits a specific number of milliseconds
|
||||||
|
* @function Test.wait
|
||||||
|
* @param {int} milliseconds - Number of milliseconds to wait
|
||||||
|
*/
|
||||||
void wait(int milliseconds);
|
void wait(int milliseconds);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Waits for all pending downloads, parsing and texture transfers to be complete
|
||||||
|
* @function Test.loadTestScene
|
||||||
|
* @param {string} sceneFile - URL of scene to load
|
||||||
|
*/
|
||||||
bool loadTestScene(QString sceneFile);
|
bool loadTestScene(QString sceneFile);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Clears all caches
|
||||||
|
* @function Test.clear
|
||||||
|
*/
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Start recording Chrome compatible tracing events
|
* Start recording Chrome compatible tracing events
|
||||||
* logRules can be used to specify a set of logging category rules to limit what gets captured
|
* logRules can be used to specify a set of logging category rules to limit what gets captured
|
||||||
|
* @function Test.startTracing
|
||||||
|
* @param {string} logrules [defaultValue=""] - See implementation for explanation
|
||||||
*/
|
*/
|
||||||
bool startTracing(QString logrules = "");
|
bool startTracing(QString logrules = "");
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Stop recording Chrome compatible tracing events and serialize recorded events to a file
|
* Stop recording Chrome compatible tracing events and serialize recorded events to a file
|
||||||
* Using a filename with a .gz extension will automatically compress the output file
|
* Using a filename with a .gz extension will automatically compress the output file
|
||||||
|
* @function Test.stopTracing
|
||||||
|
* @param {string} filename - Name of file to save to
|
||||||
|
* @returns {bool} True if successful.
|
||||||
*/
|
*/
|
||||||
bool stopTracing(QString filename);
|
bool stopTracing(QString filename);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Starts a specific trace event
|
||||||
|
* @function Test.startTraceEvent
|
||||||
|
* @param {string} name - Name of event
|
||||||
|
*/
|
||||||
void startTraceEvent(QString name);
|
void startTraceEvent(QString name);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Stop a specific name event
|
||||||
|
* Using a filename with a .gz extension will automatically compress the output file
|
||||||
|
* @function Test.endTraceEvent
|
||||||
|
* @param {string} filename - Name of event
|
||||||
|
*/
|
||||||
void endTraceEvent(QString name);
|
void endTraceEvent(QString name);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Write detailed timing stats of next physics stepSimulation() to filename
|
* Write detailed timing stats of next physics stepSimulation() to filename
|
||||||
|
* @function Test.savePhysicsSimulationStats
|
||||||
|
* @param {string} filename - Name of file to save to
|
||||||
*/
|
*/
|
||||||
void savePhysicsSimulationStats(QString filename);
|
void savePhysicsSimulationStats(QString filename);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Profiles a specific function
|
||||||
|
* @function Test.savePhysicsSimulationStats
|
||||||
|
* @param {string} name - Name used to reference the function
|
||||||
|
* @param {function} function - Function to profile
|
||||||
|
*/
|
||||||
Q_INVOKABLE void profileRange(const QString& name, QScriptValue function);
|
Q_INVOKABLE void profileRange(const QString& name, QScriptValue function);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Clear all caches (menu command Reload Content)
|
* Clear all caches (menu command Reload Content)
|
||||||
|
* @function Test.clearCaches
|
||||||
*/
|
*/
|
||||||
void clearCaches();
|
void clearCaches();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Save a JSON object to a file in the test results location
|
* Save a JSON object to a file in the test results location
|
||||||
|
* @function Test.saveObject
|
||||||
|
* @param {string} name - Name of the object
|
||||||
|
* @param {string} filename - Name of file to save to
|
||||||
*/
|
*/
|
||||||
void saveObject(QVariant v, const QString& filename);
|
void saveObject(QVariant v, const QString& filename);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Maximizes the window
|
||||||
|
* @function Test.showMaximized
|
||||||
|
*/
|
||||||
|
void showMaximized();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool waitForCondition(qint64 maxWaitMs, std::function<bool()> condition);
|
bool waitForCondition(qint64 maxWaitMs, std::function<bool()> condition);
|
||||||
QString _testResultsLocation;
|
QString _testResultsLocation;
|
||||||
|
|
|
@ -522,7 +522,7 @@ int WindowScriptingInterface::openMessageBox(QString title, QString text, int bu
|
||||||
* <tr> <td><strong>RestoreDefaults</strong></td> <td><code>0x8000000</code></td> <td>"Restore Defaults"</td> </tr>
|
* <tr> <td><strong>RestoreDefaults</strong></td> <td><code>0x8000000</code></td> <td>"Restore Defaults"</td> </tr>
|
||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* @typedef Window.MessageBoxButton
|
* @typedef {number} Window.MessageBoxButton
|
||||||
*/
|
*/
|
||||||
int WindowScriptingInterface::createMessageBox(QString title, QString text, int buttons, int defaultButton) {
|
int WindowScriptingInterface::createMessageBox(QString title, QString text, int buttons, int defaultButton) {
|
||||||
auto messageBox = DependencyManager::get<OffscreenUi>()->createMessageBox(OffscreenUi::ICON_INFORMATION, title, text,
|
auto messageBox = DependencyManager::get<OffscreenUi>()->createMessageBox(OffscreenUi::ICON_INFORMATION, title, text,
|
||||||
|
|
|
@ -470,7 +470,7 @@ public slots:
|
||||||
* </tr>
|
* </tr>
|
||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* @typedef Window.DisplayTexture
|
* @typedef {string} Window.DisplayTexture
|
||||||
*/
|
*/
|
||||||
bool setDisplayTexture(const QString& name);
|
bool setDisplayTexture(const QString& name);
|
||||||
|
|
||||||
|
@ -523,16 +523,21 @@ public slots:
|
||||||
int openMessageBox(QString title, QString text, int buttons, int defaultButton);
|
int openMessageBox(QString title, QString text, int buttons, int defaultButton);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Open the given resource in the Interface window or in a web browser depending on the url scheme
|
* Open a URL in the Interface window or other application, depending on the URL's scheme. If the URL starts with
|
||||||
|
* <code>hifi://</code> then that URL is navigated to in Interface, otherwise the URL is opened in the application the OS
|
||||||
|
* associates with the URL's scheme (e.g., a Web browser for <code>http://</code>).
|
||||||
* @function Window.openUrl
|
* @function Window.openUrl
|
||||||
* @param {string} url - The resource to open
|
* @param {string} url - The URL to open.
|
||||||
*/
|
*/
|
||||||
void openUrl(const QUrl& url);
|
void openUrl(const QUrl& url);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* (Android only) Open the requested Activity and optionally back to the scene when the activity is done
|
* Open an Android activity and optionally return back to the scene when the activity is completed. <em>Android only.</em>
|
||||||
* @function Window.openAndroidActivity
|
* @function Window.openAndroidActivity
|
||||||
* @param {string} activityName - The name of the activity to open. One of "Home", "Login" or "Privacy Policy"
|
* @param {string} activityName - The name of the activity to open: one of <code>"Home"</code>, <code>"Login"</code>, or
|
||||||
|
* <code>"Privacy Policy"</code>.
|
||||||
|
* @param {boolean} backToScene - If <code>true</code>, the user is automatically returned back to the scene when the
|
||||||
|
* activity is completed.
|
||||||
*/
|
*/
|
||||||
void openAndroidActivity(const QString& activityName, const bool backToScene);
|
void openAndroidActivity(const QString& activityName, const bool backToScene);
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,13 @@ bool Billboard3DOverlay::applyTransformTo(Transform& transform, bool force) {
|
||||||
return transformChanged;
|
return transformChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Billboard3DOverlay::update(float duration) {
|
||||||
|
if (isFacingAvatar()) {
|
||||||
|
_renderVariableDirty = true;
|
||||||
|
}
|
||||||
|
Parent::update(duration);
|
||||||
|
}
|
||||||
|
|
||||||
Transform Billboard3DOverlay::evalRenderTransform() {
|
Transform Billboard3DOverlay::evalRenderTransform() {
|
||||||
Transform transform = getTransform();
|
Transform transform = getTransform();
|
||||||
bool transformChanged = applyTransformTo(transform, true);
|
bool transformChanged = applyTransformTo(transform, true);
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
class Billboard3DOverlay : public Planar3DOverlay, public PanelAttachable, public Billboardable {
|
class Billboard3DOverlay : public Planar3DOverlay, public PanelAttachable, public Billboardable {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
using Parent = Planar3DOverlay;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Billboard3DOverlay() {}
|
Billboard3DOverlay() {}
|
||||||
|
@ -26,6 +27,8 @@ public:
|
||||||
void setProperties(const QVariantMap& properties) override;
|
void setProperties(const QVariantMap& properties) override;
|
||||||
QVariant getProperty(const QString& property) override;
|
QVariant getProperty(const QString& property) override;
|
||||||
|
|
||||||
|
void update(float duration) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool applyTransformTo(Transform& transform, bool force = false) override;
|
virtual bool applyTransformTo(Transform& transform, bool force = false) override;
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,6 @@ void Image3DOverlay::update(float deltatime) {
|
||||||
_texture = DependencyManager::get<TextureCache>()->getTexture(_url);
|
_texture = DependencyManager::get<TextureCache>()->getTexture(_url);
|
||||||
_textureIsLoaded = false;
|
_textureIsLoaded = false;
|
||||||
}
|
}
|
||||||
if (usecTimestampNow() > _transformExpiry) {
|
|
||||||
Transform transform = getTransform();
|
|
||||||
applyTransformTo(transform);
|
|
||||||
setTransform(transform);
|
|
||||||
}
|
|
||||||
Parent::update(deltatime);
|
Parent::update(deltatime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,10 +103,9 @@ void ModelOverlay::update(float deltatime) {
|
||||||
if (_visibleDirty) {
|
if (_visibleDirty) {
|
||||||
_visibleDirty = false;
|
_visibleDirty = false;
|
||||||
// don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true
|
// don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true
|
||||||
_model->setVisibleInScene(getVisible(), scene,
|
uint8_t modelRenderTagMask = (_isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW);
|
||||||
render::ItemKey::TAG_BITS_0 |
|
_model->setTagMask(modelRenderTagMask, scene);
|
||||||
(_isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE),
|
_model->setVisibleInScene(getVisible(), scene);
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
if (_drawInFrontDirty) {
|
if (_drawInFrontDirty) {
|
||||||
_drawInFrontDirty = false;
|
_drawInFrontDirty = false;
|
||||||
|
|
|
@ -132,7 +132,6 @@ private:
|
||||||
namespace render {
|
namespace render {
|
||||||
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay);
|
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay);
|
||||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay);
|
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay);
|
||||||
template <> int payloadGetLayer(const Overlay::Pointer& overlay);
|
|
||||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args);
|
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args);
|
||||||
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay);
|
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay);
|
||||||
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems);
|
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems);
|
||||||
|
|
|
@ -53,7 +53,7 @@ const OverlayID UNKNOWN_OVERLAY_ID = OverlayID();
|
||||||
* @property {number} distance - The distance from the {@link PickRay} origin to the intersection point.
|
* @property {number} distance - The distance from the {@link PickRay} origin to the intersection point.
|
||||||
* @property {Vec3} surfaceNormal - The normal of the overlay surface at the intersection point.
|
* @property {Vec3} surfaceNormal - The normal of the overlay surface at the intersection point.
|
||||||
* @property {Vec3} intersection - The position of the intersection point.
|
* @property {Vec3} intersection - The position of the intersection point.
|
||||||
* @property {Object} extraInfo Additional intersection details, if available.
|
* @property {object} extraInfo Additional intersection details, if available.
|
||||||
*/
|
*/
|
||||||
class RayToOverlayIntersectionResult {
|
class RayToOverlayIntersectionResult {
|
||||||
public:
|
public:
|
||||||
|
@ -482,7 +482,7 @@ public slots:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Check if there is an overlay of a given ID.
|
* Check if there is an overlay of a given ID.
|
||||||
* @function Overlays.isAddedOverly
|
* @function Overlays.isAddedOverlay
|
||||||
* @param {Uuid} overlayID - The ID to check.
|
* @param {Uuid} overlayID - The ID to check.
|
||||||
* @returns {boolean} <code>true</code> if an overlay with the given ID exists, <code>false</code> otherwise.
|
* @returns {boolean} <code>true</code> if an overlay with the given ID exists, <code>false</code> otherwise.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,14 +35,18 @@ namespace render {
|
||||||
auto builder = ItemKey::Builder().withTypeShape();
|
auto builder = ItemKey::Builder().withTypeShape();
|
||||||
if (overlay->is3D()) {
|
if (overlay->is3D()) {
|
||||||
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
|
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
|
||||||
if (overlay3D->getDrawInFront() || overlay3D->getDrawHUDLayer()) {
|
if (overlay3D->getDrawInFront()) {
|
||||||
builder.withLayered();
|
builder.withLayer(render::hifi::LAYER_3D_FRONT);
|
||||||
|
} else if (overlay3D->getDrawHUDLayer()) {
|
||||||
|
builder.withLayer(render::hifi::LAYER_3D_HUD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overlay->isTransparent()) {
|
if (overlay->isTransparent()) {
|
||||||
builder.withTransparent();
|
builder.withTransparent();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
builder.withViewSpace();
|
builder.withViewSpace();
|
||||||
|
builder.withLayer(render::hifi::LAYER_2D);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!overlay->getVisible()) {
|
if (!overlay->getVisible()) {
|
||||||
|
@ -50,30 +54,14 @@ namespace render {
|
||||||
}
|
}
|
||||||
|
|
||||||
// always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view
|
// always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view
|
||||||
uint32_t viewTaskBits = render::ItemKey::TAG_BITS_0 |
|
render::hifi::Tag viewTagBits = overlay->getIsVisibleInSecondaryCamera() ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW;
|
||||||
(overlay->getIsVisibleInSecondaryCamera() ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE);
|
builder.withTagBits(viewTagBits);
|
||||||
|
|
||||||
builder.withTagBits(viewTaskBits);
|
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
|
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
|
||||||
return overlay->getBounds();
|
return overlay->getBounds();
|
||||||
}
|
}
|
||||||
template <> int payloadGetLayer(const Overlay::Pointer& overlay) {
|
|
||||||
if (overlay->is3D()) {
|
|
||||||
auto overlay3D = std::dynamic_pointer_cast<Base3DOverlay>(overlay);
|
|
||||||
if (overlay3D->getDrawInFront()) {
|
|
||||||
return Item::LAYER_3D_FRONT;
|
|
||||||
} else if (overlay3D->getDrawHUDLayer()) {
|
|
||||||
return Item::LAYER_3D_HUD;
|
|
||||||
} else {
|
|
||||||
return Item::LAYER_3D;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Item::LAYER_2D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||||
if (args) {
|
if (args) {
|
||||||
overlay->render(args);
|
overlay->render(args);
|
||||||
|
@ -83,7 +71,6 @@ namespace render {
|
||||||
return overlay->getShapeKey();
|
return overlay->getShapeKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems) {
|
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems) {
|
||||||
return overlay->fetchMetaSubItems(subItems);
|
return overlay->fetchMetaSubItems(subItems);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,15 +83,6 @@ xColor Text3DOverlay::getBackgroundColor() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Text3DOverlay::update(float deltatime) {
|
|
||||||
if (usecTimestampNow() > _transformExpiry) {
|
|
||||||
Transform transform = getTransform();
|
|
||||||
applyTransformTo(transform);
|
|
||||||
setTransform(transform);
|
|
||||||
}
|
|
||||||
Parent::update(deltatime);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Text3DOverlay::render(RenderArgs* args) {
|
void Text3DOverlay::render(RenderArgs* args) {
|
||||||
if (!_renderVisible || !getParentVisible()) {
|
if (!_renderVisible || !getParentVisible()) {
|
||||||
return; // do nothing if we're not visible
|
return; // do nothing if we're not visible
|
||||||
|
@ -306,13 +297,4 @@ QSizeF Text3DOverlay::textSize(const QString& text) const {
|
||||||
float pointToWorldScale = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
|
float pointToWorldScale = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
|
||||||
|
|
||||||
return QSizeF(extents.x, extents.y) * pointToWorldScale;
|
return QSizeF(extents.x, extents.y) * pointToWorldScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3 &direction, float &distance,
|
|
||||||
BoxFace &face, glm::vec3& surfaceNormal) {
|
|
||||||
Transform transform = getTransform();
|
|
||||||
applyTransformTo(transform, true);
|
|
||||||
setTransform(transform);
|
|
||||||
return Billboard3DOverlay::findRayIntersection(origin, direction, distance, face, surfaceNormal);
|
|
||||||
}
|
|
||||||
|
|
|
@ -30,8 +30,6 @@ public:
|
||||||
~Text3DOverlay();
|
~Text3DOverlay();
|
||||||
virtual void render(RenderArgs* args) override;
|
virtual void render(RenderArgs* args) override;
|
||||||
|
|
||||||
virtual void update(float deltatime) override;
|
|
||||||
|
|
||||||
virtual const render::ShapeKey getShapeKey() override;
|
virtual const render::ShapeKey getShapeKey() override;
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
|
@ -60,9 +58,6 @@ public:
|
||||||
|
|
||||||
QSizeF textSize(const QString& test) const; // Meters
|
QSizeF textSize(const QString& test) const; // Meters
|
||||||
|
|
||||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
|
||||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
|
||||||
|
|
||||||
virtual Text3DOverlay* createClone() const override;
|
virtual Text3DOverlay* createClone() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -259,7 +259,6 @@ void Web3DOverlay::setupQmlSurface() {
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("Web3DOverlay", this);
|
_webSurface->getSurfaceContext()->setContextProperty("Web3DOverlay", this);
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
_webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface());
|
_webSurface->getSurfaceContext()->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("desktop", DependencyManager::get<OffscreenUi>()->getDesktop());
|
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("HiFiAbout", AboutUtil::getInstance());
|
_webSurface->getSurfaceContext()->setContextProperty("HiFiAbout", AboutUtil::getInstance());
|
||||||
|
|
||||||
// Override min fps for tablet UI, for silky smooth scrolling
|
// Override min fps for tablet UI, for silky smooth scrolling
|
||||||
|
|
|
@ -70,7 +70,7 @@ public:
|
||||||
* @function AnimationCache.prefetch
|
* @function AnimationCache.prefetch
|
||||||
* @param {string} url - URL of the resource to prefetch.
|
* @param {string} url - URL of the resource to prefetch.
|
||||||
* @param {object} [extra=null]
|
* @param {object} [extra=null]
|
||||||
* @returns {Resource}
|
* @returns {ResourceObject}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
@ -79,7 +79,7 @@ public:
|
||||||
* @param {string} url - URL of the resource to load.
|
* @param {string} url - URL of the resource to load.
|
||||||
* @param {string} [fallback=""] - Fallback URL if load of the desired URL fails.
|
* @param {string} [fallback=""] - Fallback URL if load of the desired URL fails.
|
||||||
* @param {} [extra=null]
|
* @param {} [extra=null]
|
||||||
* @returns {Resource}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ public:
|
||||||
* Returns animation resource for particular animation.
|
* Returns animation resource for particular animation.
|
||||||
* @function AnimationCache.getAnimation
|
* @function AnimationCache.getAnimation
|
||||||
* @param {string} url - URL to load.
|
* @param {string} url - URL to load.
|
||||||
* @returns {Resource} animation
|
* @returns {AnimationObject} animation
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE AnimationPointer getAnimation(const QString& url) { return getAnimation(QUrl(url)); }
|
Q_INVOKABLE AnimationPointer getAnimation(const QString& url) { return getAnimation(QUrl(url)); }
|
||||||
Q_INVOKABLE AnimationPointer getAnimation(const QUrl& url);
|
Q_INVOKABLE AnimationPointer getAnimation(const QUrl& url);
|
||||||
|
@ -104,6 +104,17 @@ private:
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(AnimationPointer)
|
Q_DECLARE_METATYPE(AnimationPointer)
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* @class AnimationObject
|
||||||
|
*
|
||||||
|
* @hifi-interface
|
||||||
|
* @hifi-client-entity
|
||||||
|
* @hifi-server-entity
|
||||||
|
* @hifi-assignment-client
|
||||||
|
*
|
||||||
|
* @property {string[]} jointNames
|
||||||
|
* @property {FBXAnimationFrame[]} frames
|
||||||
|
*/
|
||||||
/// An animation loaded from the network.
|
/// An animation loaded from the network.
|
||||||
class Animation : public Resource {
|
class Animation : public Resource {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -118,9 +129,16 @@ public:
|
||||||
|
|
||||||
virtual bool isLoaded() const override;
|
virtual bool isLoaded() const override;
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* @function AnimationObject.getJointNames
|
||||||
|
* @returns {string[]}
|
||||||
|
*/
|
||||||
Q_INVOKABLE QStringList getJointNames() const;
|
Q_INVOKABLE QStringList getJointNames() const;
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* @function AnimationObject.getFrames
|
||||||
|
* @returns {FBXAnimationFrame[]}
|
||||||
|
*/
|
||||||
Q_INVOKABLE QVector<FBXAnimationFrame> getFrames() const;
|
Q_INVOKABLE QVector<FBXAnimationFrame> getFrames() const;
|
||||||
|
|
||||||
const QVector<FBXAnimationFrame>& getFramesReference() const;
|
const QVector<FBXAnimationFrame>& getFramesReference() const;
|
||||||
|
|
|
@ -77,6 +77,17 @@ private:
|
||||||
|
|
||||||
typedef QSharedPointer<Sound> SharedSoundPointer;
|
typedef QSharedPointer<Sound> SharedSoundPointer;
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* @class SoundObject
|
||||||
|
*
|
||||||
|
* @hifi-interface
|
||||||
|
* @hifi-client-entity
|
||||||
|
* @hifi-server-entity
|
||||||
|
* @hifi-assignment-client
|
||||||
|
*
|
||||||
|
* @property {boolean} downloaded
|
||||||
|
* @property {number} duration
|
||||||
|
*/
|
||||||
class SoundScriptingInterface : public QObject {
|
class SoundScriptingInterface : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -90,6 +101,10 @@ public:
|
||||||
bool isReady() const { return _sound->isReady(); }
|
bool isReady() const { return _sound->isReady(); }
|
||||||
float getDuration() { return _sound->getDuration(); }
|
float getDuration() { return _sound->getDuration(); }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* @function SoundObject.ready
|
||||||
|
* @returns {Signal}
|
||||||
|
*/
|
||||||
signals:
|
signals:
|
||||||
void ready();
|
void ready();
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ public:
|
||||||
* @function SoundCache.prefetch
|
* @function SoundCache.prefetch
|
||||||
* @param {string} url - URL of the resource to prefetch.
|
* @param {string} url - URL of the resource to prefetch.
|
||||||
* @param {object} [extra=null]
|
* @param {object} [extra=null]
|
||||||
* @returns {Resource}
|
* @returns {ResourceObject}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
@ -73,14 +73,14 @@ public:
|
||||||
* @param {string} url - URL of the resource to load.
|
* @param {string} url - URL of the resource to load.
|
||||||
* @param {string} [fallback=""] - Fallback URL if load of the desired URL fails.
|
* @param {string} [fallback=""] - Fallback URL if load of the desired URL fails.
|
||||||
* @param {} [extra=null]
|
* @param {} [extra=null]
|
||||||
* @returns {Resource}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function SoundCache.getSound
|
* @function SoundCache.getSound
|
||||||
* @param {string} url
|
* @param {string} url
|
||||||
* @returns {object}
|
* @returns {SoundObject}
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url);
|
Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url);
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -52,10 +52,15 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
|
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
|
||||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1).withMetaCullGroup();
|
ItemKey::Builder keyBuilder = ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::hifi::TAG_ALL_VIEWS).withMetaCullGroup();
|
||||||
|
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
|
||||||
|
if (!avatarPtr->getEnableMeshVisible()) {
|
||||||
|
keyBuilder.withInvisible();
|
||||||
|
}
|
||||||
|
return keyBuilder.build();
|
||||||
}
|
}
|
||||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
|
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
|
||||||
return static_pointer_cast<Avatar>(avatar)->getBounds();
|
return static_pointer_cast<Avatar>(avatar)->getRenderBounds();
|
||||||
}
|
}
|
||||||
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) {
|
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) {
|
||||||
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
|
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
|
||||||
|
@ -164,6 +169,11 @@ AABox Avatar::getBounds() const {
|
||||||
return _skeletonModel->getRenderableMeshBound();
|
return _skeletonModel->getRenderableMeshBound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AABox Avatar::getRenderBounds() const {
|
||||||
|
return _renderBound;
|
||||||
|
}
|
||||||
|
|
||||||
void Avatar::animateScaleChanges(float deltaTime) {
|
void Avatar::animateScaleChanges(float deltaTime) {
|
||||||
|
|
||||||
if (_isAnimatingScale) {
|
if (_isAnimatingScale) {
|
||||||
|
@ -569,16 +579,26 @@ static TextRenderer3D* textRenderer(TextRendererType type) {
|
||||||
|
|
||||||
void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||||
auto avatarPayload = new render::Payload<AvatarData>(self);
|
auto avatarPayload = new render::Payload<AvatarData>(self);
|
||||||
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
|
auto avatarPayloadPointer = std::shared_ptr<render::Payload<AvatarData>>(avatarPayload);
|
||||||
|
|
||||||
if (_renderItemID == render::Item::INVALID_ITEM_ID) {
|
if (_renderItemID == render::Item::INVALID_ITEM_ID) {
|
||||||
_renderItemID = scene->allocateID();
|
_renderItemID = scene->allocateID();
|
||||||
}
|
}
|
||||||
|
// INitialize the _render bound as we are creating the avatar render item
|
||||||
|
_renderBound = getBounds();
|
||||||
transaction.resetItem(_renderItemID, avatarPayloadPointer);
|
transaction.resetItem(_renderItemID, avatarPayloadPointer);
|
||||||
_skeletonModel->addToScene(scene, transaction);
|
_skeletonModel->addToScene(scene, transaction);
|
||||||
|
_skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
|
||||||
|
_skeletonModel->setGroupCulled(true);
|
||||||
|
_skeletonModel->setCanCastShadow(true);
|
||||||
|
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
|
||||||
|
|
||||||
processMaterials();
|
processMaterials();
|
||||||
for (auto& attachmentModel : _attachmentModels) {
|
for (auto& attachmentModel : _attachmentModels) {
|
||||||
attachmentModel->addToScene(scene, transaction);
|
attachmentModel->addToScene(scene, transaction);
|
||||||
|
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
|
||||||
|
attachmentModel->setGroupCulled(false);
|
||||||
|
attachmentModel->setCanCastShadow(true);
|
||||||
|
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
_mustFadeIn = true;
|
_mustFadeIn = true;
|
||||||
|
@ -637,7 +657,15 @@ void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointe
|
||||||
|
|
||||||
void Avatar::updateRenderItem(render::Transaction& transaction) {
|
void Avatar::updateRenderItem(render::Transaction& transaction) {
|
||||||
if (render::Item::isValidID(_renderItemID)) {
|
if (render::Item::isValidID(_renderItemID)) {
|
||||||
transaction.updateItem<render::Payload<AvatarData>>(_renderItemID, [](render::Payload<AvatarData>& p) {});
|
auto renderBound = getBounds();
|
||||||
|
transaction.updateItem<AvatarData>(_renderItemID,
|
||||||
|
[renderBound](AvatarData& avatar) {
|
||||||
|
auto avatarPtr = dynamic_cast<Avatar*>(&avatar);
|
||||||
|
if (avatarPtr) {
|
||||||
|
avatarPtr->_renderBound = renderBound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -759,6 +787,18 @@ void Avatar::render(RenderArgs* renderArgs) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Avatar::setEnableMeshVisible(bool isEnabled) {
|
||||||
|
if (_isMeshVisible != isEnabled) {
|
||||||
|
_isMeshVisible = isEnabled;
|
||||||
|
_needMeshVisibleSwitch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Avatar::getEnableMeshVisible() const {
|
||||||
|
return _isMeshVisible;
|
||||||
|
}
|
||||||
|
|
||||||
void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
||||||
bool canTryFade{ false };
|
bool canTryFade{ false };
|
||||||
|
|
||||||
|
@ -770,6 +810,12 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
||||||
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
|
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
|
||||||
_skeletonModel->removeFromScene(scene, transaction);
|
_skeletonModel->removeFromScene(scene, transaction);
|
||||||
_skeletonModel->addToScene(scene, transaction);
|
_skeletonModel->addToScene(scene, transaction);
|
||||||
|
|
||||||
|
_skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
|
||||||
|
_skeletonModel->setGroupCulled(true);
|
||||||
|
_skeletonModel->setCanCastShadow(true);
|
||||||
|
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
|
||||||
|
|
||||||
processMaterials();
|
processMaterials();
|
||||||
canTryFade = true;
|
canTryFade = true;
|
||||||
_isAnimatingScale = true;
|
_isAnimatingScale = true;
|
||||||
|
@ -778,9 +824,25 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
||||||
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
|
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
|
||||||
attachmentModel->removeFromScene(scene, transaction);
|
attachmentModel->removeFromScene(scene, transaction);
|
||||||
attachmentModel->addToScene(scene, transaction);
|
attachmentModel->addToScene(scene, transaction);
|
||||||
|
|
||||||
|
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
|
||||||
|
attachmentModel->setGroupCulled(false);
|
||||||
|
attachmentModel->setCanCastShadow(true);
|
||||||
|
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_needMeshVisibleSwitch) {
|
||||||
|
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
|
||||||
|
for (auto attachmentModel : _attachmentModels) {
|
||||||
|
if (attachmentModel->isRenderable()) {
|
||||||
|
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateRenderItem(transaction);
|
||||||
|
_needMeshVisibleSwitch = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (_mustFadeIn && canTryFade) {
|
if (_mustFadeIn && canTryFade) {
|
||||||
// Do it now to be sure all the sub items are ready and the fade is sent to them too
|
// Do it now to be sure all the sub items are ready and the fade is sent to them too
|
||||||
fade(transaction, render::Transition::USER_ENTER_DOMAIN);
|
fade(transaction, render::Transition::USER_ENTER_DOMAIN);
|
||||||
|
|
|
@ -74,7 +74,6 @@ public:
|
||||||
virtual void instantiableAvatar() = 0;
|
virtual void instantiableAvatar() = 0;
|
||||||
|
|
||||||
typedef render::Payload<AvatarData> Payload;
|
typedef render::Payload<AvatarData> Payload;
|
||||||
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
|
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void updateAvatarEntities();
|
void updateAvatarEntities();
|
||||||
|
@ -292,7 +291,7 @@ public:
|
||||||
*/
|
*/
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Information about a single joint in an Avatar's skeleton hierarchy.
|
* Information about a single joint in an Avatar's skeleton hierarchy.
|
||||||
* @typedef MyAvatar.SkeletonJoint
|
* @typedef {object} MyAvatar.SkeletonJoint
|
||||||
* @property {string} name - Joint name.
|
* @property {string} name - Joint name.
|
||||||
* @property {number} index - Joint index.
|
* @property {number} index - Joint index.
|
||||||
* @property {number} parentIndex - Index of this joint's parent (-1 if no parent).
|
* @property {number} parentIndex - Index of this joint's parent (-1 if no parent).
|
||||||
|
@ -322,6 +321,7 @@ public:
|
||||||
bool hasNewJointData() const { return _hasNewJointData; }
|
bool hasNewJointData() const { return _hasNewJointData; }
|
||||||
|
|
||||||
float getBoundingRadius() const;
|
float getBoundingRadius() const;
|
||||||
|
AABox getRenderBounds() const; // THis call is accessible from rendering thread only to report the bounding box of the avatar during the frame.
|
||||||
|
|
||||||
void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene);
|
void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene);
|
||||||
void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene);
|
void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene);
|
||||||
|
@ -356,6 +356,10 @@ public:
|
||||||
|
|
||||||
virtual void setAvatarEntityDataChanged(bool value) override;
|
virtual void setAvatarEntityDataChanged(bool value) override;
|
||||||
|
|
||||||
|
// Show hide the model representation of the avatar
|
||||||
|
virtual void setEnableMeshVisible(bool isEnabled);
|
||||||
|
virtual bool getEnableMeshVisible() const;
|
||||||
|
|
||||||
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override;
|
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override;
|
||||||
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override;
|
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override;
|
||||||
|
|
||||||
|
@ -532,6 +536,10 @@ protected:
|
||||||
std::mutex _materialsLock;
|
std::mutex _materialsLock;
|
||||||
|
|
||||||
void processMaterials();
|
void processMaterials();
|
||||||
|
|
||||||
|
AABox _renderBound;
|
||||||
|
bool _isMeshVisible{ true };
|
||||||
|
bool _needMeshVisibleSwitch{ true };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Avatar_h
|
#endif // hifi_Avatar_h
|
||||||
|
|
|
@ -35,7 +35,7 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
|
||||||
_useDualQuaternionSkinning = true;
|
_useDualQuaternionSkinning = true;
|
||||||
|
|
||||||
// Avatars all cast shadow
|
// Avatars all cast shadow
|
||||||
_canCastShadow = true;
|
setCanCastShadow(true);
|
||||||
|
|
||||||
assert(_owningAvatar);
|
assert(_owningAvatar);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2363,7 +2363,7 @@ glm::vec3 AvatarData::getAbsoluteJointTranslationInObjectFrame(int index) const
|
||||||
}
|
}
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @typedef AttachmentData
|
* @typedef {object} AttachmentData
|
||||||
* @property {string} modelUrl
|
* @property {string} modelUrl
|
||||||
* @property {string} jointName
|
* @property {string} jointName
|
||||||
* @property {Vec3} translation
|
* @property {Vec3} translation
|
||||||
|
|
|
@ -578,8 +578,7 @@ public:
|
||||||
* @param {Quat} rotation - The rotation of the joint relative to its parent.
|
* @param {Quat} rotation - The rotation of the joint relative to its parent.
|
||||||
* @param {Vec3} translation - The translation of the joint relative to its parent.
|
* @param {Vec3} translation - The translation of the joint relative to its parent.
|
||||||
* @example <caption>Set your avatar to it's default T-pose for a while.<br />
|
* @example <caption>Set your avatar to it's default T-pose for a while.<br />
|
||||||
* <img alt="Avatar in T-pose" src="https://docs.highfidelity.com/user/pages/06.api-reference/25.myavatar/t-pose.png" />
|
* <img alt="Avatar in T-pose" src="https://docs.highfidelity.com/images/t-pose.png" /></caption>
|
||||||
* </caption>
|
|
||||||
* // Set all joint translations and rotations to defaults.
|
* // Set all joint translations and rotations to defaults.
|
||||||
* var i, length, rotation, translation;
|
* var i, length, rotation, translation;
|
||||||
* for (i = 0, length = MyAvatar.getJointNames().length; i < length; i++) {
|
* for (i = 0, length = MyAvatar.getJointNames().length; i < length; i++) {
|
||||||
|
@ -680,8 +679,7 @@ public:
|
||||||
* @param {string} name - The name of the joint.
|
* @param {string} name - The name of the joint.
|
||||||
* @param {Quat} rotation - The rotation of the joint relative to its parent.
|
* @param {Quat} rotation - The rotation of the joint relative to its parent.
|
||||||
* @example <caption>Set your avatar to its default T-pose then rotate its right arm.<br />
|
* @example <caption>Set your avatar to its default T-pose then rotate its right arm.<br />
|
||||||
* <img alt="Avatar in T-pose with arm rotated"
|
* <img alt="Avatar in T-pose with arm rotated" src="https://docs.highfidelity.com/images/armpose.png" /></caption>
|
||||||
* src="https://docs.highfidelity.com/user/pages/06.api-reference/25.myavatar/armpose.png" /></caption>
|
|
||||||
* // Set all joint translations and rotations to defaults.
|
* // Set all joint translations and rotations to defaults.
|
||||||
* var i, length, rotation, translation;
|
* var i, length, rotation, translation;
|
||||||
* for (i = 0, length = MyAvatar.getJointNames().length; i < length; i++) {
|
* for (i = 0, length = MyAvatar.getJointNames().length; i < length; i++) {
|
||||||
|
@ -713,8 +711,7 @@ public:
|
||||||
* @param {Vec3} translation - The translation of the joint relative to its parent.
|
* @param {Vec3} translation - The translation of the joint relative to its parent.
|
||||||
* @example <caption>Stretch your avatar's neck. Depending on the avatar you are using, you will either see a gap between
|
* @example <caption>Stretch your avatar's neck. Depending on the avatar you are using, you will either see a gap between
|
||||||
* the head and body or you will see the neck stretched.<br />
|
* the head and body or you will see the neck stretched.<br />
|
||||||
* <img alt="Avatar with neck stretched"
|
* <img alt="Avatar with neck stretched" src="https://docs.highfidelity.com/images/stretched-neck.png" /></caption>
|
||||||
* src="https://docs.highfidelity.com/user/pages/06.api-reference/25.myavatar/stretched-neck.png" /></caption>
|
|
||||||
* // Stretch your avatar's neck.
|
* // Stretch your avatar's neck.
|
||||||
* MyAvatar.setJointTranslation("Neck", { x: 0, y: 25, z: 0 });
|
* MyAvatar.setJointTranslation("Neck", { x: 0, y: 25, z: 0 });
|
||||||
*
|
*
|
||||||
|
@ -798,8 +795,7 @@ public:
|
||||||
* @param {Quat[]} jointRotations - The rotations for all joints in the avatar. The values are in the same order as the
|
* @param {Quat[]} jointRotations - The rotations for all joints in the avatar. The values are in the same order as the
|
||||||
* array returned by {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}.
|
* array returned by {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}.
|
||||||
* @example <caption>Set your avatar to its default T-pose then rotate its right arm.<br />
|
* @example <caption>Set your avatar to its default T-pose then rotate its right arm.<br />
|
||||||
* <img alt="Avatar in T-pose" src="https://docs.highfidelity.com/user/pages/06.api-reference/25.myavatar/armpose.png" />
|
* <img alt="Avatar in T-pose" src="https://docs.highfidelity.com/images/armpose.png" /></caption>
|
||||||
* </caption>
|
|
||||||
* // Set all joint translations and rotations to defaults.
|
* // Set all joint translations and rotations to defaults.
|
||||||
* var i, length, rotation, translation;
|
* var i, length, rotation, translation;
|
||||||
* for (i = 0, length = MyAvatar.getJointNames().length; i < length; i++) {
|
* for (i = 0, length = MyAvatar.getJointNames().length; i < length; i++) {
|
||||||
|
|
|
@ -307,7 +307,7 @@ namespace controller {
|
||||||
* action.</td></tr>
|
* action.</td></tr>
|
||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* @typedef Controller.Actions
|
* @typedef {object} Controller.Actions
|
||||||
*/
|
*/
|
||||||
// Device functions
|
// Device functions
|
||||||
Input::NamedVector ActionsDevice::getAvailableInputs() const {
|
Input::NamedVector ActionsDevice::getAvailableInputs() const {
|
||||||
|
|
|
@ -79,7 +79,7 @@ enum Hand {
|
||||||
* {@link Controller.Hardware-Vive}.</td></tr>
|
* {@link Controller.Hardware-Vive}.</td></tr>
|
||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* @typedef Controller.Hardware
|
* @typedef {object} Controller.Hardware
|
||||||
* @example <caption>List all the currently available <code>Controller.Hardware</code> properties.</caption>
|
* @example <caption>List all the currently available <code>Controller.Hardware</code> properties.</caption>
|
||||||
* function printProperties(string, item) {
|
* function printProperties(string, item) {
|
||||||
* print(string);
|
* print(string);
|
||||||
|
|
|
@ -231,7 +231,7 @@ void StandardController::focusOutEvent() {
|
||||||
*
|
*
|
||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* @typedef Controller.Standard
|
* @typedef {object} Controller.Standard
|
||||||
*/
|
*/
|
||||||
Input::NamedVector StandardController::getAvailableInputs() const {
|
Input::NamedVector StandardController::getAvailableInputs() const {
|
||||||
static Input::NamedVector availableInputs {
|
static Input::NamedVector availableInputs {
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
|
|
||||||
const char* SRGB_TO_LINEAR_FRAG = R"SCRIBE(
|
const char* SRGB_TO_LINEAR_FRAG = R"SCRIBE(
|
||||||
|
|
||||||
|
// OpenGLDisplayPlugin_present.frag
|
||||||
|
|
||||||
uniform sampler2D colorMap;
|
uniform sampler2D colorMap;
|
||||||
|
|
||||||
in vec2 varTexCoord0;
|
in vec2 varTexCoord0;
|
||||||
|
|
|
@ -157,20 +157,20 @@ Item::Bound EntityRenderer::getBound() {
|
||||||
return _bound;
|
return _bound;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t EntityRenderer::getViewTagBits() const {
|
render::hifi::Tag EntityRenderer::getTagMask() const {
|
||||||
return render::ItemKey::TAG_BITS_0 | (_isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE);
|
return _isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemKey EntityRenderer::getKey() {
|
ItemKey EntityRenderer::getKey() {
|
||||||
if (isTransparent()) {
|
if (isTransparent()) {
|
||||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getViewTagBits());
|
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask());
|
||||||
}
|
}
|
||||||
|
|
||||||
// This allows shapes to cast shadows
|
// This allows shapes to cast shadows
|
||||||
if (_canCastShadow) {
|
if (_canCastShadow) {
|
||||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getViewTagBits()).withShadowCaster();
|
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()).withShadowCaster();
|
||||||
} else {
|
} else {
|
||||||
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getViewTagBits());
|
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "AbstractViewStateInterface.h"
|
#include "AbstractViewStateInterface.h"
|
||||||
#include "EntitiesRendererLogging.h"
|
#include "EntitiesRendererLogging.h"
|
||||||
#include <graphics-scripting/Forward.h>
|
#include <graphics-scripting/Forward.h>
|
||||||
|
#include <RenderHifi.h>
|
||||||
|
|
||||||
class EntityTreeRenderer;
|
class EntityTreeRenderer;
|
||||||
|
|
||||||
|
@ -74,7 +75,7 @@ protected:
|
||||||
virtual Item::Bound getBound() override;
|
virtual Item::Bound getBound() override;
|
||||||
virtual void render(RenderArgs* args) override final;
|
virtual void render(RenderArgs* args) override final;
|
||||||
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override;
|
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override;
|
||||||
virtual uint32_t getViewTagBits() const;
|
virtual render::hifi::Tag getTagMask() const;
|
||||||
|
|
||||||
// Returns true if the item in question needs to have updateInScene called because of internal rendering state changes
|
// Returns true if the item in question needs to have updateInScene called because of internal rendering state changes
|
||||||
virtual bool needsRenderUpdate() const;
|
virtual bool needsRenderUpdate() const;
|
||||||
|
|
|
@ -43,7 +43,7 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
|
||||||
|
|
||||||
ItemKey MaterialEntityRenderer::getKey() {
|
ItemKey MaterialEntityRenderer::getKey() {
|
||||||
ItemKey::Builder builder;
|
ItemKey::Builder builder;
|
||||||
builder.withTypeShape().withTagBits(getViewTagBits());
|
builder.withTypeShape().withTagBits(getTagMask());
|
||||||
|
|
||||||
if (!_visible) {
|
if (!_visible) {
|
||||||
builder.withInvisible();
|
builder.withInvisible();
|
||||||
|
|
|
@ -1060,9 +1060,9 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
|
||||||
|
|
||||||
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
|
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
|
||||||
if (didVisualGeometryRequestSucceed) {
|
if (didVisualGeometryRequestSucceed) {
|
||||||
_itemKey = ItemKey::Builder().withTypeMeta().withTagBits(getViewTagBits());
|
_itemKey = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask());
|
||||||
} else {
|
} else {
|
||||||
_itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(getViewTagBits());
|
_itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(getTagMask());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1070,11 +1070,11 @@ ItemKey ModelEntityRenderer::getKey() {
|
||||||
return _itemKey;
|
return _itemKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ModelEntityRenderer::getViewTagBits() const {
|
render::hifi::Tag ModelEntityRenderer::getTagMask() const {
|
||||||
// Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
|
// Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
|
||||||
return _cauterized ?
|
return _cauterized ?
|
||||||
(_isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE) : // draw in every view except the main one (view zero) (unless not visible in other views)
|
(_isVisibleInSecondaryCamera ? render::hifi::TAG_SECONDARY_VIEW : render::hifi::TAG_NONE) :
|
||||||
Parent::getViewTagBits(); // calculate which views to be shown in
|
Parent::getTagMask(); // calculate which views to be shown in
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
|
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
|
||||||
|
@ -1394,18 +1394,22 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
entity->updateModelBounds();
|
entity->updateModelBounds();
|
||||||
entity->stopModelOverrideIfNoParent();
|
entity->stopModelOverrideIfNoParent();
|
||||||
|
|
||||||
uint32_t viewTaskBits = getViewTagBits();
|
render::hifi::Tag tagMask = getTagMask();
|
||||||
if (model->isVisible() != _visible || model->getViewTagBits() != viewTaskBits) {
|
if (model->isVisible() != _visible) {
|
||||||
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
||||||
// the renderable item. As it stands now the model checks it's visible/invisible state
|
// the renderable item. As it stands now the model checks it's visible/invisible state
|
||||||
// so most of the time we don't do anything in this function.
|
// so most of the time we don't do anything in this function.
|
||||||
model->setVisibleInScene(_visible, scene, viewTaskBits, false);
|
model->setVisibleInScene(_visible, scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model->getTagMask() != tagMask) {
|
||||||
|
model->setTagMask(tagMask, scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO? early exit here when not visible?
|
// TODO? early exit here when not visible?
|
||||||
|
|
||||||
if (model->canCastShadow() != _canCastShadow) {
|
if (model->canCastShadow() != _canCastShadow) {
|
||||||
model->setCanCastShadow(_canCastShadow, scene, viewTaskBits, false);
|
model->setCanCastShadow(_canCastShadow, scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_needsCollisionGeometryUpdate) {
|
if (_needsCollisionGeometryUpdate) {
|
||||||
|
|
|
@ -164,7 +164,7 @@ protected:
|
||||||
void flagForCollisionGeometryUpdate();
|
void flagForCollisionGeometryUpdate();
|
||||||
void setCollisionMeshKey(const void* key);
|
void setCollisionMeshKey(const void* key);
|
||||||
|
|
||||||
uint32_t getViewTagBits() const override;
|
render::hifi::Tag getTagMask() const override;
|
||||||
|
|
||||||
void setIsVisibleInSecondaryCamera(bool value) override;
|
void setIsVisibleInSecondaryCamera(bool value) override;
|
||||||
|
|
||||||
|
|
|
@ -147,9 +147,9 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn
|
||||||
|
|
||||||
ItemKey ParticleEffectEntityRenderer::getKey() {
|
ItemKey ParticleEffectEntityRenderer::getKey() {
|
||||||
if (_visible) {
|
if (_visible) {
|
||||||
return ItemKey::Builder::transparentShape().withTagBits(getViewTagBits());
|
return ItemKey::Builder::transparentShape().withTagBits(getTagMask());
|
||||||
} else {
|
} else {
|
||||||
return ItemKey::Builder().withInvisible().withTagBits(getViewTagBits()).build();
|
return ItemKey::Builder().withInvisible().withTagBits(getTagMask()).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemKey PolyLineEntityRenderer::getKey() {
|
ItemKey PolyLineEntityRenderer::getKey() {
|
||||||
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getViewTagBits());
|
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask());
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapeKey PolyLineEntityRenderer::getShapeKey() {
|
ShapeKey PolyLineEntityRenderer::getShapeKey() {
|
||||||
|
|
|
@ -169,7 +169,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ItemKey getKey() override { return ItemKey::Builder::opaqueShape().withTagBits(getViewTagBits()); }
|
virtual ItemKey getKey() override { return ItemKey::Builder::opaqueShape().withTagBits(getTagMask()); }
|
||||||
virtual ShapeKey getShapeKey() override;
|
virtual ShapeKey getShapeKey() override;
|
||||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
||||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||||
|
|
|
@ -139,7 +139,7 @@ bool ShapeEntityRenderer::isTransparent() const {
|
||||||
|
|
||||||
ItemKey ShapeEntityRenderer::getKey() {
|
ItemKey ShapeEntityRenderer::getKey() {
|
||||||
ItemKey::Builder builder;
|
ItemKey::Builder builder;
|
||||||
builder.withTypeShape().withTypeMeta().withTagBits(getViewTagBits());
|
builder.withTypeShape().withTypeMeta().withTagBits(getTagMask());
|
||||||
|
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
if (isTransparent()) {
|
if (isTransparent()) {
|
||||||
|
|
|
@ -269,7 +269,7 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
||||||
|
|
||||||
|
|
||||||
ItemKey ZoneEntityRenderer::getKey() {
|
ItemKey ZoneEntityRenderer::getKey() {
|
||||||
return ItemKey::Builder().withTypeMeta().withTagBits(getViewTagBits()).build();
|
return ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||||
|
|
|
@ -46,7 +46,7 @@ bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* The AnimationProperties are used to configure an animation.
|
* The AnimationProperties are used to configure an animation.
|
||||||
* @typedef Entities.AnimationProperties
|
* @typedef {object} Entities.AnimationProperties
|
||||||
* @property {string} url="" - The URL of the FBX file that has the animation.
|
* @property {string} url="" - The URL of the FBX file that has the animation.
|
||||||
* @property {number} fps=30 - The speed in frames/s that the animation is played at.
|
* @property {number} fps=30 - The speed in frames/s that the animation is played at.
|
||||||
* @property {number} firstFrame=0 - The first frame to play in the animation.
|
* @property {number} firstFrame=0 - The first frame to play in the animation.
|
||||||
|
|
|
@ -817,7 +817,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
|
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
|
||||||
READ_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow);
|
READ_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow);
|
||||||
READ_ENTITY_PROPERTY(PROP_COLLISIONLESS, bool, setCollisionless);
|
READ_ENTITY_PROPERTY(PROP_COLLISIONLESS, bool, setCollisionless);
|
||||||
READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, setCollisionMask);
|
READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint16_t, setCollisionMask);
|
||||||
READ_ENTITY_PROPERTY(PROP_DYNAMIC, bool, setDynamic);
|
READ_ENTITY_PROPERTY(PROP_DYNAMIC, bool, setDynamic);
|
||||||
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked);
|
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked);
|
||||||
READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData);
|
READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData);
|
||||||
|
@ -1850,7 +1850,7 @@ void EntityItem::setCollisionless(bool value) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::setCollisionMask(uint8_t value) {
|
void EntityItem::setCollisionMask(uint16_t value) {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
if ((_collisionMask & ENTITY_COLLISION_MASK_DEFAULT) != (value & ENTITY_COLLISION_MASK_DEFAULT)) {
|
if ((_collisionMask & ENTITY_COLLISION_MASK_DEFAULT) != (value & ENTITY_COLLISION_MASK_DEFAULT)) {
|
||||||
_collisionMask = (value & ENTITY_COLLISION_MASK_DEFAULT);
|
_collisionMask = (value & ENTITY_COLLISION_MASK_DEFAULT);
|
||||||
|
@ -1915,7 +1915,7 @@ void EntityItem::setCreated(quint64 value) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const {
|
void EntityItem::computeCollisionGroupAndFinalMask(int32_t& group, int32_t& mask) const {
|
||||||
if (_collisionless) {
|
if (_collisionless) {
|
||||||
group = BULLET_COLLISION_GROUP_COLLISIONLESS;
|
group = BULLET_COLLISION_GROUP_COLLISIONLESS;
|
||||||
mask = 0;
|
mask = 0;
|
||||||
|
@ -1928,7 +1928,7 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask
|
||||||
group = BULLET_COLLISION_GROUP_STATIC;
|
group = BULLET_COLLISION_GROUP_STATIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t userMask = getCollisionMask();
|
uint16_t userMask = getCollisionMask();
|
||||||
|
|
||||||
if ((bool)(userMask & USER_COLLISION_GROUP_MY_AVATAR) !=
|
if ((bool)(userMask & USER_COLLISION_GROUP_MY_AVATAR) !=
|
||||||
(bool)(userMask & USER_COLLISION_GROUP_OTHER_AVATAR)) {
|
(bool)(userMask & USER_COLLISION_GROUP_OTHER_AVATAR)) {
|
||||||
|
@ -1942,7 +1942,7 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask
|
||||||
if ((bool)(_flags & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
|
if ((bool)(_flags & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
|
||||||
userMask &= ~USER_COLLISION_GROUP_MY_AVATAR;
|
userMask &= ~USER_COLLISION_GROUP_MY_AVATAR;
|
||||||
}
|
}
|
||||||
mask = Physics::getDefaultCollisionMask(group) & (int16_t)(userMask);
|
mask = Physics::getDefaultCollisionMask(group) & (int32_t)(userMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2818,8 +2818,8 @@ bool EntityItem::getCollisionless() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t EntityItem::getCollisionMask() const {
|
uint16_t EntityItem::getCollisionMask() const {
|
||||||
uint8_t result;
|
uint16_t result;
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
result = _collisionMask;
|
result = _collisionMask;
|
||||||
});
|
});
|
||||||
|
|
|
@ -291,10 +291,10 @@ public:
|
||||||
bool getCollisionless() const;
|
bool getCollisionless() const;
|
||||||
void setCollisionless(bool value);
|
void setCollisionless(bool value);
|
||||||
|
|
||||||
uint8_t getCollisionMask() const;
|
uint16_t getCollisionMask() const;
|
||||||
void setCollisionMask(uint8_t value);
|
void setCollisionMask(uint16_t value);
|
||||||
|
|
||||||
void computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const;
|
void computeCollisionGroupAndFinalMask(int32_t& group, int32_t& mask) const;
|
||||||
|
|
||||||
bool getDynamic() const;
|
bool getDynamic() const;
|
||||||
void setDynamic(bool value);
|
void setDynamic(bool value);
|
||||||
|
@ -584,7 +584,7 @@ protected:
|
||||||
bool _isVisibleInSecondaryCamera { ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA };
|
bool _isVisibleInSecondaryCamera { ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA };
|
||||||
bool _canCastShadow{ ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW };
|
bool _canCastShadow{ ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW };
|
||||||
bool _collisionless { ENTITY_ITEM_DEFAULT_COLLISIONLESS };
|
bool _collisionless { ENTITY_ITEM_DEFAULT_COLLISIONLESS };
|
||||||
uint8_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT };
|
uint16_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT };
|
||||||
bool _dynamic { ENTITY_ITEM_DEFAULT_DYNAMIC };
|
bool _dynamic { ENTITY_ITEM_DEFAULT_DYNAMIC };
|
||||||
bool _locked { ENTITY_ITEM_DEFAULT_LOCKED };
|
bool _locked { ENTITY_ITEM_DEFAULT_LOCKED };
|
||||||
QString _userData { ENTITY_ITEM_DEFAULT_USER_DATA };
|
QString _userData { ENTITY_ITEM_DEFAULT_USER_DATA };
|
||||||
|
|
|
@ -130,7 +130,7 @@ void buildStringToMaterialMappingModeLookup() {
|
||||||
addMaterialMappingMode(PROJECTED);
|
addMaterialMappingMode(PROJECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getCollisionGroupAsString(uint8_t group) {
|
QString getCollisionGroupAsString(uint16_t group) {
|
||||||
switch (group) {
|
switch (group) {
|
||||||
case USER_COLLISION_GROUP_DYNAMIC:
|
case USER_COLLISION_GROUP_DYNAMIC:
|
||||||
return "dynamic";
|
return "dynamic";
|
||||||
|
@ -146,7 +146,7 @@ QString getCollisionGroupAsString(uint8_t group) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getCollisionGroupAsBitMask(const QStringRef& name) {
|
uint16_t getCollisionGroupAsBitMask(const QStringRef& name) {
|
||||||
if (0 == name.compare(QString("dynamic"))) {
|
if (0 == name.compare(QString("dynamic"))) {
|
||||||
return USER_COLLISION_GROUP_DYNAMIC;
|
return USER_COLLISION_GROUP_DYNAMIC;
|
||||||
} else if (0 == name.compare(QString("static"))) {
|
} else if (0 == name.compare(QString("static"))) {
|
||||||
|
@ -164,7 +164,7 @@ uint8_t getCollisionGroupAsBitMask(const QStringRef& name) {
|
||||||
QString EntityItemProperties::getCollisionMaskAsString() const {
|
QString EntityItemProperties::getCollisionMaskAsString() const {
|
||||||
QString maskString("");
|
QString maskString("");
|
||||||
for (int i = 0; i < NUM_USER_COLLISION_GROUPS; ++i) {
|
for (int i = 0; i < NUM_USER_COLLISION_GROUPS; ++i) {
|
||||||
uint8_t group = 0x01 << i;
|
uint16_t group = 0x0001 << i;
|
||||||
if (group & _collisionMask) {
|
if (group & _collisionMask) {
|
||||||
maskString.append(getCollisionGroupAsString(group));
|
maskString.append(getCollisionGroupAsString(group));
|
||||||
maskString.append(',');
|
maskString.append(',');
|
||||||
|
@ -175,7 +175,7 @@ QString EntityItemProperties::getCollisionMaskAsString() const {
|
||||||
|
|
||||||
void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) {
|
void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) {
|
||||||
QVector<QStringRef> groups = maskString.splitRef(',');
|
QVector<QStringRef> groups = maskString.splitRef(',');
|
||||||
uint8_t mask = 0x00;
|
uint16_t mask = 0x0000;
|
||||||
for (auto groupName : groups) {
|
for (auto groupName : groups) {
|
||||||
mask |= getCollisionGroupAsBitMask(groupName);
|
mask |= getCollisionGroupAsBitMask(groupName);
|
||||||
}
|
}
|
||||||
|
@ -487,10 +487,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||||
* @property {boolean} locked=false - Whether or not the entity can be edited or deleted. If <code>true</code> then the
|
* @property {boolean} locked=false - Whether or not the entity can be edited or deleted. If <code>true</code> then the
|
||||||
* entity's properties other than <code>locked</code> cannot be changed, and the entity cannot be deleted.
|
* entity's properties other than <code>locked</code> cannot be changed, and the entity cannot be deleted.
|
||||||
* @property {boolean} visible=true - Whether or not the entity is rendered. If <code>true</code> then the entity is rendered.
|
* @property {boolean} visible=true - Whether or not the entity is rendered. If <code>true</code> then the entity is rendered.
|
||||||
* @property {boolean} canCastShadows=true - Whether or not the entity casts shadows. Currently applicable only to
|
* @property {boolean} canCastShadow=true - Whether or not the entity can cast a shadow. Currently applicable only to
|
||||||
* {@link Entities.EntityType|Model} and {@link Entities.EntityType|Shape} entities. Shadows are cast if inside a
|
* {@link Entities.EntityType|Model} and {@link Entities.EntityType|Shape} entities. Shadows are cast if inside a
|
||||||
* {@link Entities.EntityType|Zone} entity with <code>castShadows</code> enabled in its
|
* {@link Entities.EntityType|Zone} entity with <code>castShadows</code> enabled in its
|
||||||
* {@link Entities.EntityProperties-Zone|keyLight} property.
|
* {@link Entities.EntityProperties-Zone|keyLight} property.
|
||||||
|
* @property {boolean} isVisibleInSecondaryCamera=true - Whether or not the entity is rendered in the secondary camera. If <code>true</code> then the entity is rendered.
|
||||||
*
|
*
|
||||||
* @property {Vec3} position=0,0,0 - The position of the entity.
|
* @property {Vec3} position=0,0,0 - The position of the entity.
|
||||||
* @property {Quat} rotation=0,0,0,1 - The orientation of the entity with respect to world coordinates.
|
* @property {Quat} rotation=0,0,0,1 - The orientation of the entity with respect to world coordinates.
|
||||||
|
@ -1400,7 +1401,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* The axis-aligned bounding box of an entity.
|
* The axis-aligned bounding box of an entity.
|
||||||
* @typedef Entities.BoundingBox
|
* @typedef {object} Entities.BoundingBox
|
||||||
* @property {Vec3} brn - The bottom right near (minimum axes values) corner of the AA box.
|
* @property {Vec3} brn - The bottom right near (minimum axes values) corner of the AA box.
|
||||||
* @property {Vec3} tfl - The top far left (maximum axes values) corner of the AA box.
|
* @property {Vec3} tfl - The top far left (maximum axes values) corner of the AA box.
|
||||||
* @property {Vec3} center - The center of the AA box.
|
* @property {Vec3} center - The center of the AA box.
|
||||||
|
@ -1522,7 +1523,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionless, bool, setCollisionless);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionless, bool, setCollisionless);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(ignoreForCollisions, bool, setCollisionless, getCollisionless); // legacy support
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(ignoreForCollisions, bool, setCollisionless, getCollisionless); // legacy support
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionMask, uint8_t, setCollisionMask);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionMask, uint16_t, setCollisionMask);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(collidesWith, CollisionMask);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(collidesWith, CollisionMask);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(collisionsWillMove, bool, setDynamic, getDynamic); // legacy support
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(collisionsWillMove, bool, setDynamic, getDynamic); // legacy support
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(dynamic, bool, setDynamic);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(dynamic, bool, setDynamic);
|
||||||
|
@ -2581,7 +2582,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONLESS, bool, setCollisionless);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONLESS, bool, setCollisionless);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_MASK, uint8_t, setCollisionMask);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_MASK, uint16_t, setCollisionMask);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DYNAMIC, bool, setDynamic);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DYNAMIC, bool, setDynamic);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData);
|
||||||
|
|
|
@ -148,7 +148,7 @@ public:
|
||||||
DEFINE_PROPERTY_REF(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY);
|
DEFINE_PROPERTY_REF(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY);
|
||||||
DEFINE_PROPERTY(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING);
|
DEFINE_PROPERTY(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING);
|
||||||
DEFINE_PROPERTY(PROP_COLLISIONLESS, Collisionless, collisionless, bool, ENTITY_ITEM_DEFAULT_COLLISIONLESS);
|
DEFINE_PROPERTY(PROP_COLLISIONLESS, Collisionless, collisionless, bool, ENTITY_ITEM_DEFAULT_COLLISIONLESS);
|
||||||
DEFINE_PROPERTY(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint8_t, ENTITY_COLLISION_MASK_DEFAULT);
|
DEFINE_PROPERTY(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint16_t, ENTITY_COLLISION_MASK_DEFAULT);
|
||||||
DEFINE_PROPERTY(PROP_DYNAMIC, Dynamic, dynamic, bool, ENTITY_ITEM_DEFAULT_DYNAMIC);
|
DEFINE_PROPERTY(PROP_DYNAMIC, Dynamic, dynamic, bool, ENTITY_ITEM_DEFAULT_DYNAMIC);
|
||||||
DEFINE_PROPERTY(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool, LightEntityItem::DEFAULT_IS_SPOTLIGHT);
|
DEFINE_PROPERTY(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool, LightEntityItem::DEFAULT_IS_SPOTLIGHT);
|
||||||
DEFINE_PROPERTY(PROP_INTENSITY, Intensity, intensity, float, LightEntityItem::DEFAULT_INTENSITY);
|
DEFINE_PROPERTY(PROP_INTENSITY, Intensity, intensity, float, LightEntityItem::DEFAULT_INTENSITY);
|
||||||
|
|
|
@ -1688,15 +1688,21 @@ QVector<QUuid> EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) {
|
||||||
if (!_entityTree) {
|
if (!_entityTree) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID);
|
|
||||||
if (!entity) {
|
|
||||||
qCDebug(entities) << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
_entityTree->withReadLock([&] {
|
_entityTree->withReadLock([&] {
|
||||||
entity->forEachChild([&](SpatiallyNestablePointer child) {
|
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||||
|
if (!parentFinder) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool success;
|
||||||
|
SpatiallyNestableWeakPointer parentWP = parentFinder->find(parentID, success);
|
||||||
|
if (!success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SpatiallyNestablePointer parent = parentWP.lock();
|
||||||
|
if (!parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parent->forEachChild([&](SpatiallyNestablePointer child) {
|
||||||
result.push_back(child->getID());
|
result.push_back(child->getID());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1226,12 +1226,11 @@ public slots:
|
||||||
|
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Get the IDs of entities, overlays, and avatars that are directly parented to an entity. To get all descendants of an
|
* Get the IDs of entities, overlays, and avatars that are directly parented to an entity, overlay, or avatar model. Recurse on the IDs returned by the function to get all descendants of an entity, overlay, or avatar.
|
||||||
* entity, recurse on the IDs returned by the function.
|
|
||||||
* @function Entities.getChildrenIDs
|
* @function Entities.getChildrenIDs
|
||||||
* @param {Uuid} parentID - The ID of the entity to get the children IDs of.
|
* @param {Uuid} parentID - The ID of the entity, overlay, or avatar to get the children IDs of.
|
||||||
* @returns {Uuid[]} An array of entity, overlay, and avatar IDs that are parented directly to the <code>parentID</code>
|
* @returns {Uuid[]} An array of entity, overlay, and avatar IDs that are parented directly to the <code>parentID</code>
|
||||||
* entity. Does not include children's children, etc. The array is empty if no children can be found or
|
* entity, overlay, or avatar. Does not include children's children, etc. The array is empty if no children can be found or
|
||||||
* <code>parentID</code> cannot be found.
|
* <code>parentID</code> cannot be found.
|
||||||
* @example <caption>Report the children of an entity.</caption>
|
* @example <caption>Report the children of an entity.</caption>
|
||||||
* function createEntity(description, position, parent) {
|
* function createEntity(description, position, parent) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ class ReadBitstreamToTreeParams;
|
||||||
* @property {Vec3} direction=0,-1,0 - The direction the light is shining.
|
* @property {Vec3} direction=0,-1,0 - The direction the light is shining.
|
||||||
* @property {boolean} castShadows=false - If <code>true</code> then shadows are cast. Shadows are cast by avatars, plus
|
* @property {boolean} castShadows=false - If <code>true</code> then shadows are cast. Shadows are cast by avatars, plus
|
||||||
* {@link Entities.EntityType|Model} and {@link Entities.EntityType|Shape} entities that have their
|
* {@link Entities.EntityType|Model} and {@link Entities.EntityType|Shape} entities that have their
|
||||||
* <code>{@link Entities.EntityProperties|canCastShadows}</code> property set to <code>true</code>.
|
* <code>{@link Entities.EntityProperties|canCastShadow}</code> property set to <code>true</code>.
|
||||||
*/
|
*/
|
||||||
class KeyLightPropertyGroup : public PropertyGroup {
|
class KeyLightPropertyGroup : public PropertyGroup {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -258,6 +258,11 @@ public:
|
||||||
QHash<QString, size_t> texcoordSetMap;
|
QHash<QString, size_t> texcoordSetMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* @typedef {object} FBXAnimationFrame
|
||||||
|
* @property {Quat[]} rotations
|
||||||
|
* @property {Vec3[]} translations
|
||||||
|
*/
|
||||||
/// A single animation frame extracted from an FBX document.
|
/// A single animation frame extracted from an FBX document.
|
||||||
class FBXAnimationFrame {
|
class FBXAnimationFrame {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1174,7 +1174,7 @@ bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int byteL
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GLTFAccessorComponentType::UNSIGNED_INT: {
|
case GLTFAccessorComponentType::UNSIGNED_INT: {
|
||||||
readArray<quint8>(bin, byteOffset, byteLength, outarray, accessorType);
|
readArray<quint32>(bin, byteOffset, byteLength, outarray, accessorType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GLTFAccessorComponentType::UNSIGNED_SHORT: {
|
case GLTFAccessorComponentType::UNSIGNED_SHORT: {
|
||||||
|
|
|
@ -190,7 +190,7 @@ namespace GLTFBufferViewTarget {
|
||||||
struct GLTFBufferView {
|
struct GLTFBufferView {
|
||||||
int buffer; //required
|
int buffer; //required
|
||||||
int byteLength; //required
|
int byteLength; //required
|
||||||
int byteOffset;
|
int byteOffset { 0 };
|
||||||
int target;
|
int target;
|
||||||
QMap<QString, bool> defined;
|
QMap<QString, bool> defined;
|
||||||
void dump() {
|
void dump() {
|
||||||
|
@ -470,7 +470,7 @@ namespace GLTFAccessorComponentType {
|
||||||
}
|
}
|
||||||
struct GLTFAccessor {
|
struct GLTFAccessor {
|
||||||
int bufferView;
|
int bufferView;
|
||||||
int byteOffset;
|
int byteOffset { 0 };
|
||||||
int componentType; //required
|
int componentType; //required
|
||||||
int count; //required
|
int count; //required
|
||||||
int type; //required
|
int type; //required
|
||||||
|
|
|
@ -2,15 +2,64 @@
|
||||||
|
|
||||||
#include "GLLogging.h"
|
#include "GLLogging.h"
|
||||||
|
|
||||||
namespace gl {
|
#include <QtCore/QJsonDocument>
|
||||||
|
#include <QtCore/QJsonValue>
|
||||||
|
#include <QtCore/QJsonObject>
|
||||||
|
#include <QtCore/QFileInfo>
|
||||||
|
#include <QtCore/QCryptographicHash>
|
||||||
|
|
||||||
|
#include <shared/FileUtils.h>
|
||||||
|
|
||||||
|
using namespace gl;
|
||||||
|
|
||||||
|
void Uniform::load(GLuint glprogram, int index) {
|
||||||
|
const GLint NAME_LENGTH = 256;
|
||||||
|
GLchar glname[NAME_LENGTH];
|
||||||
|
GLint length = 0;
|
||||||
|
glGetActiveUniform(glprogram, index, NAME_LENGTH, &length, &size, &type, glname);
|
||||||
|
name = std::string(glname, length);
|
||||||
|
location = glGetUniformLocation(glprogram, glname);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uniforms gl::loadUniforms(GLuint glprogram) {
|
||||||
|
GLint uniformsCount = 0;
|
||||||
|
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
||||||
|
|
||||||
|
Uniforms result;
|
||||||
|
result.resize(uniformsCount);
|
||||||
|
for (int i = 0; i < uniformsCount; i++) {
|
||||||
|
result[i].load(glprogram, i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SEPARATE_PROGRAM
|
#ifdef SEPARATE_PROGRAM
|
||||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& message) {
|
bool gl::compileShader(GLenum shaderDomain,
|
||||||
|
const std::string& shaderSource,
|
||||||
|
GLuint& shaderObject,
|
||||||
|
GLuint& programObject,
|
||||||
|
std::string& message) {
|
||||||
|
return compileShader(shaderDomain, std::vector<std::string>{ shaderSource }, shaderObject, programObject, message);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& message) {
|
bool gl::compileShader(GLenum shaderDomain, const std::string& shaderSource, GLuint& shaderObject, std::string& message) {
|
||||||
|
return compileShader(shaderDomain, std::vector<std::string>{ shaderSource }, shaderObject, message);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (shaderSource.empty()) {
|
|
||||||
|
#ifdef SEPARATE_PROGRAM
|
||||||
|
bool gl::compileShader(GLenum shaderDomain,
|
||||||
|
const std::string& shaderSource,
|
||||||
|
GLuint& shaderObject,
|
||||||
|
GLuint& programObject,
|
||||||
|
std::string& message) {
|
||||||
|
#else
|
||||||
|
bool gl::compileShader(GLenum shaderDomain,
|
||||||
|
const std::vector<std::string>& shaderSources,
|
||||||
|
GLuint& shaderObject,
|
||||||
|
std::string& message) {
|
||||||
|
#endif
|
||||||
|
if (shaderSources.empty()) {
|
||||||
qCDebug(glLogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
|
qCDebug(glLogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -23,9 +72,11 @@ namespace gl {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign the source
|
// Assign the source
|
||||||
const int NUM_SOURCE_STRINGS = 2;
|
std::vector<const GLchar*> cstrs;
|
||||||
const GLchar* srcstr[] = { defines.c_str(), shaderSource.c_str() };
|
for (const auto& str : shaderSources) {
|
||||||
glShaderSource(glshader, NUM_SOURCE_STRINGS, srcstr, NULL);
|
cstrs.push_back(str.c_str());
|
||||||
|
}
|
||||||
|
glShaderSource(glshader, static_cast<GLint>(cstrs.size()), cstrs.data(), NULL);
|
||||||
|
|
||||||
// Compile !
|
// Compile !
|
||||||
glCompileShader(glshader);
|
glCompileShader(glshader);
|
||||||
|
@ -66,7 +117,7 @@ namespace gl {
|
||||||
|
|
||||||
qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
|
qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
|
||||||
int lineNumber = 0;
|
int lineNumber = 0;
|
||||||
for (auto s : srcstr) {
|
for (const auto& s : cstrs) {
|
||||||
QString str(s);
|
QString str(s);
|
||||||
QStringList lines = str.split("\n");
|
QStringList lines = str.split("\n");
|
||||||
for (auto& line : lines) {
|
for (auto& line : lines) {
|
||||||
|
@ -142,7 +193,7 @@ namespace gl {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message, std::vector<GLchar>& binary) {
|
GLuint gl::compileProgram(const std::vector<GLuint>& glshaders, std::string& message, CachedShader& cachedShader) {
|
||||||
// A brand new program:
|
// A brand new program:
|
||||||
GLuint glprogram = glCreateProgram();
|
GLuint glprogram = glCreateProgram();
|
||||||
if (!glprogram) {
|
if (!glprogram) {
|
||||||
|
@ -150,14 +201,21 @@ GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE);
|
bool binaryLoaded = false;
|
||||||
// Create the program from the sub shaders
|
|
||||||
for (auto so : glshaders) {
|
|
||||||
glAttachShader(glprogram, so);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link!
|
if (glshaders.empty() && cachedShader) {
|
||||||
glLinkProgram(glprogram);
|
glProgramBinary(glprogram, cachedShader.format, cachedShader.binary.data(), (GLsizei)cachedShader.binary.size());
|
||||||
|
binaryLoaded = true;
|
||||||
|
} else {
|
||||||
|
// glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE);
|
||||||
|
// Create the program from the sub shaders
|
||||||
|
for (auto so : glshaders) {
|
||||||
|
glAttachShader(glprogram, so);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link!
|
||||||
|
glLinkProgram(glprogram);
|
||||||
|
}
|
||||||
|
|
||||||
GLint linked = 0;
|
GLint linked = 0;
|
||||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||||
|
@ -205,25 +263,73 @@ GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message
|
||||||
}
|
}
|
||||||
|
|
||||||
// If linked get the binaries
|
// If linked get the binaries
|
||||||
if (linked) {
|
if (linked && !binaryLoaded) {
|
||||||
GLint binaryLength = 0;
|
GLint binaryLength = 0;
|
||||||
glGetProgramiv(glprogram, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
glGetProgramiv(glprogram, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
||||||
|
|
||||||
if (binaryLength > 0) {
|
if (binaryLength > 0) {
|
||||||
GLint numBinFormats = 0;
|
cachedShader.binary.resize(binaryLength);
|
||||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinFormats);
|
glGetProgramBinary(glprogram, binaryLength, NULL, &cachedShader.format, cachedShader.binary.data());
|
||||||
if (numBinFormats > 0) {
|
|
||||||
binary.resize(binaryLength);
|
|
||||||
std::vector<GLint> binFormats(numBinFormats);
|
|
||||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, binFormats.data());
|
|
||||||
|
|
||||||
GLenum programBinFormat;
|
|
||||||
glGetProgramBinary(glprogram, binaryLength, NULL, &programBinFormat, binary.data());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return glprogram;
|
return glprogram;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString& getShaderCacheFile() {
|
||||||
|
static const QString SHADER_CACHE_FOLDER{ "shaders" };
|
||||||
|
static const QString SHADER_CACHE_FILE_NAME{ "cache.json" };
|
||||||
|
static const QString SHADER_CACHE_FILE = FileUtils::standardPath(SHADER_CACHE_FOLDER) + SHADER_CACHE_FILE_NAME;
|
||||||
|
return SHADER_CACHE_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* SHADER_JSON_TYPE_KEY = "type";
|
||||||
|
static const char* SHADER_JSON_SOURCE_KEY = "source";
|
||||||
|
static const char* SHADER_JSON_DATA_KEY = "data";
|
||||||
|
|
||||||
|
void gl::loadShaderCache(ShaderCache& cache) {
|
||||||
|
QString shaderCacheFile = getShaderCacheFile();
|
||||||
|
if (QFileInfo(shaderCacheFile).exists()) {
|
||||||
|
QString json = FileUtils::readFile(shaderCacheFile);
|
||||||
|
auto root = QJsonDocument::fromJson(json.toUtf8()).object();
|
||||||
|
for (const auto& qhash : root.keys()) {
|
||||||
|
auto programObject = root[qhash].toObject();
|
||||||
|
QByteArray qbinary = QByteArray::fromBase64(programObject[SHADER_JSON_DATA_KEY].toString().toUtf8());
|
||||||
|
std::string hash = qhash.toStdString();
|
||||||
|
auto& cachedShader = cache[hash];
|
||||||
|
cachedShader.binary.resize(qbinary.size());
|
||||||
|
memcpy(cachedShader.binary.data(), qbinary.data(), qbinary.size());
|
||||||
|
cachedShader.format = (GLenum)programObject[SHADER_JSON_TYPE_KEY].toInt();
|
||||||
|
cachedShader.source = programObject[SHADER_JSON_SOURCE_KEY].toString().toStdString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl::saveShaderCache(const ShaderCache& cache) {
|
||||||
|
QByteArray json;
|
||||||
|
{
|
||||||
|
QVariantMap variantMap;
|
||||||
|
for (const auto& entry : cache) {
|
||||||
|
const auto& key = entry.first;
|
||||||
|
const auto& type = entry.second.format;
|
||||||
|
const auto& binary = entry.second.binary;
|
||||||
|
QVariantMap qentry;
|
||||||
|
qentry[SHADER_JSON_TYPE_KEY] = QVariant(type);
|
||||||
|
qentry[SHADER_JSON_SOURCE_KEY] = QString(entry.second.source.c_str());
|
||||||
|
qentry[SHADER_JSON_DATA_KEY] = QByteArray{ binary.data(), (int)binary.size() }.toBase64();
|
||||||
|
variantMap[key.c_str()] = qentry;
|
||||||
|
}
|
||||||
|
json = QJsonDocument::fromVariant(variantMap).toJson(QJsonDocument::Indented);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!json.isEmpty()) {
|
||||||
|
QString shaderCacheFile = getShaderCacheFile();
|
||||||
|
QFile saveFile(shaderCacheFile);
|
||||||
|
saveFile.open(QFile::WriteOnly | QFile::Text | QFile::Truncate);
|
||||||
|
saveFile.write(json);
|
||||||
|
saveFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gl::getShaderHash(const std::string& shaderSource) {
|
||||||
|
return QCryptographicHash::hash(QByteArray(shaderSource.c_str()), QCryptographicHash::Md5).toBase64().toStdString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,15 +14,47 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace gl {
|
namespace gl {
|
||||||
|
|
||||||
|
struct Uniform {
|
||||||
|
std::string name;
|
||||||
|
GLint size{ -1 };
|
||||||
|
GLenum type{ GL_FLOAT };
|
||||||
|
GLint location{ -1 };
|
||||||
|
void load(GLuint glprogram, int index);
|
||||||
|
};
|
||||||
|
|
||||||
|
using Uniforms = std::vector<Uniform>;
|
||||||
|
|
||||||
|
Uniforms loadUniforms(GLuint glprogram);
|
||||||
|
|
||||||
|
struct CachedShader {
|
||||||
|
GLenum format{ 0 };
|
||||||
|
std::string source;
|
||||||
|
std::vector<char> binary;
|
||||||
|
inline operator bool() const {
|
||||||
|
return format != 0 && !binary.empty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using ShaderCache = std::unordered_map<std::string, CachedShader>;
|
||||||
|
|
||||||
|
std::string getShaderHash(const std::string& shaderSource);
|
||||||
|
void loadShaderCache(ShaderCache& cache);
|
||||||
|
void saveShaderCache(const ShaderCache& cache);
|
||||||
|
|
||||||
|
|
||||||
#ifdef SEPARATE_PROGRAM
|
#ifdef SEPARATE_PROGRAM
|
||||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& message);
|
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, GLuint &shaderObject, GLuint &programObject, std::string& message);
|
||||||
|
bool compileShader(GLenum shaderDomain, const std::vector<std::string>& shaderSources, GLuint &shaderObject, GLuint &programObject, std::string& message);
|
||||||
#else
|
#else
|
||||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& message);
|
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, GLuint &shaderObject, std::string& message);
|
||||||
|
bool compileShader(GLenum shaderDomain, const std::vector<std::string>& shaderSources, GLuint &shaderObject, std::string& message);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message, std::vector<GLchar>& binary);
|
GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message, CachedShader& binary);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,13 +124,16 @@ void GLBackend::init() {
|
||||||
GLBackend::GLBackend() {
|
GLBackend::GLBackend() {
|
||||||
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
||||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment);
|
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment);
|
||||||
|
initShaderBinaryCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLBackend::~GLBackend() {}
|
||||||
|
|
||||||
GLBackend::~GLBackend() {
|
void GLBackend::shutdown() {
|
||||||
killInput();
|
killInput();
|
||||||
killTransform();
|
killTransform();
|
||||||
killTextureManagementStage();
|
killTextureManagementStage();
|
||||||
|
killShaderBinaryCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::renderPassTransfer(const Batch& batch) {
|
void GLBackend::renderPassTransfer(const Batch& batch) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <QtCore/QLoggingCategory>
|
#include <QtCore/QLoggingCategory>
|
||||||
|
|
||||||
#include <gl/Config.h>
|
#include <gl/Config.h>
|
||||||
|
#include <gl/GLShaders.h>
|
||||||
|
|
||||||
#include <gpu/Forward.h>
|
#include <gpu/Forward.h>
|
||||||
#include <gpu/Context.h>
|
#include <gpu/Context.h>
|
||||||
|
@ -71,6 +72,9 @@ public:
|
||||||
|
|
||||||
virtual ~GLBackend();
|
virtual ~GLBackend();
|
||||||
|
|
||||||
|
// Shutdown rendering and persist any required resources
|
||||||
|
void shutdown() override;
|
||||||
|
|
||||||
void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false);
|
void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false);
|
||||||
void render(const Batch& batch) final override;
|
void render(const Batch& batch) final override;
|
||||||
|
|
||||||
|
@ -455,6 +459,13 @@ protected:
|
||||||
virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
|
virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
|
||||||
virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
|
virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
|
||||||
virtual std::string getBackendShaderHeader() const = 0;
|
virtual std::string getBackendShaderHeader() const = 0;
|
||||||
|
// For a program, this will return a string containing all the source files (without any
|
||||||
|
// backend headers or defines). For a vertex, fragment or geometry shader, this will
|
||||||
|
// return the fully customized shader with all the version and backend specific
|
||||||
|
// preprocessor directives
|
||||||
|
// The program string returned can be used as a key for a cache of shader binaries
|
||||||
|
// The shader strings can be reliably sent to the low level `compileShader` functions
|
||||||
|
virtual std::string getShaderSource(const Shader& shader, int version) final;
|
||||||
virtual void makeProgramBindings(ShaderObject& shaderObject);
|
virtual void makeProgramBindings(ShaderObject& shaderObject);
|
||||||
class ElementResource {
|
class ElementResource {
|
||||||
public:
|
public:
|
||||||
|
@ -465,12 +476,12 @@ protected:
|
||||||
ElementResource getFormatFromGLUniform(GLenum gltype);
|
ElementResource getFormatFromGLUniform(GLenum gltype);
|
||||||
static const GLint UNUSED_SLOT {-1};
|
static const GLint UNUSED_SLOT {-1};
|
||||||
static bool isUnusedSlot(GLint binding) { return (binding == UNUSED_SLOT); }
|
static bool isUnusedSlot(GLint binding) { return (binding == UNUSED_SLOT); }
|
||||||
virtual int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
|
virtual int makeUniformSlots(const ShaderObject& program, const Shader::BindingSet& slotBindings,
|
||||||
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers);
|
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers);
|
||||||
virtual int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers);
|
virtual int makeUniformBlockSlots(const ShaderObject& program, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers);
|
||||||
virtual int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& resourceBuffers) = 0;
|
virtual int makeResourceBufferSlots(const ShaderObject& program, const Shader::BindingSet& slotBindings, Shader::SlotSet& resourceBuffers) = 0;
|
||||||
virtual int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs);
|
virtual int makeInputSlots(const ShaderObject& program, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs);
|
||||||
virtual int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs);
|
virtual int makeOutputSlots(const ShaderObject& program, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs);
|
||||||
|
|
||||||
|
|
||||||
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
||||||
|
@ -489,6 +500,19 @@ protected:
|
||||||
|
|
||||||
void resetStages();
|
void resetStages();
|
||||||
|
|
||||||
|
// Stores cached binary versions of the shaders for quicker startup on subsequent runs
|
||||||
|
// Note that shaders in the cache can still fail to load due to hardware or driver
|
||||||
|
// changes that invalidate the cached binary, in which case we fall back on compiling
|
||||||
|
// the source again
|
||||||
|
struct ShaderBinaryCache {
|
||||||
|
std::mutex _mutex;
|
||||||
|
std::vector<GLint> _formats;
|
||||||
|
std::unordered_map<std::string, ::gl::CachedShader> _binaries;
|
||||||
|
} _shaderBinaryCache;
|
||||||
|
|
||||||
|
virtual void initShaderBinaryCache();
|
||||||
|
virtual void killShaderBinaryCache();
|
||||||
|
|
||||||
struct TextureManagementStageState {
|
struct TextureManagementStageState {
|
||||||
bool _sparseCapable { false };
|
bool _sparseCapable { false };
|
||||||
GLTextureTransferEnginePointer _transferEngine;
|
GLTextureTransferEnginePointer _transferEngine;
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
using namespace gpu::gl;
|
using namespace gpu::gl;
|
||||||
|
using CachedShader = ::gl::CachedShader;
|
||||||
|
|
||||||
|
|
||||||
// Shader domain
|
// Shader domain
|
||||||
static const size_t NUM_SHADER_DOMAINS = 3;
|
static const size_t NUM_SHADER_DOMAINS = 3;
|
||||||
|
@ -68,9 +70,45 @@ static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
|
||||||
stereoVersion
|
stereoVersion
|
||||||
} };
|
} };
|
||||||
|
|
||||||
|
static std::string getShaderTypeString(Shader::Type type) {
|
||||||
|
switch (type) {
|
||||||
|
case Shader::Type::VERTEX:
|
||||||
|
return "vertex";
|
||||||
|
case Shader::Type::PIXEL:
|
||||||
|
return "pixel";
|
||||||
|
case Shader::Type::GEOMETRY:
|
||||||
|
return "geometry";
|
||||||
|
case Shader::Type::PROGRAM:
|
||||||
|
return "program";
|
||||||
|
default:
|
||||||
|
qFatal("Unexpected shader type %d", type);
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GLBackend::getShaderSource(const Shader& shader, int version) {
|
||||||
|
if (shader.isProgram()) {
|
||||||
|
std::string result;
|
||||||
|
result.append("// VERSION " + std::to_string(version));
|
||||||
|
for (const auto& subShader : shader.getShaders()) {
|
||||||
|
result.append("//-------- ");
|
||||||
|
result.append(getShaderTypeString(subShader->getType()));
|
||||||
|
result.append("\n");
|
||||||
|
result.append(subShader->getSource().getCode());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string shaderDefines = getBackendShaderHeader() + "\n"
|
||||||
|
+ (supportsBindless() ? textureTableVersion : "\n")
|
||||||
|
+ DOMAIN_DEFINES[shader.getType()] + "\n"
|
||||||
|
+ VERSION_DEFINES[version];
|
||||||
|
|
||||||
|
return shaderDefines + "\n" + shader.getSource().getCode();
|
||||||
|
}
|
||||||
|
|
||||||
GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) {
|
GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) {
|
||||||
// Any GLSLprogram ? normally yes...
|
// Any GLSLprogram ? normally yes...
|
||||||
const std::string& shaderSource = shader.getSource().getCode();
|
|
||||||
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
|
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
|
||||||
GLShader::ShaderObjects shaderObjects;
|
GLShader::ShaderObjects shaderObjects;
|
||||||
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
|
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
|
||||||
|
@ -78,11 +116,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co
|
||||||
|
|
||||||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
for (int version = 0; version < GLShader::NumVersions; version++) {
|
||||||
auto& shaderObject = shaderObjects[version];
|
auto& shaderObject = shaderObjects[version];
|
||||||
|
auto shaderSource = getShaderSource(shader, version);
|
||||||
std::string shaderDefines = getBackendShaderHeader() + "\n"
|
|
||||||
+ (supportsBindless() ? textureTableVersion : "\n")
|
|
||||||
+ DOMAIN_DEFINES[shader.getType()] + "\n"
|
|
||||||
+ VERSION_DEFINES[version];
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
bool retest = true;
|
bool retest = true;
|
||||||
std::string currentSrc = shaderSource;
|
std::string currentSrc = shaderSource;
|
||||||
|
@ -90,7 +124,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co
|
||||||
// The retest bool is set to false as soon as the compilation succeed to wexit the while loop.
|
// The retest bool is set to false as soon as the compilation succeed to wexit the while loop.
|
||||||
// The handler tells us if we should retry or not while returning a modified version of the source.
|
// The handler tells us if we should retry or not while returning a modified version of the source.
|
||||||
while (retest) {
|
while (retest) {
|
||||||
bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
|
bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderObject.glshader, compilationLogs[version].message);
|
||||||
compilationLogs[version].compiled = result;
|
compilationLogs[version].compiled = result;
|
||||||
if (!result) {
|
if (!result) {
|
||||||
std::string newSrc;
|
std::string newSrc;
|
||||||
|
@ -101,7 +135,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
|
compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderObject.glshader, compilationLogs[version].message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!compilationLogs[version].compiled) {
|
if (!compilationLogs[version].compiled) {
|
||||||
|
@ -120,43 +154,80 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::atomic<size_t> gpuBinaryShadersLoaded;
|
||||||
|
|
||||||
GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler) {
|
GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler) {
|
||||||
if (!program.isProgram()) {
|
if (!program.isProgram()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLShader::ShaderObjects programObjects;
|
GLShader::ShaderObjects programObjects;
|
||||||
|
|
||||||
program.incrementCompilationAttempt();
|
program.incrementCompilationAttempt();
|
||||||
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
|
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
|
||||||
|
|
||||||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
for (int version = 0; version < GLShader::NumVersions; version++) {
|
||||||
auto& programObject = programObjects[version];
|
auto& programObject = programObjects[version];
|
||||||
|
auto programSource = getShaderSource(program, version);
|
||||||
|
auto hash = ::gl::getShaderHash(programSource);
|
||||||
|
|
||||||
// Let's go through every shaders and make sure they are ready to go
|
CachedShader cachedBinary;
|
||||||
std::vector< GLuint > shaderGLObjects;
|
{
|
||||||
for (auto subShader : program.getShaders()) {
|
Lock shaderCacheLock{ _shaderBinaryCache._mutex };
|
||||||
auto object = GLShader::sync((*this), *subShader, handler);
|
if (_shaderBinaryCache._binaries.count(hash) != 0) {
|
||||||
if (object) {
|
cachedBinary = _shaderBinaryCache._binaries[hash];
|
||||||
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
|
}
|
||||||
} else {
|
}
|
||||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?";
|
|
||||||
compilationLogs[version].compiled = false;
|
|
||||||
compilationLogs[version].message = std::string("Failed to compile, one of the shaders of the program is not compiled ?");
|
GLuint glprogram = 0;
|
||||||
program.setCompilationLogs(compilationLogs);
|
|
||||||
return nullptr;
|
// If we have a cached binary program, try to load it instead of compiling the individual shaders
|
||||||
|
if (cachedBinary) {
|
||||||
|
glprogram = ::gl::compileProgram({}, compilationLogs[version].message, cachedBinary);
|
||||||
|
if (0 != glprogram) {
|
||||||
|
++gpuBinaryShadersLoaded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have no program, then either no cached binary, or the binary failed to load (perhaps a GPU driver update invalidated the cache)
|
||||||
|
if (0 == glprogram) {
|
||||||
|
cachedBinary = CachedShader();
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> shaderCacheLock{ _shaderBinaryCache._mutex };
|
||||||
|
_shaderBinaryCache._binaries.erase(hash);
|
||||||
|
}
|
||||||
|
// Let's go through every shaders and make sure they are ready to go
|
||||||
|
std::vector<GLuint> shaderGLObjects;
|
||||||
|
shaderGLObjects.reserve(program.getShaders().size());
|
||||||
|
for (auto subShader : program.getShaders()) {
|
||||||
|
auto object = GLShader::sync((*this), *subShader, handler);
|
||||||
|
if (object) {
|
||||||
|
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
|
||||||
|
} else {
|
||||||
|
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?";
|
||||||
|
compilationLogs[version].compiled = false;
|
||||||
|
compilationLogs[version].message = std::string("Failed to compile, one of the shaders of the program is not compiled ?");
|
||||||
|
program.setCompilationLogs(compilationLogs);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glprogram = ::gl::compileProgram(shaderGLObjects, compilationLogs[version].message, cachedBinary);
|
||||||
|
if (cachedBinary) {
|
||||||
|
cachedBinary.source = programSource;
|
||||||
|
std::unique_lock<std::mutex> shaderCacheLock{ _shaderBinaryCache._mutex };
|
||||||
|
_shaderBinaryCache._binaries[hash] = cachedBinary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint glprogram = ::gl::compileProgram(shaderGLObjects, compilationLogs[version].message, compilationLogs[version].binary);
|
|
||||||
if (glprogram == 0) {
|
if (glprogram == 0) {
|
||||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str();
|
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str();
|
||||||
program.setCompilationLogs(compilationLogs);
|
program.setCompilationLogs(compilationLogs);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
compilationLogs[version].compiled = true;
|
compilationLogs[version].compiled = true;
|
||||||
programObject.glprogram = glprogram;
|
programObject.glprogram = glprogram;
|
||||||
|
|
||||||
makeProgramBindings(programObject);
|
makeProgramBindings(programObject);
|
||||||
}
|
}
|
||||||
// Compilation feedback
|
// Compilation feedback
|
||||||
|
@ -338,20 +409,15 @@ GLBackend::ElementResource GLBackend::getFormatFromGLUniform(GLenum gltype) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int GLBackend::makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
|
int GLBackend::makeUniformSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,
|
||||||
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) {
|
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) {
|
||||||
GLint uniformsCount = 0;
|
auto& glprogram = shaderProgram.glprogram;
|
||||||
|
|
||||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
for (const auto& uniform : shaderProgram.uniforms) {
|
||||||
|
const auto& type = uniform.type;
|
||||||
for (int i = 0; i < uniformsCount; i++) {
|
const auto& location = uniform.location;
|
||||||
const GLint NAME_LENGTH = 256;
|
const auto& size = uniform.size;
|
||||||
GLchar name[NAME_LENGTH];
|
const auto& name = uniform.name;
|
||||||
GLint length = 0;
|
|
||||||
GLint size = 0;
|
|
||||||
GLenum type = 0;
|
|
||||||
glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
|
||||||
GLint location = glGetUniformLocation(glprogram, name);
|
|
||||||
const GLint INVALID_UNIFORM_LOCATION = -1;
|
const GLint INVALID_UNIFORM_LOCATION = -1;
|
||||||
|
|
||||||
// Try to make sense of the gltype
|
// Try to make sense of the gltype
|
||||||
|
@ -359,8 +425,8 @@ int GLBackend::makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slot
|
||||||
|
|
||||||
// The uniform as a standard var type
|
// The uniform as a standard var type
|
||||||
if (location != INVALID_UNIFORM_LOCATION) {
|
if (location != INVALID_UNIFORM_LOCATION) {
|
||||||
|
auto sname = uniform.name;
|
||||||
// Let's make sure the name doesn't contains an array element
|
// Let's make sure the name doesn't contains an array element
|
||||||
std::string sname(name);
|
|
||||||
auto foundBracket = sname.find_first_of('[');
|
auto foundBracket = sname.find_first_of('[');
|
||||||
if (foundBracket != std::string::npos) {
|
if (foundBracket != std::string::npos) {
|
||||||
// std::string arrayname = sname.substr(0, foundBracket);
|
// std::string arrayname = sname.substr(0, foundBracket);
|
||||||
|
@ -397,10 +463,11 @@ int GLBackend::makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return uniformsCount;
|
return static_cast<uint32_t>(shaderProgram.uniforms.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
int GLBackend::makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) {
|
int GLBackend::makeUniformBlockSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) {
|
||||||
|
const auto& glprogram = shaderProgram.glprogram;
|
||||||
GLint buffersCount = 0;
|
GLint buffersCount = 0;
|
||||||
|
|
||||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount);
|
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount);
|
||||||
|
@ -479,7 +546,8 @@ int GLBackend::makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet&
|
||||||
return buffersCount;
|
return buffersCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GLBackend::makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) {
|
int GLBackend::makeInputSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) {
|
||||||
|
const auto& glprogram = shaderProgram.glprogram;
|
||||||
GLint inputsCount = 0;
|
GLint inputsCount = 0;
|
||||||
|
|
||||||
glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount);
|
glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount);
|
||||||
|
@ -501,7 +569,7 @@ int GLBackend::makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBi
|
||||||
return inputsCount;
|
return inputsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GLBackend::makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) {
|
int GLBackend::makeOutputSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) {
|
||||||
/* GLint outputsCount = 0;
|
/* GLint outputsCount = 0;
|
||||||
|
|
||||||
glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount);
|
glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount);
|
||||||
|
@ -525,67 +593,19 @@ void GLBackend::makeProgramBindings(ShaderObject& shaderObject) {
|
||||||
if (!shaderObject.glprogram) {
|
if (!shaderObject.glprogram) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GLuint glprogram = shaderObject.glprogram;
|
}
|
||||||
GLint loc = -1;
|
|
||||||
|
|
||||||
//Check for gpu specific attribute slotBindings
|
void GLBackend::initShaderBinaryCache() {
|
||||||
loc = glGetAttribLocation(glprogram, "inPosition");
|
GLint numBinFormats = 0;
|
||||||
if (loc >= 0 && loc != gpu::Stream::POSITION) {
|
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinFormats);
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition");
|
if (numBinFormats > 0) {
|
||||||
}
|
_shaderBinaryCache._formats.resize(numBinFormats);
|
||||||
|
glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, _shaderBinaryCache._formats.data());
|
||||||
loc = glGetAttribLocation(glprogram, "inNormal");
|
}
|
||||||
if (loc >= 0 && loc != gpu::Stream::NORMAL) {
|
::gl::loadShaderCache(_shaderBinaryCache._binaries);
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal");
|
}
|
||||||
}
|
|
||||||
|
void GLBackend::killShaderBinaryCache() {
|
||||||
loc = glGetAttribLocation(glprogram, "inColor");
|
::gl::saveShaderCache(_shaderBinaryCache._binaries);
|
||||||
if (loc >= 0 && loc != gpu::Stream::COLOR) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inTexCoord0");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::TEXCOORD) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inTangent");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::TANGENT) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent");
|
|
||||||
}
|
|
||||||
|
|
||||||
char attribName[] = "inTexCoordn";
|
|
||||||
for (auto i = 0; i < 4; i++) {
|
|
||||||
auto streamId = gpu::Stream::TEXCOORD1 + i;
|
|
||||||
|
|
||||||
attribName[strlen(attribName) - 1] = '1' + i;
|
|
||||||
loc = glGetAttribLocation(glprogram, attribName);
|
|
||||||
if (loc >= 0 && loc != streamId) {
|
|
||||||
glBindAttribLocation(glprogram, streamId, attribName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inSkinClusterIndex");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inSkinClusterWeight");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "_drawCallInfo");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link again to take into account the assigned attrib location
|
|
||||||
glLinkProgram(glprogram);
|
|
||||||
|
|
||||||
GLint linked = 0;
|
|
||||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
|
||||||
if (!linked) {
|
|
||||||
qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,22 +68,23 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin
|
||||||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
for (int version = 0; version < GLShader::NumVersions; version++) {
|
||||||
auto& shaderObject = object->_shaderObjects[version];
|
auto& shaderObject = object->_shaderObjects[version];
|
||||||
if (shaderObject.glprogram) {
|
if (shaderObject.glprogram) {
|
||||||
|
shaderObject.uniforms = ::gl::loadUniforms(shaderObject.glprogram);
|
||||||
Shader::SlotSet buffers;
|
Shader::SlotSet buffers;
|
||||||
backend.makeUniformBlockSlots(shaderObject.glprogram, slotBindings, buffers);
|
backend.makeUniformBlockSlots(shaderObject, slotBindings, buffers);
|
||||||
|
|
||||||
Shader::SlotSet uniforms;
|
Shader::SlotSet uniforms;
|
||||||
Shader::SlotSet textures;
|
Shader::SlotSet textures;
|
||||||
Shader::SlotSet samplers;
|
Shader::SlotSet samplers;
|
||||||
backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers);
|
backend.makeUniformSlots(shaderObject, slotBindings, uniforms, textures, samplers);
|
||||||
|
|
||||||
Shader::SlotSet resourceBuffers;
|
Shader::SlotSet resourceBuffers;
|
||||||
backend.makeResourceBufferSlots(shaderObject.glprogram, slotBindings, resourceBuffers);
|
backend.makeResourceBufferSlots(shaderObject, slotBindings, resourceBuffers);
|
||||||
|
|
||||||
Shader::SlotSet inputs;
|
Shader::SlotSet inputs;
|
||||||
backend.makeInputSlots(shaderObject.glprogram, slotBindings, inputs);
|
backend.makeInputSlots(shaderObject, slotBindings, inputs);
|
||||||
|
|
||||||
Shader::SlotSet outputs;
|
Shader::SlotSet outputs;
|
||||||
backend.makeOutputSlots(shaderObject.glprogram, slotBindings, outputs);
|
backend.makeOutputSlots(shaderObject, slotBindings, outputs);
|
||||||
|
|
||||||
// Define the public slots only from the default version
|
// Define the public slots only from the default version
|
||||||
if (version == 0) {
|
if (version == 0) {
|
||||||
|
|
|
@ -9,14 +9,17 @@
|
||||||
#define hifi_gpu_gl_GLShader_h
|
#define hifi_gpu_gl_GLShader_h
|
||||||
|
|
||||||
#include "GLShared.h"
|
#include "GLShared.h"
|
||||||
|
#include <gl/GLShaders.h>
|
||||||
|
|
||||||
namespace gpu { namespace gl {
|
namespace gpu { namespace gl {
|
||||||
|
|
||||||
struct ShaderObject {
|
struct ShaderObject {
|
||||||
|
using Uniforms = ::gl::Uniforms;
|
||||||
GLuint glshader { 0 };
|
GLuint glshader { 0 };
|
||||||
GLuint glprogram { 0 };
|
GLuint glprogram { 0 };
|
||||||
GLint transformCameraSlot { -1 };
|
GLint transformCameraSlot { -1 };
|
||||||
GLint transformObjectSlot { -1 };
|
GLint transformObjectSlot { -1 };
|
||||||
|
Uniforms uniforms;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GLShader : public GPUObject {
|
class GLShader : public GPUObject {
|
||||||
|
|
|
@ -173,7 +173,7 @@ protected:
|
||||||
|
|
||||||
std::string getBackendShaderHeader() const override;
|
std::string getBackendShaderHeader() const override;
|
||||||
void makeProgramBindings(ShaderObject& shaderObject) override;
|
void makeProgramBindings(ShaderObject& shaderObject) override;
|
||||||
int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override;
|
int makeResourceBufferSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,20 +22,13 @@ std::string GL41Backend::getBackendShaderHeader() const {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GL41Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
int GL41Backend::makeResourceBufferSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
||||||
GLint ssboCount = 0;
|
GLint ssboCount = 0;
|
||||||
GLint uniformsCount = 0;
|
const auto& glprogram = shaderProgram.glprogram;
|
||||||
|
for (const auto& uniform : shaderProgram.uniforms) {
|
||||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
const auto& name = uniform.name;
|
||||||
|
const auto& type = uniform.type;
|
||||||
for (int i = 0; i < uniformsCount; i++) {
|
const auto& location = uniform.location;
|
||||||
const GLint NAME_LENGTH = 256;
|
|
||||||
GLchar name[NAME_LENGTH];
|
|
||||||
GLint length = 0;
|
|
||||||
GLint size = 0;
|
|
||||||
GLenum type = 0;
|
|
||||||
glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
|
||||||
GLint location = glGetUniformLocation(glprogram, name);
|
|
||||||
const GLint INVALID_UNIFORM_LOCATION = -1;
|
const GLint INVALID_UNIFORM_LOCATION = -1;
|
||||||
|
|
||||||
// Try to make sense of the gltype
|
// Try to make sense of the gltype
|
||||||
|
|
|
@ -31,6 +31,10 @@ bool GL41Backend::supportedTextureFormat(const gpu::Element& format) {
|
||||||
case gpu::Semantic::COMPRESSED_EAC_RED_SIGNED:
|
case gpu::Semantic::COMPRESSED_EAC_RED_SIGNED:
|
||||||
case gpu::Semantic::COMPRESSED_EAC_XY:
|
case gpu::Semantic::COMPRESSED_EAC_XY:
|
||||||
case gpu::Semantic::COMPRESSED_EAC_XY_SIGNED:
|
case gpu::Semantic::COMPRESSED_EAC_XY_SIGNED:
|
||||||
|
// The ARB_texture_compression_bptc extension is not supported on 4.1
|
||||||
|
// See https://www.g-truc.net/doc/OpenGL%204%20Hardware%20Matrix.pdf
|
||||||
|
case gpu::Semantic::COMPRESSED_BC6_RGB:
|
||||||
|
case gpu::Semantic::COMPRESSED_BC7_SRGBA:
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -274,7 +274,7 @@ protected:
|
||||||
// Shader Stage
|
// Shader Stage
|
||||||
std::string getBackendShaderHeader() const override;
|
std::string getBackendShaderHeader() const override;
|
||||||
void makeProgramBindings(ShaderObject& shaderObject) override;
|
void makeProgramBindings(ShaderObject& shaderObject) override;
|
||||||
int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override;
|
int makeResourceBufferSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override;
|
||||||
|
|
||||||
// Texture Management Stage
|
// Texture Management Stage
|
||||||
void initTextureManagementStage() override;
|
void initTextureManagementStage() override;
|
||||||
|
|
|
@ -27,7 +27,8 @@ std::string GL45Backend::getBackendShaderHeader() const {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GL45Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
int GL45Backend::makeResourceBufferSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
||||||
|
const auto& glprogram = shaderProgram.glprogram;
|
||||||
GLint buffersCount = 0;
|
GLint buffersCount = 0;
|
||||||
glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &buffersCount);
|
glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &buffersCount);
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ using namespace gpu::gl45;
|
||||||
|
|
||||||
bool GL45Backend::supportedTextureFormat(const gpu::Element& format) {
|
bool GL45Backend::supportedTextureFormat(const gpu::Element& format) {
|
||||||
switch (format.getSemantic()) {
|
switch (format.getSemantic()) {
|
||||||
|
// ETC textures are actually required by the OpenGL spec as of 4.3, but aren't always supported by hardware
|
||||||
|
// They'll be recompressed by OpenGL, which will be slow or have poor quality, so disable them for now
|
||||||
case gpu::Semantic::COMPRESSED_ETC2_RGB:
|
case gpu::Semantic::COMPRESSED_ETC2_RGB:
|
||||||
case gpu::Semantic::COMPRESSED_ETC2_SRGB:
|
case gpu::Semantic::COMPRESSED_ETC2_SRGB:
|
||||||
case gpu::Semantic::COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA:
|
case gpu::Semantic::COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA:
|
||||||
|
|
|
@ -164,7 +164,7 @@ protected:
|
||||||
|
|
||||||
std::string getBackendShaderHeader() const override;
|
std::string getBackendShaderHeader() const override;
|
||||||
void makeProgramBindings(ShaderObject& shaderObject) override;
|
void makeProgramBindings(ShaderObject& shaderObject) override;
|
||||||
int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override;
|
int makeResourceBufferSlots(const ShaderObject& shaderObject, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,20 +25,15 @@ std::string GLESBackend::getBackendShaderHeader() const {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GLESBackend::makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
int GLESBackend::makeResourceBufferSlots(const ShaderObject& shaderObject, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
||||||
GLint ssboCount = 0;
|
GLint ssboCount = 0;
|
||||||
GLint uniformsCount = 0;
|
GLint uniformsCount = 0;
|
||||||
|
const auto& glprogram = shaderObject.glprogram;
|
||||||
|
|
||||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
for (const auto& uniform : shaderObject.uniforms) {
|
||||||
|
const auto& type = uniform.type;
|
||||||
for (int i = 0; i < uniformsCount; i++) {
|
const auto& location = uniform.location;
|
||||||
const GLint NAME_LENGTH = 256;
|
const auto& name = uniform.name;
|
||||||
GLchar name[NAME_LENGTH];
|
|
||||||
GLint length = 0;
|
|
||||||
GLint size = 0;
|
|
||||||
GLenum type = 0;
|
|
||||||
glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
|
||||||
GLint location = glGetUniformLocation(glprogram, name);
|
|
||||||
const GLint INVALID_UNIFORM_LOCATION = -1;
|
const GLint INVALID_UNIFORM_LOCATION = -1;
|
||||||
|
|
||||||
// Try to make sense of the gltype
|
// Try to make sense of the gltype
|
||||||
|
|
|
@ -53,6 +53,13 @@ Context::~Context() {
|
||||||
_batchPool.clear();
|
_batchPool.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Context::shutdown() {
|
||||||
|
if (_backend) {
|
||||||
|
_backend->shutdown();
|
||||||
|
_backend.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& Context::getBackendVersion() const {
|
const std::string& Context::getBackendVersion() const {
|
||||||
return _backend->getVersion();
|
return _backend->getVersion();
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ class Backend {
|
||||||
public:
|
public:
|
||||||
virtual ~Backend(){};
|
virtual ~Backend(){};
|
||||||
|
|
||||||
|
virtual void shutdown() {}
|
||||||
virtual const std::string& getVersion() const = 0;
|
virtual const std::string& getVersion() const = 0;
|
||||||
|
|
||||||
void setStereoState(const StereoState& stereo) { _stereo = stereo; }
|
void setStereoState(const StereoState& stereo) { _stereo = stereo; }
|
||||||
|
@ -154,6 +155,7 @@ public:
|
||||||
Context();
|
Context();
|
||||||
~Context();
|
~Context();
|
||||||
|
|
||||||
|
void shutdown();
|
||||||
const std::string& getBackendVersion() const;
|
const std::string& getBackendVersion() const;
|
||||||
|
|
||||||
void beginFrame(const glm::mat4& renderView = glm::mat4(), const glm::mat4& renderPose = glm::mat4());
|
void beginFrame(const glm::mat4& renderView = glm::mat4(), const glm::mat4& renderPose = glm::mat4());
|
||||||
|
|
|
@ -54,13 +54,11 @@ public:
|
||||||
|
|
||||||
struct CompilationLog {
|
struct CompilationLog {
|
||||||
std::string message;
|
std::string message;
|
||||||
std::vector<char> binary;
|
|
||||||
bool compiled{ false };
|
bool compiled{ false };
|
||||||
|
|
||||||
CompilationLog() {}
|
CompilationLog() {}
|
||||||
CompilationLog(const CompilationLog& src) :
|
CompilationLog(const CompilationLog& src) :
|
||||||
message(src.message),
|
message(src.message),
|
||||||
binary(src.binary),
|
|
||||||
compiled(src.compiled) {}
|
compiled(src.compiled) {}
|
||||||
};
|
};
|
||||||
using CompilationLogs = std::vector<CompilationLog>;
|
using CompilationLogs = std::vector<CompilationLog>;
|
||||||
|
|
|
@ -279,7 +279,7 @@ controller::Input KeyboardMouseDevice::InputDevice::makeInput(KeyboardMouseDevic
|
||||||
* moved down. The data value is how far the average position of all touch points moved.</td></tr>
|
* moved down. The data value is how far the average position of all touch points moved.</td></tr>
|
||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* @typedef Controller.Hardware-Keyboard
|
* @typedef {object} Controller.Hardware-Keyboard
|
||||||
* @todo <em>Currently, the mouse wheel in an ordinary mouse generates left/right wheel events instead of up/down.</em>
|
* @todo <em>Currently, the mouse wheel in an ordinary mouse generates left/right wheel events instead of up/down.</em>
|
||||||
*/
|
*/
|
||||||
controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInputs() const {
|
controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInputs() const {
|
||||||
|
|
|
@ -179,7 +179,7 @@ public:
|
||||||
* @function ModelCache.prefetch
|
* @function ModelCache.prefetch
|
||||||
* @param {string} url - URL of the resource to prefetch.
|
* @param {string} url - URL of the resource to prefetch.
|
||||||
* @param {object} [extra=null]
|
* @param {object} [extra=null]
|
||||||
* @returns {Resource}
|
* @returns {ResourceObject}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
@ -188,7 +188,7 @@ public:
|
||||||
* @param {string} url - URL of the resource to load.
|
* @param {string} url - URL of the resource to load.
|
||||||
* @param {string} [fallback=""] - Fallback URL if load of the desired URL fails.
|
* @param {string} [fallback=""] - Fallback URL if load of the desired URL fails.
|
||||||
* @param {} [extra=null]
|
* @param {} [extra=null]
|
||||||
* @returns {Resource}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,7 @@ public:
|
||||||
* @function TextureCache.prefetch
|
* @function TextureCache.prefetch
|
||||||
* @param {string} url - URL of the resource to prefetch.
|
* @param {string} url - URL of the resource to prefetch.
|
||||||
* @param {object} [extra=null]
|
* @param {object} [extra=null]
|
||||||
* @returns {Resource}
|
* @returns {ResourceObject}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
@ -204,7 +204,7 @@ public:
|
||||||
* @param {string} url - URL of the resource to load.
|
* @param {string} url - URL of the resource to load.
|
||||||
* @param {string} [fallback=""] - Fallback URL if load of the desired URL fails.
|
* @param {string} [fallback=""] - Fallback URL if load of the desired URL fails.
|
||||||
* @param {} [extra=null]
|
* @param {} [extra=null]
|
||||||
* @returns {Resource}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ protected:
|
||||||
* @param {string} url
|
* @param {string} url
|
||||||
* @param {number} type
|
* @param {number} type
|
||||||
* @param {number} [maxNumPixels=67108864]
|
* @param {number} [maxNumPixels=67108864]
|
||||||
* @returns {Resource}
|
* @returns {ResourceObject}
|
||||||
*/
|
*/
|
||||||
// Overload ResourceCache::prefetch to allow specifying texture type for loads
|
// Overload ResourceCache::prefetch to allow specifying texture type for loads
|
||||||
Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
|
Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <QtCore/QStringList>
|
#include <QtCore/QStringList>
|
||||||
#include <QtCore/QStandardPaths>
|
#include <QtCore/QStandardPaths>
|
||||||
#include <QtCore/QUrlQuery>
|
#include <QtCore/QUrlQuery>
|
||||||
|
#include <QtCore/QThreadPool>
|
||||||
#include <QtNetwork/QHttpMultiPart>
|
#include <QtNetwork/QHttpMultiPart>
|
||||||
#include <QtNetwork/QNetworkRequest>
|
#include <QtNetwork/QNetworkRequest>
|
||||||
#include <qthread.h>
|
#include <qthread.h>
|
||||||
|
@ -743,6 +744,9 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure openssl/Qt config is set up.
|
||||||
|
QSslConfiguration::defaultConfiguration();
|
||||||
|
|
||||||
// make sure we don't already have an outbound keypair generation request
|
// make sure we don't already have an outbound keypair generation request
|
||||||
if (!_isWaitingForKeypairResponse) {
|
if (!_isWaitingForKeypairResponse) {
|
||||||
_isWaitingForKeypairResponse = true;
|
_isWaitingForKeypairResponse = true;
|
||||||
|
@ -751,94 +755,75 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI
|
||||||
qCDebug(networking) << "Clearing current private key in DataServerAccountInfo";
|
qCDebug(networking) << "Clearing current private key in DataServerAccountInfo";
|
||||||
_accountInfo.setPrivateKey(QByteArray());
|
_accountInfo.setPrivateKey(QByteArray());
|
||||||
|
|
||||||
// setup a new QThread to generate the keypair on, in case it takes a while
|
// Create a runnable keypair generated to create an RSA pair and exit.
|
||||||
QThread* generateThread = new QThread(this);
|
|
||||||
generateThread->setObjectName("Account Manager Generator Thread");
|
|
||||||
|
|
||||||
// setup a keypair generator
|
|
||||||
RSAKeypairGenerator* keypairGenerator = new RSAKeypairGenerator;
|
RSAKeypairGenerator* keypairGenerator = new RSAKeypairGenerator;
|
||||||
|
|
||||||
if (!isUserKeypair) {
|
if (!isUserKeypair) {
|
||||||
keypairGenerator->setDomainID(domainID);
|
|
||||||
_accountInfo.setDomainID(domainID);
|
_accountInfo.setDomainID(domainID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// start keypair generation when the thread starts
|
|
||||||
connect(generateThread, &QThread::started, keypairGenerator, &RSAKeypairGenerator::generateKeypair);
|
|
||||||
|
|
||||||
// handle success or failure of keypair generation
|
// handle success or failure of keypair generation
|
||||||
connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this, &AccountManager::processGeneratedKeypair);
|
connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this,
|
||||||
connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair,
|
&AccountManager::processGeneratedKeypair);
|
||||||
this, &AccountManager::handleKeypairGenerationError);
|
connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair, this,
|
||||||
|
&AccountManager::handleKeypairGenerationError);
|
||||||
connect(keypairGenerator, &QObject::destroyed, generateThread, &QThread::quit);
|
|
||||||
connect(generateThread, &QThread::finished, generateThread, &QThread::deleteLater);
|
|
||||||
|
|
||||||
keypairGenerator->moveToThread(generateThread);
|
|
||||||
|
|
||||||
qCDebug(networking) << "Starting worker thread to generate 2048-bit RSA keypair.";
|
qCDebug(networking) << "Starting worker thread to generate 2048-bit RSA keypair.";
|
||||||
generateThread->start();
|
// Start on Qt's global thread pool.
|
||||||
|
QThreadPool::globalInstance()->start(keypairGenerator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountManager::processGeneratedKeypair() {
|
void AccountManager::processGeneratedKeypair(QByteArray publicKey, QByteArray privateKey) {
|
||||||
|
|
||||||
qCDebug(networking) << "Generated 2048-bit RSA keypair. Uploading public key now.";
|
qCDebug(networking) << "Generated 2048-bit RSA keypair. Uploading public key now.";
|
||||||
|
|
||||||
RSAKeypairGenerator* keypairGenerator = qobject_cast<RSAKeypairGenerator*>(sender());
|
// hold the private key to later set our metaverse API account info if upload succeeds
|
||||||
|
_pendingPrivateKey = privateKey;
|
||||||
|
|
||||||
if (keypairGenerator) {
|
// upload the public key so data-web has an up-to-date key
|
||||||
// hold the private key to later set our metaverse API account info if upload succeeds
|
const QString USER_PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key";
|
||||||
_pendingPrivateKey = keypairGenerator->getPrivateKey();
|
const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key";
|
||||||
|
|
||||||
// upload the public key so data-web has an up-to-date key
|
QString uploadPath;
|
||||||
const QString USER_PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key";
|
const auto& domainID = _accountInfo.getDomainID();
|
||||||
const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key";
|
if (domainID.isNull()) {
|
||||||
|
uploadPath = USER_PUBLIC_KEY_UPDATE_PATH;
|
||||||
QString uploadPath;
|
|
||||||
const auto& domainID = keypairGenerator->getDomainID();
|
|
||||||
if (domainID.isNull()) {
|
|
||||||
uploadPath = USER_PUBLIC_KEY_UPDATE_PATH;
|
|
||||||
} else {
|
|
||||||
uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(domainID));
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup a multipart upload to send up the public key
|
|
||||||
QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
|
||||||
|
|
||||||
QHttpPart publicKeyPart;
|
|
||||||
publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
|
||||||
|
|
||||||
publicKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
|
||||||
QVariant("form-data; name=\"public_key\"; filename=\"public_key\""));
|
|
||||||
publicKeyPart.setBody(keypairGenerator->getPublicKey());
|
|
||||||
requestMultiPart->append(publicKeyPart);
|
|
||||||
|
|
||||||
if (!domainID.isNull()) {
|
|
||||||
const auto& key = getTemporaryDomainKey(domainID);
|
|
||||||
QHttpPart apiKeyPart;
|
|
||||||
publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
|
||||||
apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
|
||||||
QVariant("form-data; name=\"api_key\""));
|
|
||||||
apiKeyPart.setBody(key.toUtf8());
|
|
||||||
requestMultiPart->append(apiKeyPart);
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup callback parameters so we know once the keypair upload has succeeded or failed
|
|
||||||
JSONCallbackParameters callbackParameters;
|
|
||||||
callbackParameters.jsonCallbackReceiver = this;
|
|
||||||
callbackParameters.jsonCallbackMethod = "publicKeyUploadSucceeded";
|
|
||||||
callbackParameters.errorCallbackReceiver = this;
|
|
||||||
callbackParameters.errorCallbackMethod = "publicKeyUploadFailed";
|
|
||||||
|
|
||||||
sendRequest(uploadPath, AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation,
|
|
||||||
callbackParameters, QByteArray(), requestMultiPart);
|
|
||||||
|
|
||||||
keypairGenerator->deleteLater();
|
|
||||||
} else {
|
} else {
|
||||||
qCWarning(networking) << "Expected processGeneratedKeypair to be called by a live RSAKeypairGenerator"
|
uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(domainID));
|
||||||
<< "but the casted sender is NULL. Will not process generated keypair.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setup a multipart upload to send up the public key
|
||||||
|
QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||||
|
|
||||||
|
QHttpPart publicKeyPart;
|
||||||
|
publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||||
|
|
||||||
|
publicKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||||
|
QVariant("form-data; name=\"public_key\"; filename=\"public_key\""));
|
||||||
|
publicKeyPart.setBody(publicKey);
|
||||||
|
requestMultiPart->append(publicKeyPart);
|
||||||
|
|
||||||
|
// Currently broken? We don't have the temporary domain key.
|
||||||
|
if (!domainID.isNull()) {
|
||||||
|
const auto& key = getTemporaryDomainKey(domainID);
|
||||||
|
QHttpPart apiKeyPart;
|
||||||
|
publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||||
|
apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||||
|
QVariant("form-data; name=\"api_key\""));
|
||||||
|
apiKeyPart.setBody(key.toUtf8());
|
||||||
|
requestMultiPart->append(apiKeyPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup callback parameters so we know once the keypair upload has succeeded or failed
|
||||||
|
JSONCallbackParameters callbackParameters;
|
||||||
|
callbackParameters.jsonCallbackReceiver = this;
|
||||||
|
callbackParameters.jsonCallbackMethod = "publicKeyUploadSucceeded";
|
||||||
|
callbackParameters.errorCallbackReceiver = this;
|
||||||
|
callbackParameters.errorCallbackMethod = "publicKeyUploadFailed";
|
||||||
|
|
||||||
|
sendRequest(uploadPath, AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation,
|
||||||
|
callbackParameters, QByteArray(), requestMultiPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountManager::publicKeyUploadSucceeded(QNetworkReply& reply) {
|
void AccountManager::publicKeyUploadSucceeded(QNetworkReply& reply) {
|
||||||
|
@ -877,6 +862,4 @@ void AccountManager::handleKeypairGenerationError() {
|
||||||
|
|
||||||
// reset our waiting state for keypair response
|
// reset our waiting state for keypair response
|
||||||
_isWaitingForKeypairResponse = false;
|
_isWaitingForKeypairResponse = false;
|
||||||
|
|
||||||
sender()->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ signals:
|
||||||
private slots:
|
private slots:
|
||||||
void processReply();
|
void processReply();
|
||||||
void handleKeypairGenerationError();
|
void handleKeypairGenerationError();
|
||||||
void processGeneratedKeypair();
|
void processGeneratedKeypair(QByteArray publicKey, QByteArray privateKey);
|
||||||
void publicKeyUploadSucceeded(QNetworkReply& reply);
|
void publicKeyUploadSucceeded(QNetworkReply& reply);
|
||||||
void publicKeyUploadFailed(QNetworkReply& reply);
|
void publicKeyUploadFailed(QNetworkReply& reply);
|
||||||
void generateNewKeypair(bool isUserKeypair = true, const QUuid& domainID = QUuid());
|
void generateNewKeypair(bool isUserKeypair = true, const QUuid& domainID = QUuid());
|
||||||
|
|
|
@ -138,7 +138,7 @@ public:
|
||||||
* </tr>
|
* </tr>
|
||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* @typedef location.LookupTrigger
|
* @typedef {number} location.LookupTrigger
|
||||||
*/
|
*/
|
||||||
enum LookupTrigger {
|
enum LookupTrigger {
|
||||||
UserInput,
|
UserInput,
|
||||||
|
@ -184,7 +184,7 @@ public slots:
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Go to a specified metaverse address.
|
* Go to a specified metaverse address.
|
||||||
* @function location.handleLookupString
|
* @function location.handleLookupString
|
||||||
* @param {string} address - The address to go to: a <code>"hifi:/"<code> address, an IP address (e.g.,
|
* @param {string} address - The address to go to: a <code>"hifi://"<code> address, an IP address (e.g.,
|
||||||
* <code>"127.0.0.1"</code> or <code>"localhost"</code>), a domain name, a named path on a domain (starts with
|
* <code>"127.0.0.1"</code> or <code>"localhost"</code>), a domain name, a named path on a domain (starts with
|
||||||
* <code>"/"</code>), a position or position and orientation, or a user (starts with <code>"@"</code>).
|
* <code>"/"</code>), a position or position and orientation, or a user (starts with <code>"@"</code>).
|
||||||
* @param {boolean} fromSuggestions=false - Set to <code>true</code> if the address is obtained from the "Goto" dialog.
|
* @param {boolean} fromSuggestions=false - Set to <code>true</code> if the address is obtained from the "Goto" dialog.
|
||||||
|
|
|
@ -137,7 +137,7 @@ public:
|
||||||
* </tr>
|
* </tr>
|
||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* @typedef Window.ConnectionRefusedReason
|
* @typedef {number} Window.ConnectionRefusedReason
|
||||||
*/
|
*/
|
||||||
enum class ConnectionRefusedReason : uint8_t {
|
enum class ConnectionRefusedReason : uint8_t {
|
||||||
Unknown,
|
Unknown,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue