3
0
Fork 0
mirror of https://github.com/JulianGro/overte.git synced 2025-04-13 03:32:31 +02:00

Merged with master

This commit is contained in:
Olivier Prat 2018-10-24 08:27:39 +02:00
commit 69ace03919
273 changed files with 5264 additions and 3368 deletions
.eslintrc.jsBUILD.mdBUILD_LINUX.mdBUILD_OSX.mdBUILD_WIN.mdCMakeLists.txt
android
assignment-client/src
cmake
domain-server/resources/web/content/js
interface
libraries

View file

@ -36,6 +36,7 @@ module.exports = {
"GlobalServices": false,
"GooglePoly": false,
"Graphics": false,
"HifiAbout": false,
"HMD": false,
"LaserPointers": false,
"location": true,

View file

@ -9,6 +9,7 @@
- [cmake](https://cmake.org/download/): 3.9
- [Qt](https://www.qt.io/download-open-source): 5.10.1
- [Python](https://www.python.org/downloads/): 3.6 or higher
- [OpenSSL](https://www.openssl.org/): Use the latest available 1.0 version (**NOT** 1.1) of OpenSSL to avoid security vulnerabilities.
- [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)

View file

@ -40,6 +40,11 @@ Install build tools:
sudo apt-get install cmake
```
Install Python 3:
```bash
sudo apt-get install python3.6
```
### Get code and checkout the tag you need

View file

@ -6,6 +6,10 @@ Please read the [general build guide](BUILD.md) for information on dependencies
brew install cmake openssl qt
### Python 3
Download an install Python 3.6.6 or higher from [here](https://www.python.org/downloads/). Execute the `Update Shell Profile.command` script that is provided with the installer.
### OpenSSL
Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations.
@ -28,7 +32,9 @@ Note that this uses the version from the homebrew formula at the time of this wr
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
cmake .. -GXcode
cmake .. -G Xcode
If `cmake` complains about Python 3 being missing, you may need to update your CMake binary with command `brew upgrade cmake`, or by downloading and running the latest CMake installer, depending on how you originally instaled CMake
After running cmake, you will have the make files or Xcode project file necessary to build all of the components. Open the hifi.xcodeproj file, choose ALL_BUILD from the Product > Scheme menu (or target drop down), and click Run.

View file

@ -5,11 +5,17 @@ Note: We are now using Visual Studio 2017 and Qt 5.10.1. If you are upgrading fr
Note: The prerequisites will require about 10 GB of space on your drive. You will also need a system with at least 8GB of main memory.
### Step 1. Visual Studio 2017
### Step 1. Visual Studio 2017 & Python
If you dont 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 on the right on the Summary toolbar, check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)".
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)". If you do not already have a python development environment installed, also check "Python Development" in this screen.
If you already have Visual Studio installed and need to add python, open the "Add or remove programs" control panel and find the "Microsoft Visual Studio Installer". Select it and click "Modify". In the installer, select "Modify" again, then check "Python Development" and allow the installer to apply the changes.
### Step 1a. Alternate Python
If you do not wish to use the Python installation bundled with Visual Studio, you can download the installer from [here](https://www.python.org/downloads/). Ensure you get version 3.6.6 or higher.
### Step 2. Installing CMake

View file

@ -7,6 +7,11 @@ else()
cmake_minimum_required(VERSION 3.2)
endif()
# squelch the Policy CMP0074 warning without requiring an update to cmake 3.12.
if ((${CMAKE_MAJOR_VERSION} EQUAL 3 AND ${CMAKE_MINOR_VERSION} GREATER 11) OR ${CMAKE_MAJOR_VERSION} GREATER 3)
cmake_policy(SET CMP0074 NEW)
endif()
project(hifi)
include("cmake/init.cmake")

View file

@ -24,7 +24,6 @@ android {
'-DANDROID_STL=c++_shared',
'-DQT_CMAKE_PREFIX_PATH=' + HIFI_ANDROID_PRECOMPILED + '/qt/lib/cmake',
'-DNATIVE_SCRIBE=' + HIFI_ANDROID_PRECOMPILED + '/scribe' + EXEC_SUFFIX,
'-DNATIVE_SHREFLECT=' + HIFI_ANDROID_PRECOMPILED + '/shreflect' + EXEC_SUFFIX,
'-DHIFI_ANDROID_PRECOMPILED=' + HIFI_ANDROID_PRECOMPILED,
'-DRELEASE_NUMBER=' + RELEASE_NUMBER,
'-DRELEASE_TYPE=' + RELEASE_TYPE,

View file

@ -161,31 +161,19 @@ def packages = [
]
]
def scribeLocalFile='scribe' + EXEC_SUFFIX
def scribeFile='scribe_linux_x86_64'
def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6'
def scribeVersion='u_iTrJDaE95i2abTPXOpPZckGBIim53G'
def shreflectLocalFile='shreflect' + EXEC_SUFFIX
def shreflectFile='shreflect_linux_x86_64'
def shreflectChecksum='d6094a8580066c0b6f4e80b5adfb1d98'
def shreflectVersion='jnrpudh6fptIg6T2.Z6fgKP2ultAdKmE'
def scribeChecksum='4635c28192724281d2367ce9e94380ab'
def scribeVersion='mPAY_N846oZH1tPY1bwChB_hzqkiYyoC'
if (Os.isFamily(Os.FAMILY_MAC)) {
scribeFile = 'scribe_osx_x86_64'
scribeChecksum='72db9d32d4e1e50add755570ac5eb749'
scribeVersion='DAW0DmnjCRib4MD8x93bgc2Z2MpPojZC'
shreflectFile='shreflect_osx_x86_64'
shreflectChecksum='d613ef0703c21371fee93fd2e54b964f'
shreflectVersion='.rYNzjSFq6WtWDnE5KIKRIAGyJtr__ad'
scribeChecksum='1ead61c285d265eba9a5ef91ae3b7c26'
scribeVersion='4TAXWdo9fviw60N2wUA8HNyQ9TabjZa3'
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
scribeFile = 'scribe_win32_x86_64.exe'
scribeChecksum='678e43d290c90fda670c6fefe038a06d'
scribeVersion='PuullrA_bPlO9kXZRt8rLe536X1UI.m7'
shreflectFile='shreflect_win32_x86_64.exe'
shreflectChecksum='6f4a77b8cceb3f1bbc655132c3665060'
shreflectVersion='iIyCyza1nelkbI7ihybF59bBlwrfAC3D'
scribeChecksum='9c29a62595daf4844f95f6744d568c15'
scribeVersion='DUoxjufeX8ZAIVRBKRczWTuZwT13enTv'
}
def options = [
@ -461,27 +449,11 @@ task fixScribePermissions(type: Exec, dependsOn: verifyScribe) {
commandLine 'chmod', 'a+x', HIFI_ANDROID_PRECOMPILED + '/' + scribeLocalFile
}
task downloadShreflect(type: Download) {
src baseUrl + shreflectFile + '?versionId=' + shreflectVersion
dest new File(baseFolder, shreflectLocalFile)
onlyIfNewer true
}
task verifyShreflect(type: Verify, dependsOn: downloadShreflect) {
src new File(baseFolder, shreflectLocalFile);
checksum shreflectChecksum
}
task fixShreflectPermissions(type: Exec, dependsOn: verifyShreflect) {
commandLine 'chmod', 'a+x', HIFI_ANDROID_PRECOMPILED + '/' + shreflectLocalFile
}
task setupScribe(dependsOn: [verifyScribe, verifyShreflect]) { }
task setupScribe(dependsOn: [verifyScribe]) { }
// On Windows, we don't need to set the executable bit, but on OSX and Unix we do
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
setupScribe.dependsOn fixScribePermissions
setupScribe.dependsOn fixShreflectPermissions
}
task extractGvrBinaries(dependsOn: extractDependencies) {

View file

@ -222,7 +222,8 @@ void Agent::requestScript() {
return;
}
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, scriptURL);
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
this, scriptURL, true, -1, "Agent::requestScript");
if (!request) {
qWarning() << "Could not create ResourceRequest for Agent script at" << scriptURL.toString();

View file

@ -21,7 +21,6 @@
#include <QtCore/QTimer>
#include <QUuid>
#include <ClientTraitsHandler.h>
#include <EntityEditPacketSender.h>
#include <EntityTree.h>
#include <ScriptEngine.h>

View file

@ -35,6 +35,7 @@
#include "AssignmentClientLogging.h"
#include "AssignmentFactory.h"
#include "ResourceRequestObserver.h"
const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client";
const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000;
@ -49,6 +50,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
DependencyManager::set<tracing::Tracer>();
DependencyManager::set<StatTracker>();
DependencyManager::set<AccountManager>();
DependencyManager::set<ResourceRequestObserver>();
auto addressManager = DependencyManager::set<AddressManager>();

View file

@ -6,6 +6,10 @@ if (NOT "${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
message( FATAL_ERROR "Only 64 bit builds supported." )
endif()
if (USE_CCACHE OR "$ENV{USE_CCACHE}")
configure_ccache()
endif()
if (WIN32)
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)

42
cmake/externals/glslang/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,42 @@
set(EXTERNAL_NAME glslang)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL https://github.com/KhronosGroup/glslang/archive/7.8.2853.zip
URL_MD5 4f93e3818528176c622c137fba05cbf8
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>-$<CONFIG>
LOG_DOWNLOAD 1
LOG_CONFIGURE 1
LOG_BUILD 1
)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
# includes
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$<CONFIG>")
list(APPEND INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include)
#list(APPEND INCLUDE_DIRS ${INSTALL_DIR}/include)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INCLUDE_DIRS} CACHE PATH "List of glslang include directories")
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIR} CACHE PATH "List of glslang include directories")
set(LIB_DIR ${SUFFIXED_INSTALL_DIR}/lib)
list(APPEND LIB_NAMES glslang HLSL OGLCompiler OSDependent SPIRV SPVRemapper)
include(SelectLibraryConfigurations)
foreach(BASE_LIB ${LIB_NAMES})
string(TOUPPER ${BASE_LIB} BASE_LIB_UPPER)
list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE "${LIB_DIR}/${BASE_LIB}.lib")
list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "${LIB_DIR}/${BASE_LIB}d.lib")
endforeach()
select_library_configurations(${EXTERNAL_NAME_UPPER})
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE FILEPATH "Location of glslang libraries")
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Location of glslang libraries")

View file

@ -4,8 +4,8 @@ set(EXTERNAL_NAME serverless-content)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC73.zip
URL_MD5 0c5edfb63cafb042311d3cf25261fbf2
URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC75.zip
URL_MD5 b4225d058952e17976ac228330ce8d51
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""

View file

@ -0,0 +1,34 @@
set(EXTERNAL_NAME spirv_binaries)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
include(ExternalProject)
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/vulkan/vulkansdk-win32-1.1.82.1.tar.gz)
set(DOWNLOAD_MD5 3a83ef490bce248b1a4d6726a3e5893e)
set(BIN_DIR "Bin")
elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/vulkan/vulkansdk-macos-1.1.82.1.tar.gz)
set(DOWNLOAD_MD5 a57d37275b2c5db023ba8e84a63461ff)
set(BIN_DIR "macOS/bin")
else ()
set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/vulkan/vulkansdk-linux-x86_64-1.1.82.1.tar.gz)
set(DOWNLOAD_MD5 5a7c9eeda8cee6b36724da7f7cbe5ec6)
set(BIN_DIR "x86_64/bin")
endif ()
ExternalProject_Add(
${EXTERNAL_NAME}
URL ${DOWNLOAD_URL}
URL_MD5 ${DOWNLOAD_MD5}
BUILD_COMMAND ""
CONFIGURE_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
set(${EXTERNAL_NAME_UPPER}_DIR "${SOURCE_DIR}/${BIN_DIR}" CACHE FILEPATH "SPIRV binary tools location")

View file

@ -0,0 +1,35 @@
set(EXTERNAL_NAME spirv_cross)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL https://github.com/KhronosGroup/SPIRV-Cross/archive/2018-08-07.zip
URL_MD5 11198e4dc6a815ffbdb7a0a56d2d9261
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>-$<CONFIG> ${EXTRA_CMAKE_FLAGS}
LOG_DOWNLOAD 1
LOG_CONFIGURE 1
LOG_BUILD 1
)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$<CONFIG>")
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include CACHE PATH "List of Draco include directories")
if (UNIX)
set(LIB_PREFIX "lib")
set(LIB_EXT "a")
elseif (WIN32)
set(LIB_EXT "lib")
endif ()
foreach(lib glsl msl cpp hlsl reflect util core)
list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/spirv-cross-${lib}.${LIB_EXT})
endforeach()
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Path to SPIRV-Cross libraries")

View file

@ -0,0 +1,18 @@
set(EXTERNAL_NAME spirv_headers)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL https://github.com/KhronosGroup/SPIRV-Headers/archive/2c512180ca03b5d4f56283efc85745775b45fdc4.zip
URL_MD5 83e652221b5f21d5fdb61c45f5b4d9f9
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ${EXTRA_CMAKE_FLAGS}
LOG_DOWNLOAD 1
LOG_CONFIGURE 1
LOG_BUILD 1
)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
set(${EXTERNAL_NAME_UPPER}_ROOT ${INSTALL_DIR} CACHE PATH "List of include directories")

View file

@ -0,0 +1,33 @@
set(EXTERNAL_NAME spirv_tools)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL https://github.com/KhronosGroup/SPIRV-Tools/archive/v2018.4.zip
URL_MD5 7a7c69cf6ff0318910b4bfbdf30bcfc9
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DSPIRV-Headers_SOURCE_DIR=${SPIRV_HEADERS_ROOT} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>-$<CONFIG> ${EXTRA_CMAKE_FLAGS}
LOG_DOWNLOAD 1
LOG_CONFIGURE 1
LOG_BUILD 1
)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$<CONFIG>")
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include CACHE PATH "List of SPIRV-Tools include directories")
if (UNIX)
set(LIB_PREFIX "lib")
set(LIB_EXT "a")
elseif (WIN32)
set(LIB_EXT "lib")
endif ()
list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/SPIRV-Tools-opt.${LIB_EXT})
list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/SPIRV-Tools-link.${LIB_EXT})
list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/SPIRV-Tools.${LIB_EXT})
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Path to SPIRV-Tool libraries")

View file

@ -10,6 +10,10 @@ if (POLICY CMP0042)
cmake_policy(SET CMP0042 NEW)
endif ()
if (POLICY CMP0074)
cmake_policy(SET CMP0074 OLD)
endif ()
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMakeTargets")
# Hide automoc folders (for IDEs)

View file

@ -8,34 +8,132 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
# FIXME use the built tools
macro(AUTOSCRIBE_APPEND_QRC)
string(CONCAT SHADER_QRC "${SHADER_QRC}" "<file alias=\"${ARGV0}\">${ARGV1}</file>\n")
endmacro()
set(VULKAN_DIR $ENV{VULKAN_SDK})
set(GLSLANG_EXEC "${VULKAN_DIR}/Bin/glslangValidator.exe")
set(SPIRV_CROSS_EXEC "${VULKAN_DIR}/Bin/spirv-cross.exe")
set(SPIRV_OPT_EXEC "${VULKAN_DIR}/Bin/spirv-opt.exe")
set(GLSLC_EXEC "${VULKAN_DIR}/Bin/glslc.exe")
set(SCRIBE_EXEC "D:/scribe.exe")
macro(AUTOSCRIBE_PLATFORM_SHADER)
set(AUTOSCRIBE_PLATFORM_PATH "${ARGV0}")
string(REGEX MATCH "([0-9]+(es)?)(/stereo)?" PLATFORM_PATH_REGEX ${AUTOSCRIBE_PLATFORM_PATH})
set(AUTOSCRIBE_DIALECT "${CMAKE_MATCH_1}")
if (CMAKE_MATCH_3)
set(AUTOSCRIBE_VARIANT "stereo")
else()
set(AUTOSCRIBE_VARIANT "mono")
endif()
string(REGEX REPLACE "/" "\\\\" SOURCE_GROUP_PATH ${AUTOSCRIBE_PLATFORM_PATH})
set(SOURCE_GROUP_PATH "${SHADER_LIB}\\${SOURCE_GROUP_PATH}")
set(AUTOSCRIBE_DIALECT_HEADER "${AUTOSCRIBE_HEADER_DIR}/${AUTOSCRIBE_DIALECT}/header.glsl")
set(AUTOSCRIBE_VARIANT_HEADER "${AUTOSCRIBE_HEADER_DIR}/${AUTOSCRIBE_VARIANT}.glsl")
set(AUTOSCRIBE_OUTPUT_FILE "${SHADERS_DIR}/${SHADER_LIB}/${AUTOSCRIBE_PLATFORM_PATH}/${SHADER_NAME}.${SHADER_TYPE}")
AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/scribe" "${AUTOSCRIBE_OUTPUT_FILE}")
source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_OUTPUT_FILE})
set_property(SOURCE ${AUTOSCRIBE_OUTPUT_FILE} PROPERTY SKIP_AUTOMOC ON)
list(APPEND SCRIBED_SHADERS ${AUTOSCRIBE_OUTPUT_FILE})
set(AUTOSCRIBE_SPIRV_FILE "${AUTOSCRIBE_OUTPUT_FILE}.spv")
# don't add unoptimized spirv to the QRC
#AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/spirv_unopt" "${AUTOSCRIBE_SPIRV_FILE}")
source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_FILE})
set_property(SOURCE ${AUTOSCRIBE_SPIRV_FILE} PROPERTY SKIP_AUTOMOC ON)
list(APPEND SPIRV_SHADERS ${AUTOSCRIBE_SPIRV_FILE})
set(AUTOSCRIBE_SPIRV_OPT_FILE "${AUTOSCRIBE_OUTPUT_FILE}.opt.spv")
AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/spirv" "${AUTOSCRIBE_SPIRV_OPT_FILE}")
source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_OPT_FILE})
set_property(SOURCE ${AUTOSCRIBE_SPIRV_OPT_FILE} PROPERTY SKIP_AUTOMOC ON)
list(APPEND SPIRV_SHADERS ${AUTOSCRIBE_SPIRV_OPT_FILE})
set(AUTOSCRIBE_SPIRV_GLSL_FILE "${AUTOSCRIBE_OUTPUT_FILE}.glsl")
AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/glsl" "${AUTOSCRIBE_SPIRV_GLSL_FILE}")
source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_GLSL_FILE})
set_property(SOURCE ${AUTOSCRIBE_SPIRV_GLSL_FILE} PROPERTY SKIP_AUTOMOC ON)
list(APPEND SPIRV_SHADERS ${AUTOSCRIBE_SPIRV_GLSL_FILE})
set(AUTOSCRIBE_SPIRV_JSON_FILE "${AUTOSCRIBE_OUTPUT_FILE}.json")
AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/json" "${AUTOSCRIBE_SPIRV_JSON_FILE}")
source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_JSON_FILE})
set_property(SOURCE ${AUTOSCRIBE_SPIRV_JSON_FILE} PROPERTY SKIP_AUTOMOC ON)
list(APPEND REFLECTED_SHADERS ${AUTOSCRIBE_SPIRV_JSON_FILE})
unset(SHADER_GEN_LINE)
list(APPEND SHADER_GEN_LINE ${AUTOSCRIBE_DIALECT})
list(APPEND SHADER_GEN_LINE ${AUTOSCRIBE_VARIANT})
file(RELATIVE_PATH TEMP_PATH ${CMAKE_SOURCE_DIR} ${SHADER_FILE})
list(APPEND SHADER_GEN_LINE ${TEMP_PATH})
file(RELATIVE_PATH TEMP_PATH ${CMAKE_SOURCE_DIR} ${AUTOSCRIBE_OUTPUT_FILE})
list(APPEND SHADER_GEN_LINE ${TEMP_PATH})
list(APPEND SHADER_GEN_LINE ${AUTOSCRIBE_SHADER_SEEN_LIBS})
string(CONCAT AUTOSCRIBE_SHADERGEN_COMMANDS "${AUTOSCRIBE_SHADERGEN_COMMANDS}" "${SHADER_GEN_LINE}\n")
# # FIXME need better mechanism for determining the include files
# add_custom_command(
# OUTPUT ${AUTOSCRIBE_OUTPUT_FILE}
# COMMAND ${SCRIBE_COMMAND} ${SHADER_FILE} ${SCRIBE_ARGS} -o ${AUTOSCRIBE_OUTPUT_FILE} -h ${AUTOSCRIBE_DIALECT_HEADER} -h ${AUTOSCRIBE_VARIANT_HEADER}
# DEPENDS ${SCRIBE_COMMAND} ${SHADER_FILE} ${AUTOSCRIBE_DIALECT_HEADER} ${AUTOSCRIBE_VARIANT_HEADER})
# # Generate the spirv file
# add_custom_command(
# OUTPUT ${AUTOSCRIBE_SPIRV_FILE}
# COMMAND ${GLSLANG_EXEC} -V110 -o ${AUTOSCRIBE_SPIRV_FILE} ${AUTOSCRIBE_OUTPUT_FILE}
# DEPENDS ${AUTOSCRIBE_OUTPUT_FILE} ${GLSLANG_EXEC})
# # Generate the optimized spirv file
# add_custom_command(
# OUTPUT ${AUTOSCRIBE_SPIRV_OPT_FILE}
# COMMAND ${SPIRV_OPT_EXEC} -O ${AUTOSCRIBE_SPIRV_FILE} -o ${AUTOSCRIBE_SPIRV_OPT_FILE}
# DEPENDS ${AUTOSCRIBE_SPIRV_FILE} ${SPIRV_OPT_EXEC})
# # Generate the optimized GLSL file
# add_custom_command(
# OUTPUT ${AUTOSCRIBE_SPIRV_GLSL_FILE}
# COMMAND ${SPIRV_CROSS_EXEC} ${SPIRV_CROSS_ARGS} ${AUTOSCRIBE_SPIRV_OPT_FILE} --output ${AUTOSCRIBE_SPIRV_GLSL_FILE}
# DEPENDS ${AUTOSCRIBE_SPIRV_OPT_FILE} ${SPIRV_CROSS_EXEC})
# # Generate the optimized spirv file
# add_custom_command(
# OUTPUT ${AUTOSCRIBE_SPIRV_JSON_FILE}
# COMMAND ${SPIRV_CROSS_EXEC} --reflect json ${AUTOSCRIBE_SPIRV_OPT_FILE} --output ${AUTOSCRIBE_SPIRV_JSON_FILE}
# DEPENDS ${AUTOSCRIBE_SPIRV_OPT_FILE} ${SPIRV_CROSS_EXEC})
endmacro()
macro(AUTOSCRIBE_SHADER)
#
# Set the include paths
#
# FIXME base the include paths off of output from the scribe tool,
# instead of treating every previously seen shader as a possible header
unset(SHADER_INCLUDE_FILES)
# Grab include files
foreach(includeFile ${ARGN})
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
endforeach()
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
endforeach()
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
#Extract the unique include shader paths
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
endforeach()
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
#message(ready for includes ${SHADER_INCLUDES_PATHS})
# make the scribe include arguments
set(SCRIBE_INCLUDES)
unset(SCRIBE_INCLUDES)
foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS})
set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/)
endforeach()
#
# Figure out the various output names
#
# Define the final name of the generated shader file
get_filename_component(SHADER_NAME ${SHADER_FILE} NAME_WE)
get_filename_component(SHADER_EXT ${SHADER_FILE} EXT)
@ -46,38 +144,36 @@ macro(AUTOSCRIBE_SHADER)
elseif(${SHADER_EXT} STREQUAL .slg)
set(SHADER_TYPE geom)
endif()
file(MAKE_DIRECTORY "${SHADERS_DIR}/${SHADER_LIB}")
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_LIB}/${SHADER_NAME}.${SHADER_TYPE}")
file(TO_CMAKE_PATH "${SHADER_TARGET}" COMPILED_SHADER)
set(REFLECTED_SHADER "${COMPILED_SHADER}.json")
set(SCRIBE_ARGS -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
set(SCRIBE_ARGS -D GLPROFILE ${GLPROFILE} -T ${SHADER_TYPE} ${SCRIBE_INCLUDES} )
# Generate the frag/vert file
add_custom_command(
OUTPUT ${SHADER_TARGET}
COMMAND ${SCRIBE_COMMAND} ${SCRIBE_ARGS}
DEPENDS ${SHADER_FILE} ${SCRIBE_COMMAND} ${SHADER_INCLUDE_FILES})
# SHADER_SCRIBED -> the output of scribe
set(SHADER_SCRIBED "${SHADERS_DIR}/${SHADER_LIB}/${SHADER_NAME}.${SHADER_TYPE}")
# Generate the json reflection
# FIXME move to spirv-cross for this task after we have spirv compatible shaders
add_custom_command(
OUTPUT ${REFLECTED_SHADER}
COMMAND ${SHREFLECT_COMMAND} ${COMPILED_SHADER}
DEPENDS ${SHREFLECT_DEPENDENCY} ${COMPILED_SHADER})
# SHADER_NAME_FILE -> a file containing the shader name and extension (useful for debugging and for
# determining the type of shader from the filename)
set(SHADER_NAME_FILE "${SHADER_SCRIBED}.name")
file(TO_CMAKE_PATH "${SHADER_SCRIBED}" SHADER_SCRIBED)
file(WRITE "${SHADER_SCRIBED}.name" "${SHADER_NAME}.${SHADER_TYPE}")
AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/name" "${SHADER_NAME_FILE}")
#output the generated file name
source_group("Compiled/${SHADER_LIB}" FILES ${COMPILED_SHADER})
set_property(SOURCE ${COMPILED_SHADER} PROPERTY SKIP_AUTOMOC ON)
list(APPEND COMPILED_SHADERS ${COMPILED_SHADER})
if (USE_GLES)
set(SPIRV_CROSS_ARGS --version 310es)
AUTOSCRIBE_PLATFORM_SHADER("310es")
AUTOSCRIBE_PLATFORM_SHADER("310es/stereo")
else()
set(SPIRV_CROSS_ARGS --version 410 --no-420pack-extension)
AUTOSCRIBE_PLATFORM_SHADER("410")
AUTOSCRIBE_PLATFORM_SHADER("410/stereo")
if (NOT APPLE)
set(SPIRV_CROSS_ARGS --version 450)
AUTOSCRIBE_PLATFORM_SHADER("450")
AUTOSCRIBE_PLATFORM_SHADER("450/stereo")
endif()
endif()
source_group("Reflected/${SHADER_LIB}" FILES ${REFLECTED_SHADER})
list(APPEND REFLECTED_SHADERS ${REFLECTED_SHADER})
string(CONCAT SHADER_QRC "${SHADER_QRC}" "<file alias=\"${SHADER_COUNT}\">${COMPILED_SHADER}</file>\n")
string(CONCAT SHADER_QRC "${SHADER_QRC}" "<file alias=\"${SHADER_COUNT}_reflection\">${REFLECTED_SHADER}</file>\n")
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${SHADER_NAME} = ${SHADER_COUNT},\n")
string(CONCAT SHADER_SHADERS_ARRAY "${SHADER_SHADERS_ARRAY}" "${SHADER_COUNT},\n")
MATH(EXPR SHADER_COUNT "${SHADER_COUNT}+1")
endmacro()
@ -86,6 +182,8 @@ macro(AUTOSCRIBE_SHADER_LIB)
message(FATAL_ERROR "AUTOSCRIBE_SHADER_LIB can only be used by the shaders library")
endif()
file(MAKE_DIRECTORY "${SHADERS_DIR}/${SHADER_LIB}")
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES "${CMAKE_SOURCE_DIR}/libraries/${SHADER_LIB}/src")
string(REGEX REPLACE "[-]" "_" SHADER_NAMESPACE ${SHADER_LIB})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace ${SHADER_NAMESPACE} {\n")
@ -165,66 +263,103 @@ macro(AUTOSCRIBE_SHADER_LIB)
# Finish the shader enums
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "} // namespace ${SHADER_NAMESPACE}\n")
#file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
#foreach(HIFI_LIBRARY ${ARGN})
#list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src)
#endforeach()
#endif()
endmacro()
macro(AUTOSCRIBE_SHADER_LIBS)
set(SCRIBE_COMMAND scribe)
set(SHREFLECT_COMMAND shreflect)
set(SHREFLECT_DEPENDENCY shreflect)
# Target dependant Custom rule on the SHADER_FILE
if (ANDROID)
set(GLPROFILE LINUX_GL)
set(SCRIBE_COMMAND ${NATIVE_SCRIBE})
set(SHREFLECT_COMMAND ${NATIVE_SHREFLECT})
unset(SHREFLECT_DEPENDENCY)
else()
if (APPLE)
set(GLPROFILE MAC_GL)
elseif(UNIX)
set(GLPROFILE LINUX_GL)
else()
set(GLPROFILE PC_GL)
endif()
endif()
message(STATUS "Shader processing start")
set(AUTOSCRIBE_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/headers)
# Start the shader IDs
set(SHADER_COUNT 1)
set(SHADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders")
set(SHADER_ENUMS "")
file(MAKE_DIRECTORY ${SHADERS_DIR})
set(SHADER_ENUMS "")
set(SHADER_COUNT 1)
#
# Scribe generation & program defintiion
#
foreach(SHADER_LIB ${ARGN})
list(APPEND AUTOSCRIBE_SHADER_SEEN_LIBS ${SHADER_LIB})
AUTOSCRIBE_SHADER_LIB(${SHADER_LIB})
endforeach()
# Generate the library files
configure_file(
ShaderEnums.cpp.in
${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp)
${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.cpp)
configure_file(
ShaderEnums.h.in
${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h)
configure_file(
shaders.qrc.in
${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc)
${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.h)
set(AUTOSCRIBE_SHADER_LIB_SRC "${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h;${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp")
set(QT_RESOURCES_FILE ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc)
configure_file(shaders.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc)
list(APPEND QT_RESOURCES_FILE ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc)
list(APPEND AUTOSCRIBE_SHADER_HEADERS ${AUTOSCRIBE_HEADER_DIR}/mono.glsl ${AUTOSCRIBE_HEADER_DIR}/stereo.glsl)
list(APPEND AUTOSCRIBE_SHADER_HEADERS ${AUTOSCRIBE_HEADER_DIR}/450/header.glsl ${AUTOSCRIBE_HEADER_DIR}/410/header.glsl ${AUTOSCRIBE_HEADER_DIR}/310es/header.glsl)
source_group("Shader Headers" FILES ${AUTOSCRIBE_HEADER_DIR}/mono.glsl ${AUTOSCRIBE_HEADER_DIR}/stereo.glsl)
source_group("Shader Headers\\450" FILES ${AUTOSCRIBE_HEADER_DIR}/450/header.glsl)
source_group("Shader Headers\\410" FILES ${AUTOSCRIBE_HEADER_DIR}/410/header.glsl)
source_group("Shader Headers\\310es" FILES ${AUTOSCRIBE_HEADER_DIR}/310es/header.glsl)
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${AUTOSCRIBE_SHADER_HEADERS})
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.h ${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.cpp)
# Write the shadergen command list
set(AUTOSCRIBE_SHADERGEN_COMMANDS_FILE ${CMAKE_CURRENT_BINARY_DIR}/shadergen.txt)
file(WRITE ${AUTOSCRIBE_SHADERGEN_COMMANDS_FILE} "${AUTOSCRIBE_SHADERGEN_COMMANDS}")
# grab the SPIRV binaries we require
# note we don't use the normal ADD_DEPENDENCY_EXTERNAL_PROJECTS macro because only a custom command
# depends on these, not any of our build artifacts, so there's no valid target for the add_dependencies
# call in ADD_DEPENDENCY_EXTERNAL_PROJECTS to use
add_subdirectory(${EXTERNAL_PROJECT_DIR}/spirv_binaries ${EXTERNALS_BINARY_DIR}/spirv_binaries)
target_python()
# A custom python script which will generate
if (ANDROID)
add_custom_command(
OUTPUT ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS}
COMMENT "Generating/updating shaders"
COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_SOURCE_DIR}/tools/shadergen.py
--commands ${AUTOSCRIBE_SHADERGEN_COMMANDS_FILE}
--spirv-binaries ${SPIRV_BINARIES_DIR}
--scribe ${NATIVE_SCRIBE}
--build-dir ${CMAKE_CURRENT_BINARY_DIR}
--source-dir ${CMAKE_SOURCE_DIR}
DEPENDS ${AUTOSCRIBE_SHADER_HEADERS} spirv_binaries ${CMAKE_SOURCE_DIR}/tools/shadergen.py ${ALL_SCRIBE_SHADERS})
else()
add_custom_command(
OUTPUT ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS}
COMMENT "Generating/updating shaders"
COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_SOURCE_DIR}/tools/shadergen.py
--commands ${AUTOSCRIBE_SHADERGEN_COMMANDS_FILE}
--spirv-binaries ${SPIRV_BINARIES_DIR}
--scribe $<TARGET_FILE:scribe>
--build-dir ${CMAKE_CURRENT_BINARY_DIR}
--source-dir ${CMAKE_SOURCE_DIR}
DEPENDS ${AUTOSCRIBE_SHADER_HEADERS} scribe spirv_binaries ${CMAKE_SOURCE_DIR}/tools/shadergen.py ${ALL_SCRIBE_SHADERS})
endif()
add_custom_target(shadergen DEPENDS ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS})
set_target_properties(shadergen PROPERTIES FOLDER "Shaders")
# Custom targets required to force generation of the shaders via scribe
add_custom_target(scribe_shaders SOURCES ${ALL_SCRIBE_SHADERS})
add_custom_target(compiled_shaders SOURCES ${COMPILED_SHADERS})
add_custom_target(reflected_shaders SOURCES ${REFLECTED_SHADERS})
add_custom_target(scribe_shaders SOURCES ${ALL_SCRIBE_SHADERS} ${AUTOSCRIBE_SHADER_HEADERS})
set_target_properties(scribe_shaders PROPERTIES FOLDER "Shaders")
set_target_properties(compiled_shaders PROPERTIES FOLDER "Shaders")
add_custom_target(scribed_shaders SOURCES ${SCRIBED_SHADERS})
set_target_properties(scribed_shaders PROPERTIES FOLDER "Shaders")
add_dependencies(scribed_shaders shadergen)
add_custom_target(spirv_shaders SOURCES ${SPIRV_SHADERS})
set_target_properties(spirv_shaders PROPERTIES FOLDER "Shaders")
add_dependencies(spirv_shaders shadergen)
add_custom_target(reflected_shaders SOURCES ${REFLECTED_SHADERS})
set_target_properties(reflected_shaders PROPERTIES FOLDER "Shaders")
add_dependencies(reflected_shaders shadergen)
message(STATUS "Shader processing end")
endmacro()

View file

@ -0,0 +1,45 @@
#
# ConfigureCCache.cmake
# cmake/macros
#
# Created by Clement Brisset on 10/10/18.
# Copyright 2018 High Fidelity, Inc.
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
#
macro(configure_ccache)
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
message(STATUS "Configuring ccache")
# Set up wrapper scripts
set(C_LAUNCHER "${CCACHE_PROGRAM}")
set(CXX_LAUNCHER "${CCACHE_PROGRAM}")
set(LAUNCH_C_IN "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/launch-c.in")
set(LAUNCH_CXX_IN "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/launch-cxx.in")
set(LAUNCH_C "${CMAKE_BINARY_DIR}/CMakeFiles/launch-c")
set(LAUNCH_CXX "${CMAKE_BINARY_DIR}/CMakeFiles/launch-cxx")
configure_file(${LAUNCH_C_IN} ${LAUNCH_C})
configure_file(${LAUNCH_CXX_IN} ${LAUNCH_CXX})
execute_process(COMMAND chmod a+rx ${LAUNCH_C} ${LAUNCH_CXX})
if(CMAKE_GENERATOR STREQUAL "Xcode")
# Set Xcode project attributes to route compilation and linking
# through our scripts
set(CMAKE_XCODE_ATTRIBUTE_CC ${LAUNCH_C})
set(CMAKE_XCODE_ATTRIBUTE_CXX ${LAUNCH_CXX})
set(CMAKE_XCODE_ATTRIBUTE_LD ${LAUNCH_C})
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS ${LAUNCH_CXX})
else()
# Support Unix Makefiles and Ninja
set(CMAKE_C_COMPILER_LAUNCHER ${LAUNCH_C})
set(CMAKE_CXX_COMPILER_LAUNCHER ${LAUNCH_CXX})
endif()
else()
message(WARNING "Could not find ccache")
endif()
endmacro()

View file

@ -0,0 +1,22 @@
macro(TARGET_PYTHON)
if (NOT HIFI_PYTHON_EXEC)
# Find the python interpreter
if (CAME_VERSION VERSION_LESS 3.12)
# this logic is deprecated in CMake after 3.12
# FIXME eventually we should make 3.12 the min cmake verion and just use the Python3 find_package path
set(Python_ADDITIONAL_VERSIONS 3)
find_package(PythonInterp)
set(HIFI_PYTHON_VERSION ${PYTHON_VERSION_STRING})
set(HIFI_PYTHON_EXEC ${PYTHON_EXECUTABLE})
else()
# the new hotness
find_package(Python3)
set(HIFI_PYTHON_VERSION ${Python3_VERSION})
set(HIFI_PYTHON_EXEC ${Python3_EXECUTABLE})
endif()
if ((NOT HIFI_PYTHON_EXEC) OR (HIFI_PYTHON_VERSION VERSION_LESS 3.5))
message(FATAL_ERROR "Unable to locate Python interpreter 3.5 or higher")
endif()
endif()
endmacro()

View file

@ -0,0 +1,15 @@
macro(TARGET_SPIRV)
add_dependency_external_projects(spirv_cross)
target_link_libraries(${TARGET_NAME} ${SPIRV_CROSS_LIBRARIES})
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SPIRV_CROSS_INCLUDE_DIRS})
# spirv-tools requires spirv-headers
add_dependency_external_projects(spirv_headers)
add_dependency_external_projects(spirv_tools)
target_link_libraries(${TARGET_NAME} ${SPIRV_TOOLS_LIBRARIES})
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SPIRV_TOOLS_INCLUDE_DIRS})
add_dependency_external_projects(glslang)
target_link_libraries(${TARGET_NAME} ${GLSLANG_LIBRARIES})
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${GLSLANG_INCLUDE_DIRS})
endmacro()

View file

@ -0,0 +1,10 @@
#
# Created by Bradley Austin Davis on 2016/02/16
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
macro(TARGET_SPIRV_BINARIES)
add_dependency_external_projects(spirv_binaries)
endmacro()

View file

@ -0,0 +1,19 @@
#
# Created by Bradley Austin Davis on 2016/02/16
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
macro(TARGET_VULKAN)
find_package(Vulkan)
if (Vulkan_FOUND)
add_definitions(-DHAVE_VULKAN)
target_include_directories(${TARGET_NAME} PRIVATE ${Vulkan_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${Vulkan_LIBRARIES})
add_dependency_external_projects(glslang)
target_include_directories(${TARGET_NAME} PRIVATE ${GLSLANG_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${GLSLANG_LIBRARIES})
endif()
endmacro()

View file

@ -0,0 +1,12 @@
#!/bin/sh
# Xcode generator doesn't include the compiler as the
# first argument, Ninja and Makefiles do. Handle both cases.
if [[ "$1" = "${CMAKE_C_COMPILER}" ]] ; then
shift
fi
export CCACHE_CPP2=true
export CCACHE_HARDLINK=true
export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,file_stat_matches
exec "${C_LAUNCHER}" "${CMAKE_C_COMPILER}" "$@"

View file

@ -0,0 +1,12 @@
#!/bin/sh
# Xcode generator doesn't include the compiler as the
# first argument, Ninja and Makefiles do. Handle both cases.
if [[ "$1" = "${CMAKE_CXX_COMPILER}" ]] ; then
shift
fi
export CCACHE_CPP2=true
export CCACHE_HARDLINK=true
export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,file_stat_matches
exec "${CXX_LAUNCHER}" "${CMAKE_CXX_COMPILER}" "$@"

View file

@ -59,6 +59,7 @@ $(document).ready(function(){
$.ajax({
url: '/content/upload',
type: 'POST',
timeout: 3600000, // Set timeout to 1h
cache: false,
processData: false,
contentType: false,

View file

@ -133,7 +133,7 @@
{ "from": "Keyboard.W", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_FORWARD" },
{ "from": "Keyboard.S", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_BACKWARD" },
{ "from": "Keyboard.Shift", "when": ["!Keyboard.Left", "!Keyboard.Right"], "to": "Actions.SPRINT" },
{ "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },
{ "from": "Keyboard.C", "when": "!Keyboard.Control", "to": "Actions.VERTICAL_DOWN" },
{ "from": "Keyboard.Left", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
{ "from": "Keyboard.Right", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
{ "from": "Keyboard.Up", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_FORWARD" },

View file

@ -31,7 +31,7 @@ Rectangle {
scaleSlider.notify = false;
scaleSlider.value = Math.round(avatarScale * 10);
scaleSlider.notify = true;;
scaleSlider.notify = true;
if (settings.dominantHand === 'left') {
leftHandRadioButton.checked = true;

View file

@ -0,0 +1,364 @@
//
// ItemUnderTest
// qml/hifi/commerce/marketplaceItemTester
//
// Load items not in the marketplace for testing purposes
//
// Created by Kerry Ivan Kurian on 2018-10-18
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.10
import QtQuick.Controls 2.3
import Hifi 1.0 as Hifi
import "qrc:////qml//styles-uit" as HifiStylesUit
import "qrc:////qml//controls-uit" as HifiControlsUit
Rectangle {
id: root;
color: hifi.colors.baseGray
width: parent.width - 16
height: childrenRect.height + itemHeaderContainer.anchors.topMargin + detailsContainer.anchors.topMargin
property var detailsExpanded: false
property var actions: {
"forward": function(resource, assetType, resourceObjectId){
switch(assetType) {
case "application":
Commerce.installApp(resource, true);
break;
case "avatar":
MyAvatar.useFullAvatarURL(resource);
break;
case "content set":
urlHandler.handleUrl("hifi://localhost/0,0,0");
Commerce.replaceContentSet(toUrl(resource), "");
break;
case "entity":
case "wearable":
rezEntity(resource, assetType, resourceObjectId);
break;
default:
print("Marketplace item tester unsupported assetType " + assetType);
}
},
"trash": function(resource, assetType){
if ("application" === assetType) {
Commerce.uninstallApp(resource);
}
sendToScript({
method: "tester_deleteResourceObject",
objectId: resourceListModel.get(index).resourceObjectId});
resourceListModel.remove(index);
}
}
Item {
id: itemHeaderContainer
anchors.top: parent.top
anchors.topMargin: 8
anchors.left: parent.left
anchors.leftMargin: 8
width: parent.width - 16
height: childrenRect.height
Item {
id: itemNameContainer
width: parent.width * 0.5
height: childrenRect.height
HifiStylesUit.RalewaySemiBold {
id: resourceName
height: paintedHeight
width: parent.width
text: {
var match = resource.match(/\/([^/]*)$/);
return match ? match[1] : resource;
}
size: 14
color: hifi.colors.white
wrapMode: Text.WrapAnywhere
}
HifiStylesUit.RalewayRegular {
id: resourceUrl
anchors.top: resourceName.bottom;
anchors.topMargin: 4;
height: paintedHeight
width: parent.width
text: resource
size: 12
color: hifi.colors.faintGray;
wrapMode: Text.WrapAnywhere
}
}
HifiControlsUit.ComboBox {
id: comboBox
anchors.left: itemNameContainer.right
anchors.leftMargin: 4
anchors.verticalCenter: itemNameContainer.verticalCenter
height: 30
width: parent.width * 0.3 - anchors.leftMargin
model: [
"application",
"avatar",
"content set",
"entity",
"wearable",
"unknown"
]
currentIndex: (("entity or wearable" === assetType) ?
model.indexOf("unknown") : model.indexOf(assetType))
Component.onCompleted: {
onCurrentIndexChanged.connect(function() {
assetType = model[currentIndex];
sendToScript({
method: "tester_updateResourceObjectAssetType",
objectId: resourceListModel.get(index)["resourceObjectId"],
assetType: assetType });
});
}
}
Button {
id: actionButton
property var glyphs: {
"application": hifi.glyphs.install,
"avatar": hifi.glyphs.avatar,
"content set": hifi.glyphs.globe,
"entity": hifi.glyphs.wand,
"trash": hifi.glyphs.trash,
"unknown": hifi.glyphs.circleSlash,
"wearable": hifi.glyphs.hat
}
property int color: hifi.buttons.blue;
property int colorScheme: hifi.colorSchemes.dark;
anchors.left: comboBox.right
anchors.leftMargin: 4
anchors.verticalCenter: itemNameContainer.verticalCenter
width: parent.width * 0.10 - anchors.leftMargin
height: width
enabled: comboBox.model[comboBox.currentIndex] !== "unknown"
onClicked: {
if (model.currentlyRecordingResources) {
model.currentlyRecordingResources = false;
} else {
model.resourceAccessEventText = "";
model.currentlyRecordingResources = true;
root.actions["forward"](resource, comboBox.currentText, resourceObjectId);
}
sendToScript({
method: "tester_updateResourceRecordingStatus",
objectId: resourceListModel.get(index).resourceObjectId,
status: model.currentlyRecordingResources
});
}
background: Rectangle {
radius: 4;
gradient: Gradient {
GradientStop {
position: 0.2
color: {
if (!actionButton.enabled) {
hifi.buttons.disabledColorStart[actionButton.colorScheme]
} else if (actionButton.pressed) {
hifi.buttons.pressedColor[actionButton.color]
} else if (actionButton.hovered) {
hifi.buttons.hoveredColor[actionButton.color]
} else {
hifi.buttons.colorStart[actionButton.color]
}
}
}
GradientStop {
position: 1.0
color: {
if (!actionButton.enabled) {
hifi.buttons.disabledColorFinish[actionButton.colorScheme]
} else if (actionButton.pressed) {
hifi.buttons.pressedColor[actionButton.color]
} else if (actionButton.hovered) {
hifi.buttons.hoveredColor[actionButton.color]
} else {
hifi.buttons.colorFinish[actionButton.color]
}
}
}
}
}
contentItem: Item {
HifiStylesUit.HiFiGlyphs {
id: rezIcon;
text: model.currentlyRecordingResources ? hifi.glyphs.scriptStop : actionButton.glyphs[comboBox.model[comboBox.currentIndex]];
anchors.fill: parent
size: 30;
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
color: enabled ? hifi.buttons.textColor[actionButton.color]
: hifi.buttons.disabledTextColor[actionButton.colorScheme]
}
}
}
Button {
id: trashButton
property int color: hifi.buttons.red;
property int colorScheme: hifi.colorSchemes.dark;
anchors.left: actionButton.right
anchors.verticalCenter: itemNameContainer.verticalCenter
anchors.leftMargin: 4
width: parent.width * 0.10 - anchors.leftMargin
height: width
onClicked: {
root.actions["trash"](resource, comboBox.currentText, resourceObjectId);
}
background: Rectangle {
radius: 4;
gradient: Gradient {
GradientStop {
position: 0.2
color: {
if (!trashButton.enabled) {
hifi.buttons.disabledColorStart[trashButton.colorScheme]
} else if (trashButton.pressed) {
hifi.buttons.pressedColor[trashButton.color]
} else if (trashButton.hovered) {
hifi.buttons.hoveredColor[trashButton.color]
} else {
hifi.buttons.colorStart[trashButton.color]
}
}
}
GradientStop {
position: 1.0
color: {
if (!trashButton.enabled) {
hifi.buttons.disabledColorFinish[trashButton.colorScheme]
} else if (trashButton.pressed) {
hifi.buttons.pressedColor[trashButton.color]
} else if (trashButton.hovered) {
hifi.buttons.hoveredColor[trashButton.color]
} else {
hifi.buttons.colorFinish[trashButton.color]
}
}
}
}
}
contentItem: Item {
HifiStylesUit.HiFiGlyphs {
id: trashIcon;
text: hifi.glyphs.trash
anchors.fill: parent
size: 22;
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: enabled ? hifi.buttons.textColor[trashButton.color]
: hifi.buttons.disabledTextColor[trashButton.colorScheme]
}
}
}
}
Item {
id: detailsContainer
width: parent.width - 16
height: root.detailsExpanded ? 300 : 26
anchors.top: itemHeaderContainer.bottom
anchors.topMargin: 12
anchors.left: parent.left
anchors.leftMargin: 8
HifiStylesUit.HiFiGlyphs {
id: detailsToggle
anchors.left: parent.left
anchors.leftMargin: -4
anchors.top: parent.top
anchors.topMargin: -2
width: 22
text: root.detailsExpanded ? hifi.glyphs.minimize : hifi.glyphs.maximize
color: hifi.colors.white
size: 22
MouseArea {
anchors.fill: parent
onClicked: root.detailsExpanded = !root.detailsExpanded
}
}
ScrollView {
id: detailsTextContainer
anchors.top: parent.top
anchors.left: detailsToggle.right
anchors.leftMargin: 4
anchors.right: parent.right
height: detailsContainer.height - (root.detailsExpanded ? (copyToClipboardButton.height + copyToClipboardButton.anchors.topMargin) : 0)
clip: true
TextArea {
id: detailsText
readOnly: true
color: hifi.colors.white
text: {
var numUniqueResources = (model.resourceAccessEventText.split("\n").length - 1);
if (root.detailsExpanded && numUniqueResources > 0) {
return model.resourceAccessEventText
} else {
return numUniqueResources.toString() + " unique source/resource url pair" + (numUniqueResources === 1 ? "" : "s") + " recorded"
}
}
font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal })
wrapMode: TextEdit.NoWrap
background: Rectangle {
anchors.fill: parent;
color: hifi.colors.baseGrayShadow;
border.width: 0;
}
}
MouseArea {
anchors.fill: parent
onClicked: {
if (root.detailsExpanded) {
detailsText.selectAll();
} else {
root.detailsExpanded = true;
}
}
}
}
HifiControlsUit.Button {
id: copyToClipboardButton;
visible: root.detailsExpanded
color: hifi.buttons.noneBorderlessWhite
colorScheme: hifi.colorSchemes.dark
anchors.top: detailsTextContainer.bottom
anchors.topMargin: 8
anchors.right: parent.right
width: 160
height: 30
text: "Copy to Clipboard"
onClicked: {
Window.copyToClipboard(detailsText.text);
}
}
}
}

View file

@ -4,21 +4,19 @@
//
// Load items not in the marketplace for testing purposes
//
// Created by Zach Fox on 2018-09-05
// Created by Kerry Ivan Kurian on 2018-09-05
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.0
import QtQuick 2.10
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.3
import Hifi 1.0 as Hifi
import "../../../styles-uit" as HifiStylesUit
import "../../../controls-uit" as HifiControlsUit
import "qrc:////qml//styles-uit" as HifiStylesUit
import "qrc:////qml//controls-uit" as HifiControlsUit
@ -27,33 +25,223 @@ Rectangle {
property string installedApps
property var nextResourceObjectId: 0
signal sendToScript(var message)
HifiStylesUit.HifiConstants { id: hifi }
ListModel { id: resourceListModel }
color: hifi.colors.white
color: hifi.colors.darkGray
AnimatedImage {
id: spinner;
source: "spinner.gif"
width: 74;
height: width;
anchors.verticalCenter: parent.verticalCenter;
anchors.horizontalCenter: parent.horizontalCenter;
//
// TITLE BAR START
//
Item {
id: titleBarContainer
// Size
width: root.width
height: 50
// Anchors
anchors.left: parent.left
anchors.top: parent.top
// Title bar text
HifiStylesUit.RalewaySemiBold {
id: titleBarText
text: "Marketplace Item Tester"
// Text size
size: 24
// Anchors
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: 16
width: paintedWidth
// Style
color: hifi.colors.lightGrayText
// Alignment
horizontalAlignment: Text.AlignHLeft
verticalAlignment: Text.AlignVCenter
}
// Separator
HifiControlsUit.Separator {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: 1
}
}
//
// TITLE BAR END
//
Rectangle {
id: spinner
z: 999
anchors.top: titleBarContainer.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: buttonContainer.top
color: hifi.colors.darkGray
AnimatedImage {
source: "spinner.gif"
width: 74
height: width
anchors.centerIn: parent
}
}
Rectangle {
id: instructionsContainer
z: 998
color: hifi.colors.darkGray
visible: resourceListModel.count === 0 && !spinner.visible
anchors.top: titleBarContainer.bottom
anchors.topMargin: 20
anchors.left: parent.left
anchors.leftMargin: 20
anchors.right: parent.right
anchors.rightMargin: 20
anchors.bottom: buttonContainer.top
anchors.bottomMargin: 20
HifiStylesUit.RalewayRegular {
text: "Use Marketplace Item Tester to test out your items before submitting them to the Marketplace." +
"\n\nUse one of the buttons below to load your item."
// Text size
size: 20
// Anchors
anchors.fill: parent
// Style
color: hifi.colors.lightGrayText
wrapMode: Text.Wrap
// Alignment
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
ListView {
id: itemList
visible: !instructionsContainer.visible
anchors.top: titleBarContainer.bottom
anchors.topMargin: 20
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: buttonContainer.top
anchors.bottomMargin: 20
ScrollBar.vertical: ScrollBar {
visible: !instructionsContainer.visible
policy: ScrollBar.AlwaysOn
parent: itemList.parent
anchors.top: itemList.top
anchors.right: itemList.right
anchors.bottom: itemList.bottom
width: 16
}
clip: true
model: resourceListModel
spacing: 8
delegate: ItemUnderTest { }
}
Item {
id: buttonContainer
anchors.left: parent.left
anchors.leftMargin: 12
anchors.right: parent.right
anchors.rightMargin: 12
anchors.bottom: parent.bottom
anchors.bottomMargin: 12
height: 40
property string currentAction
property var actions: {
"Load File": function() {
buttonContainer.currentAction = "load file";
Window.browseChanged.connect(onResourceSelected);
Window.browseAsync("Please select a file (*.app.json *.json *.fst *.json.gz)", "", "Assets (*.app.json *.json *.fst *.json.gz)");
},
"Load URL": function() {
buttonContainer.currentAction = "load url";
Window.promptTextChanged.connect(onResourceSelected);
Window.promptAsync("Please enter a URL", "");
}
}
function onResourceSelected(resource) {
// It is possible that we received the present signal
// from something other than our browserAsync window.
// Alas, there is nothing we can do about that so charge
// ahead as though we are sure the present signal is one
// we expect.
print("!!!! resource selected");
switch(currentAction) {
case "load file":
Window.browseChanged.disconnect(onResourceSelected);
break
case "load url":
Window.promptTextChanged.disconnect(onResourceSelected);
break;
}
if (resource) {
print("!!!! building resource object");
var resourceObj = buildResourceObj(resource);
print("!!!! notifying script of resource object");
sendToScript({
method: 'tester_newResourceObject',
resourceObject: resourceObj
});
}
}
HifiControlsUit.Button {
enabled: !spinner.visible
anchors.right: parent.horizontalCenter
anchors.rightMargin: width/4
anchors.verticalCenter: parent.verticalCenter
color: hifi.buttons.blue
fontSize: 20
text: "Load File"
width: parent.width / 3
height: parent.height
onClicked: buttonContainer.actions[text]()
}
HifiControlsUit.Button {
enabled: !spinner.visible
anchors.left: parent.horizontalCenter
anchors.leftMargin: width/4
anchors.verticalCenter: parent.verticalCenter
color: hifi.buttons.blue
fontSize: 20
text: "Load URL"
width: parent.width / 3
height: parent.height
onClicked: buttonContainer.actions[text]()
}
}
function fromScript(message) {
switch (message.method) {
case "newResourceObjectInTest":
var resourceObject = message.resourceObject;
resourceListModel.clear(); // REMOVE THIS once we support specific referrers
resourceListModel.append(resourceObject);
spinner.visible = false;
break;
case "nextObjectIdInTest":
print("!!!! message from script! " + JSON.stringify(message));
nextResourceObjectId = message.id;
spinner.visible = false;
break;
case "resourceRequestEvent":
// When we support multiple items under test simultaneously,
// we'll have to replace "0" with the correct index.
resourceListModel.setProperty(0, "resourceAccessEventText", message.resourceAccessEventText);
break;
}
}
@ -64,227 +252,26 @@ Rectangle {
resource.match(/\.json\.gz$/) ? "content set" :
resource.match(/\.json$/) ? "entity or wearable" :
"unknown");
return { "id": nextResourceObjectId++,
// Uncomment this once we support more than one item in test at the same time
//nextResourceObjectId++;
return { "resourceObjectId": nextResourceObjectId,
"resource": resource,
"assetType": assetType };
}
function installResourceObj(resourceObj) {
if ("application" === resourceObj.assetType) {
Commerce.installApp(resourceObj.resource);
}
}
function addAllInstalledAppsToList() {
var i, apps = Commerce.getInstalledApps().split(","), len = apps.length;
for(i = 0; i < len - 1; ++i) {
if (i in apps) {
resourceListModel.append(buildResourceObj(apps[i]));
}
}
}
function toUrl(resource) {
var httpPattern = /^http/i;
return httpPattern.test(resource) ? resource : "file:///" + resource;
}
function rezEntity(resource, entityType) {
function rezEntity(resource, entityType, resourceObjectId) {
print("!!!! tester_rezClicked");
sendToScript({
method: 'tester_rezClicked',
itemHref: toUrl(resource),
itemType: entityType});
itemType: entityType,
itemId: resourceObjectId });
}
ListView {
anchors.fill: parent
anchors.leftMargin: 12
anchors.bottomMargin: 40
anchors.rightMargin: 12
model: resourceListModel
spacing: 5
interactive: false
delegate: RowLayout {
anchors.left: parent.left
width: parent.width
spacing: 5
property var actions: {
"forward": function(resource, assetType){
switch(assetType) {
case "application":
Commerce.openApp(resource);
break;
case "avatar":
MyAvatar.useFullAvatarURL(resource);
break;
case "content set":
urlHandler.handleUrl("hifi://localhost/0,0,0");
Commerce.replaceContentSet(toUrl(resource), "");
break;
case "entity":
case "wearable":
rezEntity(resource, assetType);
break;
default:
print("Marketplace item tester unsupported assetType " + assetType);
}
},
"trash": function(resource, assetType){
if ("application" === assetType) {
Commerce.uninstallApp(resource);
}
sendToScript({
method: "tester_deleteResourceObject",
objectId: resourceListModel.get(index).id});
resourceListModel.remove(index);
}
}
Column {
Layout.preferredWidth: root.width * .6
spacing: 5
Text {
text: {
var match = resource.match(/\/([^/]*)$/);
return match ? match[1] : resource;
}
font.pointSize: 12
horizontalAlignment: Text.AlignBottom
}
Text {
text: resource
font.pointSize: 8
width: root.width * .6
horizontalAlignment: Text.AlignBottom
wrapMode: Text.WrapAnywhere
}
}
ComboBox {
id: comboBox
Layout.preferredWidth: root.width * .2
model: [
"application",
"avatar",
"content set",
"entity",
"wearable",
"unknown"
]
currentIndex: (("entity or wearable" === assetType) ?
model.indexOf("unknown") : model.indexOf(assetType))
Component.onCompleted: {
onCurrentIndexChanged.connect(function() {
assetType = model[currentIndex];
sendToScript({
method: "tester_updateResourceObjectAssetType",
objectId: resourceListModel.get(index)["id"],
assetType: assetType });
});
}
}
Repeater {
model: [ "forward", "trash" ]
HifiStylesUit.HiFiGlyphs {
property var glyphs: {
"application": hifi.glyphs.install,
"avatar": hifi.glyphs.avatar,
"content set": hifi.glyphs.globe,
"entity": hifi.glyphs.wand,
"trash": hifi.glyphs.trash,
"unknown": hifi.glyphs.circleSlash,
"wearable": hifi.glyphs.hat,
}
text: (("trash" === modelData) ?
glyphs.trash :
glyphs[comboBox.model[comboBox.currentIndex]])
size: ("trash" === modelData) ? 22 : 30
color: hifi.colors.black
horizontalAlignment: Text.AlignHCenter
MouseArea {
anchors.fill: parent
onClicked: {
actions[modelData](resource, comboBox.currentText);
}
}
}
}
}
headerPositioning: ListView.OverlayHeader
header: HifiStylesUit.RalewayRegular {
id: rootHeader
text: "Marketplace Item Tester"
height: 80
width: paintedWidth
size: 22
color: hifi.colors.black
anchors.left: parent.left
anchors.leftMargin: 12
}
footerPositioning: ListView.OverlayFooter
footer: Row {
id: rootActions
spacing: 20
anchors.horizontalCenter: parent.horizontalCenter
property string currentAction
property var actions: {
"Load File": function(){
rootActions.currentAction = "load file";
Window.browseChanged.connect(onResourceSelected);
Window.browseAsync("Please select a file (*.app.json *.json *.fst *.json.gz)", "", "Assets (*.app.json *.json *.fst *.json.gz)");
},
"Load URL": function(){
rootActions.currentAction = "load url";
Window.promptTextChanged.connect(onResourceSelected);
Window.promptAsync("Please enter a URL", "");
}
}
function onResourceSelected(resource) {
// It is possible that we received the present signal
// from something other than our browserAsync window.
// Alas, there is nothing we can do about that so charge
// ahead as though we are sure the present signal is one
// we expect.
switch(currentAction) {
case "load file":
Window.browseChanged.disconnect(onResourceSelected);
break
case "load url":
Window.promptTextChanged.disconnect(onResourceSelected);
break;
}
if (resource) {
var resourceObj = buildResourceObj(resource);
installResourceObj(resourceObj);
sendToScript({
method: 'tester_newResourceObject',
resourceObject: resourceObj });
}
}
Repeater {
model: [ "Load File", "Load URL" ]
HifiControlsUit.Button {
color: hifi.buttons.blue
fontSize: 20
text: modelData
width: root.width / 3
height: 40
onClicked: actions[text]()
}
}
}
}
signal sendToScript(var message)
}

Binary file not shown.

Before

(image error) Size: 45 KiB

After

(image error) Size: 58 KiB

View file

@ -116,9 +116,14 @@ Rectangle {
Column {
id: column2
width: 200
height: 400
height: 600
spacing: 10
CheckBox {
id: grabbable
text: qsTr("Grabbable")
}
CheckBox {
id: dynamic
text: qsTr("Dynamic")
@ -217,9 +222,10 @@ Rectangle {
newModelDialog.sendToScript({
method: "newModelDialogAdd",
params: {
textInput: modelURL.text,
checkBox: dynamic.checked,
comboBox: collisionType.currentIndex
url: modelURL.text,
dynamic: dynamic.checked,
collisionShapeIndex: collisionType.currentIndex,
grabbable: grabbable.checked
}
});
}

View file

@ -226,6 +226,7 @@
#include "commerce/Ledger.h"
#include "commerce/Wallet.h"
#include "commerce/QmlCommerce.h"
#include "ResourceRequestObserver.h"
#include "webbrowser/WebBrowserSuggestionsEngine.h"
#include <DesktopPreviewProvider.h>
@ -947,6 +948,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<WalletScriptingInterface>();
DependencyManager::set<FadeEffect>();
DependencyManager::set<ResourceRequestObserver>();
return previousSessionCrashed;
}
@ -3129,6 +3131,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance());
surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get()));
@ -5022,12 +5025,12 @@ void Application::saveSettings() const {
PluginManager::getInstance()->saveSettings();
}
bool Application::importEntities(const QString& urlOrFilename) {
bool Application::importEntities(const QString& urlOrFilename, const bool isObservable, const qint64 callerId) {
bool success = false;
_entityClipboard->withWriteLock([&] {
_entityClipboard->eraseAllOctreeElements();
success = _entityClipboard->readFromURL(urlOrFilename);
success = _entityClipboard->readFromURL(urlOrFilename, isObservable, callerId);
if (success) {
_entityClipboard->reaverageOctreeElements();
}
@ -6811,6 +6814,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGlobalObject("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get<AddressManager>().data());
scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance());
scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue);
@ -7197,7 +7201,8 @@ void Application::addAssetToWorldFromURL(QString url) {
addAssetToWorldInfo(filename, "Downloading model file " + filename + ".");
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, QUrl(url));
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, QUrl(url), true, -1, "Application::addAssetToWorldFromURL");
connect(request, &ResourceRequest::finished, this, &Application::addAssetToWorldFromURLRequestFinished);
request->send();
}

View file

@ -52,7 +52,6 @@
#include <RunningMarker.h>
#include "avatar/MyAvatar.h"
#include "BandwidthRecorder.h"
#include "FancyCamera.h"
#include "ConnectionMonitor.h"
#include "CursorManager.h"
@ -343,7 +342,7 @@ public slots:
QVector<EntityItemID> pasteEntities(float x, float y, float z);
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs, const glm::vec3* givenOffset = nullptr);
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
bool importEntities(const QString& url);
bool importEntities(const QString& url, const bool isObservable = true, const qint64 callerId = -1);
void updateThreadPoolCount() const;
void updateSystemTabletMode();
void goToErrorDomainURL(QUrl errorDomainURL);

View file

@ -53,7 +53,8 @@ void ATPAssetMigrator::loadEntityServerFile() {
auto migrateResources = [=](QUrl migrationURL, QJsonValueRef jsonValue, bool isModelURL) {
auto request =
DependencyManager::get<ResourceManager>()->createResourceRequest(this, migrationURL);
DependencyManager::get<ResourceManager>()->createResourceRequest(
this, migrationURL, true, -1, "ATPAssetMigrator::loadEntityServerFile");
if (request) {
qCDebug(asset_migrator) << "Requesting" << migrationURL << "for ATP asset migration";

View file

@ -26,6 +26,7 @@
#include <AccountManager.h>
#include <AddressManager.h>
#include <AudioClient.h>
#include <ClientTraitsHandler.h>
#include <display-plugins/DisplayPlugin.h>
#include <FSTReader.h>
#include <GeometryUtil.h>
@ -463,10 +464,74 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
}
}
void MyAvatar::updateSitStandState(float newHeightReading, float dt) {
const float STANDING_HEIGHT_MULTIPLE = 1.2f;
const float SITTING_HEIGHT_MULTIPLE = 0.833f;
const float SITTING_TIMEOUT = 4.0f; // 4 seconds
const float STANDING_TIMEOUT = 0.3333f; // 1/3 second
const float SITTING_UPPER_BOUND = 1.52f;
if (!getIsSitStandStateLocked()) {
if (!getIsAway() && qApp->isHMDMode()) {
if (getIsInSittingState()) {
if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) {
// if we recenter upwards then no longer in sitting state
_sitStandStateTimer += dt;
if (_sitStandStateTimer > STANDING_TIMEOUT) {
_averageUserHeightSensorSpace = newHeightReading;
_tippingPoint = newHeightReading;
setIsInSittingState(false);
}
} else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) {
// if we are mis labelled as sitting but we are standing in the real world this will
// make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state
_sitStandStateTimer += dt;
if (_sitStandStateTimer > SITTING_TIMEOUT) {
_averageUserHeightSensorSpace = newHeightReading;
_tippingPoint = newHeightReading;
// here we stay in sit state but reset the average height
setIsInSittingState(true);
}
} else {
// sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please)
if (_averageUserHeightSensorSpace > SITTING_UPPER_BOUND) {
setIsInSittingState(false);
} else {
// tipping point is average height when sitting.
_tippingPoint = _averageUserHeightSensorSpace;
_sitStandStateTimer = 0.0f;
}
}
} else {
// in the standing state
if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) {
_sitStandStateTimer += dt;
if (_sitStandStateTimer > SITTING_TIMEOUT) {
_averageUserHeightSensorSpace = newHeightReading;
_tippingPoint = newHeightReading;
setIsInSittingState(true);
}
} else {
// use the mode height for the tipping point when we are standing.
_tippingPoint = getCurrentStandingHeight();
_sitStandStateTimer = 0.0f;
}
}
} else {
//if you are away then reset the average and set state to standing.
_averageUserHeightSensorSpace = _userHeight.get();
_tippingPoint = _userHeight.get();
setIsInSittingState(false);
}
}
}
void MyAvatar::update(float deltaTime) {
// update moving average of HMD facing in xz plane.
const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength();
const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders
const float COSINE_THIRTY_DEGREES = 0.866f;
const float SQUATTY_TIMEOUT = 30.0f; // 30 seconds
const float HEIGHT_FILTER_COEFFICIENT = 0.01f;
float tau = deltaTime / HMD_FACING_TIMESCALE;
setHipToHandController(computeHandAzimuth());
@ -493,11 +558,36 @@ void MyAvatar::update(float deltaTime) {
_smoothOrientationTimer += deltaTime;
}
float newHeightReading = getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y;
int newHeightReadingInCentimeters = glm::floor(newHeightReading * CENTIMETERS_PER_METER);
_recentModeReadings.insert(newHeightReadingInCentimeters);
setCurrentStandingHeight(computeStandingHeightMode(getControllerPoseInAvatarFrame(controller::Action::HEAD)));
setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD)));
controller::Pose newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD);
if (newHeightReading.isValid()) {
int newHeightReadingInCentimeters = glm::floor(newHeightReading.getTranslation().y * CENTIMETERS_PER_METER);
_averageUserHeightSensorSpace = lerp(_averageUserHeightSensorSpace, newHeightReading.getTranslation().y, HEIGHT_FILTER_COEFFICIENT);
_recentModeReadings.insert(newHeightReadingInCentimeters);
setCurrentStandingHeight(computeStandingHeightMode(newHeightReading));
setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD)));
}
// if the spine is straight and the head is below the default position by 5 cm then increment squatty count.
const float SQUAT_THRESHOLD = 0.05f;
glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head"));
glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2"));
glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f);
if (glm::length(upSpine2) > 0.0f) {
upSpine2 = glm::normalize(upSpine2);
}
float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f));
if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_THIRTY_DEGREES)) {
_squatTimer += deltaTime;
if (_squatTimer > SQUATTY_TIMEOUT) {
_squatTimer = 0.0f;
_follow._squatDetected = true;
}
} else {
_squatTimer = 0.0f;
}
// put update sit stand state counts here
updateSitStandState(newHeightReading.getTranslation().y, deltaTime);
if (_drawAverageFacingEnabled) {
auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
@ -3557,12 +3647,9 @@ glm::vec3 MyAvatar::computeCounterBalance() {
glm::vec3 counterBalancedCg = (1.0f / DEFAULT_AVATAR_HIPS_MASS) * counterBalancedForHead;
// find the height of the hips
const float UPPER_LEG_FRACTION = 0.3333f;
glm::vec3 xzDiff((cgHeadMass.position.x - counterBalancedCg.x), 0.0f, (cgHeadMass.position.z - counterBalancedCg.z));
float headMinusHipXz = glm::length(xzDiff);
float headHipDefault = glm::length(tposeHead - tposeHips);
float hipFootDefault = tposeHips.y - tposeRightFoot.y;
float sitSquatThreshold = tposeHips.y - (UPPER_LEG_FRACTION * hipFootDefault);
float hipHeight = 0.0f;
if (headHipDefault > headMinusHipXz) {
hipHeight = sqrtf((headHipDefault * headHipDefault) - (headMinusHipXz * headMinusHipXz));
@ -3574,10 +3661,6 @@ glm::vec3 MyAvatar::computeCounterBalance() {
if (counterBalancedCg.y > (tposeHips.y + 0.05f)) {
// if the height is higher than default hips, clamp to default hips
counterBalancedCg.y = tposeHips.y + 0.05f;
} else if (counterBalancedCg.y < sitSquatThreshold) {
//do a height reset
setResetMode(true);
_follow.activate(FollowHelper::Vertical);
}
return counterBalancedCg;
}
@ -3818,6 +3901,18 @@ bool MyAvatar::getIsInWalkingState() const {
return _isInWalkingState;
}
bool MyAvatar::getIsInSittingState() const {
return _isInSittingState.get();
}
MyAvatar::SitStandModelType MyAvatar::getUserRecenterModel() const {
return _userRecenterModel.get();
}
bool MyAvatar::getIsSitStandStateLocked() const {
return _lockSitStandState.get();
}
float MyAvatar::getWalkSpeed() const {
return _walkSpeed.get() * _walkSpeedScalar;
}
@ -3838,6 +3933,61 @@ void MyAvatar::setIsInWalkingState(bool isWalking) {
_isInWalkingState = isWalking;
}
void MyAvatar::setIsInSittingState(bool isSitting) {
_sitStandStateTimer = 0.0f;
_squatTimer = 0.0f;
// on reset height we need the count to be more than one in case the user sits and stands up quickly.
_isInSittingState.set(isSitting);
setResetMode(true);
if (isSitting) {
setCenterOfGravityModelEnabled(false);
} else {
setCenterOfGravityModelEnabled(true);
}
setSitStandStateChange(true);
}
void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) {
_userRecenterModel.set(modelName);
switch (modelName) {
case MyAvatar::SitStandModelType::ForceSit:
setHMDLeanRecenterEnabled(true);
setIsInSittingState(true);
setIsSitStandStateLocked(true);
break;
case MyAvatar::SitStandModelType::ForceStand:
setHMDLeanRecenterEnabled(true);
setIsInSittingState(false);
setIsSitStandStateLocked(true);
break;
case MyAvatar::SitStandModelType::Auto:
default:
setHMDLeanRecenterEnabled(true);
setIsInSittingState(false);
setIsSitStandStateLocked(false);
break;
case MyAvatar::SitStandModelType::DisableHMDLean:
setHMDLeanRecenterEnabled(false);
setIsInSittingState(false);
setIsSitStandStateLocked(false);
break;
}
}
void MyAvatar::setIsSitStandStateLocked(bool isLocked) {
_lockSitStandState.set(isLocked);
_sitStandStateTimer = 0.0f;
_squatTimer = 0.0f;
_averageUserHeightSensorSpace = _userHeight.get();
_tippingPoint = _userHeight.get();
if (!isLocked) {
// always start the auto transition mode in standing state.
setIsInSittingState(false);
}
}
void MyAvatar::setWalkSpeed(float value) {
_walkSpeed.set(value);
}
@ -3854,6 +4004,14 @@ float MyAvatar::getSprintSpeed() const {
return _sprintSpeed.get();
}
void MyAvatar::setSitStandStateChange(bool stateChanged) {
_sitStandStateChange = stateChanged;
}
float MyAvatar::getSitStandStateChange() const {
return _sitStandStateChange;
}
QVector<QString> MyAvatar::getScriptUrls() {
QVector<QString> scripts = _skeletonModel->isLoaded() ? _skeletonModel->getFBXGeometry().scripts : QVector<QString>();
return scripts;
@ -3997,6 +4155,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
// x axis of currentBodyMatrix in world space.
glm::vec3 right = glm::normalize(glm::vec3(currentBodyMatrix[0][0], currentBodyMatrix[1][0], currentBodyMatrix[2][0]));
glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);
controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD);
float forwardLeanAmount = glm::dot(forward, offset);
float lateralLeanAmount = glm::dot(right, offset);
@ -4005,14 +4164,19 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
const float MAX_FORWARD_LEAN = 0.15f;
const float MAX_BACKWARD_LEAN = 0.1f;
if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) {
return true;
bool stepDetected = false;
if (myAvatar.getIsInSittingState()) {
if (!withinBaseOfSupport(currentHeadPose)) {
stepDetected = true;
}
} else if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) {
stepDetected = true;
} else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) {
return true;
stepDetected = true;
} else {
stepDetected = fabs(lateralLeanAmount) > MAX_LATERAL_LEAN;
}
return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN;
return stepDetected;
}
bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const {
@ -4021,6 +4185,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons
controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD);
controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND);
controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND);
controller::Pose currentHeadSensorPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD);
bool stepDetected = false;
float myScale = myAvatar.getAvatarScale();
@ -4030,7 +4195,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons
} else {
if (!withinBaseOfSupport(currentHeadPose) &&
headAngularVelocityBelowThreshold(currentHeadPose) &&
isWithinThresholdHeightMode(currentHeadPose, myAvatar.getCurrentStandingHeight(), myScale) &&
isWithinThresholdHeightMode(currentHeadSensorPose, myAvatar.getCurrentStandingHeight(), myScale) &&
handDirectionMatchesHeadDirection(currentLeftHandPose, currentRightHandPose, currentHeadPose) &&
handAngularVelocityBelowThreshold(currentLeftHandPose, currentRightHandPose) &&
headVelocityGreaterThanThreshold(currentHeadPose) &&
@ -4046,6 +4211,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons
glm::vec3 currentHeadPosition = currentHeadPose.getTranslation();
float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition);
if (!isActive(Horizontal) &&
(!isActive(Vertical)) &&
(glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) {
myAvatar.setResetMode(true);
stepDetected = true;
@ -4061,10 +4227,32 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons
bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
const float CYLINDER_TOP = 0.1f;
const float CYLINDER_BOTTOM = -1.5f;
const float SITTING_BOTTOM = -0.02f;
glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);
bool returnValue = false;
return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM);
if (myAvatar.getSitStandStateChange()) {
returnValue = true;
} else {
if (myAvatar.getIsInSittingState()) {
if (myAvatar.getIsSitStandStateLocked()) {
returnValue = (offset.y > CYLINDER_TOP);
}
if (offset.y < SITTING_BOTTOM) {
// we recenter more easily when in sitting state.
returnValue = true;
}
} else {
// in the standing state
returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM);
// finally check for squats in standing
if (_squatDetected) {
returnValue = true;
}
}
}
return returnValue;
}
void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix,
@ -4085,9 +4273,10 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
}
}
} else {
// center of gravity model is not enabled
if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
activate(Horizontal);
if (myAvatar.getEnableStepResetRotation()) {
if (myAvatar.getEnableStepResetRotation() && !myAvatar.getIsInSittingState()) {
activate(Rotation);
myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing());
}
@ -4095,6 +4284,9 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
}
if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) {
activate(Vertical);
if (_squatDetected) {
_squatDetected = false;
}
}
} else {
if (!isActive(Rotation) && getForceActivateRotation()) {
@ -4144,7 +4336,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
myAvatar.getCharacterController()->setFollowParameters(followWorldPose, getMaxTimeRemaining());
}
glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) {
glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) {
if (isActive()) {
float dt = myAvatar.getCharacterController()->getFollowTime();
decrementTimeRemaining(dt);
@ -4161,6 +4353,11 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co
glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix),
sensorLinearDisplacement + extractTranslation(currentBodyMatrix));
if (myAvatar.getSitStandStateChange()) {
myAvatar.setSitStandStateChange(false);
deactivate(Vertical);
setTranslation(newBodyMat, extractTranslation(myAvatar.deriveBodyFromHMDSensor()));
}
return newBodyMat;
} else {
return currentBodyMatrix;

View file

@ -21,7 +21,6 @@
#include <AvatarConstants.h>
#include <avatars-renderer/Avatar.h>
#include <avatars-renderer/ScriptAvatar.h>
#include <ClientTraitsHandler.h>
#include <controllers/Pose.h>
#include <controllers/Actions.h>
#include <EntityItem.h>
@ -142,6 +141,8 @@ class MyAvatar : public Avatar {
* @property {number} walkSpeed
* @property {number} walkBackwardSpeed
* @property {number} sprintSpeed
* @property {number} isInSittingState
* @property {number} userRecenterModel
*
* @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the
* registration point of the 3D model.
@ -242,6 +243,9 @@ class MyAvatar : public Avatar {
Q_PROPERTY(float walkSpeed READ getWalkSpeed WRITE setWalkSpeed);
Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed);
Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed);
Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState);
Q_PROPERTY(MyAvatar::SitStandModelType userRecenterModel READ getUserRecenterModel WRITE setUserRecenterModel);
Q_PROPERTY(bool isSitStandStateLocked READ getIsSitStandStateLocked WRITE setIsSitStandStateLocked);
const QString DOMINANT_LEFT_HAND = "left";
const QString DOMINANT_RIGHT_HAND = "right";
@ -262,6 +266,15 @@ public:
};
Q_ENUM(DriveKeys)
enum SitStandModelType {
ForceSit = 0,
ForceStand,
Auto,
DisableHMDLean,
NumSitStandTypes
};
Q_ENUM(SitStandModelType)
explicit MyAvatar(QThread* thread);
virtual ~MyAvatar();
@ -1121,12 +1134,21 @@ public:
void setIsInWalkingState(bool isWalking);
bool getIsInWalkingState() const;
void setIsInSittingState(bool isSitting);
bool getIsInSittingState() const;
void setUserRecenterModel(MyAvatar::SitStandModelType modelName);
MyAvatar::SitStandModelType getUserRecenterModel() const;
void setIsSitStandStateLocked(bool isLocked);
bool getIsSitStandStateLocked() const;
void setWalkSpeed(float value);
float getWalkSpeed() const;
void setWalkBackwardSpeed(float value);
float getWalkBackwardSpeed() const;
void setSprintSpeed(float value);
float getSprintSpeed() const;
void setSitStandStateChange(bool stateChanged);
float getSitStandStateChange() const;
void updateSitStandState(float newHeightReading, float dt);
QVector<QString> getScriptUrls();
@ -1532,6 +1554,7 @@ signals:
*/
void disableHandTouchForIDChanged(const QUuid& entityID, bool disable);
private slots:
void leaveDomain();
void updateCollisionCapsuleCache();
@ -1742,7 +1765,7 @@ private:
bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const;
bool shouldActivateHorizontalCG(MyAvatar& myAvatar) const;
void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput);
glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix);
glm::mat4 postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix);
bool getForceActivateRotation() const;
void setForceActivateRotation(bool val);
bool getForceActivateVertical() const;
@ -1751,6 +1774,7 @@ private:
void setForceActivateHorizontal(bool val);
bool getToggleHipsFollowing() const;
void setToggleHipsFollowing(bool followHead);
bool _squatDetected { false };
std::atomic<bool> _forceActivateRotation { false };
std::atomic<bool> _forceActivateVertical { false };
std::atomic<bool> _forceActivateHorizontal { false };
@ -1820,10 +1844,13 @@ private:
std::mutex _pinnedJointsMutex;
std::vector<int> _pinnedJoints;
void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize);
// height of user in sensor space, when standing erect.
ThreadSafeValueCache<float> _userHeight { DEFAULT_AVATAR_HEIGHT };
void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize);
float _averageUserHeightSensorSpace { _userHeight.get() };
bool _sitStandStateChange { false };
ThreadSafeValueCache<bool> _lockSitStandState { false };
// max unscaled forward movement speed
ThreadSafeValueCache<float> _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED };
@ -1831,6 +1858,11 @@ private:
ThreadSafeValueCache<float> _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR };
float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR };
bool _isInWalkingState { false };
ThreadSafeValueCache<bool> _isInSittingState { false };
ThreadSafeValueCache<MyAvatar::SitStandModelType> _userRecenterModel { MyAvatar::SitStandModelType::Auto };
float _sitStandStateTimer { 0.0f };
float _squatTimer { 0.0f };
float _tippingPoint { _userHeight.get() };
// load avatar scripts once when rig is ready
bool _shouldLoadScripts { false };

View file

@ -46,7 +46,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
}
glm::mat4 hipsMat;
if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && myAvatar->getHMDLeanRecenterEnabled()) {
if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && !(myAvatar->getIsInSittingState()) && myAvatar->getHMDLeanRecenterEnabled()) {
// then we use center of gravity model
hipsMat = myAvatar->deriveBodyUsingCgModel();
} else {
@ -250,6 +250,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
bool headExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Head"), currentHeadPose);
bool hipsExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Hips"), currentHipsPose);
if (spine2Exists && headExists && hipsExists) {
AnimPose rigSpaceYaw(myAvatar->getSpine2RotationRigSpace());
glm::vec3 u, v, w;
glm::vec3 fwd = rigSpaceYaw.rot() * glm::vec3(0.0f, 0.0f, 1.0f);

View file

@ -315,7 +315,7 @@ QString QmlCommerce::getInstalledApps(const QString& justInstalledAppID) {
return installedAppsFromMarketplace;
}
bool QmlCommerce::installApp(const QString& itemHref) {
bool QmlCommerce::installApp(const QString& itemHref, const bool& alsoOpenImmediately) {
if (!QDir(_appsPath).exists()) {
if (!QDir().mkdir(_appsPath)) {
qCDebug(commerce) << "Couldn't make _appsPath directory.";
@ -325,7 +325,8 @@ bool QmlCommerce::installApp(const QString& itemHref) {
QUrl appHref(itemHref);
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, appHref);
auto request =
DependencyManager::get<ResourceManager>()->createResourceRequest(this, appHref, true, -1, "QmlCommerce::installApp");
if (!request) {
qCDebug(commerce) << "Couldn't create resource request for app.";
@ -357,13 +358,22 @@ bool QmlCommerce::installApp(const QString& itemHref) {
QJsonObject appFileJsonObject = appFileJsonDocument.object();
QString scriptUrl = appFileJsonObject["scriptURL"].toString();
if ((DependencyManager::get<ScriptEngines>()->loadScript(scriptUrl.trimmed())).isNull()) {
qCDebug(commerce) << "Couldn't load script.";
return false;
// Don't try to re-load (install) a script if it's already running
QStringList runningScripts = DependencyManager::get<ScriptEngines>()->getRunningScripts();
if (!runningScripts.contains(scriptUrl)) {
if ((DependencyManager::get<ScriptEngines>()->loadScript(scriptUrl.trimmed())).isNull()) {
qCDebug(commerce) << "Couldn't load script.";
return false;
}
QFileInfo appFileInfo(appFile);
emit appInstalled(appFileInfo.baseName());
}
if (alsoOpenImmediately) {
QmlCommerce::openApp(itemHref);
}
QFileInfo appFileInfo(appFile);
emit appInstalled(appFileInfo.baseName());
return true;
});
request->send();

View file

@ -88,7 +88,7 @@ protected:
Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID);
Q_INVOKABLE QString getInstalledApps(const QString& justInstalledAppID = "");
Q_INVOKABLE bool installApp(const QString& appHref);
Q_INVOKABLE bool installApp(const QString& appHref, const bool& alsoOpenImmediately = false);
Q_INVOKABLE bool uninstallApp(const QString& appHref);
Q_INVOKABLE bool openApp(const QString& appHref);

View file

@ -91,7 +91,9 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
return; // bail since piggyback version doesn't match
}
qApp->trackIncomingOctreePacket(*message, sendingNode, wasStatsPacket);
if (packetType != PacketType::EntityQueryInitialResultsComplete) {
qApp->trackIncomingOctreePacket(*message, sendingNode, wasStatsPacket);
}
// seek back to beginning of packet after tracking
message->seek(0);

View file

@ -46,11 +46,17 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, float
return retVal;
}
bool ClipboardScriptingInterface::importEntities(const QString& filename) {
bool ClipboardScriptingInterface::importEntities(
const QString& filename,
const bool isObservable,
const qint64 callerId
) {
bool retVal;
BLOCKING_INVOKE_METHOD(qApp, "importEntities",
Q_RETURN_ARG(bool, retVal),
Q_ARG(const QString&, filename));
Q_ARG(const QString&, filename),
Q_ARG(const bool, isObservable),
Q_ARG(const qint64, callerId));
return retVal;
}

View file

@ -50,9 +50,11 @@ public:
* You can generate a JSON file using {@link Clipboard.exportEntities}.
* @function Clipboard.importEntities
* @param {string} filename Path and name of file to import.
* @param {boolean} does the ResourceRequestObserver observe this request?
* @param {number} optional internal id of object causing this import.
* @returns {boolean} <code>true</code> if the import was successful, otherwise <code>false</code>.
*/
Q_INVOKABLE bool importEntities(const QString& filename);
Q_INVOKABLE bool importEntities(const QString& filename, const bool isObservable = true, const qint64 callerId = -1);
/**jsdoc
* Export the entities specified to a JSON file.

View file

@ -259,6 +259,39 @@ void setupPreferences() {
auto preference = new CheckPreference(VR_MOVEMENT, "Show room boundaries while teleporting", getter, setter);
preferences->addPreference(preference);
}
{
auto getter = [myAvatar]()->int {
switch (myAvatar->getUserRecenterModel()) {
case MyAvatar::SitStandModelType::Auto:
default:
return 0;
case MyAvatar::SitStandModelType::ForceSit:
return 1;
case MyAvatar::SitStandModelType::DisableHMDLean:
return 2;
}
};
auto setter = [myAvatar](int value) {
switch (value) {
case 0:
default:
myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto);
break;
case 1:
myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit);
break;
case 2:
myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean);
break;
}
};
auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter);
QStringList items;
items << "Auto - turns on avatar leaning when standing in real world" << "Seated - disables all avatar leaning while sitting in real world" << "Disabled - allows avatar sitting on the floor [Experimental]";
preference->setHeading("Avatar leaning behavior");
preference->setItems(items);
preferences->addPreference(preference);
}
{
auto getter = [=]()->float { return myAvatar->getUserHeight(); };
auto setter = [=](float value) { myAvatar->setUserHeight(value); };

View file

@ -59,6 +59,7 @@
#include "raypick/PointerScriptingInterface.h"
#include <display-plugins/CompositorHelper.h>
#include "AboutUtil.h"
#include "ResourceRequestObserver.h"
static int MAX_WINDOW_SIZE = 4096;
static const float METERS_TO_INCHES = 39.3701f;
@ -269,6 +270,7 @@ void Web3DOverlay::setupQmlSurface(bool isTablet) {
_webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface());
_webSurface->getSurfaceContext()->setContextProperty("HiFiAbout", AboutUtil::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
// Override min fps for tablet UI, for silky smooth scrolling
setMaxFPS(90);

View file

@ -1,6 +1,6 @@
set(TARGET_NAME avatars-renderer)
setup_hifi_library(Network Script)
link_hifi_libraries(shared gpu graphics animation model-networking script-engine render render-utils image trackers entities-renderer)
link_hifi_libraries(shared shaders gpu graphics animation model-networking script-engine render render-utils image trackers entities-renderer)
include_hifi_library_headers(avatars)
include_hifi_library_headers(networking)
include_hifi_library_headers(fbx)

View file

@ -1731,6 +1731,7 @@ void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) {
glm::vec3 Avatar::getWorldFeetPosition() {
ShapeInfo shapeInfo;
computeShapeInfo(shapeInfo);
glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = halfHeight
glm::vec3 localFeet(0.0f, shapeInfo.getOffset().y - halfExtents.y - halfExtents.x, 0.0f);

View file

@ -44,6 +44,7 @@
#include "AvatarLogging.h"
#include "AvatarTraits.h"
#include "ClientTraitsHandler.h"
#include "ResourceRequestObserver.h"
//#define WANT_DEBUG
@ -2161,11 +2162,21 @@ void AvatarData::updateJointMappings() {
}
if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) {
////
// TODO: Should we rely upon HTTPResourceRequest for ResourceRequestObserver instead?
// HTTPResourceRequest::doSend() covers all of the following and
// then some. It doesn't cover the connect() call, so we may
// want to add a HTTPResourceRequest::doSend() method that does
// connects.
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest = QNetworkRequest(_skeletonModelURL);
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
DependencyManager::get<ResourceRequestObserver>()->update(
_skeletonModelURL, -1, "AvatarData::updateJointMappings");
QNetworkReply* networkReply = networkAccessManager.get(networkRequest);
//
////
connect(networkReply, &QNetworkReply::finished, this, &AvatarData::setJointMappingsFromNetworkReply);
}
}

View file

@ -31,7 +31,27 @@ ClientTraitsHandler::ClientTraitsHandler(AvatarData* owningAvatar) :
nodeList->getPacketReceiver().registerListener(PacketType::SetAvatarTraits, this, "processTraitOverride");
}
void ClientTraitsHandler::markTraitUpdated(AvatarTraits::TraitType updatedTrait) {
Lock lock(_traitLock);
_traitStatuses[updatedTrait] = Updated;
_hasChangedTraits = true;
}
void ClientTraitsHandler::markInstancedTraitUpdated(AvatarTraits::TraitType traitType, QUuid updatedInstanceID) {
Lock lock(_traitLock);
_traitStatuses.instanceInsert(traitType, updatedInstanceID, Updated);
_hasChangedTraits = true;
}
void ClientTraitsHandler::markInstancedTraitDeleted(AvatarTraits::TraitType traitType, QUuid deleteInstanceID) {
Lock lock(_traitLock);
_traitStatuses.instanceInsert(traitType, deleteInstanceID, Deleted);
_hasChangedTraits = true;
}
void ClientTraitsHandler::resetForNewMixer() {
Lock lock(_traitLock);
// re-set the current version to 0
_currentTraitVersion = AvatarTraits::DEFAULT_TRAIT_VERSION;
@ -46,6 +66,8 @@ void ClientTraitsHandler::resetForNewMixer() {
}
void ClientTraitsHandler::sendChangedTraitsToMixer() {
Lock lock(_traitLock);
if (hasChangedTraits() || _shouldPerformInitialSend) {
// we have at least one changed trait to send
@ -113,6 +135,7 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() {
void ClientTraitsHandler::processTraitOverride(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
if (sendingNode->getType() == NodeType::AvatarMixer) {
Lock lock(_traitLock);
while (message->getBytesLeftToRead()) {
AvatarTraits::TraitType traitType;
message->readPrimitive(&traitType);

View file

@ -26,14 +26,11 @@ public:
void sendChangedTraitsToMixer();
bool hasChangedTraits() { return _hasChangedTraits; }
bool hasChangedTraits() const { return _hasChangedTraits; }
void markTraitUpdated(AvatarTraits::TraitType updatedTrait)
{ _traitStatuses[updatedTrait] = Updated; _hasChangedTraits = true; }
void markInstancedTraitUpdated(AvatarTraits::TraitType traitType, QUuid updatedInstanceID)
{ _traitStatuses.instanceInsert(traitType, updatedInstanceID, Updated); _hasChangedTraits = true; }
void markInstancedTraitDeleted(AvatarTraits::TraitType traitType, QUuid deleteInstanceID)
{ _traitStatuses.instanceInsert(traitType, deleteInstanceID, Deleted); _hasChangedTraits = true; }
void markTraitUpdated(AvatarTraits::TraitType updatedTrait);
void markInstancedTraitUpdated(AvatarTraits::TraitType traitType, QUuid updatedInstanceID);
void markInstancedTraitDeleted(AvatarTraits::TraitType traitType, QUuid deleteInstanceID);
void resetForNewMixer();
@ -41,17 +38,21 @@ public slots:
void processTraitOverride(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
private:
using Mutex = std::recursive_mutex;
using Lock = std::lock_guard<Mutex>;
enum ClientTraitStatus {
Unchanged,
Updated,
Deleted
};
AvatarData* _owningAvatar;
AvatarData* const _owningAvatar;
Mutex _traitLock;
AvatarTraits::AssociatedTraitValues<ClientTraitStatus, Unchanged> _traitStatuses;
AvatarTraits::TraitVersion _currentTraitVersion { AvatarTraits::DEFAULT_TRAIT_VERSION };
AvatarTraits::TraitVersion _currentTraitVersion { AvatarTraits::DEFAULT_TRAIT_VERSION };
AvatarTraits::TraitVersion _currentSkeletonVersion { AvatarTraits::NULL_TRAIT_VERSION };
bool _shouldPerformInitialSend { false };

View file

@ -2,11 +2,11 @@ struct TextureData {
ivec2 textureSize;
};
layout(std140, binding=0) uniform textureDataBuffer {
LAYOUT_STD140(binding=0) uniform textureDataBuffer {
TextureData textureData;
};
layout(binding=0) uniform sampler2D colorMap;
LAYOUT(binding=0) uniform sampler2D colorMap;
layout(location=0) in vec2 varTexCoord0;
layout(location=0) out vec4 outFragColor;

View file

@ -363,56 +363,35 @@ void OpenGLDisplayPlugin::customizeContext() {
}
if (!_presentPipeline) {
gpu::StatePointer blendState = gpu::StatePointer(new gpu::State());
blendState->setDepthTest(gpu::State::DepthTest(false));
blendState->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
gpu::StatePointer scissorState = gpu::StatePointer(new gpu::State());
scissorState->setDepthTest(gpu::State::DepthTest(false));
scissorState->setScissorEnable(true);
{
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::drawTexture);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(gpu::State::DepthTest(false));
state->setScissorEnable(true);
_simplePipeline = gpu::Pipeline::create(program, state);
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::DrawTexture);
_simplePipeline = gpu::Pipeline::create(program, scissorState);
_hudPipeline = gpu::Pipeline::create(program, blendState);
}
{
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::display_plugins::program::SrgbToLinear);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(gpu::State::DepthTest(false));
state->setScissorEnable(true);
_presentPipeline = gpu::Pipeline::create(program, state);
_presentPipeline = gpu::Pipeline::create(program, scissorState);
}
{
auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawUnitQuadTexcoord);
auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTexture);
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(gpu::State::DepthTest(false));
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_hudPipeline = gpu::Pipeline::create(program, state);
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::DrawTextureMirroredX);
_mirrorHUDPipeline = gpu::Pipeline::create(program, blendState);
}
{
auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawUnitQuadTexcoord);
auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTextureMirroredX);
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(gpu::State::DepthTest(false));
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_mirrorHUDPipeline = gpu::Pipeline::create(program, state);
}
{
auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawTransformUnitQuad);
auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTexture);
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(gpu::State::DepthTest(false));
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_cursorPipeline = gpu::Pipeline::create(program, state);
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::DrawTransformedTexture);
_cursorPipeline = gpu::Pipeline::create(program, blendState);
}
}
updateCompositeFramebuffer();

View file

@ -1,10 +1,10 @@
// OpenGLDisplayPlugin_present.frag
layout(binding = 0) uniform sampler2D colorMap;
LAYOUT(binding=0) uniform sampler2D colorMap;
layout(location = 0) in vec2 varTexCoord0;
layout(location=0) in vec2 varTexCoord0;
layout(location = 0) out vec4 outFragColor;
layout(location=0) out vec4 outFragColor;
float sRGBFloatToLinear(float value) {
const float SRGB_ELBOW = 0.04045;

View file

@ -30,12 +30,14 @@ using namespace render::entities;
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
static const float SPHERE_ENTITY_SCALE = 0.5f;
static_assert(shader::render_utils::program::simple != 0, "Validate simple program exists");
static_assert(shader::render_utils::program::simple_transparent != 0, "Validate simple transparent program exists");
ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
_procedural._vertexSource = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::simple);
// FIXME: Setup proper uniform slots and use correct pipelines for forward rendering
_procedural._opaquefragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple);
_procedural._transparentfragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_transparent);
_procedural._opaqueFragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::simple);
_procedural._transparentFragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::simple_transparent);
_procedural._opaqueState->setCullMode(gpu::State::CULL_NONE);
_procedural._opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMaskDrawShape(*_procedural._opaqueState);

View file

@ -15,7 +15,7 @@
<@include DeferredBufferWrite.slh@>
// the albedo texture
layout(binding=0) uniform sampler2D originalTexture;
LAYOUT(binding=0) uniform sampler2D originalTexture;
// the interpolated normal
layout(location=0) in vec3 interpolatedNormal;

View file

@ -18,7 +18,7 @@
<$declareFadeFragment()$>
// the albedo texture
layout(binding=0) uniform sampler2D originalTexture;
LAYOUT(binding=0) uniform sampler2D originalTexture;
// the interpolated normal
layout(location=0) in vec3 interpolatedNormal;
@ -30,7 +30,7 @@ struct PolyLineUniforms {
vec3 color;
};
layout(binding=0) uniform polyLineBuffer {
LAYOUT(binding=0) uniform polyLineBuffer {
PolyLineUniforms polyline;
};

View file

@ -20,15 +20,15 @@ layout(location=RENDER_UTILS_ATTR_NORMAL_MS) in vec3 _normal;
layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _position;
layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition;
layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap;
layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap;
layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap;
LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap;
LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap;
LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap;
struct PolyvoxParams {
vec4 voxelVolumeSize;
};
layout(binding=0) uniform polyvoxParamsBuffer {
LAYOUT(binding=0) uniform polyvoxParamsBuffer {
PolyvoxParams params;
};

View file

@ -23,15 +23,15 @@ layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _position;
layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition;
layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _worldFadePosition;
layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap;
layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap;
layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap;
LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap;
LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap;
LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap;
struct PolyvoxParams {
vec4 voxelVolumeSize;
};
layout(binding=0) uniform polyvoxParamsBuffer {
LAYOUT(binding=0) uniform polyvoxParamsBuffer {
PolyvoxParams params;
};

View file

@ -10,7 +10,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
layout(binding=0) uniform sampler2D colorMap;
LAYOUT(binding=0) uniform sampler2D colorMap;
layout(location=0) in vec4 varColor;
layout(location=1) in vec2 varTexcoord;

View file

@ -43,7 +43,7 @@ struct ParticleUniforms {
vec2 spare;
};
layout(std140, binding=0) uniform particleBuffer {
LAYOUT_STD140(binding=0) uniform particleBuffer {
ParticleUniforms particle;
};

View file

@ -5,4 +5,4 @@ include_hifi_library_headers(fbx)
include_hifi_library_headers(gpu)
include_hifi_library_headers(image)
include_hifi_library_headers(ktx)
link_hifi_libraries(shared networking octree avatars graphics model-networking)
link_hifi_libraries(shared shaders networking octree avatars graphics model-networking)

View file

@ -200,7 +200,8 @@ void EntityEditFilters::addFilter(EntityItemID entityID, QString filterURL) {
_filterDataMap.insert(entityID, filterData);
_lock.unlock();
auto scriptRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(this, scriptURL);
auto scriptRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(
this, scriptURL, true, -1, "EntityEditFilters::addFilter");
if (!scriptRequest) {
qWarning() << "Could not create ResourceRequest for Entity Edit filter script at" << scriptURL.toString();
scriptRequestFinished(entityID);

View file

@ -953,7 +953,8 @@ bool GLTFReader::doesResourceExist(const QString& url) {
}
std::tuple<bool, QByteArray> GLTFReader::requestData(QUrl& url) {
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, url, true, -1, "GLTFReader::requestData");
if (!request) {
return std::make_tuple(false, QByteArray());

View file

@ -443,7 +443,8 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file
}
std::tuple<bool, QByteArray> requestData(QUrl& url) {
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, url, true, -1, "(OBJReader) requestData");
if (!request) {
return std::make_tuple(false, QByteArray());

View file

@ -14,14 +14,17 @@ using namespace gl;
void Uniform::load(GLuint glprogram, int index) {
this->index = index;
const GLint NAME_LENGTH = 256;
GLchar glname[NAME_LENGTH];
GLint length = 0;
glGetActiveUniform(glprogram, index, NAME_LENGTH, &length, &size, &type, glname);
// Length does NOT include the null terminator
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetActiveUniform.xhtml
name = std::string(glname, length);
binding = glGetUniformLocation(glprogram, glname);
if (index >= 0) {
static const GLint NAME_LENGTH = 1024;
GLchar glname[NAME_LENGTH];
memset(glname, 0, NAME_LENGTH);
GLint length = 0;
glGetActiveUniform(glprogram, index, NAME_LENGTH, &length, &size, &type, glname);
// Length does NOT include the null terminator
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetActiveUniform.xhtml
name = std::string(glname, length);
binding = glGetUniformLocation(glprogram, name.c_str());
}
}
bool isTextureType(GLenum type) {

View file

@ -1,6 +1,6 @@
set(TARGET_NAME gpu-gl-common)
setup_hifi_library(Concurrent)
link_hifi_libraries(shared gl gpu)
link_hifi_libraries(shared gl gpu shaders)
GroupSources("src")
target_opengl()

View file

@ -643,18 +643,21 @@ protected:
}
} _pipeline;
// Backend dependant compilation of the shader
// Backend dependent compilation of the shader
virtual void postLinkProgram(ShaderObject& programObject, const Shader& program) const;
virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
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
// 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 std::string getShaderSource(const Shader& shader, shader::Variant version) final;
shader::Variant getShaderVariant() const { return isStereo() ? shader::Variant::Stereo : shader::Variant::Mono; }
virtual shader::Dialect getShaderDialect() const = 0;
class ElementResource {
public:
gpu::Element _element;

View file

@ -54,7 +54,7 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
// check the program cache
// pick the program version
#ifdef GPU_STEREO_CAMERA_BUFFER
GLuint glprogram = pipelineObject->_program->getProgram((GLShader::Version)isStereo());
GLuint glprogram = pipelineObject->_program->getProgram(getShaderVariant());
#else
GLuint glprogram = pipelineObject->_program->getProgram();
#endif

View file

@ -25,120 +25,53 @@ static const std::array<GLenum, NUM_SHADER_DOMAINS> SHADER_DOMAINS{ {
GL_GEOMETRY_SHADER,
} };
// Domain specific defines
// Must match the order of type specified in gpu::Shader::Type
static const std::array<std::string, NUM_SHADER_DOMAINS> DOMAIN_DEFINES{ {
"#define GPU_VERTEX_SHADER",
"#define GPU_PIXEL_SHADER",
"#define GPU_GEOMETRY_SHADER",
} };
// Stereo specific defines
static const std::string stereoVersion{
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
R"SHADER(
#define GPU_TRANSFORM_IS_STEREO
#define GPU_TRANSFORM_STEREO_CAMERA
#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED
#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN
)SHADER"
#endif
#ifdef GPU_STEREO_DRAWCALL_DOUBLED
#ifdef GPU_STEREO_CAMERA_BUFFER
R"SHADER(
#define GPU_TRANSFORM_IS_STEREO
#define GPU_TRANSFORM_STEREO_CAMERA
#define GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED
)SHADER"
#else
R"SHADER(
#define GPU_TRANSFORM_IS_STEREO
)SHADER"
#endif
#endif
};
// TextureTable specific defines
static const std::string textureTableVersion {
"#extension GL_ARB_bindless_texture : require\n#define GPU_TEXTURE_TABLE_BINDLESS\n"
};
// Versions specific of the shader
static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
"",
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) {
std::string GLBackend::getShaderSource(const Shader& shader, shader::Variant variant) {
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());
if (subShader) {
result += subShader->getSource().getSource(getShaderDialect(), variant);
}
}
return result;
}
std::string shaderDefines = getBackendShaderHeader() + "\n"
+ (supportsBindless() ? textureTableVersion : "\n")
+ DOMAIN_DEFINES[shader.getType()] + "\n"
+ VERSION_DEFINES[version];
return shaderDefines + "\n" + shader.getSource().getCode();
}
return shader.getSource().getSource(getShaderDialect(), variant);
}
GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) {
// Any GLSLprogram ? normally yes...
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
GLShader::ShaderObjects shaderObjects;
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
const auto& variants = shader::allVariants();
Shader::CompilationLogs compilationLogs(variants.size());
shader.incrementCompilationAttempt();
for (int version = 0; version < GLShader::NumVersions; version++) {
auto& shaderObject = shaderObjects[version];
auto shaderSource = getShaderSource(shader, version);
for (const auto& variant : variants) {
auto index = static_cast<uint32_t>(variant);
auto shaderSource = getShaderSource(shader, variant);
auto& shaderObject = shaderObjects[index];
if (handler) {
bool retest = true;
std::string currentSrc = shaderSource;
// When a Handler is specified, we can try multiple times to build the shader and let the handler change the source if the compilation fails.
// 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 exit the while loop.
// The handler tells us if we should retry or not while returning a modified version of the source.
while (retest) {
bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderObject.glshader, compilationLogs[version].message);
compilationLogs[version].compiled = result;
bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderObject.glshader, compilationLogs[index].message);
compilationLogs[index].compiled = result;
if (!result) {
std::string newSrc;
retest = handler(shader, currentSrc, compilationLogs[version], newSrc);
retest = handler(shader, currentSrc, compilationLogs[index], newSrc);
currentSrc = newSrc;
} else {
retest = false;
}
}
} else {
compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderObject.glshader, compilationLogs[version].message);
compilationLogs[index].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderObject.glshader, compilationLogs[index].message);
}
if (!compilationLogs[version].compiled) {
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str();
if (!compilationLogs[index].compiled) {
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[index].message.c_str();
shader.setCompilationLogs(compilationLogs);
return nullptr;
}
@ -162,11 +95,13 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
GLShader::ShaderObjects programObjects;
program.incrementCompilationAttempt();
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
const auto& variants = shader::allVariants();
Shader::CompilationLogs compilationLogs(variants.size());
for (int version = 0; version < GLShader::NumVersions; version++) {
auto& programObject = programObjects[version];
auto programSource = getShaderSource(program, version);
for (const auto& variant : variants) {
auto index = static_cast<uint32_t>(variant);
auto& programObject = programObjects[index];
auto programSource = getShaderSource(program, variant);
auto hash = ::gl::getShaderHash(programSource);
CachedShader cachedBinary;
@ -199,11 +134,11 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
for (auto subShader : program.getShaders()) {
auto object = GLShader::sync((*this), *subShader, handler);
if (object) {
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
shaderGLObjects.push_back(object->_shaderObjects[index].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 ?");
compilationLogs[index].compiled = false;
compilationLogs[index].message = std::string("Failed to compile, one of the shaders of the program is not compiled ?");
program.setCompilationLogs(compilationLogs);
return nullptr;
}
@ -211,9 +146,9 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
glprogram = ::gl::buildProgram(shaderGLObjects);
if (!::gl::linkProgram(glprogram, compilationLogs[version].message)) {
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str();
compilationLogs[version].compiled = false;
if (!::gl::linkProgram(glprogram, compilationLogs[index].message)) {
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[index].message.c_str();
compilationLogs[index].compiled = false;
glDeleteProgram(glprogram);
glprogram = 0;
return nullptr;
@ -228,12 +163,12 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
}
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[index].message.c_str();
program.setCompilationLogs(compilationLogs);
return nullptr;
}
compilationLogs[version].compiled = true;
compilationLogs[index].compiled = true;
programObject.glprogram = glprogram;
postLinkProgram(programObject, program);
}
@ -249,7 +184,10 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
static const GLint INVALID_UNIFORM_INDEX = -1;
GLint GLBackend::getRealUniformLocation(GLint location) const {
auto& shader = _pipeline._programShader->_shaderObjects[(GLShader::Version)isStereo()];
auto variant = isStereo() ? shader::Variant::Stereo : shader::Variant::Mono;
auto index = static_cast<uint32_t>(variant);
auto& shader = _pipeline._programShader->_shaderObjects[index];
auto itr = shader.uniformRemap.find(location);
if (itr == shader.uniformRemap.end()) {
// This shouldn't happen, because we use reflection to determine all the possible
@ -264,20 +202,23 @@ GLint GLBackend::getRealUniformLocation(GLint location) const {
void GLBackend::postLinkProgram(ShaderObject& shaderObject, const Shader& program) const {
const auto& glprogram = shaderObject.glprogram;
const auto& expectedUniforms = program.getUniforms();
const auto expectedLocationsByName = expectedUniforms.getLocationsByName();
const auto uniforms = ::gl::Uniform::load(glprogram, expectedUniforms.getNames());
auto& uniformRemap = shaderObject.uniformRemap;
const auto& expectedUniforms = program.getReflection().uniforms;
// Pre-initialize all the uniforms with an invalid location
for (const auto& entry : expectedLocationsByName) {
auto& uniformRemap = shaderObject.uniformRemap;
// initialize all the uniforms with an invalid location
for (const auto& entry : expectedUniforms) {
uniformRemap[entry.second] = INVALID_UNIFORM_INDEX;
}
// Now load up all the actual found uniform location
// Get the actual uniform locations from the shader
const auto names = Shader::Reflection::getNames(expectedUniforms);
const auto uniforms = ::gl::Uniform::load(glprogram, names);
// Now populate the remapping with the found locations
for (const auto& uniform : uniforms) {
const auto& name = uniform.name;
const auto& expectedLocation = expectedLocationsByName.at(name);
const auto& expectedLocation = expectedUniforms.at(name);
const auto& location = uniform.binding;
uniformRemap[expectedLocation] = location;
}
@ -462,3 +403,4 @@ void GLBackend::initShaderBinaryCache() {
void GLBackend::killShaderBinaryCache() {
::gl::saveShaderCache(_shaderBinaryCache._binaries);
}

View file

@ -52,7 +52,7 @@ GLPipeline* GLPipeline::sync(GLBackend& backend, const Pipeline& pipeline) {
// Special case for view correction matrices, any pipeline that declares the correction buffer
// uniform will automatically have it provided without any client code necessary.
// Required for stable lighting in the HMD.
object->_cameraCorrection = shader->getUniformBuffers().isValid(gpu::slot::buffer::CameraCorrection);
object->_cameraCorrection = shader->getReflection().validUniformBuffer(gpu::slot::buffer::CameraCorrection);
object->_program = programObject;
object->_state = stateObject;

View file

@ -14,43 +14,45 @@
namespace gpu { namespace gl {
struct ShaderObject {
GLuint glshader { 0 };
GLuint glprogram { 0 };
enum class BindingType
{
INPUT,
OUTPUT,
TEXTURE,
SAMPLER,
UNIFORM_BUFFER,
RESOURCE_BUFFER,
UNIFORM,
};
using LocationMap = std::unordered_map <GLuint, GLuint>;
LocationMap uniformRemap;
using LocationMap = std::unordered_map<std::string, int32_t>;
using ReflectionMap = std::map<BindingType, LocationMap>;
using UniformMap = std::unordered_map<GLuint, GLuint>;
GLuint glshader{ 0 };
GLuint glprogram{ 0 };
UniformMap uniformRemap;
};
class GLShader : public GPUObject {
public:
static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr);
enum Version {
Mono = 0,
Stereo,
NumVersions
};
using ShaderObject = gpu::gl::ShaderObject;
using ShaderObjects = std::array< ShaderObject, NumVersions >;
using UniformMapping = std::map<GLint, GLint>;
using UniformMappingVersions = std::vector<UniformMapping>;
using ShaderObjects = std::array<ShaderObject, shader::NUM_VARIANTS>;
GLShader(const std::weak_ptr<GLBackend>& backend);
~GLShader();
ShaderObjects _shaderObjects;
GLuint getProgram(Version version = Mono) const {
return _shaderObjects[version].glprogram;
GLuint getProgram(shader::Variant version = shader::Variant::Mono) const {
return _shaderObjects[static_cast<uint32_t>(version)].glprogram;
}
const std::weak_ptr<GLBackend> _backend;
};
} }
}} // namespace gpu::gl
#endif

View file

@ -1,6 +1,6 @@
set(TARGET_NAME gpu-gl)
setup_hifi_library(Concurrent)
link_hifi_libraries(shared gl gpu gpu-gl-common)
link_hifi_libraries(shared gl gpu gpu-gl-common shaders)
if (UNIX)
target_link_libraries(${TARGET_NAME} pthread)
endif(UNIX)

View file

@ -170,8 +170,7 @@ protected:
// Output stage
void do_blit(const Batch& batch, size_t paramOffset) override;
std::string getBackendShaderHeader() const override;
shader::Dialect getShaderDialect() const override { return shader::Dialect::glsl410; }
void postLinkProgram(ShaderObject& programObject, const Shader& program) const override;
};

View file

@ -12,22 +12,13 @@ using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl41;
// GLSL version
std::string GL41Backend::getBackendShaderHeader() const {
static const std::string header(
R"SHADER(#version 410 core
#define GPU_GL410
#define BITFIELD int
)SHADER");
return header;
}
void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& program) const {
Parent::postLinkProgram(programObject, program);
const auto& glprogram = programObject.glprogram;
const auto& reflection = program.getReflection();
// For the UBOs, use glUniformBlockBinding to fixup the locations based on the reflection
{
const auto expectedUbos = program.getUniformBuffers().getLocationsByName();
const auto& expectedUbos = reflection.uniformBuffers;
auto ubos = ::gl::UniformBlock::load(glprogram);
for (const auto& ubo : ubos) {
const auto& name = ubo.name;
@ -41,7 +32,7 @@ void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& pro
// For the Textures, use glUniform1i to fixup the active texture slots based on the reflection
{
const auto expectedTextures = program.getTextures().getLocationsByName();
const auto& expectedTextures = reflection.textures;
for (const auto& expectedTexture : expectedTextures) {
auto location = glGetUniformLocation(glprogram, expectedTexture.first.c_str());
if (location < 0) {
@ -53,8 +44,9 @@ void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& pro
// For the resource buffers, do the same as for the textures, since in GL 4.1 that's how they're implemented
{
const auto expectedResourceBuffers = program.getResourceBuffers().getLocationsByName();
const auto resourceBufferUniforms = ::gl::Uniform::loadByName(glprogram, program.getResourceBuffers().getNames());
const auto& expectedResourceBuffers = reflection.resourceBuffers;
const auto names = Shader::Reflection::getNames(expectedResourceBuffers);
const auto resourceBufferUniforms = ::gl::Uniform::loadByName(glprogram, names);
for (const auto& resourceBuffer : resourceBufferUniforms) {
const auto& targetBinding = expectedResourceBuffers.at(resourceBuffer.name);
glProgramUniform1i(glprogram, resourceBuffer.binding, targetBinding + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT);

View file

@ -23,7 +23,7 @@
#define GPU_BINDLESS_TEXTURES 0
namespace gpu { namespace gl45 {
using namespace gpu::gl;
using TextureWeakPointer = std::weak_ptr<Texture>;
@ -56,6 +56,7 @@ public:
using Parent = GLTexture;
friend class GL45Backend;
static GLuint allocate(const Texture& texture);
protected:
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
void generateMips() const override;
@ -88,6 +89,7 @@ public:
virtual const Bindless& getBindless() const;
void releaseBindless() const;
void recreateBindless() const;
private:
mutable Bindless _bindless;
#endif
@ -98,10 +100,11 @@ public:
mutable Sampler _cachedSampler{ getInvalidSampler() };
};
#if GPU_BINDLESS_TEXTURES
#if GPU_BINDLESS_TEXTURES
class GL45TextureTable : public GLObject<TextureTable> {
static GLuint allocate();
using Parent = GLObject<TextureTable>;
public:
using BindlessArray = std::array<GL45Texture::Bindless, TextureTable::COUNT>;
@ -116,7 +119,6 @@ public:
};
#endif
//
// Textures that have fixed allocation sizes and cannot be managed at runtime
//
@ -134,12 +136,13 @@ public:
void allocateStorage() const;
void syncSampler() const override;
const Size _size { 0 };
const Size _size{ 0 };
};
class GL45AttachmentTexture : public GL45FixedAllocationTexture {
using Parent = GL45FixedAllocationTexture;
friend class GL45Backend;
protected:
GL45AttachmentTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
~GL45AttachmentTexture();
@ -148,6 +151,7 @@ public:
class GL45StrictResourceTexture : public GL45FixedAllocationTexture {
using Parent = GL45FixedAllocationTexture;
friend class GL45Backend;
protected:
GL45StrictResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
~GL45StrictResourceTexture();
@ -179,6 +183,7 @@ public:
class GL45ResourceTexture : public GL45VariableAllocationTexture {
using Parent = GL45VariableAllocationTexture;
friend class GL45Backend;
protected:
GL45ResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
@ -186,7 +191,6 @@ public:
size_t promote() override;
size_t demote() override;
void populateTransferQueue(TransferQueue& pendingTransfers) override;
void allocateStorage(uint16 mip);
Size copyMipsFromTexture();
@ -226,7 +230,6 @@ public:
};
#endif
protected:
void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override;
@ -244,7 +247,6 @@ protected:
GLuint getQueryID(const QueryPointer& query) override;
GLQuery* syncGPUObject(const Query& query) override;
// Draw Stage
void do_draw(const Batch& batch, size_t paramOffset) override;
void do_drawIndexed(const Batch& batch, size_t paramOffset) override;
@ -270,7 +272,7 @@ protected:
void do_blit(const Batch& batch, size_t paramOffset) override;
// Shader Stage
std::string getBackendShaderHeader() const override;
shader::Dialect getShaderDialect() const override;
// Texture Management Stage
void initTextureManagementStage() override;
@ -282,9 +284,8 @@ protected:
#endif
};
} }
}} // namespace gpu::gl45
Q_DECLARE_LOGGING_CATEGORY(gpugl45logging)
#endif

View file

@ -7,22 +7,16 @@
//
#include "GL45Backend.h"
#include <gpu/gl/GLShader.h>
//#include <gl/GLShaders.h>
using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl45;
// GLSL version
std::string GL45Backend::getBackendShaderHeader() const {
static const std::string header(
R"SHADER(#version 450 core
#define GPU_GL450
#define BITFIELD int
)SHADER"
#ifdef GPU_SSBO_TRANSFORM_OBJECT
R"SHADER(#define GPU_SSBO_TRANSFORM_OBJECT)SHADER"
shader::Dialect GL45Backend::getShaderDialect() const {
#if defined(Q_OS_MAC)
// We build, but don't actually use GL 4.5 on OSX
throw std::runtime_error("GL 4.5 unavailable on OSX");
#else
return shader::Dialect::glsl450;
#endif
);
return header;
}

View file

@ -1,5 +1,5 @@
set(TARGET_NAME gpu-gles)
setup_hifi_library(Gui Concurrent)
link_hifi_libraries(shared gl gpu gpu-gl-common)
link_hifi_libraries(shared shaders gl gpu gpu-gl-common)
GroupSources("src")
target_opengl()

View file

@ -27,11 +27,7 @@ class GLESBackend : public GLBackend {
friend class Context;
public:
static const GLint TRANSFORM_OBJECT_SLOT { 31 };
static const GLint RESOURCE_TRANSFER_TEX_UNIT { 32 };
static const GLint RESOURCE_TRANSFER_EXTRA_TEX_UNIT { 33 };
static const GLint RESOURCE_BUFFER_TEXBUF_TEX_UNIT { 34 };
static const GLint RESOURCE_BUFFER_SLOT0_TEX_UNIT { 35 };
explicit GLESBackend(bool syncCache) : Parent(syncCache) {}
GLESBackend() : Parent() {}
virtual ~GLESBackend() {
@ -166,7 +162,7 @@ protected:
// Output stage
void do_blit(const Batch& batch, size_t paramOffset) override;
std::string getBackendShaderHeader() const override;
shader::Dialect getShaderDialect() const override { return shader::Dialect::glsl310es; }
};
} }

View file

@ -12,15 +12,3 @@ using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gles;
// GLSL version
std::string GLESBackend::getBackendShaderHeader() const {
static const std::string header(
R"SHADER(#version 310 es
#extension GL_EXT_texture_buffer : enable
precision highp float;
precision highp samplerBuffer;
precision highp sampler2DShadow;
#define BITFIELD highp int
)SHADER");
return header;
}

View file

@ -60,12 +60,11 @@ void GLESBackend::transferTransformState(const Batch& batch) const {
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glActiveTexture(GL_TEXTURE0 + GLESBackend::TRANSFORM_OBJECT_SLOT);
glActiveTexture(GL_TEXTURE0 + slot::texture::ObjectTransforms);
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
if (!batch._objects.empty()) {
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer);
}
CHECK_GL_ERROR();
// Make sure the current Camera offset is unknown before render Draw

View file

@ -17,7 +17,7 @@ struct DrawColorParams {
vec4 color;
};
layout(binding=0) uniform drawColorParamsBuffer {
LAYOUT(binding=0) uniform drawColorParamsBuffer {
DrawColorParams params;
};

View file

@ -13,13 +13,13 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
layout(binding=0) uniform sampler2D colorMap;
LAYOUT(binding=0) uniform sampler2D colorMap;
struct DrawColorParams {
vec4 color;
};
layout(binding=0) uniform drawColorParams {
LAYOUT(binding=0) uniform drawColorParams {
DrawColorParams params;
};

View file

@ -25,7 +25,7 @@ struct TexCoordRectParams {
vec4 texcoordRect;
};
layout(binding=0) uniform texcoordRectBuffer {
LAYOUT(binding=0) uniform texcoordRectBuffer {
TexCoordRectParams params;
};

View file

@ -14,7 +14,7 @@
//
layout(binding=0) uniform sampler2D colorMap;
LAYOUT(binding=0) uniform sampler2D colorMap;
layout(location=0) in vec2 varTexCoord0;
layout(location=0) out vec4 outFragColor;

View file

@ -1,2 +1 @@
VERTEX DrawUnitQuadTexcoord
FRAGMENT DrawTexture

View file

@ -14,7 +14,7 @@
//
layout(binding=0) uniform sampler2D colorMap;
LAYOUT(binding=0) uniform sampler2D colorMap;
layout(location=0) in vec2 varTexCoord0;
layout(location=0) out vec4 outFragColor;

View file

@ -0,0 +1 @@
VERTEX DrawUnitQuadTexcoord

View file

@ -16,7 +16,7 @@
<@include gpu/ShaderConstants.h@>
layout(binding=0) uniform sampler2D colorMap;
LAYOUT(binding=0) uniform sampler2D colorMap;
layout(location=0) in vec2 varTexCoord0;

View file

@ -0,0 +1,2 @@
VERTEX DrawTransformUnitQuad
FRAGMENT DrawTexture

View file

@ -13,7 +13,7 @@
<@include gpu/ShaderConstants.h@>
layout(binding=GPU_TEXTURE_MIP_CREATION_INPUT) uniform sampler2D texMap;
LAYOUT(binding=GPU_TEXTURE_MIP_CREATION_INPUT) uniform sampler2D texMap;
in vec2 varTexCoord0;

View file

@ -10,44 +10,49 @@
//
#include "Shader.h"
#include <math.h>
#include <QDebug>
#include <set>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <shaders/Shaders.h>
#include "Context.h"
using namespace gpu;
std::atomic<uint32_t> Shader::_nextShaderID( 1 );
Shader::DomainShaderMaps Shader::_domainShaderMaps;
Shader::ProgramMap Shader::_programMap;
Shader::Shader(Type type, const Source& source) :
_source(source),
_type(type),
_ID(_nextShaderID++)
Shader::Shader(Type type, const Source& source, bool dynamic) :
_type(type)
{
auto& thisSource = const_cast<Source&>(_source);
thisSource = source;
if (!dynamic) {
thisSource.id = source.id;
}
}
Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel):
_type(type),
_ID(_nextShaderID++)
Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel) :
_type(type)
{
auto& shaders = const_cast<Shaders&>(_shaders);
if (geometry) {
_shaders.resize(3);
_shaders[VERTEX] = vertex;
_shaders[GEOMETRY] = geometry;
_shaders[PIXEL] = pixel;
shaders.resize(3);
shaders[VERTEX] = vertex;
shaders[GEOMETRY] = geometry;
shaders[PIXEL] = pixel;
} else {
_shaders.resize(2);
_shaders[VERTEX] = vertex;
_shaders[PIXEL] = pixel;
shaders.resize(2);
shaders[VERTEX] = vertex;
shaders[PIXEL] = pixel;
}
auto& reflection = const_cast<Reflection&>(getReflection());
for (const auto& subShader : _shaders) {
reflection.merge(subShader->getReflection());
}
if (_shaders[VERTEX]) {
reflection.inputs = _shaders[VERTEX]->getReflection().inputs;
}
if (_shaders[PIXEL]) {
reflection.outputs = _shaders[PIXEL]->getReflection().outputs;
}
}
@ -55,46 +60,27 @@ Shader::~Shader()
{
}
void populateSlotSet(Shader::SlotSet& slotSet, const Shader::LocationMap& map) {
for (const auto& entry : map) {
const auto& name = entry.first;
const auto& location = entry.second;
slotSet.insert({ name, location, Element() });
}
static std::unordered_map<uint32_t, std::weak_ptr<Shader>> _shaderCache;
Shader::ID Shader::getID() const {
if (isProgram()) {
return (_shaders[VERTEX]->getID() << 16) | (_shaders[PIXEL]->getID());
}
return _source.id;
}
Shader::Pointer Shader::createOrReuseDomainShader(Type type, const Source& source) {
auto found = _domainShaderMaps[type].find(source);
if (found != _domainShaderMaps[type].end()) {
Shader::Pointer Shader::createOrReuseDomainShader(Type type, uint32_t sourceId) {
// Don't attempt to cache non-static shaders
auto found = _shaderCache.find(sourceId);
if (found != _shaderCache.end()) {
auto sharedShader = (*found).second.lock();
if (sharedShader) {
return sharedShader;
}
}
auto shader = Pointer(new Shader(type, source));
const auto& reflection = source.getReflection();
if (0 != reflection.count(BindingType::INPUT)) {
populateSlotSet(shader->_inputs, reflection.find(BindingType::INPUT)->second);
}
if (0 != reflection.count(BindingType::OUTPUT)) {
populateSlotSet(shader->_outputs, reflection.find(BindingType::OUTPUT)->second);
}
if (0 != reflection.count(BindingType::UNIFORM_BUFFER)) {
populateSlotSet(shader->_uniformBuffers, reflection.find(BindingType::UNIFORM_BUFFER)->second);
}
if (0 != reflection.count(BindingType::RESOURCE_BUFFER)) {
populateSlotSet(shader->_resourceBuffers, reflection.find(BindingType::RESOURCE_BUFFER)->second);
}
if (0 != reflection.count(BindingType::TEXTURE)) {
populateSlotSet(shader->_textures, reflection.find(BindingType::TEXTURE)->second);
}
if (0 != reflection.count(BindingType::SAMPLER)) {
populateSlotSet(shader->_samplers, reflection.find(BindingType::SAMPLER)->second);
}
if (0 != reflection.count(BindingType::UNIFORM)) {
populateSlotSet(shader->_uniforms, reflection.find(BindingType::UNIFORM)->second);
}
_domainShaderMaps[type].emplace(source, std::weak_ptr<Shader>(shader));
auto shader = Pointer(new Shader(type, getShaderSource(sourceId), false));
_shaderCache.insert({ sourceId, shader });
return shader;
}
@ -137,28 +123,6 @@ ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& verte
// Program is a new one, let's create it
auto program = Pointer(new Shader(type, vertexShader, geometryShader, pixelShader));
// Combine the slots from the sub-shaders
for (const auto& shader : program->_shaders) {
const auto& reflection = shader->_source.getReflection();
if (0 != reflection.count(BindingType::UNIFORM_BUFFER)) {
populateSlotSet(program->_uniformBuffers, reflection.find(BindingType::UNIFORM_BUFFER)->second);
}
if (0 != reflection.count(BindingType::RESOURCE_BUFFER)) {
populateSlotSet(program->_resourceBuffers, reflection.find(BindingType::RESOURCE_BUFFER)->second);
}
if (0 != reflection.count(BindingType::TEXTURE)) {
populateSlotSet(program->_textures, reflection.find(BindingType::TEXTURE)->second);
}
if (0 != reflection.count(BindingType::SAMPLER)) {
populateSlotSet(program->_samplers, reflection.find(BindingType::SAMPLER)->second);
}
if (0 != reflection.count(BindingType::UNIFORM)) {
populateSlotSet(program->_uniforms, reflection.find(BindingType::UNIFORM)->second);
}
}
_programMap.emplace(key, std::weak_ptr<Shader>(program));
return program;
}
@ -175,24 +139,21 @@ void Shader::incrementCompilationAttempt() const {
}
Shader::Pointer Shader::createVertex(const Source& source) {
return createOrReuseDomainShader(VERTEX, source);
return Pointer(new Shader(VERTEX, source, true));
}
Shader::Pointer Shader::createPixel(const Source& source) {
return createOrReuseDomainShader(FRAGMENT, source);
return Pointer(new Shader(FRAGMENT, source, true));
}
Shader::Pointer Shader::createVertex(uint32_t id) {
return createVertex(getShaderSource(id));
return createOrReuseDomainShader(VERTEX, id);
}
Shader::Pointer Shader::createPixel(uint32_t id) {
return createPixel(getShaderSource(id));
return createOrReuseDomainShader(FRAGMENT, id);
}
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, pixelShader);
}
Shader::Pointer Shader::createProgram(uint32_t programId) {
auto vertexShader = createVertex(shader::getVertexId(programId));
@ -200,98 +161,15 @@ Shader::Pointer Shader::createProgram(uint32_t programId) {
return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, fragmentShader);
}
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
return Pointer(new Shader(PROGRAM, vertexShader, nullptr, pixelShader));
}
// Dynamic program, bypass caching
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
return createOrReuseProgramShader(PROGRAM, vertexShader, geometryShader, pixelShader);
return Pointer(new Shader(PROGRAM, vertexShader, geometryShader, pixelShader));
}
static const std::string IGNORED_BINDING = "transformObjectBuffer";
void updateBindingsFromJsonObject(Shader::LocationMap& inOutSet, const QJsonObject& json) {
for (const auto& key : json.keys()) {
auto keyStr = key.toStdString();
if (IGNORED_BINDING == keyStr) {
continue;
}
inOutSet[keyStr] = json[key].toInt();
}
}
void updateTextureAndResourceBuffersFromJsonObjects(Shader::LocationMap& inOutTextures, Shader::LocationMap& inOutResourceBuffers,
const QJsonObject& json, const QJsonObject& types) {
static const std::string RESOURCE_BUFFER_TEXTURE_TYPE = "samplerBuffer";
for (const auto& key : json.keys()) {
auto keyStr = key.toStdString();
if (keyStr == IGNORED_BINDING) {
continue;
}
auto location = json[key].toInt();
auto type = types[key].toString().toStdString();
if (type == RESOURCE_BUFFER_TEXTURE_TYPE) {
inOutResourceBuffers[keyStr] = location;
} else {
inOutTextures[key.toStdString()] = location;
}
}
}
Shader::ReflectionMap getShaderReflection(const std::string& reflectionJson) {
if (reflectionJson.empty() && reflectionJson != std::string("null")) {
return {};
}
#define REFLECT_KEY_INPUTS "inputs"
#define REFLECT_KEY_OUTPUTS "outputs"
#define REFLECT_KEY_UBOS "uniformBuffers"
#define REFLECT_KEY_SSBOS "storageBuffers"
#define REFLECT_KEY_UNIFORMS "uniforms"
#define REFLECT_KEY_TEXTURES "textures"
#define REFLECT_KEY_TEXTURE_TYPES "textureTypes"
auto doc = QJsonDocument::fromJson(reflectionJson.c_str());
if (doc.isNull()) {
qWarning() << "Invalid shader reflection JSON" << reflectionJson.c_str();
return {};
}
Shader::ReflectionMap result;
auto json = doc.object();
if (json.contains(REFLECT_KEY_INPUTS)) {
updateBindingsFromJsonObject(result[Shader::BindingType::INPUT], json[REFLECT_KEY_INPUTS].toObject());
}
if (json.contains(REFLECT_KEY_OUTPUTS)) {
updateBindingsFromJsonObject(result[Shader::BindingType::OUTPUT], json[REFLECT_KEY_OUTPUTS].toObject());
}
// FIXME eliminate the last of the uniforms
if (json.contains(REFLECT_KEY_UNIFORMS)) {
updateBindingsFromJsonObject(result[Shader::BindingType::UNIFORM], json[REFLECT_KEY_UNIFORMS].toObject());
}
if (json.contains(REFLECT_KEY_UBOS)) {
updateBindingsFromJsonObject(result[Shader::BindingType::UNIFORM_BUFFER], json[REFLECT_KEY_UBOS].toObject());
}
// SSBOs need to come BEFORE the textures. In GL 4.5 the reflection slots aren't really used, but in 4.1 the slots
// are used to explicitly setup bindings after shader linkage, so we want the resource buffer slots to contain the
// texture locations, not the SSBO locations
if (json.contains(REFLECT_KEY_SSBOS)) {
updateBindingsFromJsonObject(result[Shader::BindingType::RESOURCE_BUFFER], json[REFLECT_KEY_SSBOS].toObject());
}
// samplerBuffer textures map to gpu ResourceBuffer, while all other textures map to regular gpu Texture
if (json.contains(REFLECT_KEY_TEXTURES)) {
updateTextureAndResourceBuffersFromJsonObjects(
result[Shader::BindingType::TEXTURE],
result[Shader::BindingType::RESOURCE_BUFFER],
json[REFLECT_KEY_TEXTURES].toObject(),
json[REFLECT_KEY_TEXTURE_TYPES].toObject());
}
return result;
}
Shader::Source Shader::getShaderSource(uint32_t id) {
auto source = shader::loadShaderSource(id);
auto reflectionJson = shader::loadShaderReflection(id);
auto reflection = getShaderReflection(reflectionJson);
return { source, reflection };
const Shader::Source& Shader::getShaderSource(uint32_t id) {
return shader::Source::get(id);
}

View file

@ -19,6 +19,7 @@
#include <unordered_map>
#include <map>
#include <functional>
#include <shaders/Shaders.h>
#include <QUrl>
namespace gpu {
@ -42,58 +43,10 @@ public:
typedef std::shared_ptr<Shader> Pointer;
typedef std::vector<Pointer> Shaders;
// Needs to match values in shaders/Shaders.h
enum class BindingType
{
INVALID = -1,
INPUT = 0,
OUTPUT,
TEXTURE,
SAMPLER,
UNIFORM_BUFFER,
RESOURCE_BUFFER,
UNIFORM,
};
using LocationMap = std::unordered_map<std::string, int32_t>;
using ReflectionMap = std::map<BindingType, LocationMap>;
class Source {
public:
enum Language
{
INVALID = -1,
GLSL = 0,
SPIRV = 1,
MSL = 2,
HLSL = 3,
};
Source() {}
Source(const std::string& code, const ReflectionMap& reflection, Language lang = GLSL) :
_code(code), _reflection(reflection), _lang(lang) {}
Source(const Source& source) : _code(source._code), _reflection(source._reflection), _lang(source._lang) {}
virtual ~Source() {}
virtual const std::string& getCode() const { return _code; }
virtual const ReflectionMap& getReflection() const { return _reflection; }
class Less {
public:
bool operator()(const Source& x, const Source& y) const {
if (x._lang == y._lang) {
return x._code < y._code;
} else {
return (x._lang < y._lang);
}
}
};
protected:
std::string _code;
ReflectionMap _reflection;
Language _lang;
};
using Source = shader::Source;
using Reflection = shader::Reflection;
using Dialect = shader::Dialect;
using Variant = shader::Variant;
struct CompilationLog {
std::string message;
@ -112,85 +65,13 @@ public:
bool operator()(const T& x, const T& y) const { return x._name < y._name; }
};
class Slot {
public:
std::string _name;
int32 _location{ INVALID_LOCATION };
Element _element;
uint16 _resourceType{ Resource::BUFFER };
uint32 _size{ 0 };
Slot(const Slot& s) :
_name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {}
Slot(Slot&& s) :
_name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {}
Slot(const std::string& name,
int32 location,
const Element& element,
uint16 resourceType = Resource::BUFFER,
uint32 size = 0) :
_name(name),
_location(location), _element(element), _resourceType(resourceType), _size(size) {}
Slot(const std::string& name) : _name(name) {}
Slot& operator=(const Slot& s) {
_name = s._name;
_location = s._location;
_element = s._element;
_resourceType = s._resourceType;
_size = s._size;
return (*this);
}
};
class SlotSet : protected std::set<Slot, Less<Slot>> {
using Parent = std::set<Slot, Less<Slot>>;
public:
void insert(const Parent::value_type& value) {
Parent::insert(value);
if (value._location != INVALID_LOCATION) {
_validSlots.insert(value._location);
}
}
using Parent::begin;
using Parent::empty;
using Parent::end;
using Parent::size;
using LocationMap = std::unordered_map<std::string, int32>;
using NameVector = std::vector<std::string>;
NameVector getNames() const {
NameVector result;
for (const auto& entry : *this) {
result.push_back(entry._name);
}
return result;
}
LocationMap getLocationsByName() const {
LocationMap result;
for (const auto& entry : *this) {
result.insert({ entry._name, entry._location });
}
return result;
}
bool isValid(int32 slot) const { return 0 != _validSlots.count(slot); }
protected:
std::unordered_set<int> _validSlots;
};
static Source getShaderSource(uint32_t id);
static Source getVertexShaderSource(uint32_t id) { return getShaderSource(id); }
static Source getFragmentShaderSource(uint32_t id) { return getShaderSource(id); }
static const Source& getShaderSource(uint32_t id);
static const Source& getVertexShaderSource(uint32_t id) { return getShaderSource(id); }
static const Source& getFragmentShaderSource(uint32_t id) { return getShaderSource(id); }
static Pointer createVertex(const Source& source);
static Pointer createPixel(const Source& source);
static Pointer createGeometry(const Source& source);
static Pointer createVertex(uint32_t shaderId);
static Pointer createPixel(uint32_t shaderId);
static Pointer createGeometry(uint32_t shaderId);
@ -201,8 +82,7 @@ public:
~Shader();
ID getID() const { return _ID; }
ID getID() const;
Type getType() const { return _type; }
bool isProgram() const { return getType() > NUM_DOMAINS; }
bool isDomain() const { return getType() < NUM_DOMAINS; }
@ -211,17 +91,12 @@ public:
const Shaders& getShaders() const { return _shaders; }
// Access the exposed uniform, input and output slot
const SlotSet& getUniforms() const { return _uniforms; }
const SlotSet& getUniformBuffers() const { return _uniformBuffers; }
const SlotSet& getResourceBuffers() const { return _resourceBuffers; }
const SlotSet& getTextures() const { return _textures; }
const SlotSet& getSamplers() const { return _samplers; }
const Reflection& getReflection() const { return _source.reflection; }
// Compilation Handler can be passed while compiling a shader (in the makeProgram call) to be able to give the hand to
// the caller thread if the comilation fails and to prvide a different version of the source for it
// the caller thread if the compilation fails and to provide a different version of the source for it
// @param0 the Shader object that just failed to compile
// @param1 the original source code as submited to the compiler
// @param1 the original source code as submitted to the compiler
// @param2 the compilation log containing the error message
// @param3 a new string ready to be filled with the new version of the source that could be proposed from the handler functor
// @return boolean true if the backend should keep trying to compile the shader with the new source returned or false to stop and fail that shader compilation
@ -240,32 +115,21 @@ public:
const GPUObjectPointer gpuObject{};
protected:
Shader(Type type, const Source& source);
Shader(Type type, const Source& source, bool dynamic);
Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel);
Shader(const Shader& shader); // deep copy of the sysmem shader
Shader& operator=(const Shader& shader); // deep copy of the sysmem texture
// Source contains the actual source code or nothing if the shader is a program
Source _source;
const Source _source;
// if shader is composed of sub shaders, here they are
Shaders _shaders;
// List of exposed uniform, input and output slots
SlotSet _uniforms;
SlotSet _uniformBuffers;
SlotSet _resourceBuffers;
SlotSet _textures;
SlotSet _samplers;
SlotSet _inputs;
SlotSet _outputs;
const Shaders _shaders;
// The type of the shader, the master key
Type _type;
// The unique identifier of a shader in the GPU lib
uint32_t _ID{ 0 };
const Type _type;
// Number of attempts to compile the shader
mutable uint32_t _numCompilationAttempts{ 0 };
@ -277,13 +141,9 @@ protected:
// Global maps of the shaders
// Unique shader ID
static std::atomic<ID> _nextShaderID;
//static std::atomic<ID> _nextShaderID;
using ShaderMap = std::map<Source, std::weak_ptr<Shader>, Source::Less>;
using DomainShaderMaps = std::array<ShaderMap, NUM_DOMAINS>;
static DomainShaderMaps _domainShaderMaps;
static ShaderPointer createOrReuseDomainShader(Type type, const Source& source);
static ShaderPointer createOrReuseDomainShader(Type type, uint32_t sourceId);
using ProgramMapKey = glm::uvec3; // The IDs of the shaders in a program make its key
class ProgramKeyLess {

View file

@ -98,21 +98,6 @@ enum Attribute {
};
} // namespace attr
namespace uniform {
enum Uniform {
Extra0 = GPU_UNIFORM_EXTRA0,
Extra1 = GPU_UNIFORM_EXTRA1,
Extra2 = GPU_UNIFORM_EXTRA2,
Extra3 = GPU_UNIFORM_EXTRA3,
Extra4 = GPU_UNIFORM_EXTRA4,
Extra5 = GPU_UNIFORM_EXTRA5,
Extra6 = GPU_UNIFORM_EXTRA6,
Extra7 = GPU_UNIFORM_EXTRA7,
Extra8 = GPU_UNIFORM_EXTRA8,
Extra9 = GPU_UNIFORM_EXTRA9,
};
} // namespace uniform
} } // namespace gpu::slot
// !>

View file

@ -16,7 +16,7 @@
#define TransformCamera _TransformCamera
layout(std140, binding=GPU_BUFFER_TRANSFORM_CAMERA) uniform transformCameraBuffer {
LAYOUT_STD140(binding=GPU_BUFFER_TRANSFORM_CAMERA) uniform transformCameraBuffer {
#ifdef GPU_TRANSFORM_IS_STEREO
#ifdef GPU_TRANSFORM_STEREO_CAMERA
TransformCamera _camera[2];
@ -26,7 +26,7 @@ layout(std140, binding=GPU_BUFFER_TRANSFORM_CAMERA) uniform transformCameraBuffe
#else
TransformCamera _camera;
#endif
};
} _cameraBlock;
#ifdef GPU_VERTEX_SHADER
#ifdef GPU_TRANSFORM_IS_STEREO
@ -76,12 +76,12 @@ TransformCamera getTransformCamera() {
_stereoSide = gl_InstanceID % 2;
#endif
#endif
return _camera[_stereoSide];
return _cameraBlock._camera[_stereoSide];
#else
return _camera;
return _cameraBlock._camera;
#endif
#else
return _camera;
return _cameraBlock._camera;
#endif
}
@ -93,7 +93,7 @@ bool cam_isStereo() {
#ifdef GPU_TRANSFORM_IS_STEREO
return getTransformCamera()._stereoInfo.x > 0.0;
#else
return _camera._stereoInfo.x > 0.0;
return _cameraBlock._camera._stereoInfo.x > 0.0;
#endif
}
@ -102,10 +102,10 @@ float cam_getStereoSide() {
#ifdef GPU_TRANSFORM_STEREO_CAMERA
return getTransformCamera()._stereoInfo.y;
#else
return _camera._stereoInfo.y;
return _cameraBlock._camera._stereoInfo.y;
#endif
#else
return _camera._stereoInfo.y;
return _cameraBlock._camera._stereoInfo.y;
#endif
}
@ -120,7 +120,7 @@ struct TransformObject {
layout(location=GPU_ATTR_DRAW_CALL_INFO) in ivec2 _drawCallInfo;
#if defined(GPU_SSBO_TRANSFORM_OBJECT)
layout(std140, binding=GPU_STORAGE_TRANSFORM_OBJECT) buffer transformObjectBuffer {
LAYOUT_STD140(binding=GPU_STORAGE_TRANSFORM_OBJECT) buffer transformObjectBuffer {
TransformObject _object[];
};
TransformObject getTransformObject() {
@ -128,7 +128,7 @@ TransformObject getTransformObject() {
return transformObject;
}
#else
layout(binding=GPU_TEXTURE_TRANSFORM_OBJECT) uniform samplerBuffer transformObjectBuffer;
LAYOUT(binding=GPU_TEXTURE_TRANSFORM_OBJECT) uniform samplerBuffer transformObjectBuffer;
TransformObject getTransformObject() {
int offset = 8 * _drawCallInfo.x;
@ -167,7 +167,9 @@ TransformObject getTransformObject() {
vec4 eyeClipEdge[2]= vec4[2](vec4(-1,0,0,1), vec4(1,0,0,1));
vec2 eyeOffsetScale = vec2(-0.5, +0.5);
uint eyeIndex = uint(_stereoSide);
#ifndef GPU_GLES
gl_ClipDistance[0] = dot(<$clipPos$>, eyeClipEdge[eyeIndex]);
#endif
float newClipPosX = <$clipPos$>.x * 0.5 + eyeOffsetScale[eyeIndex] * <$clipPos$>.w;
<$clipPos$>.x = newClipPosX;
#endif

View file

@ -51,7 +51,7 @@ float getLightAmbientMapNumMips(LightAmbient l) { return l._ambient.y; }
<@if N@>
layout(binding=GRAPHICS_BUFFER_LIGHT) uniform lightBuffer {
LAYOUT(binding=GRAPHICS_BUFFER_LIGHT) uniform lightBuffer {
Light lightArray[<$N$>];
};
Light getLight(int index) {
@ -59,7 +59,7 @@ Light getLight(int index) {
}
<@else@>
layout(binding=GRAPHICS_BUFFER_KEY_LIGHT) uniform keyLightBuffer {
LAYOUT(binding=GRAPHICS_BUFFER_KEY_LIGHT) uniform keyLightBuffer {
Light light;
};
Light getKeyLight() {
@ -79,7 +79,7 @@ Light getKeyLight() {
<@if N@>
layout(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer {
LAYOUT(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer {
LightAmbient lightAmbientArray[<$N$>];
};
@ -88,7 +88,7 @@ LightAmbient getLightAmbient(int index) {
}
<@else@>
layout(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer {
LAYOUT(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer {
LightAmbient lightAmbient;
};

View file

@ -48,7 +48,7 @@ struct Material {
vec4 _scatteringSpare2Key;
};
layout(binding=GRAPHICS_BUFFER_MATERIAL) uniform materialBuffer {
LAYOUT(binding=GRAPHICS_BUFFER_MATERIAL) uniform materialBuffer {
Material _mat;
TexMapArray _texMapArray;
};

View file

@ -11,6 +11,7 @@
<@if not MODEL_MATERIAL_TEXTURES_SLH@>
<@def MODEL_MATERIAL_TEXTURES_SLH@>
<@include graphics/ShaderConstants.h@>
<@include graphics/Material.slh@>
<@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@>
@ -91,21 +92,21 @@ float fetchScatteringMap(vec2 uv) {
#else
<@if withAlbedo@>
layout(binding=GRAPHICS_TEXTURE_MATERIAL_ALBEDO) uniform sampler2D albedoMap;
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_ALBEDO) uniform sampler2D albedoMap;
vec4 fetchAlbedoMap(vec2 uv) {
return texture(albedoMap, uv, TAA_TEXTURE_LOD_BIAS);
}
<@endif@>
<@if withRoughness@>
layout(binding=GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS) uniform sampler2D roughnessMap;
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS) uniform sampler2D roughnessMap;
float fetchRoughnessMap(vec2 uv) {
return (texture(roughnessMap, uv, TAA_TEXTURE_LOD_BIAS).r);
}
<@endif@>
<@if withNormal@>
layout(binding=GRAPHICS_TEXTURE_MATERIAL_NORMAL) uniform sampler2D normalMap;
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_NORMAL) uniform sampler2D normalMap;
vec3 fetchNormalMap(vec2 uv) {
// unpack normal, swizzle to get into hifi tangent space with Y axis pointing out
vec2 t = 2.0 * (texture(normalMap, uv, TAA_TEXTURE_LOD_BIAS).rg - vec2(0.5, 0.5));
@ -115,28 +116,28 @@ vec3 fetchNormalMap(vec2 uv) {
<@endif@>
<@if withMetallic@>
layout(binding=GRAPHICS_TEXTURE_MATERIAL_METALLIC) uniform sampler2D metallicMap;
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_METALLIC) uniform sampler2D metallicMap;
float fetchMetallicMap(vec2 uv) {
return (texture(metallicMap, uv, TAA_TEXTURE_LOD_BIAS).r);
}
<@endif@>
<@if withEmissive@>
layout(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap;
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap;
vec3 fetchEmissiveMap(vec2 uv) {
return texture(emissiveMap, uv, TAA_TEXTURE_LOD_BIAS).rgb;
}
<@endif@>
<@if withOcclusion@>
layout(binding=GRAPHICS_TEXTURE_MATERIAL_OCCLUSION) uniform sampler2D occlusionMap;
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_OCCLUSION) uniform sampler2D occlusionMap;
float fetchOcclusionMap(vec2 uv) {
return texture(occlusionMap, uv).r;
}
<@endif@>
<@if withScattering@>
layout(binding=GRAPHICS_TEXTURE_MATERIAL_SCATTERING) uniform sampler2D scatteringMap;
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_SCATTERING) uniform sampler2D scatteringMap;
float fetchScatteringMap(vec2 uv) {
float scattering = texture(scatteringMap, uv, TAA_TEXTURE_LOD_BIAS).r; // boolean scattering for now
return max(((scattering - 0.1) / 0.9), 0.0);
@ -185,7 +186,7 @@ float fetchScatteringMap(vec2 uv) {
<$declareMaterialTexMapArrayBuffer()$>
layout(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap;
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap;
vec3 fetchLightmapMap(vec2 uv) {
vec2 lightmapParams = getTexMapArray()._lightmapParams.xy;
return (vec3(lightmapParams.x) + lightmapParams.y * texture(emissiveMap, uv).rgb);

View file

@ -12,13 +12,13 @@
//
<@include graphics/ShaderConstants.h@>
layout(binding=GRAPHICS_TEXTURE_SKYBOX) uniform samplerCube cubeMap;
LAYOUT(binding=GRAPHICS_TEXTURE_SKYBOX) uniform samplerCube cubeMap;
struct Skybox {
vec4 color;
};
layout(binding=GRAPHICS_BUFFER_SKYBOX_PARAMS) uniform skyboxBuffer {
LAYOUT(binding=GRAPHICS_BUFFER_SKYBOX_PARAMS) uniform skyboxBuffer {
Skybox skybox;
};

Some files were not shown because too many files have changed in this diff Show more