mirror of
https://github.com/lubosz/overte.git
synced 2025-08-08 04:08:13 +02:00
Merge branch 'master' of http://github.com/highfidelity/hifi into scribe
This commit is contained in:
commit
ac92b3c130
115 changed files with 1541 additions and 31847 deletions
|
@ -453,7 +453,7 @@ void EntityServer::domainSettingsRequestFailed() {
|
||||||
void EntityServer::startDynamicDomainVerification() {
|
void EntityServer::startDynamicDomainVerification() {
|
||||||
qCDebug(entities) << "Starting Dynamic Domain Verification...";
|
qCDebug(entities) << "Starting Dynamic Domain Verification...";
|
||||||
|
|
||||||
QString thisDomainID = DependencyManager::get<AddressManager>()->getDomainId().remove(QRegExp("\\{|\\}"));
|
QString thisDomainID = DependencyManager::get<AddressManager>()->getDomainID().remove(QRegExp("\\{|\\}"));
|
||||||
|
|
||||||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
||||||
QHash<QString, EntityItemID> localMap(tree->getEntityCertificateIDMap());
|
QHash<QString, EntityItemID> localMap(tree->getEntityCertificateIDMap());
|
||||||
|
|
35
cmake/externals/crashpad/CMakeLists.txt
vendored
Normal file
35
cmake/externals/crashpad/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
include(ExternalProject)
|
||||||
|
set(EXTERNAL_NAME crashpad)
|
||||||
|
|
||||||
|
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
ExternalProject_Add(
|
||||||
|
${EXTERNAL_NAME}
|
||||||
|
URL https://backtrace.io/download/crashpad_062317.zip
|
||||||
|
URL_MD5 65817e564b3628492abfc1dbd2a1e98b
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
LOG_DOWNLOAD 1
|
||||||
|
)
|
||||||
|
|
||||||
|
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||||
|
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of Crashpad include directories")
|
||||||
|
|
||||||
|
set(LIB_EXT "lib")
|
||||||
|
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad release library")
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base release library")
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util release library")
|
||||||
|
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad debug library")
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base debug library")
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util debug library")
|
||||||
|
|
||||||
|
set(CRASHPAD_HANDLER_EXE_PATH ${SOURCE_DIR}/out/Release_x64/crashpad_handler.exe CACHE FILEPATH "Path to the Crashpad handler executable")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# Hide this external target (for ide users)
|
||||||
|
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
|
@ -1,34 +0,0 @@
|
||||||
#
|
|
||||||
# AddBugSplat.cmake
|
|
||||||
# cmake/macros
|
|
||||||
#
|
|
||||||
# Created by Ryan Huffman on 02/09/16.
|
|
||||||
# Copyright 2016 High Fidelity, Inc.
|
|
||||||
#
|
|
||||||
# Distributed under the Apache License, Version 2.0.
|
|
||||||
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
#
|
|
||||||
|
|
||||||
macro(add_bugsplat)
|
|
||||||
get_property(BUGSPLAT_CHECKED GLOBAL PROPERTY CHECKED_FOR_BUGSPLAT_ONCE)
|
|
||||||
|
|
||||||
if (NOT BUGSPLAT_CHECKED)
|
|
||||||
find_package(BugSplat)
|
|
||||||
set_property(GLOBAL PROPERTY CHECKED_FOR_BUGSPLAT_ONCE TRUE)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (BUGSPLAT_FOUND)
|
|
||||||
add_definitions(-DHAS_BUGSPLAT)
|
|
||||||
|
|
||||||
target_include_directories(${TARGET_NAME} PRIVATE ${BUGSPLAT_INCLUDE_DIRS})
|
|
||||||
target_link_libraries(${TARGET_NAME} ${BUGSPLAT_LIBRARIES})
|
|
||||||
add_paths_to_fixup_libs(${BUGSPLAT_DLL_PATH})
|
|
||||||
|
|
||||||
add_custom_command(TARGET ${TARGET_NAME}
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${BUGSPLAT_RC_DLL_PATH} "$<TARGET_FILE_DIR:${TARGET_NAME}>/")
|
|
||||||
add_custom_command(TARGET ${TARGET_NAME}
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${BUGSPLAT_EXE_PATH} "$<TARGET_FILE_DIR:${TARGET_NAME}>/")
|
|
||||||
endif ()
|
|
||||||
endmacro()
|
|
58
cmake/macros/AddCrashpad.cmake
Normal file
58
cmake/macros/AddCrashpad.cmake
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#
|
||||||
|
# AddCrashpad.cmake
|
||||||
|
# cmake/macros
|
||||||
|
#
|
||||||
|
# Created by Clement Brisset on 01/19/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(add_crashpad)
|
||||||
|
set (USE_CRASHPAD TRUE)
|
||||||
|
if ("$ENV{CMAKE_BACKTRACE_URL}" STREQUAL "")
|
||||||
|
set(USE_CRASHPAD FALSE)
|
||||||
|
else()
|
||||||
|
set(CMAKE_BACKTRACE_URL $ENV{CMAKE_BACKTRACE_URL})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if ("$ENV{CMAKE_BACKTRACE_TOKEN}" STREQUAL "")
|
||||||
|
set(USE_CRASHPAD FALSE)
|
||||||
|
else()
|
||||||
|
set(CMAKE_BACKTRACE_TOKEN $ENV{CMAKE_BACKTRACE_TOKEN})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (WIN32 AND USE_CRASHPAD)
|
||||||
|
get_property(CRASHPAD_CHECKED GLOBAL PROPERTY CHECKED_FOR_CRASHPAD_ONCE)
|
||||||
|
if (NOT CRASHPAD_CHECKED)
|
||||||
|
|
||||||
|
add_dependency_external_projects(crashpad)
|
||||||
|
find_package(crashpad REQUIRED)
|
||||||
|
|
||||||
|
set_property(GLOBAL PROPERTY CHECKED_FOR_CRASHPAD_ONCE TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_definitions(-DHAS_CRASHPAD)
|
||||||
|
add_definitions(-DCMAKE_BACKTRACE_URL=\"${CMAKE_BACKTRACE_URL}\")
|
||||||
|
add_definitions(-DCMAKE_BACKTRACE_TOKEN=\"${CMAKE_BACKTRACE_TOKEN}\")
|
||||||
|
|
||||||
|
target_include_directories(${TARGET_NAME} PRIVATE ${CRASHPAD_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(${TARGET_NAME} ${CRASHPAD_LIBRARY} ${CRASHPAD_BASE_LIBRARY} ${CRASHPAD_UTIL_LIBRARY})
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS "/ignore:4099")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${TARGET_NAME}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${CRASHPAD_HANDLER_EXE_PATH} "$<TARGET_FILE_DIR:${TARGET_NAME}>/"
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
PROGRAMS ${CRASHPAD_HANDLER_EXE_PATH}
|
||||||
|
DESTINATION ${INTERFACE_INSTALL_DIR}
|
||||||
|
COMPONENT ${CLIENT_COMPONENT}
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
endmacro()
|
7
cmake/macros/AddCustomQrcPath.cmake
Normal file
7
cmake/macros/AddCustomQrcPath.cmake
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# adds a custom path and local path to the inserted CUSTOM_PATHS_VAR list which
|
||||||
|
# can be given to the GENERATE_QRC command
|
||||||
|
|
||||||
|
function(ADD_CUSTOM_QRC_PATH CUSTOM_PATHS_VAR IMPORT_PATH LOCAL_PATH)
|
||||||
|
list(APPEND ${CUSTOM_PATHS_VAR} "${IMPORT_PATH}=${LOCAL_PATH}")
|
||||||
|
set(${CUSTOM_PATHS_VAR} ${${CUSTOM_PATHS_VAR}} PARENT_SCOPE)
|
||||||
|
endfunction()
|
14
cmake/macros/FindNPM.cmake
Normal file
14
cmake/macros/FindNPM.cmake
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#
|
||||||
|
# FindNPM.cmake
|
||||||
|
# cmake/macros
|
||||||
|
#
|
||||||
|
# Created by Thijs Wenker on 01/23/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(find_npm)
|
||||||
|
find_program(NPM_EXECUTABLE "npm")
|
||||||
|
endmacro()
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
function(GENERATE_QRC)
|
function(GENERATE_QRC)
|
||||||
set(oneValueArgs OUTPUT PREFIX PATH)
|
set(oneValueArgs OUTPUT PREFIX PATH)
|
||||||
set(multiValueArgs GLOBS)
|
set(multiValueArgs CUSTOM_PATHS GLOBS)
|
||||||
cmake_parse_arguments(GENERATE_QRC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
cmake_parse_arguments(GENERATE_QRC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||||
if ("${GENERATE_QRC_PREFIX}" STREQUAL "")
|
if ("${GENERATE_QRC_PREFIX}" STREQUAL "")
|
||||||
set(QRC_PREFIX_PATH /)
|
set(QRC_PREFIX_PATH /)
|
||||||
|
@ -20,6 +20,13 @@ function(GENERATE_QRC)
|
||||||
endforeach()
|
endforeach()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
foreach(CUSTOM_PATH ${GENERATE_QRC_CUSTOM_PATHS})
|
||||||
|
string(REPLACE "=" ";" CUSTOM_PATH ${CUSTOM_PATH})
|
||||||
|
list(GET CUSTOM_PATH 0 IMPORT_PATH)
|
||||||
|
list(GET CUSTOM_PATH 1 LOCAL_PATH)
|
||||||
|
set(QRC_CONTENTS "${QRC_CONTENTS}<file alias=\"${LOCAL_PATH}\">${IMPORT_PATH}</file>\n")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
set(GENERATE_QRC_DEPENDS ${ALL_FILES} PARENT_SCOPE)
|
set(GENERATE_QRC_DEPENDS ${ALL_FILES} PARENT_SCOPE)
|
||||||
configure_file("${HF_CMAKE_DIR}/templates/resources.qrc.in" ${GENERATE_QRC_OUTPUT})
|
configure_file("${HF_CMAKE_DIR}/templates/resources.qrc.in" ${GENERATE_QRC_OUTPUT})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
#
|
|
||||||
# FindBugSplat.cmake
|
|
||||||
# cmake/modules
|
|
||||||
#
|
|
||||||
# Created by Ryan Huffman on 02/09/16.
|
|
||||||
# Copyright 2016 High Fidelity, Inc.
|
|
||||||
#
|
|
||||||
# Distributed under the Apache License, Version 2.0.
|
|
||||||
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
#
|
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
|
||||||
hifi_library_search_hints("BugSplat")
|
|
||||||
|
|
||||||
find_path(BUGSPLAT_INCLUDE_DIRS NAMES BugSplat.h PATH_SUFFIXES inc HINTS ${BUGSPLAT_SEARCH_DIRS})
|
|
||||||
|
|
||||||
find_library(BUGSPLAT_LIBRARY_RELEASE "BugSplat64.lib" PATH_SUFFIXES "lib64" HINTS ${BUGSPLAT_SEARCH_DIRS})
|
|
||||||
find_path(BUGSPLAT_DLL_PATH NAMES "BugSplat64.dll" PATH_SUFFIXES "bin64" HINTS ${BUGSPLAT_SEARCH_DIRS})
|
|
||||||
find_file(BUGSPLAT_RC_DLL_PATH NAMES "BugSplatRc64.dll" PATH_SUFFIXES "bin64" HINTS ${BUGSPLAT_SEARCH_DIRS})
|
|
||||||
find_file(BUGSPLAT_EXE_PATH NAMES "BsSndRpt64.exe" PATH_SUFFIXES "bin64" HINTS ${BUGSPLAT_SEARCH_DIRS})
|
|
||||||
|
|
||||||
include(SelectLibraryConfigurations)
|
|
||||||
select_library_configurations(BUGSPLAT)
|
|
||||||
|
|
||||||
set(BUGSPLAT_LIBRARIES ${BUGSPLAT_LIBRARY_RELEASE})
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(BUGSPLAT_REQUIREMENTS BUGSPLAT_INCLUDE_DIRS BUGSPLAT_LIBRARIES BUGSPLAT_DLL_PATH BUGSPLAT_RC_DLL_PATH BUGSPLAT_EXE_PATH)
|
|
||||||
find_package_handle_standard_args(BugSplat DEFAULT_MSG ${BUGSPLAT_REQUIREMENTS})
|
|
41
cmake/modules/FindCrashpad.cmake
Normal file
41
cmake/modules/FindCrashpad.cmake
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#
|
||||||
|
# FindCrashpad.cmake
|
||||||
|
#
|
||||||
|
# Try to find Crashpad libraries and include path.
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# CRASHPAD_FOUND
|
||||||
|
# CRASHPAD_INCLUDE_DIRS
|
||||||
|
# CRASHPAD_LIBRARY
|
||||||
|
# CRASHPAD_BASE_LIBRARY
|
||||||
|
# CRASHPAD_UTIL_LIBRARY
|
||||||
|
#
|
||||||
|
# Created on 01/19/2018 by Clement Brisset
|
||||||
|
# Copyright 2018 High Fidelity, Inc.
|
||||||
|
#
|
||||||
|
# Distributed under the Apache License, Version 2.0.
|
||||||
|
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
#
|
||||||
|
|
||||||
|
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||||
|
hifi_library_search_hints("crashpad")
|
||||||
|
|
||||||
|
find_path(CRASHPAD_INCLUDE_DIRS base/macros.h PATH_SUFFIXES include HINTS ${CRASHPAD_SEARCH_DIRS})
|
||||||
|
|
||||||
|
find_library(CRASHPAD_LIBRARY_RELEASE crashpad PATH_SUFFIXES "Release_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
|
||||||
|
find_library(CRASHPAD_BASE_LIBRARY_RELEASE base PATH_SUFFIXES "Release_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
|
||||||
|
find_library(CRASHPAD_UTIL_LIBRARY_RELEASE util PATH_SUFFIXES "Release_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
|
||||||
|
|
||||||
|
find_library(CRASHPAD_LIBRARY_DEBUG crashpad PATH_SUFFIXES "Debug_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
|
||||||
|
find_library(CRASHPAD_BASE_LIBRARY_DEBUG base PATH_SUFFIXES "Debug_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
|
||||||
|
find_library(CRASHPAD_UTIL_LIBRARY_DEBUG util PATH_SUFFIXES "Debug_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
|
||||||
|
|
||||||
|
find_file(CRASHPAD_HANDLER_EXE_PATH NAME "crashpad_handler.exe" PATH_SUFFIXES "Release_x64" HINTS ${CRASHPAD_SEARCH_DIRS})
|
||||||
|
|
||||||
|
include(SelectLibraryConfigurations)
|
||||||
|
select_library_configurations(CRASHPAD)
|
||||||
|
select_library_configurations(CRASHPAD_BASE)
|
||||||
|
select_library_configurations(CRASHPAD_UTIL)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(CRASHPAD DEFAULT_MSG CRASHPAD_INCLUDE_DIRS CRASHPAD_LIBRARY CRASHPAD_BASE_LIBRARY CRASHPAD_UTIL_LIBRARY)
|
|
@ -823,6 +823,7 @@ Section "-Core installation"
|
||||||
Delete "$INSTDIR\server-console.exe"
|
Delete "$INSTDIR\server-console.exe"
|
||||||
RMDir /r "$INSTDIR\locales"
|
RMDir /r "$INSTDIR\locales"
|
||||||
RMDir /r "$INSTDIR\resources\app"
|
RMDir /r "$INSTDIR\resources\app"
|
||||||
|
RMDir /r "$INSTDIR\client"
|
||||||
Delete "$INSTDIR\resources\atom.asar"
|
Delete "$INSTDIR\resources\atom.asar"
|
||||||
Delete "$INSTDIR\build-info.json"
|
Delete "$INSTDIR\build-info.json"
|
||||||
Delete "$INSTDIR\content_resources_200_percent.pak"
|
Delete "$INSTDIR\content_resources_200_percent.pak"
|
||||||
|
|
|
@ -157,7 +157,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
DependencyManager::set<StatTracker>();
|
DependencyManager::set<StatTracker>();
|
||||||
|
|
||||||
LogUtils::init();
|
LogUtils::init();
|
||||||
Setting::init();
|
|
||||||
|
|
||||||
qDebug() << "Setting up domain-server";
|
qDebug() << "Setting up domain-server";
|
||||||
qDebug() << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
qDebug() << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
||||||
|
|
|
@ -29,6 +29,8 @@ int main(int argc, char* argv[]) {
|
||||||
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
||||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||||
|
|
||||||
|
Setting::init();
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,9 +11,17 @@ function(JOIN VALUES GLUE OUTPUT)
|
||||||
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
|
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
set(CUSTOM_INTERFACE_QRC_PATHS "")
|
||||||
|
|
||||||
|
find_npm()
|
||||||
|
|
||||||
|
if (BUILD_TOOLS AND NPM_EXECUTABLE)
|
||||||
|
add_custom_qrc_path(CUSTOM_INTERFACE_QRC_PATHS "${CMAKE_SOURCE_DIR}/tools/jsdoc/out/hifiJSDoc.json" "auto-complete/hifiJSDoc.json")
|
||||||
|
endif ()
|
||||||
|
|
||||||
set(RESOURCES_QRC ${CMAKE_CURRENT_BINARY_DIR}/resources.qrc)
|
set(RESOURCES_QRC ${CMAKE_CURRENT_BINARY_DIR}/resources.qrc)
|
||||||
set(RESOURCES_RCC ${CMAKE_CURRENT_SOURCE_DIR}/compiledResources/resources.rcc)
|
set(RESOURCES_RCC ${CMAKE_CURRENT_SOURCE_DIR}/compiledResources/resources.rcc)
|
||||||
generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *)
|
generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources CUSTOM_PATHS ${CUSTOM_INTERFACE_QRC_PATHS} GLOBS *)
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${RESOURCES_RCC}
|
OUTPUT ${RESOURCES_RCC}
|
||||||
|
@ -163,6 +171,11 @@ else ()
|
||||||
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if (BUILD_TOOLS AND NPM_EXECUTABLE)
|
||||||
|
# require JSDoc to be build before interface is deployed (Console Auto-complete)
|
||||||
|
add_dependencies(resources jsdoc)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_dependencies(${TARGET_NAME} resources)
|
add_dependencies(${TARGET_NAME} resources)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
@ -206,6 +219,7 @@ target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries
|
||||||
|
|
||||||
target_bullet()
|
target_bullet()
|
||||||
target_opengl()
|
target_opengl()
|
||||||
|
add_crashpad()
|
||||||
|
|
||||||
# perform standard include and linking for found externals
|
# perform standard include and linking for found externals
|
||||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||||
|
@ -289,6 +303,7 @@ if (APPLE)
|
||||||
|
|
||||||
set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources")
|
set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources")
|
||||||
|
|
||||||
|
|
||||||
# copy script files beside the executable
|
# copy script files beside the executable
|
||||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||||
|
@ -350,8 +365,6 @@ if (SCRIPTS_INSTALL_DIR)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_bugsplat()
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set(EXTRA_DEPLOY_OPTIONS "--qmldir \"${PROJECT_SOURCE_DIR}/resources/qml\"")
|
set(EXTRA_DEPLOY_OPTIONS "--qmldir \"${PROJECT_SOURCE_DIR}/resources/qml\"")
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,12 @@ Original.Button {
|
||||||
Tablet.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onFocusChanged: {
|
||||||
|
if (focus) {
|
||||||
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Tablet.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
|
@ -59,6 +65,8 @@ Original.Button {
|
||||||
hifi.buttons.pressedColor[control.color]
|
hifi.buttons.pressedColor[control.color]
|
||||||
} else if (control.hovered) {
|
} else if (control.hovered) {
|
||||||
hifi.buttons.hoveredColor[control.color]
|
hifi.buttons.hoveredColor[control.color]
|
||||||
|
} else if (!control.hovered && control.focus) {
|
||||||
|
hifi.buttons.focusedColor[control.color]
|
||||||
} else {
|
} else {
|
||||||
hifi.buttons.colorStart[control.color]
|
hifi.buttons.colorStart[control.color]
|
||||||
}
|
}
|
||||||
|
@ -73,6 +81,8 @@ Original.Button {
|
||||||
hifi.buttons.pressedColor[control.color]
|
hifi.buttons.pressedColor[control.color]
|
||||||
} else if (control.hovered) {
|
} else if (control.hovered) {
|
||||||
hifi.buttons.hoveredColor[control.color]
|
hifi.buttons.hoveredColor[control.color]
|
||||||
|
} else if (!control.hovered && control.focus) {
|
||||||
|
hifi.buttons.focusedColor[control.color]
|
||||||
} else {
|
} else {
|
||||||
hifi.buttons.colorFinish[control.color]
|
hifi.buttons.colorFinish[control.color]
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,12 @@ Original.Button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onFocusChanged: {
|
||||||
|
if (focus) {
|
||||||
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Tablet.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
|
@ -50,6 +56,8 @@ Original.Button {
|
||||||
hifi.buttons.pressedColor[control.color]
|
hifi.buttons.pressedColor[control.color]
|
||||||
} else if (control.hovered) {
|
} else if (control.hovered) {
|
||||||
hifi.buttons.hoveredColor[control.color]
|
hifi.buttons.hoveredColor[control.color]
|
||||||
|
} else if (!control.hovered && control.focus) {
|
||||||
|
hifi.buttons.focusedColor[control.color]
|
||||||
} else {
|
} else {
|
||||||
hifi.buttons.colorStart[control.color]
|
hifi.buttons.colorStart[control.color]
|
||||||
}
|
}
|
||||||
|
@ -64,6 +72,8 @@ Original.Button {
|
||||||
hifi.buttons.pressedColor[control.color]
|
hifi.buttons.pressedColor[control.color]
|
||||||
} else if (control.hovered) {
|
} else if (control.hovered) {
|
||||||
hifi.buttons.hoveredColor[control.color]
|
hifi.buttons.hoveredColor[control.color]
|
||||||
|
} else if (!control.hovered && control.focus) {
|
||||||
|
hifi.buttons.focusedColor[control.color]
|
||||||
} else {
|
} else {
|
||||||
hifi.buttons.colorFinish[control.color]
|
hifi.buttons.colorFinish[control.color]
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ TableView {
|
||||||
size: hifi.fontSizes.tableHeadingIcon
|
size: hifi.fontSizes.tableHeadingIcon
|
||||||
anchors {
|
anchors {
|
||||||
left: titleText.right
|
left: titleText.right
|
||||||
leftMargin: -hifi.fontSizes.tableHeadingIcon / 3 - (centerHeaderText ? 5 : 0)
|
leftMargin: -hifi.fontSizes.tableHeadingIcon / 3 - (centerHeaderText ? 15 : 10)
|
||||||
right: parent.right
|
right: parent.right
|
||||||
rightMargin: hifi.dimensions.tablePadding
|
rightMargin: hifi.dimensions.tablePadding
|
||||||
verticalCenter: titleText.verticalCenter
|
verticalCenter: titleText.verticalCenter
|
||||||
|
|
|
@ -110,7 +110,17 @@ ModalWindow {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
fileTableView.forceActiveFocus();
|
focusTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: focusTimer
|
||||||
|
interval: 10
|
||||||
|
running: false
|
||||||
|
repeat: false
|
||||||
|
onTriggered: {
|
||||||
|
fileTableView.contentItem.forceActiveFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -130,7 +140,9 @@ ModalWindow {
|
||||||
drag.target: root
|
drag.target: root
|
||||||
onClicked: {
|
onClicked: {
|
||||||
d.clearSelection();
|
d.clearSelection();
|
||||||
frame.forceActiveFocus(); // Defocus text field so that the keyboard gets hidden.
|
// Defocus text field so that the keyboard gets hidden.
|
||||||
|
// Clicking also breaks keyboard navigation apart from backtabbing to cancel
|
||||||
|
frame.forceActiveFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +162,11 @@ ModalWindow {
|
||||||
size: 30
|
size: 30
|
||||||
enabled: fileTableModel.parentFolder && fileTableModel.parentFolder !== ""
|
enabled: fileTableModel.parentFolder && fileTableModel.parentFolder !== ""
|
||||||
onClicked: d.navigateUp();
|
onClicked: d.navigateUp();
|
||||||
|
Keys.onReturnPressed: { d.navigateUp(); }
|
||||||
|
KeyNavigation.tab: homeButton
|
||||||
|
KeyNavigation.backtab: upButton
|
||||||
|
KeyNavigation.left: upButton
|
||||||
|
KeyNavigation.right: homeButton
|
||||||
}
|
}
|
||||||
|
|
||||||
GlyphButton {
|
GlyphButton {
|
||||||
|
@ -160,6 +177,10 @@ ModalWindow {
|
||||||
width: height
|
width: height
|
||||||
enabled: d.homeDestination ? true : false
|
enabled: d.homeDestination ? true : false
|
||||||
onClicked: d.navigateHome();
|
onClicked: d.navigateHome();
|
||||||
|
Keys.onReturnPressed: { d.navigateHome(); }
|
||||||
|
KeyNavigation.tab: fileTableView.contentItem
|
||||||
|
KeyNavigation.backtab: upButton
|
||||||
|
KeyNavigation.left: upButton
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,9 +249,15 @@ ModalWindow {
|
||||||
d.currentSelectionUrl = helper.pathToUrl(currentText);
|
d.currentSelectionUrl = helper.pathToUrl(currentText);
|
||||||
}
|
}
|
||||||
fileTableModel.folder = folder;
|
fileTableModel.folder = folder;
|
||||||
fileTableView.forceActiveFocus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyNavigation.up: fileTableView.contentItem
|
||||||
|
KeyNavigation.down: fileTableView.contentItem
|
||||||
|
KeyNavigation.tab: fileTableView.contentItem
|
||||||
|
KeyNavigation.backtab: fileTableView.contentItem
|
||||||
|
KeyNavigation.left: fileTableView.contentItem
|
||||||
|
KeyNavigation.right: fileTableView.contentItem
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
|
@ -483,7 +510,6 @@ ModalWindow {
|
||||||
}
|
}
|
||||||
headerVisible: !selectDirectory
|
headerVisible: !selectDirectory
|
||||||
onDoubleClicked: navigateToRow(row);
|
onDoubleClicked: navigateToRow(row);
|
||||||
focus: true
|
|
||||||
Keys.onReturnPressed: navigateToCurrentRow();
|
Keys.onReturnPressed: navigateToCurrentRow();
|
||||||
Keys.onEnterPressed: navigateToCurrentRow();
|
Keys.onEnterPressed: navigateToCurrentRow();
|
||||||
|
|
||||||
|
@ -560,7 +586,7 @@ ModalWindow {
|
||||||
resizable: true
|
resizable: true
|
||||||
}
|
}
|
||||||
TableViewColumn {
|
TableViewColumn {
|
||||||
id: fileMofifiedColumn
|
id: fileModifiedColumn
|
||||||
role: "fileModified"
|
role: "fileModified"
|
||||||
title: "Date"
|
title: "Date"
|
||||||
width: 0.3 * fileTableView.width
|
width: 0.3 * fileTableView.width
|
||||||
|
@ -571,7 +597,7 @@ ModalWindow {
|
||||||
TableViewColumn {
|
TableViewColumn {
|
||||||
role: "fileSize"
|
role: "fileSize"
|
||||||
title: "Size"
|
title: "Size"
|
||||||
width: fileTableView.width - fileNameColumn.width - fileMofifiedColumn.width
|
width: fileTableView.width - fileNameColumn.width - fileModifiedColumn.width
|
||||||
movable: false
|
movable: false
|
||||||
resizable: true
|
resizable: true
|
||||||
visible: !selectDirectory
|
visible: !selectDirectory
|
||||||
|
@ -649,6 +675,8 @@ ModalWindow {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyNavigation.tab: root.saveDialog ? currentSelection : openButton
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
|
@ -665,6 +693,10 @@ ModalWindow {
|
||||||
activeFocusOnTab: !readOnly
|
activeFocusOnTab: !readOnly
|
||||||
onActiveFocusChanged: if (activeFocus) { selectAll(); }
|
onActiveFocusChanged: if (activeFocus) { selectAll(); }
|
||||||
onAccepted: okAction.trigger();
|
onAccepted: okAction.trigger();
|
||||||
|
KeyNavigation.up: fileTableView.contentItem
|
||||||
|
KeyNavigation.down: openButton
|
||||||
|
KeyNavigation.tab: openButton
|
||||||
|
KeyNavigation.backtab: fileTableView.contentItem
|
||||||
}
|
}
|
||||||
|
|
||||||
FileTypeSelection {
|
FileTypeSelection {
|
||||||
|
@ -675,8 +707,6 @@ ModalWindow {
|
||||||
right: parent.right
|
right: parent.right
|
||||||
}
|
}
|
||||||
visible: !selectDirectory && filtersCount > 1
|
visible: !selectDirectory && filtersCount > 1
|
||||||
KeyNavigation.left: fileTableView
|
|
||||||
KeyNavigation.right: openButton
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Keyboard {
|
Keyboard {
|
||||||
|
@ -704,18 +734,18 @@ ModalWindow {
|
||||||
color: hifi.buttons.blue
|
color: hifi.buttons.blue
|
||||||
action: okAction
|
action: okAction
|
||||||
Keys.onReturnPressed: okAction.trigger()
|
Keys.onReturnPressed: okAction.trigger()
|
||||||
KeyNavigation.up: selectionType
|
|
||||||
KeyNavigation.left: selectionType
|
|
||||||
KeyNavigation.right: cancelButton
|
KeyNavigation.right: cancelButton
|
||||||
|
KeyNavigation.up: root.saveDialog ? currentSelection : fileTableView.contentItem
|
||||||
|
KeyNavigation.tab: cancelButton
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: cancelButton
|
id: cancelButton
|
||||||
action: cancelAction
|
action: cancelAction
|
||||||
KeyNavigation.up: selectionType
|
Keys.onReturnPressed: { cancelAction.trigger() }
|
||||||
KeyNavigation.left: openButton
|
KeyNavigation.left: openButton
|
||||||
KeyNavigation.right: fileTableView.contentItem
|
KeyNavigation.up: root.saveDialog ? currentSelection : fileTableView.contentItem
|
||||||
Keys.onReturnPressed: { canceled(); root.enabled = false }
|
KeyNavigation.backtab: openButton
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,16 @@ ModalWindow {
|
||||||
return OffscreenUi.waitForMessageBoxResult(root);
|
return OffscreenUi.waitForMessageBoxResult(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Keys.onRightPressed: if (defaultButton === OriginalDialogs.StandardButton.Yes) {
|
||||||
|
yesButton.forceActiveFocus()
|
||||||
|
} else if (defaultButton === OriginalDialogs.StandardButton.Ok) {
|
||||||
|
okButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
Keys.onTabPressed: if (defaultButton === OriginalDialogs.StandardButton.Yes) {
|
||||||
|
yesButton.forceActiveFocus()
|
||||||
|
} else if (defaultButton === OriginalDialogs.StandardButton.Ok) {
|
||||||
|
okButton.forceActiveFocus()
|
||||||
|
}
|
||||||
property alias detailedText: detailedText.text
|
property alias detailedText: detailedText.text
|
||||||
property alias text: mainTextContainer.text
|
property alias text: mainTextContainer.text
|
||||||
property alias informativeText: informativeTextContainer.text
|
property alias informativeText: informativeTextContainer.text
|
||||||
|
@ -47,7 +57,6 @@ ModalWindow {
|
||||||
onIconChanged: updateIcon();
|
onIconChanged: updateIcon();
|
||||||
property int defaultButton: OriginalDialogs.StandardButton.NoButton;
|
property int defaultButton: OriginalDialogs.StandardButton.NoButton;
|
||||||
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
|
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
|
||||||
focus: defaultButton === OriginalDialogs.StandardButton.NoButton
|
|
||||||
|
|
||||||
property int titleWidth: 0
|
property int titleWidth: 0
|
||||||
onTitleWidthChanged: d.resize();
|
onTitleWidthChanged: d.resize();
|
||||||
|
@ -134,16 +143,35 @@ ModalWindow {
|
||||||
MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.StandardButton.Reset; }
|
MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.StandardButton.Reset; }
|
||||||
MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.StandardButton.Discard; }
|
MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.StandardButton.Discard; }
|
||||||
MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.StandardButton.NoToAll; }
|
MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.StandardButton.NoToAll; }
|
||||||
MessageDialogButton { dialog: root; text: qsTr("No"); button: OriginalDialogs.StandardButton.No; }
|
MessageDialogButton {
|
||||||
|
id: noButton
|
||||||
|
dialog: root
|
||||||
|
text: qsTr("No")
|
||||||
|
button: OriginalDialogs.StandardButton.No
|
||||||
|
KeyNavigation.left: yesButton
|
||||||
|
KeyNavigation.backtab: yesButton
|
||||||
|
}
|
||||||
MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.StandardButton.YesToAll; }
|
MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.StandardButton.YesToAll; }
|
||||||
MessageDialogButton { dialog: root; text: qsTr("Yes"); button: OriginalDialogs.StandardButton.Yes; }
|
MessageDialogButton {
|
||||||
|
id: yesButton
|
||||||
|
dialog: root
|
||||||
|
text: qsTr("Yes")
|
||||||
|
button: OriginalDialogs.StandardButton.Yes
|
||||||
|
KeyNavigation.right: noButton
|
||||||
|
KeyNavigation.tab: noButton
|
||||||
|
}
|
||||||
MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.StandardButton.Apply; }
|
MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.StandardButton.Apply; }
|
||||||
MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.StandardButton.Ignore; }
|
MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.StandardButton.Ignore; }
|
||||||
MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.StandardButton.Retry; }
|
MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.StandardButton.Retry; }
|
||||||
MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.StandardButton.SaveAll; }
|
MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.StandardButton.SaveAll; }
|
||||||
MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.StandardButton.Save; }
|
MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.StandardButton.Save; }
|
||||||
MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.StandardButton.Open; }
|
MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.StandardButton.Open; }
|
||||||
MessageDialogButton { dialog: root; text: qsTr("OK"); button: OriginalDialogs.StandardButton.Ok; }
|
MessageDialogButton {
|
||||||
|
id: okButton
|
||||||
|
dialog: root
|
||||||
|
text: qsTr("OK")
|
||||||
|
button: OriginalDialogs.StandardButton.Ok
|
||||||
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: moreButton
|
id: moreButton
|
||||||
|
@ -230,12 +258,6 @@ ModalWindow {
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
root.click(OriginalDialogs.StandardButton.Cancel)
|
root.click(OriginalDialogs.StandardButton.Cancel)
|
||||||
break
|
break
|
||||||
|
|
||||||
case Qt.Key_Enter:
|
|
||||||
case Qt.Key_Return:
|
|
||||||
event.accepted = true
|
|
||||||
root.click(root.defaultButton)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,19 +95,19 @@ ModalWindow {
|
||||||
TextField {
|
TextField {
|
||||||
id: textResult
|
id: textResult
|
||||||
label: root.label
|
label: root.label
|
||||||
focus: items ? false : true
|
|
||||||
visible: items ? false : true
|
visible: items ? false : true
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left;
|
left: parent.left;
|
||||||
right: parent.right;
|
right: parent.right;
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
}
|
}
|
||||||
|
KeyNavigation.down: acceptButton
|
||||||
|
KeyNavigation.tab: acceptButton
|
||||||
}
|
}
|
||||||
|
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: comboBox
|
id: comboBox
|
||||||
label: root.label
|
label: root.label
|
||||||
focus: true
|
|
||||||
visible: items ? true : false
|
visible: items ? true : false
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
|
@ -115,6 +115,8 @@ ModalWindow {
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
}
|
}
|
||||||
model: items ? items : []
|
model: items ? items : []
|
||||||
|
KeyNavigation.down: acceptButton
|
||||||
|
KeyNavigation.tab: acceptButton
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +137,6 @@ ModalWindow {
|
||||||
|
|
||||||
Flow {
|
Flow {
|
||||||
id: buttons
|
id: buttons
|
||||||
focus: true
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
layoutDirection: Qt.RightToLeft
|
layoutDirection: Qt.RightToLeft
|
||||||
|
@ -145,8 +146,21 @@ ModalWindow {
|
||||||
margins: 0
|
margins: 0
|
||||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
bottomMargin: hifi.dimensions.contentSpacing.y
|
||||||
}
|
}
|
||||||
Button { action: cancelAction }
|
Button {
|
||||||
Button { action: acceptAction }
|
id: cancelButton
|
||||||
|
action: cancelAction
|
||||||
|
KeyNavigation.left: acceptButton
|
||||||
|
KeyNavigation.up: items ? comboBox : textResult
|
||||||
|
KeyNavigation.backtab: acceptButton
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
id: acceptButton
|
||||||
|
action: acceptAction
|
||||||
|
KeyNavigation.right: cancelButton
|
||||||
|
KeyNavigation.up: items ? comboBox : textResult
|
||||||
|
KeyNavigation.tab: cancelButton
|
||||||
|
KeyNavigation.backtab: items ? comboBox : textResult
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Action {
|
Action {
|
||||||
|
@ -184,7 +198,13 @@ ModalWindow {
|
||||||
|
|
||||||
case Qt.Key_Return:
|
case Qt.Key_Return:
|
||||||
case Qt.Key_Enter:
|
case Qt.Key_Enter:
|
||||||
acceptAction.trigger()
|
if (acceptButton.focus) {
|
||||||
|
acceptAction.trigger()
|
||||||
|
} else if (cancelButton.focus) {
|
||||||
|
cancelAction.trigger()
|
||||||
|
} else if (comboBox.focus || comboBox.popup.focus) {
|
||||||
|
comboBox.showList()
|
||||||
|
}
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -194,6 +214,10 @@ ModalWindow {
|
||||||
keyboardEnabled = HMD.active;
|
keyboardEnabled = HMD.active;
|
||||||
updateIcon();
|
updateIcon();
|
||||||
d.resize();
|
d.resize();
|
||||||
textResult.forceActiveFocus();
|
if (items) {
|
||||||
|
comboBox.forceActiveFocus()
|
||||||
|
} else {
|
||||||
|
textResult.forceActiveFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,21 @@ import "../../controls-uit"
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
property var dialog;
|
property var dialog;
|
||||||
property int button: StandardButton.NoButton;
|
property int button: StandardButton.Ok;
|
||||||
|
|
||||||
color: dialog.defaultButton === button ? hifi.buttons.blue : hifi.buttons.white
|
color: focus ? hifi.buttons.blue : hifi.buttons.white
|
||||||
focus: dialog.defaultButton === button
|
|
||||||
onClicked: dialog.click(button)
|
onClicked: dialog.click(button)
|
||||||
visible: dialog.buttons & button
|
visible: dialog.buttons & button
|
||||||
|
Keys.onPressed: {
|
||||||
|
if (!focus) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch (event.key) {
|
||||||
|
case Qt.Key_Enter:
|
||||||
|
case Qt.Key_Return:
|
||||||
|
event.accepted = true
|
||||||
|
dialog.click(button)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ Column {
|
||||||
property int labelSize: 20;
|
property int labelSize: 20;
|
||||||
|
|
||||||
property string metaverseServerUrl: '';
|
property string metaverseServerUrl: '';
|
||||||
|
property string protocol: '';
|
||||||
property string actions: 'snapshot';
|
property string actions: 'snapshot';
|
||||||
// sendToScript doesn't get wired until after everything gets created. So we have to queue fillDestinations on nextTick.
|
// sendToScript doesn't get wired until after everything gets created. So we have to queue fillDestinations on nextTick.
|
||||||
property string labelText: actions;
|
property string labelText: actions;
|
||||||
|
@ -102,7 +103,7 @@ Column {
|
||||||
'include_actions=' + actions,
|
'include_actions=' + actions,
|
||||||
'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'),
|
'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'),
|
||||||
'require_online=true',
|
'require_online=true',
|
||||||
'protocol=' + encodeURIComponent(Window.protocolSignature()),
|
'protocol=' + protocol,
|
||||||
'page=' + pageNumber
|
'page=' + pageNumber
|
||||||
];
|
];
|
||||||
var url = metaverseBase + 'user_stories?' + options.join('&');
|
var url = metaverseBase + 'user_stories?' + options.join('&');
|
||||||
|
|
|
@ -12,7 +12,7 @@ StackView {
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
function pushSource(path) {
|
function pushSource(path) {
|
||||||
editRoot.push(Qt.resolvedUrl(path));
|
editRoot.push(Qt.resolvedUrl("../../" + path));
|
||||||
editRoot.currentItem.sendToScript.connect(editRoot.sendToScript);
|
editRoot.currentItem.sendToScript.connect(editRoot.sendToScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ StackView {
|
||||||
console.debug('TabletAddressDialog::fromScript: refreshFeeds', 'feeds = ', feeds);
|
console.debug('TabletAddressDialog::fromScript: refreshFeeds', 'feeds = ', feeds);
|
||||||
|
|
||||||
feeds.forEach(function(feed) {
|
feeds.forEach(function(feed) {
|
||||||
|
feed.protocol = encodeURIComponent(message.protocolSignature);
|
||||||
Qt.callLater(feed.fillDestinations);
|
Qt.callLater(feed.fillDestinations);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ Item {
|
||||||
|
|
||||||
GridView {
|
GridView {
|
||||||
id: gridView
|
id: gridView
|
||||||
|
flickableDirection: Flickable.AutoFlickIfNeeded
|
||||||
keyNavigationEnabled: false
|
keyNavigationEnabled: false
|
||||||
highlightFollowsCurrentItem: false
|
highlightFollowsCurrentItem: false
|
||||||
|
|
||||||
|
@ -144,23 +144,20 @@ Item {
|
||||||
bottomMargin: 0
|
bottomMargin: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
function setButtonState(buttonIndex, buttonstate) {
|
onCurrentIndexChanged: {
|
||||||
if (buttonIndex < 0 || gridView.contentItem === undefined
|
previousGridIndex = currentIndex
|
||||||
|| gridView.contentItem.children.length - 1 < buttonIndex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var itemat = gridView.contentItem.children[buttonIndex].children[0];
|
|
||||||
if (itemat.isActive) {
|
|
||||||
itemat.state = "active state";
|
|
||||||
} else {
|
|
||||||
itemat.state = buttonstate;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onCurrentIndexChanged: {
|
onMovementStarted: {
|
||||||
setButtonState(previousGridIndex, "base state");
|
if (currentIndex < 0 || gridView.currentItem === undefined || gridView.contentItem.children.length - 1 < currentIndex) {
|
||||||
setButtonState(currentIndex, "hover state");
|
return;
|
||||||
previousGridIndex = currentIndex
|
}
|
||||||
|
var button = gridView.contentItem.children[currentIndex].children[0];
|
||||||
|
if (button.isActive) {
|
||||||
|
button.state = "active state";
|
||||||
|
} else {
|
||||||
|
button.state = "base state";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cellWidth: width/3
|
cellWidth: width/3
|
||||||
|
|
|
@ -219,6 +219,7 @@ Item {
|
||||||
readonly property var colorFinish: [ colors.lightGrayText, colors.blueAccent, "#94132e", colors.black, Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0) ]
|
readonly property var colorFinish: [ colors.lightGrayText, colors.blueAccent, "#94132e", colors.black, Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0), Qt.rgba(0, 0, 0, 0) ]
|
||||||
readonly property var hoveredColor: [ colorStart[white], colorStart[blue], colorStart[red], colorFinish[black], colorStart[none], colorStart[noneBorderless], colorStart[noneBorderlessWhite], colorStart[noneBorderlessGray] ]
|
readonly property var hoveredColor: [ colorStart[white], colorStart[blue], colorStart[red], colorFinish[black], colorStart[none], colorStart[noneBorderless], colorStart[noneBorderlessWhite], colorStart[noneBorderlessGray] ]
|
||||||
readonly property var pressedColor: [ colorFinish[white], colorFinish[blue], colorFinish[red], colorStart[black], colorStart[none], colorStart[noneBorderless], colorStart[noneBorderlessWhite], colorStart[noneBorderlessGray] ]
|
readonly property var pressedColor: [ colorFinish[white], colorFinish[blue], colorFinish[red], colorStart[black], colorStart[none], colorStart[noneBorderless], colorStart[noneBorderlessWhite], colorStart[noneBorderlessGray] ]
|
||||||
|
readonly property var focusedColor: [ colors.lightGray50, colors.blueAccent, colors.redAccent, colors.darkGray, colorStart[none], colorStart[noneBorderless], colorStart[noneBorderlessWhite], colorStart[noneBorderlessGray] ]
|
||||||
readonly property var disabledColorStart: [ colorStart[white], colors.baseGrayHighlight]
|
readonly property var disabledColorStart: [ colorStart[white], colors.baseGrayHighlight]
|
||||||
readonly property var disabledColorFinish: [ colorFinish[white], colors.baseGrayShadow]
|
readonly property var disabledColorFinish: [ colorFinish[white], colors.baseGrayShadow]
|
||||||
readonly property var disabledTextColor: [ colors.lightGrayText, colors.baseGrayShadow]
|
readonly property var disabledTextColor: [ colors.lightGrayText, colors.baseGrayShadow]
|
||||||
|
|
|
@ -149,6 +149,7 @@
|
||||||
#include "avatar/AvatarManager.h"
|
#include "avatar/AvatarManager.h"
|
||||||
#include "avatar/MyHead.h"
|
#include "avatar/MyHead.h"
|
||||||
#include "CrashHandler.h"
|
#include "CrashHandler.h"
|
||||||
|
#include "Crashpad.h"
|
||||||
#include "devices/DdeFaceTracker.h"
|
#include "devices/DdeFaceTracker.h"
|
||||||
#include "DiscoverabilityManager.h"
|
#include "DiscoverabilityManager.h"
|
||||||
#include "GLCanvas.h"
|
#include "GLCanvas.h"
|
||||||
|
@ -396,6 +397,7 @@ public:
|
||||||
setObjectName("Deadlock Watchdog");
|
setObjectName("Deadlock Watchdog");
|
||||||
// Give the heartbeat an initial value
|
// Give the heartbeat an initial value
|
||||||
_heartbeat = usecTimestampNow();
|
_heartbeat = usecTimestampNow();
|
||||||
|
_paused = false;
|
||||||
connect(qApp, &QCoreApplication::aboutToQuit, [this] {
|
connect(qApp, &QCoreApplication::aboutToQuit, [this] {
|
||||||
_quit = true;
|
_quit = true;
|
||||||
});
|
});
|
||||||
|
@ -413,11 +415,20 @@ public:
|
||||||
*crashTrigger = 0xDEAD10CC;
|
*crashTrigger = 0xDEAD10CC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pause() {
|
||||||
|
_paused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resume() {
|
||||||
|
_paused = false;
|
||||||
|
updateHeartbeat();
|
||||||
|
}
|
||||||
|
|
||||||
void run() override {
|
void run() override {
|
||||||
while (!_quit) {
|
while (!_quit) {
|
||||||
QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
|
QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
|
||||||
// Don't do heartbeat detection under nsight
|
// Don't do heartbeat detection under nsight
|
||||||
if (nsightActive()) {
|
if (nsightActive() || _paused) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us
|
uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us
|
||||||
|
@ -473,6 +484,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::atomic<bool> _paused;
|
||||||
static std::atomic<uint64_t> _heartbeat;
|
static std::atomic<uint64_t> _heartbeat;
|
||||||
static std::atomic<uint64_t> _maxElapsed;
|
static std::atomic<uint64_t> _maxElapsed;
|
||||||
static std::atomic<int> _maxElapsedAverage;
|
static std::atomic<int> _maxElapsedAverage;
|
||||||
|
@ -481,6 +493,7 @@ public:
|
||||||
bool _quit { false };
|
bool _quit { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::atomic<bool> DeadlockWatchdogThread::_paused;
|
||||||
std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;
|
std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;
|
||||||
std::atomic<uint64_t> DeadlockWatchdogThread::_maxElapsed;
|
std::atomic<uint64_t> DeadlockWatchdogThread::_maxElapsed;
|
||||||
std::atomic<int> DeadlockWatchdogThread::_maxElapsedAverage;
|
std::atomic<int> DeadlockWatchdogThread::_maxElapsedAverage;
|
||||||
|
@ -656,8 +669,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Setting::init();
|
|
||||||
|
|
||||||
// Tell the plugin manager about our statically linked plugins
|
// Tell the plugin manager about our statically linked plugins
|
||||||
auto pluginManager = PluginManager::getInstance();
|
auto pluginManager = PluginManager::getInstance();
|
||||||
pluginManager->setInputPluginProvider([] { return getInputPlugins(); });
|
pluginManager->setInputPluginProvider([] { return getInputPlugins(); });
|
||||||
|
@ -909,6 +920,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
|
|
||||||
_logger->setSessionID(accountManager->getSessionID());
|
_logger->setSessionID(accountManager->getSessionID());
|
||||||
|
|
||||||
|
setCrashAnnotation("metaverse_session_id", accountManager->getSessionID().toString().toStdString());
|
||||||
|
|
||||||
if (steamClient) {
|
if (steamClient) {
|
||||||
qCDebug(interfaceapp) << "[VERSION] SteamVR buildID:" << steamClient->getSteamVRBuildID();
|
qCDebug(interfaceapp) << "[VERSION] SteamVR buildID:" << steamClient->getSteamVRBuildID();
|
||||||
}
|
}
|
||||||
|
@ -2269,6 +2282,11 @@ void Application::initializeGL() {
|
||||||
initDisplay();
|
initDisplay();
|
||||||
qCDebug(interfaceapp, "Initialized Display.");
|
qCDebug(interfaceapp, "Initialized Display.");
|
||||||
|
|
||||||
|
#ifdef Q_OS_OSX
|
||||||
|
// FIXME: on mac os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread.
|
||||||
|
DeadlockWatchdogThread::pause();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Set up the render engine
|
// Set up the render engine
|
||||||
render::CullFunctor cullFunctor = LODManager::shouldRender;
|
render::CullFunctor cullFunctor = LODManager::shouldRender;
|
||||||
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
|
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
|
||||||
|
@ -2277,6 +2295,11 @@ void Application::initializeGL() {
|
||||||
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
|
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
|
||||||
#endif
|
#endif
|
||||||
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED);
|
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED);
|
||||||
|
|
||||||
|
#ifdef Q_OS_OSX
|
||||||
|
DeadlockWatchdogThread::resume();
|
||||||
|
#endif
|
||||||
|
|
||||||
_renderEngine->load();
|
_renderEngine->load();
|
||||||
_renderEngine->registerScene(_main3DScene);
|
_renderEngine->registerScene(_main3DScene);
|
||||||
|
|
||||||
|
@ -6272,7 +6295,7 @@ void Application::showAssetServerWidget(QString filePath) {
|
||||||
if (!hmd->getShouldShowTablet() && !isHMDMode()) {
|
if (!hmd->getShouldShowTablet() && !isHMDMode()) {
|
||||||
DependencyManager::get<OffscreenUi>()->show(url, "AssetServer", startUpload);
|
DependencyManager::get<OffscreenUi>()->show(url, "AssetServer", startUpload);
|
||||||
} else {
|
} else {
|
||||||
static const QUrl url("../dialogs/TabletAssetServer.qml");
|
static const QUrl url("hifi/dialogs/TabletAssetServer.qml");
|
||||||
tablet->pushOntoStack(url);
|
tablet->pushOntoStack(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
//
|
|
||||||
// CrashReporter.cpp
|
|
||||||
// interface/src
|
|
||||||
//
|
|
||||||
// Created by Ryan Huffman on 11 April 2016.
|
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "CrashReporter.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <new.h>
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <DbgHelp.h>
|
|
||||||
|
|
||||||
#include <csignal>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
|
|
||||||
#pragma comment(lib, "Dbghelp.lib")
|
|
||||||
|
|
||||||
// SetUnhandledExceptionFilter can be overridden by the CRT at the point that an error occurs. More information
|
|
||||||
// can be found here: http://www.codeproject.com/Articles/154686/SetUnhandledExceptionFilter-and-the-C-C-Runtime-Li
|
|
||||||
// A fairly common approach is to patch the SetUnhandledExceptionFilter so that it cannot be overridden and so
|
|
||||||
// that the applicaiton can handle it itself.
|
|
||||||
// The CAPIHook class referenced in the above article is not openly available, but a similar implementation
|
|
||||||
// can be found here: http://blog.kalmbach-software.de/2008/04/02/unhandled-exceptions-in-vc8-and-above-for-x86-and-x64/
|
|
||||||
// The below has been adapted to work with different library and functions.
|
|
||||||
BOOL redirectLibraryFunctionToFunction(char* library, char* function, void* fn)
|
|
||||||
{
|
|
||||||
HMODULE lib = LoadLibrary(library);
|
|
||||||
if (lib == NULL) return FALSE;
|
|
||||||
void *pOrgEntry = GetProcAddress(lib, function);
|
|
||||||
if (pOrgEntry == NULL) return FALSE;
|
|
||||||
|
|
||||||
DWORD dwOldProtect = 0;
|
|
||||||
SIZE_T jmpSize = 5;
|
|
||||||
#ifdef _M_X64
|
|
||||||
jmpSize = 13;
|
|
||||||
#endif
|
|
||||||
BOOL bProt = VirtualProtect(pOrgEntry, jmpSize,
|
|
||||||
PAGE_EXECUTE_READWRITE, &dwOldProtect);
|
|
||||||
BYTE newJump[20];
|
|
||||||
void *pNewFunc = fn;
|
|
||||||
#ifdef _M_IX86
|
|
||||||
DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
|
|
||||||
dwOrgEntryAddr += jmpSize; // add 5 for 5 op-codes for jmp rel32
|
|
||||||
DWORD dwNewEntryAddr = (DWORD)pNewFunc;
|
|
||||||
DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
|
|
||||||
// JMP rel32: Jump near, relative, displacement relative to next instruction.
|
|
||||||
newJump[0] = 0xE9; // JMP rel32
|
|
||||||
memcpy(&newJump[1], &dwRelativeAddr, sizeof(pNewFunc));
|
|
||||||
#elif _M_X64
|
|
||||||
// We must use R10 or R11, because these are "scratch" registers
|
|
||||||
// which need not to be preserved accross function calls
|
|
||||||
// For more info see: Register Usage for x64 64-Bit
|
|
||||||
// http://msdn.microsoft.com/en-us/library/ms794547.aspx
|
|
||||||
// Thanks to Matthew Smith!!!
|
|
||||||
newJump[0] = 0x49; // MOV R11, ...
|
|
||||||
newJump[1] = 0xBB; // ...
|
|
||||||
memcpy(&newJump[2], &pNewFunc, sizeof(pNewFunc));
|
|
||||||
//pCur += sizeof (ULONG_PTR);
|
|
||||||
newJump[10] = 0x41; // JMP R11, ...
|
|
||||||
newJump[11] = 0xFF; // ...
|
|
||||||
newJump[12] = 0xE3; // ...
|
|
||||||
#endif
|
|
||||||
SIZE_T bytesWritten;
|
|
||||||
BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
|
|
||||||
pOrgEntry, newJump, jmpSize, &bytesWritten);
|
|
||||||
|
|
||||||
if (bProt != FALSE)
|
|
||||||
{
|
|
||||||
DWORD dwBuf;
|
|
||||||
VirtualProtect(pOrgEntry, jmpSize, dwOldProtect, &dwBuf);
|
|
||||||
}
|
|
||||||
return bRet;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printStackTrace(ULONG framesToSkip = 1) {
|
|
||||||
HANDLE process = GetCurrentProcess();
|
|
||||||
SymInitialize(process, NULL, TRUE);
|
|
||||||
void* stack[100];
|
|
||||||
uint16_t frames = CaptureStackBackTrace(framesToSkip, 100, stack, NULL);
|
|
||||||
SYMBOL_INFO* symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
|
|
||||||
symbol->MaxNameLen = 255;
|
|
||||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
||||||
|
|
||||||
for (uint16_t i = 0; i < frames; ++i) {
|
|
||||||
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
|
|
||||||
qWarning() << QString("%1: %2 - 0x%0X").arg(QString::number(frames - i - 1), QString(symbol->Name), QString::number(symbol->Address, 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
free(symbol);
|
|
||||||
|
|
||||||
// Try to force the log to sync to the filesystem
|
|
||||||
auto app = qApp;
|
|
||||||
if (app && app->getLogger()) {
|
|
||||||
app->getLogger()->sync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleSignal(int signal) {
|
|
||||||
// Throw so BugSplat can handle
|
|
||||||
throw(signal);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __cdecl handlePureVirtualCall() {
|
|
||||||
qWarning() << "Pure virtual function call detected";
|
|
||||||
printStackTrace(2);
|
|
||||||
// Throw so BugSplat can handle
|
|
||||||
throw("ERROR: Pure virtual call");
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleInvalidParameter(const wchar_t * expression, const wchar_t * function, const wchar_t * file,
|
|
||||||
unsigned int line, uintptr_t pReserved ) {
|
|
||||||
// Throw so BugSplat can handle
|
|
||||||
throw("ERROR: Invalid parameter");
|
|
||||||
}
|
|
||||||
|
|
||||||
int handleNewError(size_t size) {
|
|
||||||
// Throw so BugSplat can handle
|
|
||||||
throw("ERROR: Errors calling new");
|
|
||||||
}
|
|
||||||
|
|
||||||
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI noop_SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
_purecall_handler __cdecl noop_set_purecall_handler(_purecall_handler pNew) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAS_BUGSPLAT
|
|
||||||
|
|
||||||
static const DWORD BUG_SPLAT_FLAGS = MDSF_PREVENTHIJACKING | MDSF_USEGUARDMEMORY;
|
|
||||||
|
|
||||||
CrashReporter::CrashReporter(QString bugSplatDatabase, QString bugSplatApplicationName, QString version)
|
|
||||||
: mpSender(qPrintable(bugSplatDatabase), qPrintable(bugSplatApplicationName), qPrintable(version), nullptr, BUG_SPLAT_FLAGS)
|
|
||||||
{
|
|
||||||
signal(SIGSEGV, handleSignal);
|
|
||||||
signal(SIGABRT, handleSignal);
|
|
||||||
_set_purecall_handler(handlePureVirtualCall);
|
|
||||||
_set_invalid_parameter_handler(handleInvalidParameter);
|
|
||||||
_set_new_mode(1);
|
|
||||||
_set_new_handler(handleNewError);
|
|
||||||
|
|
||||||
// Disable WER popup
|
|
||||||
//SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
|
|
||||||
//_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
|
||||||
|
|
||||||
// QtWebEngineCore internally sets its own purecall handler, overriding our own error handling. This disables that.
|
|
||||||
if (!redirectLibraryFunctionToFunction("msvcr120.dll", "_set_purecall_handler", &noop_set_purecall_handler)) {
|
|
||||||
qWarning() << "Failed to patch _set_purecall_handler";
|
|
||||||
}
|
|
||||||
// Patch SetUnhandledExceptionFilter to keep the CRT from overriding our own error handling.
|
|
||||||
if (!redirectLibraryFunctionToFunction("kernel32.dll", "SetUnhandledExceptionFilter", &noop_SetUnhandledExceptionFilter)) {
|
|
||||||
qWarning() << "Failed to patch setUnhandledExceptionFilter";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
|
@ -1,32 +0,0 @@
|
||||||
//
|
|
||||||
// CrashReporter.h
|
|
||||||
// interface/src
|
|
||||||
//
|
|
||||||
// Created by Ryan Huffman on 11 April 2016.
|
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef hifi_CrashReporter_h
|
|
||||||
#define hifi_CrashReporter_h
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#ifdef HAS_BUGSPLAT
|
|
||||||
|
|
||||||
#include <BugSplat.h>
|
|
||||||
|
|
||||||
class CrashReporter {
|
|
||||||
public:
|
|
||||||
CrashReporter(QString bugSplatDatabase, QString bugSplatApplicationName, QString version);
|
|
||||||
|
|
||||||
MiniDmpSender mpSender;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // hifi_CrashReporter_h
|
|
101
interface/src/Crashpad.cpp
Normal file
101
interface/src/Crashpad.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
//
|
||||||
|
// Crashpad.cpp
|
||||||
|
// interface/src
|
||||||
|
//
|
||||||
|
// Created by Clement Brisset on 01/19/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
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Crashpad.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#if HAS_CRASHPAD
|
||||||
|
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#include <BuildInfo.h>
|
||||||
|
|
||||||
|
#include <client/crashpad_client.h>
|
||||||
|
#include <client/crash_report_database.h>
|
||||||
|
#include <client/settings.h>
|
||||||
|
// #include <client/annotation_list.h>
|
||||||
|
// #include <client/crashpad_info.h>
|
||||||
|
|
||||||
|
using namespace crashpad;
|
||||||
|
|
||||||
|
static const std::string BACKTRACE_URL { CMAKE_BACKTRACE_URL };
|
||||||
|
static const std::string BACKTRACE_TOKEN { CMAKE_BACKTRACE_TOKEN };
|
||||||
|
|
||||||
|
extern QString qAppFileName();
|
||||||
|
|
||||||
|
// crashpad::AnnotationList* crashpadAnnotations { nullptr };
|
||||||
|
|
||||||
|
bool startCrashHandler() {
|
||||||
|
if (BACKTRACE_URL.empty() || BACKTRACE_TOKEN.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CrashpadClient client;
|
||||||
|
std::vector<std::string> arguments;
|
||||||
|
|
||||||
|
std::map<std::string, std::string> annotations;
|
||||||
|
annotations["token"] = BACKTRACE_TOKEN;
|
||||||
|
annotations["format"] = "minidump";
|
||||||
|
annotations["version"] = BuildInfo::VERSION.toStdString();
|
||||||
|
|
||||||
|
arguments.push_back("--no-rate-limit");
|
||||||
|
|
||||||
|
// Setup Crashpad DB directory
|
||||||
|
const auto crashpadDbName = "crashpad-db";
|
||||||
|
const auto crashpadDbDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
|
||||||
|
QDir(crashpadDbDir).mkpath(crashpadDbName); // Make sure the directory exists
|
||||||
|
const auto crashpadDbPath = crashpadDbDir.toStdString() + "/" + crashpadDbName;
|
||||||
|
|
||||||
|
// Locate Crashpad handler
|
||||||
|
const std::string CRASHPAD_HANDLER_PATH = QFileInfo(qAppFileName()).absolutePath().toStdString() + "/crashpad_handler.exe";
|
||||||
|
|
||||||
|
// Setup different file paths
|
||||||
|
base::FilePath::StringType dbPath;
|
||||||
|
base::FilePath::StringType handlerPath;
|
||||||
|
dbPath.assign(crashpadDbPath.cbegin(), crashpadDbPath.cend());
|
||||||
|
handlerPath.assign(CRASHPAD_HANDLER_PATH.cbegin(), CRASHPAD_HANDLER_PATH.cend());
|
||||||
|
|
||||||
|
base::FilePath db(dbPath);
|
||||||
|
base::FilePath handler(handlerPath);
|
||||||
|
|
||||||
|
auto database = crashpad::CrashReportDatabase::Initialize(db);
|
||||||
|
if (database == nullptr || database->GetSettings() == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable automated uploads.
|
||||||
|
database->GetSettings()->SetUploadsEnabled(true);
|
||||||
|
|
||||||
|
return client.StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCrashAnnotation(std::string name, std::string value) {
|
||||||
|
// if (!crashpadAnnotations) {
|
||||||
|
// crashpadAnnotations = new crashpad::AnnotationList(); // don't free this, let it leak
|
||||||
|
// crashpad::CrashpadInfo* crashpad_info = crashpad::GetCrashpadInfo();
|
||||||
|
// crashpad_info->set_simple_annotations(crashpadAnnotations);
|
||||||
|
// }
|
||||||
|
// crashpadAnnotations->SetKeyValue(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
bool startCrashHandler() {
|
||||||
|
qDebug() << "No crash handler available.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCrashAnnotation(std::string name, std::string value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
20
interface/src/Crashpad.h
Normal file
20
interface/src/Crashpad.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//
|
||||||
|
// Crashpad.h
|
||||||
|
// interface/src
|
||||||
|
//
|
||||||
|
// Created by Clement Brisset on 01/19/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
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_Crashpad_h
|
||||||
|
#define hifi_Crashpad_h
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
bool startCrashHandler();
|
||||||
|
void setCrashAnnotation(std::string name, std::string value);
|
||||||
|
|
||||||
|
#endif // hifi_Crashpad_h
|
|
@ -20,7 +20,7 @@
|
||||||
#include <render/Args.h>
|
#include <render/Args.h>
|
||||||
|
|
||||||
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0f;
|
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0f;
|
||||||
const float DEFAULT_HMD_LOD_DOWN_FPS = 45.0f;
|
const float DEFAULT_HMD_LOD_DOWN_FPS = 34.0f;
|
||||||
const float DEFAULT_DESKTOP_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_DESKTOP_LOD_DOWN_FPS; // msec
|
const float DEFAULT_DESKTOP_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_DESKTOP_LOD_DOWN_FPS; // msec
|
||||||
const float DEFAULT_HMD_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_HMD_LOD_DOWN_FPS; // msec
|
const float DEFAULT_HMD_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_HMD_LOD_DOWN_FPS; // msec
|
||||||
const float MAX_LIKELY_DESKTOP_FPS = 59.0f; // this is essentially, V-synch - 1 fps
|
const float MAX_LIKELY_DESKTOP_FPS = 59.0f; // this is essentially, V-synch - 1 fps
|
||||||
|
|
|
@ -282,7 +282,7 @@ Menu::Menu() {
|
||||||
|
|
||||||
// Navigate > Show Address Bar
|
// Navigate > Show Address Bar
|
||||||
addActionToQMenuAndActionHash(navigateMenu, MenuOption::AddressBar, Qt::CTRL | Qt::Key_L,
|
addActionToQMenuAndActionHash(navigateMenu, MenuOption::AddressBar, Qt::CTRL | Qt::Key_L,
|
||||||
dialogsManager.data(), SLOT(showAddressBar()));
|
dialogsManager.data(), SLOT(toggleAddressBar()));
|
||||||
|
|
||||||
// Navigate > LocationBookmarks related menus -- Note: the LocationBookmarks class adds its own submenus here.
|
// Navigate > LocationBookmarks related menus -- Note: the LocationBookmarks class adds its own submenus here.
|
||||||
auto locationBookmarks = DependencyManager::get<LocationBookmarks>();
|
auto locationBookmarks = DependencyManager::get<LocationBookmarks>();
|
||||||
|
|
|
@ -3238,8 +3238,6 @@ bool MyAvatar::pinJoint(int index, const glm::vec3& position, const glm::quat& o
|
||||||
slamPosition(position);
|
slamPosition(position);
|
||||||
setWorldOrientation(orientation);
|
setWorldOrientation(orientation);
|
||||||
|
|
||||||
_skeletonModel->getRig().setMaxHipsOffsetLength(0.05f);
|
|
||||||
|
|
||||||
auto it = std::find(_pinnedJoints.begin(), _pinnedJoints.end(), index);
|
auto it = std::find(_pinnedJoints.begin(), _pinnedJoints.end(), index);
|
||||||
if (it == _pinnedJoints.end()) {
|
if (it == _pinnedJoints.end()) {
|
||||||
_pinnedJoints.push_back(index);
|
_pinnedJoints.push_back(index);
|
||||||
|
@ -3259,12 +3257,6 @@ bool MyAvatar::clearPinOnJoint(int index) {
|
||||||
auto it = std::find(_pinnedJoints.begin(), _pinnedJoints.end(), index);
|
auto it = std::find(_pinnedJoints.begin(), _pinnedJoints.end(), index);
|
||||||
if (it != _pinnedJoints.end()) {
|
if (it != _pinnedJoints.end()) {
|
||||||
_pinnedJoints.erase(it);
|
_pinnedJoints.erase(it);
|
||||||
|
|
||||||
auto hipsIndex = getJointIndex("Hips");
|
|
||||||
if (index == hipsIndex) {
|
|
||||||
_skeletonModel->getRig().setMaxHipsOffsetLength(FLT_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -81,7 +81,7 @@ class MyAvatar : public Avatar {
|
||||||
* and MyAvatar.customListenOrientation properties.
|
* and MyAvatar.customListenOrientation properties.
|
||||||
* @property customListenPosition {Vec3} If MyAvatar.audioListenerMode == MyAvatar.audioListenerModeHead, then this determines the position
|
* @property customListenPosition {Vec3} If MyAvatar.audioListenerMode == MyAvatar.audioListenerModeHead, then this determines the position
|
||||||
* of audio spatialization listener.
|
* of audio spatialization listener.
|
||||||
* @property customListenOreintation {Quat} If MyAvatar.audioListenerMode == MyAvatar.audioListenerModeHead, then this determines the orientation
|
* @property customListenOrientation {Quat} If MyAvatar.audioListenerMode == MyAvatar.audioListenerModeHead, then this determines the orientation
|
||||||
* of the audio spatialization listener.
|
* of the audio spatialization listener.
|
||||||
* @property audioListenerModeHead {number} READ-ONLY. When passed to MyAvatar.audioListenerMode, it will set the audio listener
|
* @property audioListenerModeHead {number} READ-ONLY. When passed to MyAvatar.audioListenerMode, it will set the audio listener
|
||||||
* around the avatar's head.
|
* around the avatar's head.
|
||||||
|
|
|
@ -43,8 +43,6 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
|
||||||
AnimPose result = AnimPose(worldToSensorMat * avatarTransform.getMatrix() * Matrices::Y_180);
|
AnimPose result = AnimPose(worldToSensorMat * avatarTransform.getMatrix() * Matrices::Y_180);
|
||||||
result.scale() = glm::vec3(1.0f, 1.0f, 1.0f);
|
result.scale() = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||||
return result;
|
return result;
|
||||||
} else {
|
|
||||||
DebugDraw::getInstance().removeMarker("pinnedHips");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 hipsMat = myAvatar->deriveBodyFromHMDSensor();
|
glm::mat4 hipsMat = myAvatar->deriveBodyFromHMDSensor();
|
||||||
|
|
|
@ -26,15 +26,11 @@
|
||||||
|
|
||||||
#include "AddressManager.h"
|
#include "AddressManager.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "Crashpad.h"
|
||||||
#include "InterfaceLogging.h"
|
#include "InterfaceLogging.h"
|
||||||
#include "UserActivityLogger.h"
|
#include "UserActivityLogger.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
#ifdef HAS_BUGSPLAT
|
|
||||||
#include <BugSplat.h>
|
|
||||||
#include <CrashReporter.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
extern "C" {
|
extern "C" {
|
||||||
typedef int(__stdcall * CHECKMINSPECPROC) ();
|
typedef int(__stdcall * CHECKMINSPECPROC) ();
|
||||||
|
@ -42,11 +38,6 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
#if HAS_BUGSPLAT
|
|
||||||
static QString BUG_SPLAT_DATABASE = "interface_alpha";
|
|
||||||
static QString BUG_SPLAT_APPLICATION_NAME = "Interface";
|
|
||||||
CrashReporter crashReporter { BUG_SPLAT_DATABASE, BUG_SPLAT_APPLICATION_NAME, BuildInfo::VERSION };
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
|
QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
|
||||||
|
@ -71,6 +62,17 @@ int main(int argc, const char* argv[]) {
|
||||||
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
||||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||||
|
|
||||||
|
Setting::init();
|
||||||
|
|
||||||
|
// Instance UserActivityLogger now that the settings are loaded
|
||||||
|
auto& ual = UserActivityLogger::getInstance();
|
||||||
|
qDebug() << "UserActivityLogger is enabled:" << ual.isEnabled();
|
||||||
|
|
||||||
|
if (ual.isEnabled()) {
|
||||||
|
auto crashHandlerStarted = startCrashHandler();
|
||||||
|
qDebug() << "Crash handler started:" << crashHandlerStarted;
|
||||||
|
}
|
||||||
|
|
||||||
QStringList arguments;
|
QStringList arguments;
|
||||||
for (int i = 0; i < argc; ++i) {
|
for (int i = 0; i < argc; ++i) {
|
||||||
arguments << argv[i];
|
arguments << argv[i];
|
||||||
|
@ -259,7 +261,6 @@ int main(int argc, const char* argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Setup local server
|
// Setup local server
|
||||||
QLocalServer server { &app };
|
QLocalServer server { &app };
|
||||||
|
@ -268,29 +269,8 @@ int main(int argc, const char* argv[]) {
|
||||||
server.removeServer(applicationName);
|
server.removeServer(applicationName);
|
||||||
server.listen(applicationName);
|
server.listen(applicationName);
|
||||||
|
|
||||||
QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection, Qt::DirectConnection);
|
QObject::connect(&server, &QLocalServer::newConnection,
|
||||||
|
&app, &Application::handleLocalServerConnection, Qt::DirectConnection);
|
||||||
#ifdef HAS_BUGSPLAT
|
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
|
||||||
crashReporter.mpSender.setDefaultUserName(qPrintable(accountManager->getAccountInfo().getUsername()));
|
|
||||||
QObject::connect(accountManager.data(), &AccountManager::usernameChanged, &app, [&crashReporter](const QString& newUsername) {
|
|
||||||
crashReporter.mpSender.setDefaultUserName(qPrintable(newUsername));
|
|
||||||
});
|
|
||||||
|
|
||||||
// BugSplat WILL NOT work with file paths that do not use OS native separators.
|
|
||||||
auto logger = app.getLogger();
|
|
||||||
auto logPath = QDir::toNativeSeparators(logger->getFilename());
|
|
||||||
crashReporter.mpSender.sendAdditionalFile(qPrintable(logPath));
|
|
||||||
|
|
||||||
QMetaObject::Connection connection;
|
|
||||||
connection = QObject::connect(logger, &FileLogger::rollingLogFile, &app, [&crashReporter, &connection](QString newFilename) {
|
|
||||||
// We only want to add the first rolled log file (the "beginning" of the log) to BugSplat to ensure we don't exceed the 2MB
|
|
||||||
// zipped limit, so we disconnect here.
|
|
||||||
QObject::disconnect(connection);
|
|
||||||
auto rolledLogPath = QDir::toNativeSeparators(newFilename);
|
|
||||||
crashReporter.mpSender.sendAdditionalFile(qPrintable(rolledLogPath));
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
|
|
||||||
printSystemInformation();
|
printSystemInformation();
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ CheckoutProxy::CheckoutProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(q
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletScriptingInterface::WalletScriptingInterface() {
|
WalletScriptingInterface::WalletScriptingInterface() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletScriptingInterface::refreshWalletStatus() {
|
void WalletScriptingInterface::refreshWalletStatus() {
|
||||||
|
@ -26,4 +27,19 @@ void WalletScriptingInterface::refreshWalletStatus() {
|
||||||
void WalletScriptingInterface::setWalletStatus(const uint& status) {
|
void WalletScriptingInterface::setWalletStatus(const uint& status) {
|
||||||
_walletStatus = status;
|
_walletStatus = status;
|
||||||
emit DependencyManager::get<Wallet>()->walletStatusResult(status);
|
emit DependencyManager::get<Wallet>()->walletStatusResult(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WalletScriptingInterface::proveAvatarEntityOwnershipVerification(const QUuid& entityID) {
|
||||||
|
QSharedPointer<ContextOverlayInterface> contextOverlayInterface = DependencyManager::get<ContextOverlayInterface>();
|
||||||
|
EntityItemProperties entityProperties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID,
|
||||||
|
contextOverlayInterface->getEntityPropertyFlags());
|
||||||
|
if (entityProperties.getClientOnly()) {
|
||||||
|
if (!entityID.isNull() && entityProperties.getCertificateID().length() > 0) {
|
||||||
|
contextOverlayInterface->requestOwnershipVerification(entityID);
|
||||||
|
} else {
|
||||||
|
qCDebug(entities) << "Failed to prove ownership of:" << entityID << "is null or not a certified item";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCDebug(entities) << "Failed to prove ownership of:" << entityID << "is not an avatar entity";
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@
|
||||||
#include <OffscreenUi.h>
|
#include <OffscreenUi.h>
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "commerce/Wallet.h"
|
#include "commerce/Wallet.h"
|
||||||
|
#include "ui/overlays/ContextOverlayInterface.h"
|
||||||
|
|
||||||
class CheckoutProxy : public QmlWrapper {
|
class CheckoutProxy : public QmlWrapper {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -39,6 +40,7 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void refreshWalletStatus();
|
Q_INVOKABLE void refreshWalletStatus();
|
||||||
Q_INVOKABLE uint getWalletStatus() { return _walletStatus; }
|
Q_INVOKABLE uint getWalletStatus() { return _walletStatus; }
|
||||||
|
Q_INVOKABLE void proveAvatarEntityOwnershipVerification(const QUuid& entityID);
|
||||||
// setWalletStatus() should never be made Q_INVOKABLE. If it were,
|
// setWalletStatus() should never be made Q_INVOKABLE. If it were,
|
||||||
// scripts could cause the Wallet to incorrectly report its status.
|
// scripts could cause the Wallet to incorrectly report its status.
|
||||||
void setWalletStatus(const uint& status);
|
void setWalletStatus(const uint& status);
|
||||||
|
@ -46,6 +48,8 @@ public:
|
||||||
signals:
|
signals:
|
||||||
void walletStatusChanged();
|
void walletStatusChanged();
|
||||||
void walletNotSetup();
|
void walletNotSetup();
|
||||||
|
void ownershipVerificationSuccess(const QUuid& entityID);
|
||||||
|
void ownershipVerificationFailed(const QUuid& entityID);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint _walletStatus;
|
uint _walletStatus;
|
||||||
|
|
|
@ -105,14 +105,14 @@ void WindowScriptingInterface::raiseMainWindow() {
|
||||||
/// \param const QString& message message to display
|
/// \param const QString& message message to display
|
||||||
/// \return QScriptValue::UndefinedValue
|
/// \return QScriptValue::UndefinedValue
|
||||||
void WindowScriptingInterface::alert(const QString& message) {
|
void WindowScriptingInterface::alert(const QString& message) {
|
||||||
OffscreenUi::asyncWarning("", message);
|
OffscreenUi::asyncWarning("", message, QMessageBox::Ok, QMessageBox::Ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display a confirmation box with the options 'Yes' and 'No'
|
/// Display a confirmation box with the options 'Yes' and 'No'
|
||||||
/// \param const QString& message message to display
|
/// \param const QString& message message to display
|
||||||
/// \return QScriptValue `true` if 'Yes' was clicked, `false` otherwise
|
/// \return QScriptValue `true` if 'Yes' was clicked, `false` otherwise
|
||||||
QScriptValue WindowScriptingInterface::confirm(const QString& message) {
|
QScriptValue WindowScriptingInterface::confirm(const QString& message) {
|
||||||
return QScriptValue((QMessageBox::Yes == OffscreenUi::question("", message, QMessageBox::Yes | QMessageBox::No)));
|
return QScriptValue((QMessageBox::Yes == OffscreenUi::question("", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display a prompt with a text box
|
/// Display a prompt with a text box
|
||||||
|
@ -354,7 +354,7 @@ QScriptValue WindowScriptingInterface::browseAssets(const QString& title, const
|
||||||
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display a select asset dialog that lets the user select an asset from the Asset Server. If `directory` is an invalid
|
/// Display a select asset dialog that lets the user select an asset from the Asset Server. If `directory` is an invalid
|
||||||
/// directory the browser will start at the root directory.
|
/// directory the browser will start at the root directory.
|
||||||
/// \param const QString& title title of the window
|
/// \param const QString& title title of the window
|
||||||
/// \param const QString& directory directory to start the asset browser at
|
/// \param const QString& directory directory to start the asset browser at
|
||||||
|
|
|
@ -22,7 +22,7 @@ class AddressBarDialog : public OffscreenQmlDialog {
|
||||||
Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged)
|
Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged)
|
||||||
Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged)
|
Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged)
|
||||||
Q_PROPERTY(bool useFeed READ useFeed WRITE setUseFeed NOTIFY useFeedChanged)
|
Q_PROPERTY(bool useFeed READ useFeed WRITE setUseFeed NOTIFY useFeedChanged)
|
||||||
Q_PROPERTY(QString metaverseServerUrl READ metaverseServerUrl)
|
Q_PROPERTY(QString metaverseServerUrl READ metaverseServerUrl CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AddressBarDialog(QQuickItem* parent = nullptr);
|
AddressBarDialog(QQuickItem* parent = nullptr);
|
||||||
|
|
|
@ -58,7 +58,7 @@ void DialogsManager::showAddressBar() {
|
||||||
hmd->openTablet();
|
hmd->openTablet();
|
||||||
}
|
}
|
||||||
qApp->setKeyboardFocusOverlay(hmd->getCurrentTabletScreenID());
|
qApp->setKeyboardFocusOverlay(hmd->getCurrentTabletScreenID());
|
||||||
emit addressBarShown(true);
|
setAddressBarVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsManager::hideAddressBar() {
|
void DialogsManager::hideAddressBar() {
|
||||||
|
@ -71,7 +71,7 @@ void DialogsManager::hideAddressBar() {
|
||||||
hmd->closeTablet();
|
hmd->closeTablet();
|
||||||
}
|
}
|
||||||
qApp->setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
|
qApp->setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
|
||||||
emit addressBarShown(false);
|
setAddressBarVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsManager::showFeed() {
|
void DialogsManager::showFeed() {
|
||||||
|
@ -157,6 +157,24 @@ void DialogsManager::hmdToolsClosed() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DialogsManager::toggleAddressBar() {
|
||||||
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||||
|
|
||||||
|
const bool addressBarLoaded = tablet->isPathLoaded(TABLET_ADDRESS_DIALOG);
|
||||||
|
|
||||||
|
if (_addressBarVisible || addressBarLoaded) {
|
||||||
|
hideAddressBar();
|
||||||
|
} else {
|
||||||
|
showAddressBar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogsManager::setAddressBarVisible(bool addressBarVisible) {
|
||||||
|
_addressBarVisible = addressBarVisible;
|
||||||
|
emit addressBarShown(_addressBarVisible);
|
||||||
|
}
|
||||||
|
|
||||||
void DialogsManager::showTestingResults() {
|
void DialogsManager::showTestingResults() {
|
||||||
if (!_testingDialog) {
|
if (!_testingDialog) {
|
||||||
_testingDialog = new TestingDialog(qApp->getWindow());
|
_testingDialog = new TestingDialog(qApp->getWindow());
|
||||||
|
|
|
@ -39,6 +39,7 @@ public:
|
||||||
QPointer<OctreeStatsDialog> getOctreeStatsDialog() const { return _octreeStatsDialog; }
|
QPointer<OctreeStatsDialog> getOctreeStatsDialog() const { return _octreeStatsDialog; }
|
||||||
QPointer<TestingDialog> getTestingDialog() const { return _testingDialog; }
|
QPointer<TestingDialog> getTestingDialog() const { return _testingDialog; }
|
||||||
void emitAddressBarShown(bool visible) { emit addressBarShown(visible); }
|
void emitAddressBarShown(bool visible) { emit addressBarShown(visible); }
|
||||||
|
void setAddressBarVisible(bool addressBarVisible);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void showAddressBar();
|
void showAddressBar();
|
||||||
|
@ -52,6 +53,7 @@ public slots:
|
||||||
void hmdTools(bool showTools);
|
void hmdTools(bool showTools);
|
||||||
void showDomainConnectionDialog();
|
void showDomainConnectionDialog();
|
||||||
void showTestingResults();
|
void showTestingResults();
|
||||||
|
void toggleAddressBar();
|
||||||
|
|
||||||
// Application Update
|
// Application Update
|
||||||
void showUpdateDialog();
|
void showUpdateDialog();
|
||||||
|
@ -78,7 +80,7 @@ private:
|
||||||
QPointer<OctreeStatsDialog> _octreeStatsDialog;
|
QPointer<OctreeStatsDialog> _octreeStatsDialog;
|
||||||
QPointer<TestingDialog> _testingDialog;
|
QPointer<TestingDialog> _testingDialog;
|
||||||
QPointer<DomainConnectionDialog> _domainConnectionDialog;
|
QPointer<DomainConnectionDialog> _domainConnectionDialog;
|
||||||
bool _closeAddressBar { false };
|
bool _addressBarVisible { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_DialogsManager_h
|
#endif // hifi_DialogsManager_h
|
||||||
|
|
|
@ -12,10 +12,12 @@
|
||||||
#include "JSConsole.h"
|
#include "JSConsole.h"
|
||||||
|
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QKeyEvent>
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
#include <QStringListModel>
|
||||||
|
#include <QListView>
|
||||||
|
#include <QToolTip>
|
||||||
|
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <ScriptEngines.h>
|
#include <ScriptEngines.h>
|
||||||
|
@ -38,6 +40,21 @@ const QString RESULT_ERROR_STYLE = "color: #d13b22;";
|
||||||
const QString GUTTER_PREVIOUS_COMMAND = "<span style=\"color: #57b8bb;\"><</span>";
|
const QString GUTTER_PREVIOUS_COMMAND = "<span style=\"color: #57b8bb;\"><</span>";
|
||||||
const QString GUTTER_ERROR = "<span style=\"color: #d13b22;\">X</span>";
|
const QString GUTTER_ERROR = "<span style=\"color: #d13b22;\">X</span>";
|
||||||
|
|
||||||
|
const QString JSDOC_LINE_SEPARATOR = "\r";
|
||||||
|
|
||||||
|
const QString JSDOC_STYLE =
|
||||||
|
"<style type=\"text/css\"> \
|
||||||
|
.code { \
|
||||||
|
font-family: Consolas, Monaco, 'Andale Mono', monospace \
|
||||||
|
} \
|
||||||
|
pre, code { \
|
||||||
|
display: inline; \
|
||||||
|
} \
|
||||||
|
.no-wrap { \
|
||||||
|
white-space: nowrap; \
|
||||||
|
} \
|
||||||
|
</style>";
|
||||||
|
|
||||||
const QString JSConsole::_consoleFileName { "about:console" };
|
const QString JSConsole::_consoleFileName { "about:console" };
|
||||||
|
|
||||||
const QString JSON_KEY = "entries";
|
const QString JSON_KEY = "entries";
|
||||||
|
@ -49,7 +66,7 @@ QList<QString> _readLines(const QString& filename) {
|
||||||
// TODO: check root["version"]
|
// TODO: check root["version"]
|
||||||
return root[JSON_KEY].toVariant().toStringList();
|
return root[JSON_KEY].toVariant().toStringList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _writeLines(const QString& filename, const QList<QString>& lines) {
|
void _writeLines(const QString& filename, const QList<QString>& lines) {
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
file.open(QFile::WriteOnly);
|
file.open(QFile::WriteOnly);
|
||||||
|
@ -61,12 +78,71 @@ void _writeLines(const QString& filename, const QList<QString>& lines) {
|
||||||
QTextStream(&file) << json;
|
QTextStream(&file) << json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString _jsdocTypeToString(QJsonValue jsdocType) {
|
||||||
|
return jsdocType.toObject().value("names").toVariant().toStringList().join("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::readAPI() {
|
||||||
|
QFile file(PathUtils::resourcesPath() + "auto-complete/hifiJSDoc.json");
|
||||||
|
file.open(QFile::ReadOnly);
|
||||||
|
auto json = QTextStream(&file).readAll().toUtf8();
|
||||||
|
_apiDocs = QJsonDocument::fromJson(json).array();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStandardItem* getAutoCompleteItem(QJsonValue propertyObject) {
|
||||||
|
auto propertyItem = new QStandardItem(propertyObject.toObject().value("name").toString());
|
||||||
|
propertyItem->setData(propertyObject.toVariant());
|
||||||
|
return propertyItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStandardItemModel* JSConsole::getAutoCompleteModel(const QString& memberOf) {
|
||||||
|
QString memberOfProperty = nullptr;
|
||||||
|
|
||||||
|
auto model = new QStandardItemModel(this);
|
||||||
|
|
||||||
|
if (memberOf != nullptr) {
|
||||||
|
foreach(auto doc, _apiDocs) {
|
||||||
|
auto object = doc.toObject();
|
||||||
|
if (object.value("name").toString() == memberOf && object.value("scope").toString() == "global" &&
|
||||||
|
object.value("kind").toString() == "namespace") {
|
||||||
|
|
||||||
|
memberOfProperty = object.value("longname").toString();
|
||||||
|
|
||||||
|
auto properties = doc.toObject().value("properties").toArray();
|
||||||
|
foreach(auto propertyObject, properties) {
|
||||||
|
model->appendRow(getAutoCompleteItem(propertyObject));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (memberOfProperty == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(auto doc, _apiDocs) {
|
||||||
|
auto object = doc.toObject();
|
||||||
|
auto scope = object.value("scope");
|
||||||
|
if ((memberOfProperty == nullptr && scope.toString() == "global" && object.value("kind").toString() == "namespace") ||
|
||||||
|
(memberOfProperty != nullptr && object.value("memberof").toString() == memberOfProperty &&
|
||||||
|
object.value("kind").toString() != "typedef")) {
|
||||||
|
|
||||||
|
model->appendRow(getAutoCompleteItem(doc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model->sort(0);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) :
|
JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
_ui(new Ui::Console),
|
_ui(new Ui::Console),
|
||||||
_currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND),
|
_currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND),
|
||||||
_savedHistoryFilename(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + HISTORY_FILENAME),
|
_savedHistoryFilename(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + HISTORY_FILENAME),
|
||||||
_commandHistory(_readLines(_savedHistoryFilename)) {
|
_commandHistory(_readLines(_savedHistoryFilename)),
|
||||||
|
_completer(new QCompleter(this)) {
|
||||||
|
|
||||||
|
readAPI();
|
||||||
|
|
||||||
_ui->setupUi(this);
|
_ui->setupUi(this);
|
||||||
_ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap);
|
_ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap);
|
||||||
_ui->promptTextEdit->setWordWrapMode(QTextOption::NoWrap);
|
_ui->promptTextEdit->setWordWrapMode(QTextOption::NoWrap);
|
||||||
|
@ -78,38 +154,174 @@ JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) :
|
||||||
setStyleSheet(styleSheet.readAll());
|
setStyleSheet(styleSheet.readAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(_ui->scrollArea->verticalScrollBar(), SIGNAL(rangeChanged(int, int)), this, SLOT(scrollToBottom()));
|
connect(_ui->scrollArea->verticalScrollBar(), &QScrollBar::rangeChanged, this, &JSConsole::scrollToBottom);
|
||||||
connect(_ui->promptTextEdit, SIGNAL(textChanged()), this, SLOT(resizeTextInput()));
|
connect(_ui->promptTextEdit, &QTextEdit::textChanged, this, &JSConsole::resizeTextInput);
|
||||||
|
|
||||||
|
_completer->setWidget(_ui->promptTextEdit);
|
||||||
|
_completer->setModel(getAutoCompleteModel(nullptr));
|
||||||
|
_completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
|
||||||
|
_completer->setMaxVisibleItems(12);
|
||||||
|
_completer->setFilterMode(Qt::MatchStartsWith);
|
||||||
|
_completer->setWrapAround(false);
|
||||||
|
_completer->setCompletionMode(QCompleter::PopupCompletion);
|
||||||
|
_completer->setCaseSensitivity(Qt::CaseSensitive);
|
||||||
|
|
||||||
|
QListView *listView = new QListView();
|
||||||
|
listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
listView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
listView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
listView->setModelColumn(_completer->completionColumn());
|
||||||
|
|
||||||
|
_completer->setPopup(listView);
|
||||||
|
_completer->popup()->installEventFilter(this);
|
||||||
|
QObject::connect(_completer, static_cast<void(QCompleter::*)(const QModelIndex&)>(&QCompleter::activated), this,
|
||||||
|
&JSConsole::insertCompletion);
|
||||||
|
|
||||||
|
QObject::connect(_completer, static_cast<void(QCompleter::*)(const QModelIndex&)>(&QCompleter::highlighted), this,
|
||||||
|
&JSConsole::highlightedCompletion);
|
||||||
|
|
||||||
setScriptEngine(scriptEngine);
|
setScriptEngine(scriptEngine);
|
||||||
|
|
||||||
resizeTextInput();
|
resizeTextInput();
|
||||||
|
|
||||||
connect(&_executeWatcher, SIGNAL(finished()), this, SLOT(commandFinished()));
|
connect(&_executeWatcher, &QFutureWatcher<QScriptValue>::finished, this, &JSConsole::commandFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::insertCompletion(const QModelIndex& completion) {
|
||||||
|
auto jsdocObject = QJsonValue::fromVariant(completion.data(Qt::UserRole + 1)).toObject();
|
||||||
|
auto kind = jsdocObject.value("kind").toString();
|
||||||
|
auto completionString = completion.data().toString();
|
||||||
|
if (kind == "function") {
|
||||||
|
auto params = jsdocObject.value("params").toArray();
|
||||||
|
// automatically add the parenthesis/parentheses for the functions
|
||||||
|
completionString += params.isEmpty() ? "()" : "(";
|
||||||
|
}
|
||||||
|
QTextCursor textCursor = _ui->promptTextEdit->textCursor();
|
||||||
|
int extra = completionString.length() - _completer->completionPrefix().length();
|
||||||
|
textCursor.movePosition(QTextCursor::Left);
|
||||||
|
textCursor.movePosition(QTextCursor::EndOfWord);
|
||||||
|
textCursor.insertText(completionString.right(extra));
|
||||||
|
_ui->promptTextEdit->setTextCursor(textCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSConsole::highlightedCompletion(const QModelIndex& completion) {
|
||||||
|
auto jsdocObject = QJsonValue::fromVariant(completion.data(Qt::UserRole + 1)).toObject();
|
||||||
|
QString memberOf = "";
|
||||||
|
if (!_completerModule.isEmpty()) {
|
||||||
|
memberOf = _completerModule + ".";
|
||||||
|
}
|
||||||
|
auto name = memberOf + "<b>" + jsdocObject.value("name").toString() + "</b>";
|
||||||
|
auto description = jsdocObject.value("description").toString();
|
||||||
|
auto examples = jsdocObject.value("examples").toArray();
|
||||||
|
auto kind = jsdocObject.value("kind").toString();
|
||||||
|
QString returnTypeText = "";
|
||||||
|
|
||||||
|
QString paramsTable = "";
|
||||||
|
if (kind == "function") {
|
||||||
|
auto params = jsdocObject.value("params").toArray();
|
||||||
|
auto returns = jsdocObject.value("returns");
|
||||||
|
if (!returns.isUndefined()) {
|
||||||
|
returnTypeText = _jsdocTypeToString(jsdocObject.value("returns").toArray().at(0).toObject().value("type")) + " ";
|
||||||
|
}
|
||||||
|
name += "(";
|
||||||
|
if (!params.isEmpty()) {
|
||||||
|
bool hasDefaultParam = false;
|
||||||
|
bool hasOptionalParam = false;
|
||||||
|
bool firstItem = true;
|
||||||
|
foreach(auto param, params) {
|
||||||
|
auto paramObject = param.toObject();
|
||||||
|
if (!hasOptionalParam && paramObject.value("optional").toBool(false)) {
|
||||||
|
hasOptionalParam = true;
|
||||||
|
name += "<i>[";
|
||||||
|
}
|
||||||
|
if (!firstItem) {
|
||||||
|
name += ", ";
|
||||||
|
} else {
|
||||||
|
firstItem = false;
|
||||||
|
}
|
||||||
|
name += paramObject.value("name").toString();
|
||||||
|
if (!hasDefaultParam && !paramObject.value("defaultvalue").isUndefined()) {
|
||||||
|
hasDefaultParam = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasOptionalParam) {
|
||||||
|
name += "]</i>";
|
||||||
|
}
|
||||||
|
|
||||||
|
paramsTable += "<table border=\"1\" cellpadding=\"10\"><thead><tr><th>Name</th><th>Type</th>";
|
||||||
|
if (hasDefaultParam) {
|
||||||
|
paramsTable += "<th>Default</th>";
|
||||||
|
}
|
||||||
|
paramsTable += "<th>Description</th></tr></thead><tbody>";
|
||||||
|
foreach(auto param, params) {
|
||||||
|
auto paramObject = param.toObject();
|
||||||
|
paramsTable += "<tr><td>" + paramObject.value("name").toString() + "</td><td>" +
|
||||||
|
_jsdocTypeToString(paramObject.value("type")) + "</td><td>";
|
||||||
|
if (hasDefaultParam) {
|
||||||
|
paramsTable += paramObject.value("defaultvalue").toVariant().toString() + "</td><td>";
|
||||||
|
}
|
||||||
|
paramsTable += paramObject.value("description").toString() + "</td></tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
paramsTable += "</tbody></table>";
|
||||||
|
}
|
||||||
|
name += ")";
|
||||||
|
} else if (!jsdocObject.value("type").isUndefined()){
|
||||||
|
returnTypeText = _jsdocTypeToString(jsdocObject.value("type")) + " ";
|
||||||
|
}
|
||||||
|
auto popupText = JSDOC_STYLE + "<span class=\"no-wrap\">" + returnTypeText + name + "</span>";
|
||||||
|
auto descriptionText = "<p>" + description.replace(JSDOC_LINE_SEPARATOR, "<br>") + "</p>";
|
||||||
|
|
||||||
|
popupText += descriptionText;
|
||||||
|
popupText += paramsTable;
|
||||||
|
auto returns = jsdocObject.value("returns");
|
||||||
|
if (!returns.isUndefined()) {
|
||||||
|
foreach(auto returnEntry, returns.toArray()) {
|
||||||
|
auto returnsObject = returnEntry.toObject();
|
||||||
|
auto returnsDescription = returnsObject.value("description").toString().replace(JSDOC_LINE_SEPARATOR, "<br>");
|
||||||
|
popupText += "<h4>Returns</h4><p>" + returnsDescription + "</p><h5>Type</h5><pre><code>" +
|
||||||
|
_jsdocTypeToString(returnsObject.value("type")) + "</code></pre>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!examples.isEmpty()) {
|
||||||
|
popupText += "<h4>Examples</h4>";
|
||||||
|
foreach(auto example, examples) {
|
||||||
|
auto exampleText = example.toString();
|
||||||
|
auto exampleLines = exampleText.split(JSDOC_LINE_SEPARATOR);
|
||||||
|
foreach(auto exampleLine, exampleLines) {
|
||||||
|
if (exampleLine.contains("<caption>")) {
|
||||||
|
popupText += exampleLine.replace("caption>", "h5>");
|
||||||
|
} else {
|
||||||
|
popupText += "<pre><code>" + exampleLine + "\n</code></pre>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QToolTip::showText(QPoint(_completer->popup()->pos().x() + _completer->popup()->width(), _completer->popup()->pos().y()),
|
||||||
|
popupText, _completer->popup());
|
||||||
}
|
}
|
||||||
|
|
||||||
JSConsole::~JSConsole() {
|
JSConsole::~JSConsole() {
|
||||||
if (_scriptEngine) {
|
if (_scriptEngine) {
|
||||||
disconnect(_scriptEngine.data(), SIGNAL(printedMessage(const QString&)), this, SLOT(handlePrint(const QString&)));
|
disconnect(_scriptEngine.data(), nullptr, this, nullptr);
|
||||||
disconnect(_scriptEngine.data(), SIGNAL(errorMessage(const QString&)), this, SLOT(handleError(const QString&)));
|
|
||||||
_scriptEngine.reset();
|
_scriptEngine.reset();
|
||||||
}
|
}
|
||||||
delete _ui;
|
delete _ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JSConsole::setScriptEngine(const ScriptEnginePointer& scriptEngine) {
|
void JSConsole::setScriptEngine(const ScriptEnginePointer& scriptEngine) {
|
||||||
if (_scriptEngine == scriptEngine && scriptEngine != NULL) {
|
if (_scriptEngine == scriptEngine && scriptEngine != nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_scriptEngine != NULL) {
|
if (_scriptEngine != nullptr) {
|
||||||
disconnect(_scriptEngine.data(), &ScriptEngine::printedMessage, this, &JSConsole::handlePrint);
|
disconnect(_scriptEngine.data(), nullptr, this, nullptr);
|
||||||
disconnect(_scriptEngine.data(), &ScriptEngine::infoMessage, this, &JSConsole::handleInfo);
|
|
||||||
disconnect(_scriptEngine.data(), &ScriptEngine::warningMessage, this, &JSConsole::handleWarning);
|
|
||||||
disconnect(_scriptEngine.data(), &ScriptEngine::errorMessage, this, &JSConsole::handleError);
|
|
||||||
_scriptEngine.reset();
|
_scriptEngine.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if scriptEngine is NULL then create one and keep track of it using _ownScriptEngine
|
// if scriptEngine is nullptr then create one and keep track of it using _ownScriptEngine
|
||||||
if (scriptEngine.isNull()) {
|
if (scriptEngine.isNull()) {
|
||||||
_scriptEngine = DependencyManager::get<ScriptEngines>()->loadScript(_consoleFileName, false);
|
_scriptEngine = DependencyManager::get<ScriptEngines>()->loadScript(_consoleFileName, false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -199,45 +411,121 @@ void JSConsole::showEvent(QShowEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JSConsole::eventFilter(QObject* sender, QEvent* event) {
|
bool JSConsole::eventFilter(QObject* sender, QEvent* event) {
|
||||||
if (sender == _ui->promptTextEdit) {
|
if ((sender == _ui->promptTextEdit || sender == _completer->popup()) && event->type() == QEvent::KeyPress) {
|
||||||
if (event->type() == QEvent::KeyPress) {
|
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
int key = keyEvent->key();
|
||||||
int key = keyEvent->key();
|
|
||||||
|
|
||||||
if ((key == Qt::Key_Return || key == Qt::Key_Enter)) {
|
if (_completer->popup()->isVisible()) {
|
||||||
if (keyEvent->modifiers() & Qt::ShiftModifier) {
|
// The following keys are forwarded by the completer to the widget
|
||||||
// If the shift key is being used then treat it as a regular return/enter. If this isn't done,
|
switch (key) {
|
||||||
// a new QTextBlock isn't created.
|
case Qt::Key_Space:
|
||||||
keyEvent->setModifiers(keyEvent->modifiers() & ~Qt::ShiftModifier);
|
case Qt::Key_Enter:
|
||||||
} else {
|
case Qt::Key_Return:
|
||||||
QString command = _ui->promptTextEdit->toPlainText().replace("\r\n","\n").trimmed();
|
insertCompletion(_completer->popup()->currentIndex());
|
||||||
|
_completer->popup()->hide();
|
||||||
if (!command.isEmpty()) {
|
return true;
|
||||||
QTextCursor cursor = _ui->promptTextEdit->textCursor();
|
default:
|
||||||
_ui->promptTextEdit->clear();
|
return false;
|
||||||
|
|
||||||
executeCommand(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (key == Qt::Key_Down) {
|
|
||||||
// Go to the next command in history if the cursor is at the last line of the current command.
|
|
||||||
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
|
|
||||||
int blockCount = _ui->promptTextEdit->document()->blockCount();
|
|
||||||
if (blockNumber == blockCount - 1) {
|
|
||||||
setToNextCommandInHistory();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (key == Qt::Key_Up) {
|
|
||||||
// Go to the previous command in history if the cursor is at the first line of the current command.
|
|
||||||
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
|
|
||||||
if (blockNumber == 0) {
|
|
||||||
setToPreviousCommandInHistory();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key == Qt::Key_Return || key == Qt::Key_Enter) {
|
||||||
|
if (keyEvent->modifiers() & Qt::ShiftModifier) {
|
||||||
|
// If the shift key is being used then treat it as a regular return/enter. If this isn't done,
|
||||||
|
// a new QTextBlock isn't created.
|
||||||
|
keyEvent->setModifiers(keyEvent->modifiers() & ~Qt::ShiftModifier);
|
||||||
|
} else {
|
||||||
|
QString command = _ui->promptTextEdit->toPlainText().replace("\r\n", "\n").trimmed();
|
||||||
|
|
||||||
|
if (!command.isEmpty()) {
|
||||||
|
QTextCursor cursor = _ui->promptTextEdit->textCursor();
|
||||||
|
_ui->promptTextEdit->clear();
|
||||||
|
|
||||||
|
executeCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (key == Qt::Key_Down) {
|
||||||
|
// Go to the next command in history if the cursor is at the last line of the current command.
|
||||||
|
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
|
||||||
|
int blockCount = _ui->promptTextEdit->document()->blockCount();
|
||||||
|
if (blockNumber == blockCount - 1) {
|
||||||
|
setToNextCommandInHistory();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (key == Qt::Key_Up) {
|
||||||
|
// Go to the previous command in history if the cursor is at the first line of the current command.
|
||||||
|
int blockNumber = _ui->promptTextEdit->textCursor().blockNumber();
|
||||||
|
if (blockNumber == 0) {
|
||||||
|
setToPreviousCommandInHistory();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((sender == _ui->promptTextEdit || sender == _completer->popup()) && event->type() == QEvent::KeyRelease) {
|
||||||
|
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||||
|
int key = keyEvent->key();
|
||||||
|
|
||||||
|
// completer shortcut (CTRL + SPACE)
|
||||||
|
bool isCompleterShortcut = ((keyEvent->modifiers() & Qt::ControlModifier) && key == Qt::Key_Space) ||
|
||||||
|
key == Qt::Key_Period;
|
||||||
|
if (_completer->popup()->isVisible() || isCompleterShortcut) {
|
||||||
|
|
||||||
|
const bool ctrlOrShift = keyEvent->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
|
||||||
|
if (ctrlOrShift && keyEvent->text().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString eow("~!@#$%^&*()+{}|:\"<>?,/;'[]\\-="); // end of word
|
||||||
|
|
||||||
|
if (!isCompleterShortcut && (!keyEvent->text().isEmpty() && eow.contains(keyEvent->text().right(1)))) {
|
||||||
|
_completer->popup()->hide();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto textCursor = _ui->promptTextEdit->textCursor();
|
||||||
|
|
||||||
|
textCursor.select(QTextCursor::WordUnderCursor);
|
||||||
|
|
||||||
|
QString completionPrefix = textCursor.selectedText();
|
||||||
|
|
||||||
|
auto leftOfCursor = _ui->promptTextEdit->toPlainText().left(textCursor.position());
|
||||||
|
|
||||||
|
// RegEx [3] [4]
|
||||||
|
// (Module.subModule).(property/subModule)
|
||||||
|
|
||||||
|
const int MODULE_INDEX = 3;
|
||||||
|
const int PROPERTY_INDEX = 4;
|
||||||
|
// TODO: disallow invalid characters on left of property
|
||||||
|
QRegExp regExp("((([A-Za-z0-9_\\.]+)\\.)|(?!\\.))([a-zA-Z0-9_]*)$");
|
||||||
|
regExp.indexIn(leftOfCursor);
|
||||||
|
auto rexExpCapturedTexts = regExp.capturedTexts();
|
||||||
|
auto memberOf = rexExpCapturedTexts[MODULE_INDEX];
|
||||||
|
completionPrefix = rexExpCapturedTexts[PROPERTY_INDEX];
|
||||||
|
bool switchedModule = false;
|
||||||
|
if (memberOf != _completerModule) {
|
||||||
|
_completerModule = memberOf;
|
||||||
|
auto autoCompleteModel = getAutoCompleteModel(memberOf);
|
||||||
|
if (autoCompleteModel == nullptr) {
|
||||||
|
_completer->popup()->hide();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_completer->setModel(autoCompleteModel);
|
||||||
|
_completer->popup()->installEventFilter(this);
|
||||||
|
switchedModule = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switchedModule || completionPrefix != _completer->completionPrefix()) {
|
||||||
|
_completer->setCompletionPrefix(completionPrefix);
|
||||||
|
_completer->popup()->setCurrentIndex(_completer->completionModel()->index(0, 0));
|
||||||
|
}
|
||||||
|
auto cursorRect = _ui->promptTextEdit->cursorRect();
|
||||||
|
cursorRect.setWidth(_completer->popup()->sizeHintForColumn(0) +
|
||||||
|
_completer->popup()->verticalScrollBar()->sizeHint().width());
|
||||||
|
_completer->complete(cursorRect);
|
||||||
|
highlightedCompletion(_completer->popup()->currentIndex());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -321,7 +609,7 @@ void JSConsole::appendMessage(const QString& gutter, const QString& message) {
|
||||||
|
|
||||||
void JSConsole::clear() {
|
void JSConsole::clear() {
|
||||||
QLayoutItem* item;
|
QLayoutItem* item;
|
||||||
while ((item = _ui->logArea->layout()->takeAt(0)) != NULL) {
|
while ((item = _ui->logArea->layout()->takeAt(0)) != nullptr) {
|
||||||
delete item->widget();
|
delete item->widget();
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,11 @@
|
||||||
#ifndef hifi_JSConsole_h
|
#ifndef hifi_JSConsole_h
|
||||||
#define hifi_JSConsole_h
|
#define hifi_JSConsole_h
|
||||||
|
|
||||||
#include <QDialog>
|
|
||||||
#include <QEvent>
|
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QWidget>
|
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
#include <QCompleter>
|
||||||
|
#include <QtCore/QJsonArray>
|
||||||
|
|
||||||
#include "ui_console.h"
|
#include "ui_console.h"
|
||||||
#include "ScriptEngine.h"
|
#include "ScriptEngine.h"
|
||||||
|
@ -54,12 +53,20 @@ protected slots:
|
||||||
void handleError(const QString& message, const QString& scriptName);
|
void handleError(const QString& message, const QString& scriptName);
|
||||||
void commandFinished();
|
void commandFinished();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void insertCompletion(const QModelIndex& completion);
|
||||||
|
void highlightedCompletion(const QModelIndex& completion);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void appendMessage(const QString& gutter, const QString& message);
|
void appendMessage(const QString& gutter, const QString& message);
|
||||||
void setToNextCommandInHistory();
|
void setToNextCommandInHistory();
|
||||||
void setToPreviousCommandInHistory();
|
void setToPreviousCommandInHistory();
|
||||||
void resetCurrentCommandHistory();
|
void resetCurrentCommandHistory();
|
||||||
|
|
||||||
|
void readAPI();
|
||||||
|
|
||||||
|
QStandardItemModel* getAutoCompleteModel(const QString& memberOf = nullptr);
|
||||||
|
|
||||||
QFutureWatcher<QScriptValue> _executeWatcher;
|
QFutureWatcher<QScriptValue> _executeWatcher;
|
||||||
Ui::Console* _ui;
|
Ui::Console* _ui;
|
||||||
int _currentCommandInHistory;
|
int _currentCommandInHistory;
|
||||||
|
@ -68,6 +75,9 @@ private:
|
||||||
QString _rootCommand;
|
QString _rootCommand;
|
||||||
ScriptEnginePointer _scriptEngine;
|
ScriptEnginePointer _scriptEngine;
|
||||||
static const QString _consoleFileName;
|
static const QString _consoleFileName;
|
||||||
|
QJsonArray _apiDocs;
|
||||||
|
QCompleter* _completer;
|
||||||
|
QString _completerModule {""};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ const QString FATAL_TEXT = "[FATAL]";
|
||||||
const QString SUPPRESS_TEXT = "[SUPPRESS]";
|
const QString SUPPRESS_TEXT = "[SUPPRESS]";
|
||||||
const QString UNKNOWN_TEXT = "[UNKNOWN]";
|
const QString UNKNOWN_TEXT = "[UNKNOWN]";
|
||||||
|
|
||||||
LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLogDialog(parent) {
|
LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLogDialog(parent), _windowGeometry("logDialogGeometry", QRect()) {
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
setWindowTitle("Log");
|
setWindowTitle("Log");
|
||||||
|
|
||||||
|
@ -155,6 +155,11 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog
|
||||||
_clearFilterButton->show();
|
_clearFilterButton->show();
|
||||||
connect(_clearFilterButton, &QPushButton::clicked, this, &LogDialog::handleClearFilterButton);
|
connect(_clearFilterButton, &QPushButton::clicked, this, &LogDialog::handleClearFilterButton);
|
||||||
handleClearFilterButton();
|
handleClearFilterButton();
|
||||||
|
|
||||||
|
auto windowGeometry = _windowGeometry.get();
|
||||||
|
if (windowGeometry.isValid()) {
|
||||||
|
setGeometry(windowGeometry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogDialog::resizeEvent(QResizeEvent* event) {
|
void LogDialog::resizeEvent(QResizeEvent* event) {
|
||||||
|
@ -173,6 +178,11 @@ void LogDialog::resizeEvent(QResizeEvent* event) {
|
||||||
ELEMENT_HEIGHT);
|
ELEMENT_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LogDialog::closeEvent(QCloseEvent* event) {
|
||||||
|
BaseLogDialog::closeEvent(event);
|
||||||
|
_windowGeometry.set(geometry());
|
||||||
|
}
|
||||||
|
|
||||||
void LogDialog::handleRevealButton() {
|
void LogDialog::handleRevealButton() {
|
||||||
_logger->locateLog();
|
_logger->locateLog();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define hifi_LogDialog_h
|
#define hifi_LogDialog_h
|
||||||
|
|
||||||
#include "BaseLogDialog.h"
|
#include "BaseLogDialog.h"
|
||||||
|
#include <SettingHandle.h>
|
||||||
|
|
||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
@ -44,6 +45,8 @@ private slots:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
|
void closeEvent(QCloseEvent* event) override;
|
||||||
|
|
||||||
QString getCurrentLog() override;
|
QString getCurrentLog() override;
|
||||||
void printLogFile();
|
void printLogFile();
|
||||||
|
|
||||||
|
@ -62,6 +65,7 @@ private:
|
||||||
QString _filterSelection;
|
QString _filterSelection;
|
||||||
|
|
||||||
AbstractLoggerInterface* _logger;
|
AbstractLoggerInterface* _logger;
|
||||||
|
Setting::Handle<QRect> _windowGeometry;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_LogDialog_h
|
#endif // hifi_LogDialog_h
|
||||||
|
|
|
@ -266,6 +266,93 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContextOverlayInterface::requestOwnershipVerification(const QUuid& entityID) {
|
||||||
|
|
||||||
|
setLastInspectedEntity(entityID);
|
||||||
|
|
||||||
|
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags);
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
if (entityProperties.getClientOnly()) {
|
||||||
|
if (entityProperties.verifyStaticCertificateProperties()) {
|
||||||
|
SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer);
|
||||||
|
|
||||||
|
if (entityServer) {
|
||||||
|
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||||
|
QNetworkRequest networkRequest;
|
||||||
|
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
|
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||||
|
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
|
||||||
|
QJsonObject request;
|
||||||
|
request["certificate_id"] = entityProperties.getCertificateID();
|
||||||
|
networkRequest.setUrl(requestURL);
|
||||||
|
|
||||||
|
QNetworkReply* networkReply = NULL;
|
||||||
|
networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
|
||||||
|
|
||||||
|
connect(networkReply, &QNetworkReply::finished, [=]() {
|
||||||
|
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
|
||||||
|
jsonObject = jsonObject["data"].toObject();
|
||||||
|
|
||||||
|
if (networkReply->error() == QNetworkReply::NoError) {
|
||||||
|
if (!jsonObject["invalid_reason"].toString().isEmpty()) {
|
||||||
|
qCDebug(entities) << "invalid_reason not empty";
|
||||||
|
} else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") {
|
||||||
|
qCDebug(entities) << "'transfer_status' is 'failed'";
|
||||||
|
} else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") {
|
||||||
|
qCDebug(entities) << "'transfer_status' is 'pending'";
|
||||||
|
} else {
|
||||||
|
QString ownerKey = jsonObject["transfer_recipient_key"].toString();
|
||||||
|
|
||||||
|
QByteArray certID = entityProperties.getCertificateID().toUtf8();
|
||||||
|
QByteArray text = DependencyManager::get<EntityTreeRenderer>()->getTree()->computeNonce(certID, ownerKey);
|
||||||
|
QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
|
||||||
|
|
||||||
|
int certIDByteArraySize = certID.length();
|
||||||
|
int textByteArraySize = text.length();
|
||||||
|
int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
|
||||||
|
|
||||||
|
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
|
||||||
|
certIDByteArraySize + textByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
|
||||||
|
true);
|
||||||
|
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
|
||||||
|
challengeOwnershipPacket->writePrimitive(textByteArraySize);
|
||||||
|
challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
|
||||||
|
challengeOwnershipPacket->write(certID);
|
||||||
|
challengeOwnershipPacket->write(text);
|
||||||
|
challengeOwnershipPacket->write(nodeToChallengeByteArray);
|
||||||
|
nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
|
||||||
|
|
||||||
|
// Kickoff a 10-second timeout timer that marks the cert if we don't get an ownership response in time
|
||||||
|
if (thread() != QThread::currentThread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
startChallengeOwnershipTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() <<
|
||||||
|
"More info:" << networkReply->readAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
networkReply->deleteLater();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
qCWarning(context_overlay) << "Couldn't get Entity Server!";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto ledger = DependencyManager::get<Ledger>();
|
||||||
|
_challengeOwnershipTimeoutTimer.stop();
|
||||||
|
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED));
|
||||||
|
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
|
||||||
|
qCDebug(context_overlay) << "Entity" << _lastInspectedEntity << "failed static certificate verification!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
|
static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
|
||||||
void ContextOverlayInterface::openInspectionCertificate() {
|
void ContextOverlayInterface::openInspectionCertificate() {
|
||||||
// lets open the tablet to the inspection certificate QML
|
// lets open the tablet to the inspection certificate QML
|
||||||
|
@ -275,87 +362,7 @@ void ContextOverlayInterface::openInspectionCertificate() {
|
||||||
_hmdScriptingInterface->openTablet();
|
_hmdScriptingInterface->openTablet();
|
||||||
|
|
||||||
setLastInspectedEntity(_currentEntityWithContextOverlay);
|
setLastInspectedEntity(_currentEntityWithContextOverlay);
|
||||||
|
requestOwnershipVerification(_lastInspectedEntity);
|
||||||
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags);
|
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
|
||||||
|
|
||||||
if (entityProperties.getClientOnly()) {
|
|
||||||
if (entityProperties.verifyStaticCertificateProperties()) {
|
|
||||||
SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer);
|
|
||||||
|
|
||||||
if (entityServer) {
|
|
||||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
|
||||||
QNetworkRequest networkRequest;
|
|
||||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
|
||||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
|
||||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
|
||||||
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
|
|
||||||
QJsonObject request;
|
|
||||||
request["certificate_id"] = entityProperties.getCertificateID();
|
|
||||||
networkRequest.setUrl(requestURL);
|
|
||||||
|
|
||||||
QNetworkReply* networkReply = NULL;
|
|
||||||
networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
|
|
||||||
|
|
||||||
connect(networkReply, &QNetworkReply::finished, [=]() {
|
|
||||||
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
|
|
||||||
jsonObject = jsonObject["data"].toObject();
|
|
||||||
|
|
||||||
if (networkReply->error() == QNetworkReply::NoError) {
|
|
||||||
if (!jsonObject["invalid_reason"].toString().isEmpty()) {
|
|
||||||
qCDebug(entities) << "invalid_reason not empty";
|
|
||||||
} else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") {
|
|
||||||
qCDebug(entities) << "'transfer_status' is 'failed'";
|
|
||||||
} else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") {
|
|
||||||
qCDebug(entities) << "'transfer_status' is 'pending'";
|
|
||||||
} else {
|
|
||||||
QString ownerKey = jsonObject["transfer_recipient_key"].toString();
|
|
||||||
|
|
||||||
QByteArray certID = entityProperties.getCertificateID().toUtf8();
|
|
||||||
QByteArray text = DependencyManager::get<EntityTreeRenderer>()->getTree()->computeNonce(certID, ownerKey);
|
|
||||||
QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
|
|
||||||
|
|
||||||
int certIDByteArraySize = certID.length();
|
|
||||||
int textByteArraySize = text.length();
|
|
||||||
int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
|
|
||||||
|
|
||||||
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
|
|
||||||
certIDByteArraySize + textByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
|
|
||||||
true);
|
|
||||||
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
|
|
||||||
challengeOwnershipPacket->writePrimitive(textByteArraySize);
|
|
||||||
challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
|
|
||||||
challengeOwnershipPacket->write(certID);
|
|
||||||
challengeOwnershipPacket->write(text);
|
|
||||||
challengeOwnershipPacket->write(nodeToChallengeByteArray);
|
|
||||||
nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
|
|
||||||
|
|
||||||
// Kickoff a 10-second timeout timer that marks the cert if we don't get an ownership response in time
|
|
||||||
if (thread() != QThread::currentThread()) {
|
|
||||||
QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer");
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
startChallengeOwnershipTimer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() <<
|
|
||||||
"More info:" << networkReply->readAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
networkReply->deleteLater();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
qCWarning(context_overlay) << "Couldn't get Entity Server!";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto ledger = DependencyManager::get<Ledger>();
|
|
||||||
_challengeOwnershipTimeoutTimer.stop();
|
|
||||||
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED));
|
|
||||||
qCDebug(context_overlay) << "Entity" << _lastInspectedEntity << "failed static certificate verification!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,6 +404,7 @@ void ContextOverlayInterface::startChallengeOwnershipTimer() {
|
||||||
connect(&_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() {
|
connect(&_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() {
|
||||||
qCDebug(entities) << "Ownership challenge timed out for" << _lastInspectedEntity;
|
qCDebug(entities) << "Ownership challenge timed out for" << _lastInspectedEntity;
|
||||||
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_TIMEOUT));
|
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_TIMEOUT));
|
||||||
|
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
|
||||||
});
|
});
|
||||||
|
|
||||||
_challengeOwnershipTimeoutTimer.start(5000);
|
_challengeOwnershipTimeoutTimer.start(5000);
|
||||||
|
@ -421,7 +429,9 @@ void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer
|
||||||
|
|
||||||
if (verificationSuccess) {
|
if (verificationSuccess) {
|
||||||
emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS));
|
emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS));
|
||||||
|
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationSuccess(_lastInspectedEntity);
|
||||||
} else {
|
} else {
|
||||||
emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED));
|
emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED));
|
||||||
|
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "ui/overlays/Overlays.h"
|
#include "ui/overlays/Overlays.h"
|
||||||
#include "scripting/HMDScriptingInterface.h"
|
#include "scripting/HMDScriptingInterface.h"
|
||||||
#include "scripting/SelectionScriptingInterface.h"
|
#include "scripting/SelectionScriptingInterface.h"
|
||||||
|
#include "scripting/WalletScriptingInterface.h"
|
||||||
|
|
||||||
#include "EntityTree.h"
|
#include "EntityTree.h"
|
||||||
#include "ContextOverlayLogging.h"
|
#include "ContextOverlayLogging.h"
|
||||||
|
@ -33,12 +34,13 @@
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @namespace ContextOverlay
|
* @namespace ContextOverlay
|
||||||
*/
|
*/
|
||||||
class ContextOverlayInterface : public QObject, public Dependency {
|
class ContextOverlayInterface : public QObject, public Dependency {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(QUuid entityWithContextOverlay READ getCurrentEntityWithContextOverlay WRITE setCurrentEntityWithContextOverlay)
|
Q_PROPERTY(QUuid entityWithContextOverlay READ getCurrentEntityWithContextOverlay WRITE setCurrentEntityWithContextOverlay)
|
||||||
Q_PROPERTY(bool enabled READ getEnabled WRITE setEnabled)
|
Q_PROPERTY(bool enabled READ getEnabled WRITE setEnabled)
|
||||||
Q_PROPERTY(bool isInMarketplaceInspectionMode READ getIsInMarketplaceInspectionMode WRITE setIsInMarketplaceInspectionMode)
|
Q_PROPERTY(bool isInMarketplaceInspectionMode READ getIsInMarketplaceInspectionMode WRITE setIsInMarketplaceInspectionMode)
|
||||||
|
|
||||||
QSharedPointer<EntityScriptingInterface> _entityScriptingInterface;
|
QSharedPointer<EntityScriptingInterface> _entityScriptingInterface;
|
||||||
EntityPropertyFlags _entityPropertyFlags;
|
EntityPropertyFlags _entityPropertyFlags;
|
||||||
QSharedPointer<HMDScriptingInterface> _hmdScriptingInterface;
|
QSharedPointer<HMDScriptingInterface> _hmdScriptingInterface;
|
||||||
|
@ -47,9 +49,7 @@ class ContextOverlayInterface : public QObject, public Dependency {
|
||||||
OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID };
|
OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID };
|
||||||
std::shared_ptr<Image3DOverlay> _contextOverlay { nullptr };
|
std::shared_ptr<Image3DOverlay> _contextOverlay { nullptr };
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ContextOverlayInterface();
|
ContextOverlayInterface();
|
||||||
|
|
||||||
Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; }
|
Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; }
|
||||||
void setCurrentEntityWithContextOverlay(const QUuid& entityID) { _currentEntityWithContextOverlay = entityID; }
|
void setCurrentEntityWithContextOverlay(const QUuid& entityID) { _currentEntityWithContextOverlay = entityID; }
|
||||||
void setLastInspectedEntity(const QUuid& entityID) { _challengeOwnershipTimeoutTimer.stop(); _lastInspectedEntity = entityID; }
|
void setLastInspectedEntity(const QUuid& entityID) { _challengeOwnershipTimeoutTimer.stop(); _lastInspectedEntity = entityID; }
|
||||||
|
@ -57,6 +57,8 @@ public:
|
||||||
bool getEnabled() { return _enabled; }
|
bool getEnabled() { return _enabled; }
|
||||||
bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; }
|
bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; }
|
||||||
void setIsInMarketplaceInspectionMode(bool mode) { _isInMarketplaceInspectionMode = mode; }
|
void setIsInMarketplaceInspectionMode(bool mode) { _isInMarketplaceInspectionMode = mode; }
|
||||||
|
void requestOwnershipVerification(const QUuid& entityID);
|
||||||
|
EntityPropertyFlags getEntityPropertyFlags() { return _entityPropertyFlags; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void contextOverlayClicked(const QUuid& currentEntityWithContextOverlay);
|
void contextOverlayClicked(const QUuid& currentEntityWithContextOverlay);
|
||||||
|
@ -80,8 +82,7 @@ private:
|
||||||
enum {
|
enum {
|
||||||
MAX_SELECTION_COUNT = 16
|
MAX_SELECTION_COUNT = 16
|
||||||
};
|
};
|
||||||
|
bool _verboseLogging{ true };
|
||||||
bool _verboseLogging { true };
|
|
||||||
bool _enabled { true };
|
bool _enabled { true };
|
||||||
EntityItemID _currentEntityWithContextOverlay{};
|
EntityItemID _currentEntityWithContextOverlay{};
|
||||||
EntityItemID _lastInspectedEntity{};
|
EntityItemID _lastInspectedEntity{};
|
||||||
|
|
|
@ -72,6 +72,15 @@ Web3DOverlay::Web3DOverlay() {
|
||||||
connect(this, &Web3DOverlay::requestWebSurface, this, &Web3DOverlay::buildWebSurface);
|
connect(this, &Web3DOverlay::requestWebSurface, this, &Web3DOverlay::buildWebSurface);
|
||||||
connect(this, &Web3DOverlay::releaseWebSurface, this, &Web3DOverlay::destroyWebSurface);
|
connect(this, &Web3DOverlay::releaseWebSurface, this, &Web3DOverlay::destroyWebSurface);
|
||||||
connect(this, &Web3DOverlay::resizeWebSurface, this, &Web3DOverlay::onResizeWebSurface);
|
connect(this, &Web3DOverlay::resizeWebSurface, this, &Web3DOverlay::onResizeWebSurface);
|
||||||
|
|
||||||
|
//need to be intialized before Tablet 1st open
|
||||||
|
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(_url);
|
||||||
|
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||||
|
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||||
|
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||||
|
_webSurface->getSurfaceContext()->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance());
|
||||||
|
_webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) :
|
Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) :
|
||||||
|
@ -192,11 +201,6 @@ void Web3DOverlay::setupQmlSurface() {
|
||||||
|
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags);
|
_webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags);
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
_webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||||
|
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance());
|
|
||||||
|
|
||||||
// in Qt 5.10.0 there is already an "Audio" object in the QML context
|
// in Qt 5.10.0 there is already an "Audio" object in the QML context
|
||||||
// though I failed to find it (from QtMultimedia??). So.. let it be "AudioScriptingInterface"
|
// though I failed to find it (from QtMultimedia??). So.. let it be "AudioScriptingInterface"
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("AudioScriptingInterface", DependencyManager::get<AudioScriptingInterface>().data());
|
_webSurface->getSurfaceContext()->setContextProperty("AudioScriptingInterface", DependencyManager::get<AudioScriptingInterface>().data());
|
||||||
|
|
|
@ -880,25 +880,6 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
|
||||||
return _relativePoses;
|
return _relativePoses;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimPose AnimInverseKinematics::applyHipsOffset() const {
|
|
||||||
glm::vec3 hipsOffset = _hipsOffset;
|
|
||||||
AnimPose relHipsPose = _relativePoses[_hipsIndex];
|
|
||||||
float offsetLength = glm::length(hipsOffset);
|
|
||||||
const float MIN_HIPS_OFFSET_LENGTH = 0.03f;
|
|
||||||
if (offsetLength > MIN_HIPS_OFFSET_LENGTH) {
|
|
||||||
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
|
|
||||||
glm::vec3 scaledHipsOffset = scaleFactor * hipsOffset;
|
|
||||||
if (_hipsParentIndex == -1) {
|
|
||||||
relHipsPose.trans() = _relativePoses[_hipsIndex].trans() + scaledHipsOffset;
|
|
||||||
} else {
|
|
||||||
AnimPose absHipsPose = _skeleton->getAbsolutePose(_hipsIndex, _relativePoses);
|
|
||||||
absHipsPose.trans() += scaledHipsOffset;
|
|
||||||
relHipsPose = _skeleton->getAbsolutePose(_hipsParentIndex, _relativePoses).inverse() * absHipsPose;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return relHipsPose;
|
|
||||||
}
|
|
||||||
|
|
||||||
//virtual
|
//virtual
|
||||||
const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) {
|
const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) {
|
||||||
// allows solutionSource to be overridden by an animVar
|
// allows solutionSource to be overridden by an animVar
|
||||||
|
@ -996,27 +977,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
|
|
||||||
_relativePoses[_hipsIndex] = parentAbsPose.inverse() * absPose;
|
_relativePoses[_hipsIndex] = parentAbsPose.inverse() * absPose;
|
||||||
_relativePoses[_hipsIndex].scale() = glm::vec3(1.0f);
|
_relativePoses[_hipsIndex].scale() = glm::vec3(1.0f);
|
||||||
_hipsOffset = Vectors::ZERO;
|
|
||||||
|
|
||||||
} else if (_hipsIndex >= 0) {
|
|
||||||
|
|
||||||
// if there is no hips target, shift hips according to the _hipsOffset from the previous frame
|
|
||||||
AnimPose relHipsPose = applyHipsOffset();
|
|
||||||
|
|
||||||
// determine if we should begin interpolating the hips.
|
|
||||||
for (size_t i = 0; i < targets.size(); i++) {
|
|
||||||
if (_prevJointChainInfoVec[i].target.getIndex() == _hipsIndex) {
|
|
||||||
if (_prevJointChainInfoVec[i].timer > 0.0f) {
|
|
||||||
// smoothly lerp in hipsOffset
|
|
||||||
float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[i].timer) / JOINT_CHAIN_INTERP_TIME;
|
|
||||||
AnimPose prevRelHipsPose(_prevJointChainInfoVec[i].jointInfoVec[0].rot, _prevJointChainInfoVec[i].jointInfoVec[0].trans);
|
|
||||||
::blend(1, &prevRelHipsPose, &relHipsPose, alpha, &relHipsPose);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_relativePoses[_hipsIndex] = relHipsPose;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is an active jointChainInfo for the hips store the post shifted hips into it.
|
// if there is an active jointChainInfo for the hips store the post shifted hips into it.
|
||||||
|
@ -1084,11 +1044,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
|
|
||||||
solve(context, targets, dt, jointChainInfoVec);
|
solve(context, targets, dt, jointChainInfoVec);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_hipsTargetIndex < 0) {
|
|
||||||
PROFILE_RANGE_EX(simulation_animation, "ik/measureHipsOffset", 0xffff00ff, 0);
|
|
||||||
_hipsOffset = computeHipsOffset(targets, underPoses, dt, _hipsOffset);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.getEnableDebugDrawIKConstraints()) {
|
if (context.getEnableDebugDrawIKConstraints()) {
|
||||||
|
@ -1099,69 +1054,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
return _relativePoses;
|
return _relativePoses;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 AnimInverseKinematics::computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt, glm::vec3 prevHipsOffset) const {
|
|
||||||
|
|
||||||
// measure new _hipsOffset for next frame
|
|
||||||
// by looking for discrepancies between where a targeted endEffector is
|
|
||||||
// and where it wants to be (after IK solutions are done)
|
|
||||||
glm::vec3 hipsOffset = prevHipsOffset;
|
|
||||||
glm::vec3 newHipsOffset = Vectors::ZERO;
|
|
||||||
for (auto& target: targets) {
|
|
||||||
int targetIndex = target.getIndex();
|
|
||||||
if (targetIndex == _headIndex && _headIndex != -1) {
|
|
||||||
// special handling for headTarget
|
|
||||||
if (target.getType() == IKTarget::Type::RotationOnly) {
|
|
||||||
// we want to shift the hips to bring the underPose closer
|
|
||||||
// to where the head happens to be (overpose)
|
|
||||||
glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans();
|
|
||||||
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans();
|
|
||||||
const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f;
|
|
||||||
newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under);
|
|
||||||
} else if (target.getType() == IKTarget::Type::HmdHead) {
|
|
||||||
// we want to shift the hips to bring the head to its designated position
|
|
||||||
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans();
|
|
||||||
hipsOffset += target.getTranslation() - actual;
|
|
||||||
// and ignore all other targets
|
|
||||||
newHipsOffset = hipsOffset;
|
|
||||||
break;
|
|
||||||
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
|
||||||
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans();
|
|
||||||
glm::vec3 targetPosition = target.getTranslation();
|
|
||||||
newHipsOffset += targetPosition - actualPosition;
|
|
||||||
|
|
||||||
// Add downward pressure on the hips
|
|
||||||
const float PRESSURE_SCALE_FACTOR = 0.95f;
|
|
||||||
const float PRESSURE_TRANSLATION_OFFSET = 1.0f;
|
|
||||||
newHipsOffset *= PRESSURE_SCALE_FACTOR;
|
|
||||||
newHipsOffset -= PRESSURE_TRANSLATION_OFFSET;
|
|
||||||
}
|
|
||||||
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
|
||||||
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans();
|
|
||||||
glm::vec3 targetPosition = target.getTranslation();
|
|
||||||
newHipsOffset += targetPosition - actualPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// smooth transitions by relaxing hipsOffset toward the new value
|
|
||||||
const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f;
|
|
||||||
float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f;
|
|
||||||
hipsOffset += (newHipsOffset - hipsOffset) * tau;
|
|
||||||
|
|
||||||
// clamp the hips offset
|
|
||||||
float hipsOffsetLength = glm::length(hipsOffset);
|
|
||||||
if (hipsOffsetLength > _maxHipsOffsetLength) {
|
|
||||||
hipsOffset *= _maxHipsOffsetLength / hipsOffsetLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hipsOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimInverseKinematics::setMaxHipsOffsetLength(float maxLength) {
|
|
||||||
// manually adjust scale here
|
|
||||||
const float METERS_TO_CENTIMETERS = 100.0f;
|
|
||||||
_maxHipsOffsetLength = METERS_TO_CENTIMETERS * maxLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimInverseKinematics::clearIKJointLimitHistory() {
|
void AnimInverseKinematics::clearIKJointLimitHistory() {
|
||||||
for (auto& pair : _constraints) {
|
for (auto& pair : _constraints) {
|
||||||
pair.second->clearHistory();
|
pair.second->clearHistory();
|
||||||
|
|
|
@ -57,8 +57,6 @@ public:
|
||||||
|
|
||||||
void clearIKJointLimitHistory();
|
void clearIKJointLimitHistory();
|
||||||
|
|
||||||
void setMaxHipsOffsetLength(float maxLength);
|
|
||||||
|
|
||||||
float getMaxErrorOnLastSolve() { return _maxErrorOnLastSolve; }
|
float getMaxErrorOnLastSolve() { return _maxErrorOnLastSolve; }
|
||||||
|
|
||||||
enum class SolutionSource {
|
enum class SolutionSource {
|
||||||
|
@ -92,7 +90,6 @@ protected:
|
||||||
void blendToPoses(const AnimPoseVec& targetPoses, const AnimPoseVec& underPose, float blendFactor);
|
void blendToPoses(const AnimPoseVec& targetPoses, const AnimPoseVec& underPose, float blendFactor);
|
||||||
void preconditionRelativePosesToAvoidLimbLock(const AnimContext& context, const std::vector<IKTarget>& targets);
|
void preconditionRelativePosesToAvoidLimbLock(const AnimContext& context, const std::vector<IKTarget>& targets);
|
||||||
void setSecondaryTargets(const AnimContext& context);
|
void setSecondaryTargets(const AnimContext& context);
|
||||||
AnimPose applyHipsOffset() const;
|
|
||||||
|
|
||||||
// used to pre-compute information about each joint influeced by a spline IK target.
|
// used to pre-compute information about each joint influeced by a spline IK target.
|
||||||
struct SplineJointInfo {
|
struct SplineJointInfo {
|
||||||
|
@ -111,7 +108,6 @@ protected:
|
||||||
void clearConstraints();
|
void clearConstraints();
|
||||||
void initConstraints();
|
void initConstraints();
|
||||||
void initLimitCenterPoses();
|
void initLimitCenterPoses();
|
||||||
glm::vec3 computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt, glm::vec3 prevHipsOffset) const;
|
|
||||||
|
|
||||||
// no copies
|
// no copies
|
||||||
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
|
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
|
||||||
|
@ -150,9 +146,6 @@ protected:
|
||||||
|
|
||||||
mutable std::map<int, std::vector<SplineJointInfo>> _splineJointInfoMap;
|
mutable std::map<int, std::vector<SplineJointInfo>> _splineJointInfoMap;
|
||||||
|
|
||||||
// experimental data for moving hips during IK
|
|
||||||
glm::vec3 _hipsOffset { Vectors::ZERO };
|
|
||||||
float _maxHipsOffsetLength{ FLT_MAX };
|
|
||||||
int _headIndex { -1 };
|
int _headIndex { -1 };
|
||||||
int _hipsIndex { -1 };
|
int _hipsIndex { -1 };
|
||||||
int _hipsParentIndex { -1 };
|
int _hipsParentIndex { -1 };
|
||||||
|
|
|
@ -192,7 +192,11 @@ void AnimSkeleton::buildSkeletonFromJoints(const std::vector<FBXJoint>& joints)
|
||||||
_nonMirroredIndices.clear();
|
_nonMirroredIndices.clear();
|
||||||
_mirrorMap.reserve(_jointsSize);
|
_mirrorMap.reserve(_jointsSize);
|
||||||
for (int i = 0; i < _jointsSize; i++) {
|
for (int i = 0; i < _jointsSize; i++) {
|
||||||
if (_joints[i].name.endsWith("tEye")) {
|
if (_joints[i].name != "Hips" && _joints[i].name != "Spine" &&
|
||||||
|
_joints[i].name != "Spine1" && _joints[i].name != "Spine2" &&
|
||||||
|
_joints[i].name != "Neck" && _joints[i].name != "Head" &&
|
||||||
|
!((_joints[i].name.startsWith("Left") || _joints[i].name.startsWith("Right")) &&
|
||||||
|
_joints[i].name != "LeftEye" && _joints[i].name != "RightEye")) {
|
||||||
// HACK: we don't want to mirror some joints so we remember their indices
|
// HACK: we don't want to mirror some joints so we remember their indices
|
||||||
// so we can restore them after a future mirror operation
|
// so we can restore them after a future mirror operation
|
||||||
_nonMirroredIndices.push_back(i);
|
_nonMirroredIndices.push_back(i);
|
||||||
|
|
|
@ -372,18 +372,6 @@ void Rig::clearIKJointLimitHistory() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rig::setMaxHipsOffsetLength(float maxLength) {
|
|
||||||
_maxHipsOffsetLength = maxLength;
|
|
||||||
auto ikNode = getAnimInverseKinematicsNode();
|
|
||||||
if (ikNode) {
|
|
||||||
ikNode->setMaxHipsOffsetLength(_maxHipsOffsetLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float Rig::getMaxHipsOffsetLength() const {
|
|
||||||
return _maxHipsOffsetLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Rig::getIKErrorOnLastSolve() const {
|
float Rig::getIKErrorOnLastSolve() const {
|
||||||
float result = 0.0f;
|
float result = 0.0f;
|
||||||
|
|
||||||
|
|
|
@ -346,7 +346,6 @@ protected:
|
||||||
bool _enabledAnimations { true };
|
bool _enabledAnimations { true };
|
||||||
|
|
||||||
mutable uint32_t _jointNameWarningCount { 0 };
|
mutable uint32_t _jointNameWarningCount { 0 };
|
||||||
float _maxHipsOffsetLength { 1.0f };
|
|
||||||
|
|
||||||
bool _enableDebugDrawIKTargets { false };
|
bool _enableDebugDrawIKTargets { false };
|
||||||
bool _enableDebugDrawIKConstraints { false };
|
bool _enableDebugDrawIKConstraints { false };
|
||||||
|
|
|
@ -51,9 +51,9 @@ void EntityScriptServerLogClient::enableToEntityServerScriptLog(bool enable) {
|
||||||
|
|
||||||
if (_subscribed != enable) {
|
if (_subscribed != enable) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
emit receivedNewLogLines("====================== Subscribded to the Entity Script Server's log ======================");
|
emit receivedNewLogLines("====================== Subscribed to the Entity Script Server's log ======================");
|
||||||
} else {
|
} else {
|
||||||
emit receivedNewLogLines("==================== Unsubscribded from the Entity Script Server's log ====================");
|
emit receivedNewLogLines("==================== Unsubscribed from the Entity Script Server's log ====================");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_subscribed = enable;
|
_subscribed = enable;
|
||||||
|
|
|
@ -139,7 +139,7 @@ public slots:
|
||||||
Q_INVOKABLE bool canRezTmpCertified();
|
Q_INVOKABLE bool canRezTmpCertified();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function Entities.canWriteAsseets
|
* @function Entities.canWriteAssets
|
||||||
* @return {bool} `true` if the DomainServer will allow this Node/Avatar to write to the asset server
|
* @return {bool} `true` if the DomainServer will allow this Node/Avatar to write to the asset server
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE bool canWriteAssets();
|
Q_INVOKABLE bool canWriteAssets();
|
||||||
|
|
|
@ -1679,14 +1679,17 @@ void EntityTree::entityChanged(EntityItemPointer entity) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EntityTree::fixupNeedsParentFixups() {
|
void EntityTree::fixupNeedsParentFixups() {
|
||||||
PROFILE_RANGE(simulation_physics, "FixupParents");
|
PROFILE_RANGE(simulation_physics, "FixupParents");
|
||||||
MovingEntitiesOperator moveOperator;
|
MovingEntitiesOperator moveOperator;
|
||||||
|
QVector<EntityItemWeakPointer> entitiesToFixup;
|
||||||
|
{
|
||||||
|
QWriteLocker locker(&_needsParentFixupLock);
|
||||||
|
entitiesToFixup = _needsParentFixup;
|
||||||
|
_needsParentFixup.clear();
|
||||||
|
}
|
||||||
|
|
||||||
QWriteLocker locker(&_needsParentFixupLock);
|
QMutableVectorIterator<EntityItemWeakPointer> iter(entitiesToFixup);
|
||||||
|
|
||||||
QMutableVectorIterator<EntityItemWeakPointer> iter(_needsParentFixup);
|
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
EntityItemWeakPointer entityWP = iter.next();
|
EntityItemWeakPointer entityWP = iter.next();
|
||||||
EntityItemPointer entity = entityWP.lock();
|
EntityItemPointer entity = entityWP.lock();
|
||||||
|
@ -1749,6 +1752,12 @@ void EntityTree::fixupNeedsParentFixups() {
|
||||||
PerformanceTimer perfTimer("recurseTreeWithOperator");
|
PerformanceTimer perfTimer("recurseTreeWithOperator");
|
||||||
recurseTreeWithOperator(&moveOperator);
|
recurseTreeWithOperator(&moveOperator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QWriteLocker locker(&_needsParentFixupLock);
|
||||||
|
// add back the entities that did not get fixup
|
||||||
|
_needsParentFixup.append(entitiesToFixup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTree::deleteDescendantsOfAvatar(QUuid avatarID) {
|
void EntityTree::deleteDescendantsOfAvatar(QUuid avatarID) {
|
||||||
|
|
|
@ -272,6 +272,11 @@ glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParen
|
||||||
const FBXModel& model = models.value(nodeID);
|
const FBXModel& model = models.value(nodeID);
|
||||||
globalTransform = glm::translate(model.translation) * model.preTransform * glm::mat4_cast(model.preRotation *
|
globalTransform = glm::translate(model.translation) * model.preTransform * glm::mat4_cast(model.preRotation *
|
||||||
model.rotation * model.postRotation) * model.postTransform * globalTransform;
|
model.rotation * model.postRotation) * model.postTransform * globalTransform;
|
||||||
|
if (model.hasGeometricOffset) {
|
||||||
|
glm::mat4 geometricOffset = createMatFromScaleQuatAndPos(model.geometricScaling, model.geometricRotation, model.geometricTranslation);
|
||||||
|
globalTransform = globalTransform * geometricOffset;
|
||||||
|
}
|
||||||
|
|
||||||
if (mixamoHack) {
|
if (mixamoHack) {
|
||||||
// there's something weird about the models from Mixamo Fuse; they don't skin right with the full transform
|
// there's something weird about the models from Mixamo Fuse; they don't skin right with the full transform
|
||||||
return globalTransform;
|
return globalTransform;
|
||||||
|
@ -323,12 +328,12 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
void appendModelIDs(const QString& parentID, const QMultiMap<QString, QString>& connectionChildMap,
|
void appendModelIDs(const QString& parentID, const QMultiMap<QString, QString>& connectionChildMap,
|
||||||
QHash<QString, FBXModel>& models, QSet<QString>& remainingModels, QVector<QString>& modelIDs) {
|
QHash<QString, FBXModel>& models, QSet<QString>& remainingModels, QVector<QString>& modelIDs, bool isRootNode = false) {
|
||||||
if (remainingModels.contains(parentID)) {
|
if (remainingModels.contains(parentID)) {
|
||||||
modelIDs.append(parentID);
|
modelIDs.append(parentID);
|
||||||
remainingModels.remove(parentID);
|
remainingModels.remove(parentID);
|
||||||
}
|
}
|
||||||
int parentIndex = modelIDs.size() - 1;
|
int parentIndex = isRootNode ? -1 : modelIDs.size() - 1;
|
||||||
foreach (const QString& childID, connectionChildMap.values(parentID)) {
|
foreach (const QString& childID, connectionChildMap.values(parentID)) {
|
||||||
if (remainingModels.contains(childID)) {
|
if (remainingModels.contains(childID)) {
|
||||||
FBXModel& model = models[childID];
|
FBXModel& model = models[childID];
|
||||||
|
@ -1450,18 +1455,22 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
QSet<QString> remainingModels;
|
QSet<QString> remainingModels;
|
||||||
for (QHash<QString, FBXModel>::const_iterator model = models.constBegin(); model != models.constEnd(); model++) {
|
for (QHash<QString, FBXModel>::const_iterator model = models.constBegin(); model != models.constEnd(); model++) {
|
||||||
// models with clusters must be parented to the cluster top
|
// models with clusters must be parented to the cluster top
|
||||||
foreach (const QString& deformerID, _connectionChildMap.values(model.key())) {
|
// Unless the model is a root node.
|
||||||
foreach (const QString& clusterID, _connectionChildMap.values(deformerID)) {
|
bool isARootNode = !modelIDs.contains(_connectionParentMap.value(model.key()));
|
||||||
if (!clusters.contains(clusterID)) {
|
if (!isARootNode) {
|
||||||
continue;
|
foreach(const QString& deformerID, _connectionChildMap.values(model.key())) {
|
||||||
|
foreach(const QString& clusterID, _connectionChildMap.values(deformerID)) {
|
||||||
|
if (!clusters.contains(clusterID)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url);
|
||||||
|
_connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key());
|
||||||
|
_connectionParentMap.insert(model.key(), topID);
|
||||||
|
goto outerBreak;
|
||||||
}
|
}
|
||||||
QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url);
|
|
||||||
_connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key());
|
|
||||||
_connectionParentMap.insert(model.key(), topID);
|
|
||||||
goto outerBreak;
|
|
||||||
}
|
}
|
||||||
|
outerBreak: ;
|
||||||
}
|
}
|
||||||
outerBreak:
|
|
||||||
|
|
||||||
// make sure the parent is in the child map
|
// make sure the parent is in the child map
|
||||||
QString parent = _connectionParentMap.value(model.key());
|
QString parent = _connectionParentMap.value(model.key());
|
||||||
|
@ -1472,13 +1481,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
}
|
}
|
||||||
while (!remainingModels.isEmpty()) {
|
while (!remainingModels.isEmpty()) {
|
||||||
QString first = *remainingModels.constBegin();
|
QString first = *remainingModels.constBegin();
|
||||||
foreach (const QString& id, remainingModels) {
|
|
||||||
if (id < first) {
|
|
||||||
first = id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QString topID = getTopModelID(_connectionParentMap, models, first, url);
|
QString topID = getTopModelID(_connectionParentMap, models, first, url);
|
||||||
appendModelIDs(_connectionParentMap.value(topID), _connectionChildMap, models, remainingModels, modelIDs);
|
appendModelIDs(_connectionParentMap.value(topID), _connectionChildMap, models, remainingModels, modelIDs, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// figure the number of animation frames from the curves
|
// figure the number of animation frames from the curves
|
||||||
|
@ -1533,7 +1537,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
joint.transform = geometry.offset * glm::translate(joint.translation) * joint.preTransform *
|
joint.transform = geometry.offset * glm::translate(joint.translation) * joint.preTransform *
|
||||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
||||||
joint.inverseDefaultRotation = glm::inverse(combinedRotation);
|
joint.inverseDefaultRotation = glm::inverse(combinedRotation);
|
||||||
joint.distanceToParent = 0.0f;
|
joint.distanceToParent = 0.0f;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex);
|
const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex);
|
||||||
|
|
|
@ -23,25 +23,31 @@
|
||||||
#include <shared/GlobalAppProperties.h>
|
#include <shared/GlobalAppProperties.h>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include "GLLogging.h"
|
#include "GLLogging.h"
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
|
|
||||||
#if defined(DEBUG) || defined(USE_GLES)
|
|
||||||
static bool enableDebugLogger = true;
|
|
||||||
#else
|
|
||||||
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENGL");
|
|
||||||
static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "GLHelpers.h"
|
#include "GLHelpers.h"
|
||||||
|
|
||||||
using namespace gl;
|
using namespace gl;
|
||||||
|
|
||||||
|
|
||||||
|
bool Context::enableDebugLogger() {
|
||||||
|
#if defined(DEBUG) || defined(USE_GLES)
|
||||||
|
static bool enableDebugLogger = true;
|
||||||
|
#else
|
||||||
|
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENGL");
|
||||||
|
static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||||
|
#endif
|
||||||
|
static std::once_flag once;
|
||||||
|
std::call_once(once, [&] {
|
||||||
|
// If the previous run crashed, force GL debug logging on
|
||||||
|
if (qApp->property(hifi::properties::CRASHED).toBool()) {
|
||||||
|
enableDebugLogger = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return enableDebugLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::atomic<size_t> Context::_totalSwapchainMemoryUsage { 0 };
|
std::atomic<size_t> Context::_totalSwapchainMemoryUsage { 0 };
|
||||||
|
|
||||||
size_t Context::getSwapchainMemoryUsage() { return _totalSwapchainMemoryUsage.load(); }
|
size_t Context::getSwapchainMemoryUsage() { return _totalSwapchainMemoryUsage.load(); }
|
||||||
|
@ -245,10 +251,6 @@ void Context::create() {
|
||||||
// Create a temporary context to initialize glew
|
// Create a temporary context to initialize glew
|
||||||
static std::once_flag once;
|
static std::once_flag once;
|
||||||
std::call_once(once, [&] {
|
std::call_once(once, [&] {
|
||||||
// If the previous run crashed, force GL debug logging on
|
|
||||||
if (qApp->property(hifi::properties::CRASHED).toBool()) {
|
|
||||||
enableDebugLogger = true;
|
|
||||||
}
|
|
||||||
auto hdc = GetDC(hwnd);
|
auto hdc = GetDC(hwnd);
|
||||||
setupPixelFormatSimple(hdc);
|
setupPixelFormatSimple(hdc);
|
||||||
auto glrc = wglCreateContext(hdc);
|
auto glrc = wglCreateContext(hdc);
|
||||||
|
@ -328,7 +330,7 @@ void Context::create() {
|
||||||
contextAttribs.push_back(WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
|
contextAttribs.push_back(WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
|
||||||
#endif
|
#endif
|
||||||
contextAttribs.push_back(WGL_CONTEXT_FLAGS_ARB);
|
contextAttribs.push_back(WGL_CONTEXT_FLAGS_ARB);
|
||||||
if (enableDebugLogger) {
|
if (enableDebugLogger()) {
|
||||||
contextAttribs.push_back(WGL_CONTEXT_DEBUG_BIT_ARB);
|
contextAttribs.push_back(WGL_CONTEXT_DEBUG_BIT_ARB);
|
||||||
} else {
|
} else {
|
||||||
contextAttribs.push_back(0);
|
contextAttribs.push_back(0);
|
||||||
|
@ -350,7 +352,7 @@ void Context::create() {
|
||||||
if (!makeCurrent()) {
|
if (!makeCurrent()) {
|
||||||
throw std::runtime_error("Could not make context current");
|
throw std::runtime_error("Could not make context current");
|
||||||
}
|
}
|
||||||
if (enableDebugLogger) {
|
if (enableDebugLogger()) {
|
||||||
glDebugMessageCallback(debugMessageCallback, NULL);
|
glDebugMessageCallback(debugMessageCallback, NULL);
|
||||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ namespace gl {
|
||||||
Context(const Context& other);
|
Context(const Context& other);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static bool enableDebugLogger();
|
||||||
Context();
|
Context();
|
||||||
Context(QWindow* window);
|
Context(QWindow* window);
|
||||||
void release();
|
void release();
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtGui/QOffscreenSurface>
|
#include <QtGui/QOffscreenSurface>
|
||||||
#include <QtGui/QOpenGLContext>
|
#include <QtGui/QOpenGLContext>
|
||||||
|
#include <QtGui/QOpenGLDebugLogger>
|
||||||
|
|
||||||
#include "Context.h"
|
#include "Context.h"
|
||||||
#include "GLHelpers.h"
|
#include "GLHelpers.h"
|
||||||
|
@ -68,9 +69,32 @@ bool OffscreenGLCanvas::create(QOpenGLContext* sharedContext) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (gl::Context::enableDebugLogger()) {
|
||||||
|
_context->makeCurrent(_offscreenSurface);
|
||||||
|
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
|
||||||
|
connect(logger, &QOpenGLDebugLogger::messageLogged, this, &OffscreenGLCanvas::onMessageLogged);
|
||||||
|
logger->initialize();
|
||||||
|
logger->enableMessages();
|
||||||
|
logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
|
||||||
|
_context->doneCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OffscreenGLCanvas::onMessageLogged(const QOpenGLDebugMessage& debugMessage) {
|
||||||
|
auto severity = debugMessage.severity();
|
||||||
|
switch (severity) {
|
||||||
|
case QOpenGLDebugMessage::NotificationSeverity:
|
||||||
|
case QOpenGLDebugMessage::LowSeverity:
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
qDebug(glLogging) << debugMessage;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool OffscreenGLCanvas::makeCurrent() {
|
bool OffscreenGLCanvas::makeCurrent() {
|
||||||
bool result = _context->makeCurrent(_offscreenSurface);
|
bool result = _context->makeCurrent(_offscreenSurface);
|
||||||
std::call_once(_reportOnce, []{
|
std::call_once(_reportOnce, []{
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
class QOpenGLContext;
|
class QOpenGLContext;
|
||||||
class QOffscreenSurface;
|
class QOffscreenSurface;
|
||||||
class QOpenGLDebugLogger;
|
class QOpenGLDebugMessage;
|
||||||
|
|
||||||
class OffscreenGLCanvas : public QObject {
|
class OffscreenGLCanvas : public QObject {
|
||||||
public:
|
public:
|
||||||
|
@ -32,6 +32,9 @@ public:
|
||||||
}
|
}
|
||||||
QObject* getContextObject();
|
QObject* getContextObject();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onMessageLogged(const QOpenGLDebugMessage &debugMessage);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::once_flag _reportOnce;
|
std::once_flag _reportOnce;
|
||||||
QOpenGLContext* _context{ nullptr };
|
QOpenGLContext* _context{ nullptr };
|
||||||
|
|
|
@ -776,7 +776,7 @@ void AddressManager::copyPath() {
|
||||||
QApplication::clipboard()->setText(currentPath());
|
QApplication::clipboard()->setText(currentPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AddressManager::getDomainId() const {
|
QString AddressManager::getDomainID() const {
|
||||||
return DependencyManager::get<NodeList>()->getDomainHandler().getUUID().toString();
|
return DependencyManager::get<NodeList>()->getDomainHandler().getUUID().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,11 @@ const QString GET_PLACE = "/api/v1/places/%1";
|
||||||
* The location API provides facilities related to your current location in the metaverse.
|
* The location API provides facilities related to your current location in the metaverse.
|
||||||
*
|
*
|
||||||
* @namespace location
|
* @namespace location
|
||||||
* @property {Uuid} domainId - A UUID uniquely identifying the domain you're visiting. Is {@link Uuid|Uuid.NULL} if you're not
|
* @property {Uuid} domainID - A UUID uniquely identifying the domain you're visiting. Is {@link Uuid|Uuid.NULL} if you're not
|
||||||
* connected to the domain.
|
* connected to the domain.
|
||||||
* <em>Read-only.</em>
|
* <em>Read-only.</em>
|
||||||
|
* @property {Uuid} domainId - Synonym for <code>domainId</code>. <em>Read-only.</em> <strong>Deprecated:</strong> This property
|
||||||
|
* is deprecated and will soon be removed.
|
||||||
* @property {string} hostname - The name of the domain for your current metaverse address (e.g., <code>"AvatarIsland"</code>,
|
* @property {string} hostname - The name of the domain for your current metaverse address (e.g., <code>"AvatarIsland"</code>,
|
||||||
* <code>localhost</code>, or an IP address).
|
* <code>localhost</code>, or an IP address).
|
||||||
* <em>Read-only.</em>
|
* <em>Read-only.</em>
|
||||||
|
@ -66,7 +68,8 @@ class AddressManager : public QObject, public Dependency {
|
||||||
Q_PROPERTY(QString hostname READ getHost)
|
Q_PROPERTY(QString hostname READ getHost)
|
||||||
Q_PROPERTY(QString pathname READ currentPath)
|
Q_PROPERTY(QString pathname READ currentPath)
|
||||||
Q_PROPERTY(QString placename READ getPlaceName)
|
Q_PROPERTY(QString placename READ getPlaceName)
|
||||||
Q_PROPERTY(QString domainId READ getDomainId)
|
Q_PROPERTY(QString domainID READ getDomainID)
|
||||||
|
Q_PROPERTY(QString domainId READ getDomainID)
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
@ -164,7 +167,7 @@ public:
|
||||||
|
|
||||||
const QUuid& getRootPlaceID() const { return _rootPlaceID; }
|
const QUuid& getRootPlaceID() const { return _rootPlaceID; }
|
||||||
const QString& getPlaceName() const { return _shareablePlaceName.isEmpty() ? _placeName : _shareablePlaceName; }
|
const QString& getPlaceName() const { return _shareablePlaceName.isEmpty() ? _placeName : _shareablePlaceName; }
|
||||||
QString getDomainId() const;
|
QString getDomainID() const;
|
||||||
|
|
||||||
const QString& getHost() const { return _host; }
|
const QString& getHost() const { return _host; }
|
||||||
|
|
||||||
|
|
|
@ -340,14 +340,6 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (QThread::currentThread() != thread()) {
|
|
||||||
qCDebug(networking) << "Fetching asynchronously:" << url;
|
|
||||||
QMetaObject::invokeMethod(this, "getResource",
|
|
||||||
Q_ARG(QUrl, url), Q_ARG(QUrl, fallback));
|
|
||||||
// Cannot use extra parameter as it might be freed before the invocation
|
|
||||||
return QSharedPointer<Resource>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) {
|
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) {
|
||||||
return getResource(fallback, QUrl());
|
return getResource(fallback, QUrl());
|
||||||
}
|
}
|
||||||
|
@ -358,6 +350,7 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
||||||
extra);
|
extra);
|
||||||
resource->setSelf(resource);
|
resource->setSelf(resource);
|
||||||
resource->setCache(this);
|
resource->setCache(this);
|
||||||
|
resource->moveToThread(qApp->thread());
|
||||||
connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize);
|
connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize);
|
||||||
{
|
{
|
||||||
QWriteLocker locker(&_resourcesLock);
|
QWriteLocker locker(&_resourcesLock);
|
||||||
|
|
|
@ -248,7 +248,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
||||||
IsReplicatedInAvatarIdentity,
|
IsReplicatedInAvatarIdentity,
|
||||||
AvatarIdentityLookAtSnapping,
|
AvatarIdentityLookAtSnapping,
|
||||||
UpdatedMannequinDefaultAvatar,
|
UpdatedMannequinDefaultAvatar,
|
||||||
AvatarJointDefaultPoseFlags
|
AvatarJointDefaultPoseFlags,
|
||||||
|
FBXReaderNodeReparenting
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DomainConnectRequestVersion : PacketVersion {
|
enum class DomainConnectRequestVersion : PacketVersion {
|
||||||
|
|
|
@ -115,6 +115,7 @@ void CauterizedModel::updateClusterMatrices() {
|
||||||
Transform clusterTransform;
|
Transform clusterTransform;
|
||||||
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
|
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
|
||||||
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform);
|
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform);
|
||||||
|
state.clusterTransforms[j].setCauterizationParameters(0.0f, jointPose.trans());
|
||||||
#else
|
#else
|
||||||
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
|
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
|
||||||
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
|
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
|
||||||
|
@ -151,6 +152,7 @@ void CauterizedModel::updateClusterMatrices() {
|
||||||
Transform clusterTransform;
|
Transform clusterTransform;
|
||||||
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
|
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
|
||||||
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform);
|
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform);
|
||||||
|
state.clusterTransforms[j].setCauterizationParameters(1.0f, cauterizePose.trans());
|
||||||
#else
|
#else
|
||||||
glm_mat4u_mul(cauterizeMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
|
glm_mat4u_mul(cauterizeMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
|
||||||
#endif
|
#endif
|
||||||
|
@ -236,9 +238,9 @@ void CauterizedModel::updateRenderItems() {
|
||||||
renderTransform = modelTransform;
|
renderTransform = modelTransform;
|
||||||
if (clusterTransformsCauterized.size() == 1) {
|
if (clusterTransformsCauterized.size() == 1) {
|
||||||
#if defined(SKIN_DQ)
|
#if defined(SKIN_DQ)
|
||||||
Transform transform(clusterTransforms[0].getRotation(),
|
Transform transform(clusterTransformsCauterized[0].getRotation(),
|
||||||
clusterTransforms[0].getScale(),
|
clusterTransformsCauterized[0].getScale(),
|
||||||
clusterTransforms[0].getTranslation());
|
clusterTransformsCauterized[0].getTranslation());
|
||||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||||
#else
|
#else
|
||||||
renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0]));
|
renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0]));
|
||||||
|
|
|
@ -99,8 +99,9 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie
|
||||||
|
|
||||||
// Diffuse from ambient
|
// Diffuse from ambient
|
||||||
diffuse = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), lowNormalCurvature.xyz).xyz;
|
diffuse = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), lowNormalCurvature.xyz).xyz;
|
||||||
diffuse /= 3.1415926;
|
|
||||||
specular = vec3(0.0);
|
// Scattering ambient specular is the same as non scattering for now
|
||||||
|
// TODO: we should use the same specular answer as for direct lighting
|
||||||
}
|
}
|
||||||
<@endif@>
|
<@endif@>
|
||||||
|
|
||||||
|
|
|
@ -263,26 +263,34 @@ public:
|
||||||
_scale.x = p.scale().x;
|
_scale.x = p.scale().x;
|
||||||
_scale.y = p.scale().y;
|
_scale.y = p.scale().y;
|
||||||
_scale.z = p.scale().z;
|
_scale.z = p.scale().z;
|
||||||
|
_scale.w = 0.0f;
|
||||||
_dq = DualQuaternion(p.rot(), p.trans());
|
_dq = DualQuaternion(p.rot(), p.trans());
|
||||||
}
|
}
|
||||||
TransformDualQuaternion(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) {
|
TransformDualQuaternion(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) {
|
||||||
_scale.x = scale.x;
|
_scale.x = scale.x;
|
||||||
_scale.y = scale.y;
|
_scale.y = scale.y;
|
||||||
_scale.z = scale.z;
|
_scale.z = scale.z;
|
||||||
|
_scale.w = 0.0f;
|
||||||
_dq = DualQuaternion(rot, trans);
|
_dq = DualQuaternion(rot, trans);
|
||||||
}
|
}
|
||||||
TransformDualQuaternion(const Transform& transform) {
|
TransformDualQuaternion(const Transform& transform) {
|
||||||
_scale = glm::vec4(transform.getScale(), 0.0f);
|
_scale = glm::vec4(transform.getScale(), 0.0f);
|
||||||
|
_scale.w = 0.0f;
|
||||||
_dq = DualQuaternion(transform.getRotation(), transform.getTranslation());
|
_dq = DualQuaternion(transform.getRotation(), transform.getTranslation());
|
||||||
}
|
}
|
||||||
glm::vec3 getScale() const { return glm::vec3(_scale); }
|
glm::vec3 getScale() const { return glm::vec3(_scale); }
|
||||||
glm::quat getRotation() const { return _dq.getRotation(); }
|
glm::quat getRotation() const { return _dq.getRotation(); }
|
||||||
glm::vec3 getTranslation() const { return _dq.getTranslation(); }
|
glm::vec3 getTranslation() const { return _dq.getTranslation(); }
|
||||||
glm::mat4 getMatrix() const { return createMatFromScaleQuatAndPos(getScale(), getRotation(), getTranslation()); };
|
glm::mat4 getMatrix() const { return createMatFromScaleQuatAndPos(getScale(), getRotation(), getTranslation()); };
|
||||||
|
|
||||||
|
void setCauterizationParameters(float cauterizationAmount, const glm::vec3& cauterizedPosition) {
|
||||||
|
_scale.w = cauterizationAmount;
|
||||||
|
_cauterizedPosition = glm::vec4(cauterizedPosition, 1.0f);
|
||||||
|
}
|
||||||
protected:
|
protected:
|
||||||
glm::vec4 _scale { 1.0f, 1.0f, 1.0f, 0.0f };
|
glm::vec4 _scale { 1.0f, 1.0f, 1.0f, 0.0f };
|
||||||
DualQuaternion _dq;
|
DualQuaternion _dq;
|
||||||
glm::vec4 _padding;
|
glm::vec4 _cauterizedPosition { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -58,17 +58,19 @@ mat4 dualQuatToMat4(vec4 real, vec4 dual) {
|
||||||
void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
|
void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
|
||||||
|
|
||||||
// linearly blend scale and dual quaternion components
|
// linearly blend scale and dual quaternion components
|
||||||
vec3 sAccum = vec3(0.0, 0.0, 0.0);
|
vec4 sAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
vec4 cAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
|
vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
|
||||||
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
|
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
|
||||||
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
|
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
|
||||||
float clusterWeight = skinClusterWeight[i];
|
float clusterWeight = skinClusterWeight[i];
|
||||||
|
|
||||||
vec3 scale = vec3(clusterMatrix[0]);
|
vec4 scale = clusterMatrix[0];
|
||||||
vec4 real = clusterMatrix[1];
|
vec4 real = clusterMatrix[1];
|
||||||
vec4 dual = clusterMatrix[2];
|
vec4 dual = clusterMatrix[2];
|
||||||
|
vec4 cauterizedPos = clusterMatrix[3];
|
||||||
|
|
||||||
// to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
|
// to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
|
||||||
float dqClusterWeight = clusterWeight;
|
float dqClusterWeight = clusterWeight;
|
||||||
|
@ -79,6 +81,7 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio
|
||||||
sAccum += scale * clusterWeight;
|
sAccum += scale * clusterWeight;
|
||||||
rAccum += real * dqClusterWeight;
|
rAccum += real * dqClusterWeight;
|
||||||
dAccum += dual * dqClusterWeight;
|
dAccum += dual * dqClusterWeight;
|
||||||
|
cAccum += cauterizedPos * clusterWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize dual quaternion
|
// normalize dual quaternion
|
||||||
|
@ -88,25 +91,37 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio
|
||||||
|
|
||||||
// conversion from dual quaternion to 4x4 matrix.
|
// conversion from dual quaternion to 4x4 matrix.
|
||||||
mat4 m = dualQuatToMat4(rAccum, dAccum);
|
mat4 m = dualQuatToMat4(rAccum, dAccum);
|
||||||
skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
|
|
||||||
|
// sAccum.w indicates the amount of cauterization for this vertex.
|
||||||
|
// 0 indicates no cauterization and 1 indicates full cauterization.
|
||||||
|
// TODO: make this cauterization smoother or implement full dual-quaternion scale support.
|
||||||
|
const float CAUTERIZATION_THRESHOLD = 0.1;
|
||||||
|
if (sAccum.w > CAUTERIZATION_THRESHOLD) {
|
||||||
|
skinnedPosition = cAccum;
|
||||||
|
} else {
|
||||||
|
sAccum.w = 1.0;
|
||||||
|
skinnedPosition = m * (sAccum * inPosition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal,
|
void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal,
|
||||||
out vec4 skinnedPosition, out vec3 skinnedNormal) {
|
out vec4 skinnedPosition, out vec3 skinnedNormal) {
|
||||||
|
|
||||||
// linearly blend scale and dual quaternion components
|
// linearly blend scale and dual quaternion components
|
||||||
vec3 sAccum = vec3(0.0, 0.0, 0.0);
|
vec4 sAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
vec4 cAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
|
vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
|
||||||
|
|
||||||
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
|
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
|
||||||
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
|
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
|
||||||
float clusterWeight = skinClusterWeight[i];
|
float clusterWeight = skinClusterWeight[i];
|
||||||
|
|
||||||
vec3 scale = vec3(clusterMatrix[0]);
|
vec4 scale = clusterMatrix[0];
|
||||||
vec4 real = clusterMatrix[1];
|
vec4 real = clusterMatrix[1];
|
||||||
vec4 dual = clusterMatrix[2];
|
vec4 dual = clusterMatrix[2];
|
||||||
|
vec4 cauterizedPos = clusterMatrix[3];
|
||||||
|
|
||||||
// to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
|
// to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
|
||||||
float dqClusterWeight = clusterWeight;
|
float dqClusterWeight = clusterWeight;
|
||||||
|
@ -117,6 +132,7 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP
|
||||||
sAccum += scale * clusterWeight;
|
sAccum += scale * clusterWeight;
|
||||||
rAccum += real * dqClusterWeight;
|
rAccum += real * dqClusterWeight;
|
||||||
dAccum += dual * dqClusterWeight;
|
dAccum += dual * dqClusterWeight;
|
||||||
|
cAccum += cauterizedPos * clusterWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize dual quaternion
|
// normalize dual quaternion
|
||||||
|
@ -126,7 +142,18 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP
|
||||||
|
|
||||||
// conversion from dual quaternion to 4x4 matrix.
|
// conversion from dual quaternion to 4x4 matrix.
|
||||||
mat4 m = dualQuatToMat4(rAccum, dAccum);
|
mat4 m = dualQuatToMat4(rAccum, dAccum);
|
||||||
skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
|
|
||||||
|
// sAccum.w indicates the amount of cauterization for this vertex.
|
||||||
|
// 0 indicates no cauterization and 1 indicates full cauterization.
|
||||||
|
// TODO: make this cauterization smoother or implement full dual-quaternion scale support.
|
||||||
|
const float CAUTERIZATION_THRESHOLD = 0.1;
|
||||||
|
if (sAccum.w > CAUTERIZATION_THRESHOLD) {
|
||||||
|
skinnedPosition = cAccum;
|
||||||
|
} else {
|
||||||
|
sAccum.w = 1.0;
|
||||||
|
skinnedPosition = m * (sAccum * inPosition);
|
||||||
|
}
|
||||||
|
|
||||||
skinnedNormal = vec3(m * vec4(inNormal, 0));
|
skinnedNormal = vec3(m * vec4(inNormal, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,18 +161,20 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
|
||||||
out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) {
|
out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) {
|
||||||
|
|
||||||
// linearly blend scale and dual quaternion components
|
// linearly blend scale and dual quaternion components
|
||||||
vec3 sAccum = vec3(0.0, 0.0, 0.0);
|
vec4 sAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
vec4 cAccum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
|
vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
|
||||||
|
|
||||||
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
|
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
|
||||||
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
|
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
|
||||||
float clusterWeight = skinClusterWeight[i];
|
float clusterWeight = skinClusterWeight[i];
|
||||||
|
|
||||||
vec3 scale = vec3(clusterMatrix[0]);
|
vec4 scale = clusterMatrix[0];
|
||||||
vec4 real = clusterMatrix[1];
|
vec4 real = clusterMatrix[1];
|
||||||
vec4 dual = clusterMatrix[2];
|
vec4 dual = clusterMatrix[2];
|
||||||
|
vec4 cauterizedPos = clusterMatrix[3];
|
||||||
|
|
||||||
// to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
|
// to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
|
||||||
float dqClusterWeight = clusterWeight;
|
float dqClusterWeight = clusterWeight;
|
||||||
|
@ -156,6 +185,7 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
|
||||||
sAccum += scale * clusterWeight;
|
sAccum += scale * clusterWeight;
|
||||||
rAccum += real * dqClusterWeight;
|
rAccum += real * dqClusterWeight;
|
||||||
dAccum += dual * dqClusterWeight;
|
dAccum += dual * dqClusterWeight;
|
||||||
|
cAccum += cauterizedPos * clusterWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize dual quaternion
|
// normalize dual quaternion
|
||||||
|
@ -165,7 +195,18 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
|
||||||
|
|
||||||
// conversion from dual quaternion to 4x4 matrix.
|
// conversion from dual quaternion to 4x4 matrix.
|
||||||
mat4 m = dualQuatToMat4(rAccum, dAccum);
|
mat4 m = dualQuatToMat4(rAccum, dAccum);
|
||||||
skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
|
|
||||||
|
// sAccum.w indicates the amount of cauterization for this vertex.
|
||||||
|
// 0 indicates no cauterization and 1 indicates full cauterization.
|
||||||
|
// TODO: make this cauterization smoother or implement full dual-quaternion scale support.
|
||||||
|
const float CAUTERIZATION_THRESHOLD = 0.1;
|
||||||
|
if (sAccum.w > CAUTERIZATION_THRESHOLD) {
|
||||||
|
skinnedPosition = cAccum;
|
||||||
|
} else {
|
||||||
|
sAccum.w = 1.0;
|
||||||
|
skinnedPosition = m * (sAccum * inPosition);
|
||||||
|
}
|
||||||
|
|
||||||
skinnedNormal = vec3(m * vec4(inNormal, 0));
|
skinnedNormal = vec3(m * vec4(inNormal, 0));
|
||||||
skinnedTangent = vec3(m * vec4(inTangent, 0));
|
skinnedTangent = vec3(m * vec4(inTangent, 0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,36 +70,40 @@ void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program
|
||||||
|
|
||||||
void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
||||||
BatchSetter batchSetter, ItemSetter itemSetter) {
|
BatchSetter batchSetter, ItemSetter itemSetter) {
|
||||||
|
|
||||||
ShapeKey key{ filter._flags };
|
ShapeKey key{ filter._flags };
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
// don't call makeProgram on shaders that are already made.
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
|
if (program->getUniformBuffers().empty()) {
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::BUFFER::SKINNING));
|
gpu::Shader::BindingSet slotBindings;
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::BUFFER::MATERIAL));
|
slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("texMapArrayBuffer"), Slot::BUFFER::TEXMAPARRAY));
|
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::BUFFER::SKINNING));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("albedoMap"), Slot::MAP::ALBEDO));
|
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::BUFFER::MATERIAL));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("roughnessMap"), Slot::MAP::ROUGHNESS));
|
slotBindings.insert(gpu::Shader::Binding(std::string("texMapArrayBuffer"), Slot::BUFFER::TEXMAPARRAY));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::MAP::NORMAL));
|
slotBindings.insert(gpu::Shader::Binding(std::string("albedoMap"), Slot::MAP::ALBEDO));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("metallicMap"), Slot::MAP::METALLIC));
|
slotBindings.insert(gpu::Shader::Binding(std::string("roughnessMap"), Slot::MAP::ROUGHNESS));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::MAP::EMISSIVE_LIGHTMAP));
|
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::MAP::NORMAL));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), Slot::MAP::OCCLUSION));
|
slotBindings.insert(gpu::Shader::Binding(std::string("metallicMap"), Slot::MAP::METALLIC));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringMap"), Slot::MAP::SCATTERING));
|
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::MAP::EMISSIVE_LIGHTMAP));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), Slot::BUFFER::KEY_LIGHT));
|
slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), Slot::MAP::OCCLUSION));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::BUFFER::LIGHT));
|
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringMap"), Slot::MAP::SCATTERING));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER));
|
slotBindings.insert(gpu::Shader::Binding(std::string("keyLightBuffer"), Slot::BUFFER::KEY_LIGHT));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
|
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::BUFFER::LIGHT));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK));
|
slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
|
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), Slot::BUFFER::HAZE_MODEL));
|
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), Slot::BUFFER::HAZE_MODEL));
|
||||||
|
|
||||||
if (key.isTranslucent()) {
|
if (key.isTranslucent()) {
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT));
|
slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT));
|
slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT));
|
slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), Slot::BUFFER::LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
|
||||||
|
|
||||||
auto locations = std::make_shared<Locations>();
|
auto locations = std::make_shared<Locations>();
|
||||||
|
|
||||||
locations->albedoTextureUnit = program->getTextures().findLocation("albedoMap");
|
locations->albedoTextureUnit = program->getTextures().findLocation("albedoMap");
|
||||||
|
|
|
@ -150,7 +150,7 @@ signals:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Notifies scripts that a user has disconnected from the domain
|
* Notifies scripts that a user has disconnected from the domain
|
||||||
* @function Users.avatar.avatarDisconnected
|
* @function Users.avatarDisconnected
|
||||||
* @param {nodeID} NodeID The session ID of the avatar that has disconnected
|
* @param {nodeID} NodeID The session ID of the avatar that has disconnected
|
||||||
*/
|
*/
|
||||||
void avatarDisconnected(const QUuid& nodeID);
|
void avatarDisconnected(const QUuid& nodeID);
|
||||||
|
|
|
@ -12,4 +12,4 @@ if (ANDROID)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_zlib()
|
target_zlib()
|
||||||
target_nsight()
|
target_nsight()
|
||||||
|
|
|
@ -37,10 +37,10 @@
|
||||||
QString TEMP_DIR_FORMAT { "%1-%2-%3" };
|
QString TEMP_DIR_FORMAT { "%1-%2-%3" };
|
||||||
|
|
||||||
#if !defined(Q_OS_ANDROID) && defined(DEV_BUILD)
|
#if !defined(Q_OS_ANDROID) && defined(DEV_BUILD)
|
||||||
#if defined(Q_OS_OSX)
|
|
||||||
static bool USE_SOURCE_TREE_RESOURCES = true;
|
|
||||||
#else
|
|
||||||
static bool USE_SOURCE_TREE_RESOURCES() {
|
static bool USE_SOURCE_TREE_RESOURCES() {
|
||||||
|
#if defined(Q_OS_OSX)
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
static bool result = false;
|
static bool result = false;
|
||||||
static std::once_flag once;
|
static std::once_flag once;
|
||||||
std::call_once(once, [&] {
|
std::call_once(once, [&] {
|
||||||
|
@ -48,8 +48,8 @@ static bool USE_SOURCE_TREE_RESOURCES() {
|
||||||
result = QProcessEnvironment::systemEnvironment().contains(USE_SOURCE_TREE_RESOURCES_FLAG);
|
result = QProcessEnvironment::systemEnvironment().contains(USE_SOURCE_TREE_RESOURCES_FLAG);
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEV_BUILD
|
#ifdef DEV_BUILD
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "SettingHelpers.h"
|
#include "SettingHelpers.h"
|
||||||
#include "SettingManager.h"
|
#include "SettingManager.h"
|
||||||
#include "SharedLogging.h"
|
#include "SharedLogging.h"
|
||||||
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
namespace Setting {
|
namespace Setting {
|
||||||
static QSharedPointer<Manager> globalManager;
|
static QSharedPointer<Manager> globalManager;
|
||||||
|
@ -32,14 +33,34 @@ namespace Setting {
|
||||||
// tell the private instance to clean itself up on its thread
|
// tell the private instance to clean itself up on its thread
|
||||||
DependencyManager::destroy<Manager>();
|
DependencyManager::destroy<Manager>();
|
||||||
|
|
||||||
//
|
|
||||||
globalManager.reset();
|
globalManager.reset();
|
||||||
|
|
||||||
// quit the settings manager thread and wait on it to make sure it's gone
|
// quit the settings manager thread and wait on it to make sure it's gone
|
||||||
settingsManagerThread->quit();
|
settingsManagerThread->quit();
|
||||||
settingsManagerThread->wait();
|
settingsManagerThread->wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setupPrivateInstance() {
|
||||||
|
// Ensure Setting::init has already ran and qApp exists
|
||||||
|
if (qApp && globalManager) {
|
||||||
|
// Let's set up the settings Private instance on its own thread
|
||||||
|
QThread* thread = new QThread();
|
||||||
|
Q_CHECK_PTR(thread);
|
||||||
|
thread->setObjectName("Settings Thread");
|
||||||
|
|
||||||
|
QObject::connect(thread, SIGNAL(started()), globalManager.data(), SLOT(startTimer()));
|
||||||
|
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
||||||
|
QObject::connect(thread, SIGNAL(finished()), globalManager.data(), SLOT(deleteLater()));
|
||||||
|
globalManager->moveToThread(thread);
|
||||||
|
thread->start();
|
||||||
|
qCDebug(shared) << "Settings thread started.";
|
||||||
|
|
||||||
|
// Register cleanupPrivateInstance to run inside QCoreApplication's destructor.
|
||||||
|
qAddPostRoutine(cleanupPrivateInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FIXED_Q_COREAPP_STARTUP_FUNCTION(setupPrivateInstance)
|
||||||
|
|
||||||
// Sets up the settings private instance. Should only be run once at startup. preInit() must be run beforehand,
|
// Sets up the settings private instance. Should only be run once at startup. preInit() must be run beforehand,
|
||||||
void init() {
|
void init() {
|
||||||
// Set settings format
|
// Set settings format
|
||||||
|
@ -59,23 +80,9 @@ namespace Setting {
|
||||||
qCDebug(shared) << (deleted ? "Deleted" : "Failed to delete") << "settings lock file" << settingsLockFilename;
|
qCDebug(shared) << (deleted ? "Deleted" : "Failed to delete") << "settings lock file" << settingsLockFilename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Let's set up the settings Private instance on its own thread
|
|
||||||
QThread* thread = new QThread();
|
|
||||||
Q_CHECK_PTR(thread);
|
|
||||||
thread->setObjectName("Settings Thread");
|
|
||||||
|
|
||||||
globalManager = DependencyManager::set<Manager>();
|
globalManager = DependencyManager::set<Manager>();
|
||||||
|
|
||||||
QObject::connect(thread, SIGNAL(started()), globalManager.data(), SLOT(startTimer()));
|
setupPrivateInstance();
|
||||||
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
|
||||||
QObject::connect(thread, SIGNAL(finished()), globalManager.data(), SLOT(deleteLater()));
|
|
||||||
globalManager->moveToThread(thread);
|
|
||||||
thread->start();
|
|
||||||
qCDebug(shared) << "Settings thread started.";
|
|
||||||
|
|
||||||
// Register cleanupPrivateInstance to run inside QCoreApplication's destructor.
|
|
||||||
qAddPostRoutine(cleanupPrivateInstance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::init() {
|
void Interface::init() {
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
@ -62,6 +63,43 @@ extern "C" FILE * __cdecl __iob_func(void) {
|
||||||
#include "OctalCode.h"
|
#include "OctalCode.h"
|
||||||
#include "SharedLogging.h"
|
#include "SharedLogging.h"
|
||||||
|
|
||||||
|
static std::unordered_map<std::string, QVariant> stagedGlobalInstances;
|
||||||
|
|
||||||
|
|
||||||
|
std::mutex& globalInstancesMutex() {
|
||||||
|
static std::mutex mutex;
|
||||||
|
return mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void commitGlobalInstances() {
|
||||||
|
std::unique_lock<std::mutex> lock(globalInstancesMutex());
|
||||||
|
for (const auto& it : stagedGlobalInstances) {
|
||||||
|
qApp->setProperty(it.first.c_str(), it.second);
|
||||||
|
}
|
||||||
|
stagedGlobalInstances.clear();
|
||||||
|
}
|
||||||
|
FIXED_Q_COREAPP_STARTUP_FUNCTION(commitGlobalInstances)
|
||||||
|
|
||||||
|
QVariant getGlobalInstance(const char* propertyName) {
|
||||||
|
if (qApp) {
|
||||||
|
return qApp->property(propertyName);
|
||||||
|
} else {
|
||||||
|
auto it = stagedGlobalInstances.find(propertyName);
|
||||||
|
if (it != stagedGlobalInstances.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGlobalInstance(const char* propertyName, const QVariant& variant) {
|
||||||
|
if (qApp) {
|
||||||
|
qApp->setProperty(propertyName, variant);
|
||||||
|
} else {
|
||||||
|
stagedGlobalInstances[propertyName] = variant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static qint64 usecTimestampNowAdjust = 0; // in usec
|
static qint64 usecTimestampNowAdjust = 0; // in usec
|
||||||
void usecTimestampNowForceClockSkew(qint64 clockSkew) {
|
void usecTimestampNowForceClockSkew(qint64 clockSkew) {
|
||||||
::usecTimestampNowAdjust = clockSkew;
|
::usecTimestampNowAdjust = clockSkew;
|
||||||
|
|
|
@ -25,6 +25,22 @@
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
|
// Workaround for https://bugreports.qt.io/browse/QTBUG-54479
|
||||||
|
// Wrap target function inside another function that holds
|
||||||
|
// a unique string identifier and uses it to ensure it only runs once
|
||||||
|
// by storing a state within the qApp
|
||||||
|
// We cannot used std::call_once with a static once_flag because
|
||||||
|
// this is used in shared libraries that are linked by several DLLs
|
||||||
|
// (ie. plugins), meaning the static will be useless in that case
|
||||||
|
#define FIXED_Q_COREAPP_STARTUP_FUNCTION(AFUNC) \
|
||||||
|
static void AFUNC ## _fixed() { \
|
||||||
|
const auto propertyName = std::string(Q_FUNC_INFO) + __FILE__; \
|
||||||
|
if (!qApp->property(propertyName.c_str()).toBool()) { \
|
||||||
|
AFUNC(); \
|
||||||
|
qApp->setProperty(propertyName.c_str(), QVariant(true)); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
Q_COREAPP_STARTUP_FUNCTION(AFUNC ## _fixed)
|
||||||
|
|
||||||
// When writing out avatarEntities to a QByteArray, if the parentID is the ID of MyAvatar, use this ID instead. This allows
|
// When writing out avatarEntities to a QByteArray, if the parentID is the ID of MyAvatar, use this ID instead. This allows
|
||||||
// the value to be reset when the sessionID changes.
|
// the value to be reset when the sessionID changes.
|
||||||
|
@ -52,6 +68,10 @@ bool destroyGlobalInstance() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::mutex& globalInstancesMutex();
|
||||||
|
QVariant getGlobalInstance(const char* propertyName);
|
||||||
|
void setGlobalInstance(const char* propertyName, const QVariant& variant);
|
||||||
|
|
||||||
// Provides efficient access to a named global type. By storing the value
|
// Provides efficient access to a named global type. By storing the value
|
||||||
// in the QApplication by name we can implement the singleton pattern and
|
// in the QApplication by name we can implement the singleton pattern and
|
||||||
// have the single instance function across DLL boundaries.
|
// have the single instance function across DLL boundaries.
|
||||||
|
@ -60,9 +80,9 @@ T* globalInstance(const char* propertyName, Args&&... args) {
|
||||||
static T* resultInstance { nullptr };
|
static T* resultInstance { nullptr };
|
||||||
static std::mutex mutex;
|
static std::mutex mutex;
|
||||||
if (!resultInstance) {
|
if (!resultInstance) {
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
std::unique_lock<std::mutex> lock(globalInstancesMutex());
|
||||||
if (!resultInstance) {
|
if (!resultInstance) {
|
||||||
auto variant = qApp->property(propertyName);
|
auto variant = getGlobalInstance(propertyName);
|
||||||
if (variant.isNull()) {
|
if (variant.isNull()) {
|
||||||
std::unique_ptr<T>& instancePtr = globalInstancePointer<T>();
|
std::unique_ptr<T>& instancePtr = globalInstancePointer<T>();
|
||||||
if (!instancePtr.get()) {
|
if (!instancePtr.get()) {
|
||||||
|
@ -72,7 +92,7 @@ T* globalInstance(const char* propertyName, Args&&... args) {
|
||||||
}
|
}
|
||||||
void* voidInstance = &(*instancePtr);
|
void* voidInstance = &(*instancePtr);
|
||||||
variant = QVariant::fromValue(voidInstance);
|
variant = QVariant::fromValue(voidInstance);
|
||||||
qApp->setProperty(propertyName, variant);
|
setGlobalInstance(propertyName, variant);
|
||||||
}
|
}
|
||||||
void* returnedVoidInstance = variant.value<void*>();
|
void* returnedVoidInstance = variant.value<void*>();
|
||||||
resultInstance = static_cast<T*>(returnedVoidInstance);
|
resultInstance = static_cast<T*>(returnedVoidInstance);
|
||||||
|
|
|
@ -227,7 +227,7 @@ bool QmlWindowClass::isVisible() {
|
||||||
glm::vec2 QmlWindowClass::getPosition() {
|
glm::vec2 QmlWindowClass::getPosition() {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
vec2 result;
|
vec2 result;
|
||||||
BLOCKING_INVOKE_METHOD(this, "getPosition", Q_RETURN_ARG(vec2, result));
|
BLOCKING_INVOKE_METHOD(this, "getPosition", Q_RETURN_ARG(glm::vec2, result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ glm::vec2 QmlWindowClass::getPosition() {
|
||||||
|
|
||||||
void QmlWindowClass::setPosition(const glm::vec2& position) {
|
void QmlWindowClass::setPosition(const glm::vec2& position) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "setPosition", Q_ARG(vec2, position));
|
QMetaObject::invokeMethod(this, "setPosition", Q_ARG(const glm::vec2&, position));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +262,7 @@ glm::vec2 toGlm(const QSizeF& size) {
|
||||||
glm::vec2 QmlWindowClass::getSize() {
|
glm::vec2 QmlWindowClass::getSize() {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
vec2 result;
|
vec2 result;
|
||||||
BLOCKING_INVOKE_METHOD(this, "getSize", Q_RETURN_ARG(vec2, result));
|
BLOCKING_INVOKE_METHOD(this, "getSize", Q_RETURN_ARG(glm::vec2, result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ glm::vec2 QmlWindowClass::getSize() {
|
||||||
|
|
||||||
void QmlWindowClass::setSize(const glm::vec2& size) {
|
void QmlWindowClass::setSize(const glm::vec2& size) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "setSize", Q_ARG(vec2, size));
|
QMetaObject::invokeMethod(this, "setSize", Q_ARG(const glm::vec2&, size));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -543,6 +543,7 @@ void OffscreenQmlSurface::cleanup() {
|
||||||
|
|
||||||
void OffscreenQmlSurface::render() {
|
void OffscreenQmlSurface::render() {
|
||||||
#if !defined(DISABLE_QML)
|
#if !defined(DISABLE_QML)
|
||||||
|
|
||||||
if (nsightActive()) {
|
if (nsightActive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -569,14 +570,18 @@ void OffscreenQmlSurface::render() {
|
||||||
|
|
||||||
{
|
{
|
||||||
// If the most recent texture was unused, we can directly recycle it
|
// If the most recent texture was unused, we can directly recycle it
|
||||||
if (_latestTextureAndFence.first) {
|
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
offscreenTextures.releaseTexture(_latestTextureAndFence);
|
|
||||||
_latestTextureAndFence = { 0, 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
_latestTextureAndFence = { texture, glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0) };
|
|
||||||
// Fence will be used in another thread / context, so a flush is required
|
// Fence will be used in another thread / context, so a flush is required
|
||||||
glFlush();
|
glFlush();
|
||||||
|
|
||||||
|
{
|
||||||
|
Lock lock(_latestTextureAndFenceMutex);
|
||||||
|
if (_latestTextureAndFence.first) {
|
||||||
|
offscreenTextures.releaseTexture(_latestTextureAndFence);
|
||||||
|
_latestTextureAndFence = { 0, 0 };
|
||||||
|
}
|
||||||
|
_latestTextureAndFence = { texture, fence};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_quickWindow->resetOpenGLState();
|
_quickWindow->resetOpenGLState();
|
||||||
|
@ -588,13 +593,21 @@ void OffscreenQmlSurface::render() {
|
||||||
bool OffscreenQmlSurface::fetchTexture(TextureAndFence& textureAndFence) {
|
bool OffscreenQmlSurface::fetchTexture(TextureAndFence& textureAndFence) {
|
||||||
textureAndFence = { 0, 0 };
|
textureAndFence = { 0, 0 };
|
||||||
|
|
||||||
|
// Lock free early check
|
||||||
if (0 == _latestTextureAndFence.first) {
|
if (0 == _latestTextureAndFence.first) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure writes to the latest texture are complete before before returning it for reading
|
// Ensure writes to the latest texture are complete before before returning it for reading
|
||||||
textureAndFence = _latestTextureAndFence;
|
{
|
||||||
_latestTextureAndFence = { 0, 0 };
|
Lock lock(_latestTextureAndFenceMutex);
|
||||||
|
// Double check inside the lock
|
||||||
|
if (0 == _latestTextureAndFence.first) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
textureAndFence = _latestTextureAndFence;
|
||||||
|
_latestTextureAndFence = { 0, 0 };
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,10 +826,13 @@ void OffscreenQmlSurface::resize(const QSize& newSize_, bool forceResize) {
|
||||||
|
|
||||||
// Release hold on the textures of the old size
|
// Release hold on the textures of the old size
|
||||||
if (uvec2() != _size) {
|
if (uvec2() != _size) {
|
||||||
// If the most recent texture was unused, we can directly recycle it
|
{
|
||||||
if (_latestTextureAndFence.first) {
|
Lock lock(_latestTextureAndFenceMutex);
|
||||||
offscreenTextures.releaseTexture(_latestTextureAndFence);
|
// If the most recent texture was unused, we can directly recycle it
|
||||||
_latestTextureAndFence = { 0, 0 };
|
if (_latestTextureAndFence.first) {
|
||||||
|
offscreenTextures.releaseTexture(_latestTextureAndFence);
|
||||||
|
_latestTextureAndFence = { 0, 0 };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
offscreenTextures.releaseSize(_size);
|
offscreenTextures.releaseSize(_size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,6 +167,9 @@ public slots:
|
||||||
bool handlePointerEvent(const PointerEvent& event, class QTouchDevice& device, bool release = false);
|
bool handlePointerEvent(const PointerEvent& event, class QTouchDevice& device, bool release = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using Mutex = std::mutex;
|
||||||
|
using Lock = std::unique_lock<std::mutex>;
|
||||||
|
|
||||||
QQuickWindow* _quickWindow { nullptr };
|
QQuickWindow* _quickWindow { nullptr };
|
||||||
QQmlContext* _qmlContext { nullptr };
|
QQmlContext* _qmlContext { nullptr };
|
||||||
QQuickItem* _rootItem { nullptr };
|
QQuickItem* _rootItem { nullptr };
|
||||||
|
@ -188,6 +191,7 @@ private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Texture management
|
// Texture management
|
||||||
|
Mutex _latestTextureAndFenceMutex;
|
||||||
TextureAndFence _latestTextureAndFence { 0, 0 };
|
TextureAndFence _latestTextureAndFence { 0, 0 };
|
||||||
|
|
||||||
bool _render { false };
|
bool _render { false };
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
/node_modules
|
|
|
@ -1 +0,0 @@
|
||||||
web: node app.js
|
|
|
@ -1,5 +0,0 @@
|
||||||
This gameserver sets up a server with websockets that listen for messages from interface regarding when users shoot rats, and updates a real-time game board with that information. This is just a first pass, and the plan is to abstract this to work with any kind of game content creators wish to make with High Fidelity.
|
|
||||||
|
|
||||||
To enter the game: Run pistol.js and shoot at rats.
|
|
||||||
For every rat you kill, you get a point.
|
|
||||||
You're score will be displayed at https://desolate-bastion-1742.herokuapp.com/
|
|
|
@ -1,76 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var express = require('express');
|
|
||||||
var http = require('http');
|
|
||||||
var _ = require('underscore');
|
|
||||||
var shortid = require('shortid');
|
|
||||||
|
|
||||||
|
|
||||||
var app = express();
|
|
||||||
var server = http.createServer(app);
|
|
||||||
|
|
||||||
var WebSocketServer = require('websocket').server;
|
|
||||||
var wsServer = new WebSocketServer({
|
|
||||||
httpServer: server
|
|
||||||
});
|
|
||||||
|
|
||||||
var users = [];
|
|
||||||
var connections = [];
|
|
||||||
wsServer.on('request', function(request) {
|
|
||||||
console.log("SOMEONE JOINED");
|
|
||||||
var connection = request.accept(null, request.origin);
|
|
||||||
connections.push(connection);
|
|
||||||
connection.on('message', function(data) {
|
|
||||||
var userData = JSON.parse(data.utf8Data);
|
|
||||||
var user = _.find(users, function(user) {
|
|
||||||
return user.username === userData.username;
|
|
||||||
});
|
|
||||||
if (user) {
|
|
||||||
// This user already exists, so just update score
|
|
||||||
users[users.indexOf(user)].score = userData.score;
|
|
||||||
} else {
|
|
||||||
users.push({
|
|
||||||
id: shortid.generate(),
|
|
||||||
username: userData.username,
|
|
||||||
score: userData.score
|
|
||||||
});
|
|
||||||
}
|
|
||||||
connections.forEach(function(aConnection) {
|
|
||||||
aConnection.sendUTF(JSON.stringify({
|
|
||||||
users: users
|
|
||||||
}));
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/users', function(req, res) {
|
|
||||||
res.send({
|
|
||||||
users: users
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Configuration */
|
|
||||||
app.set('views', __dirname + '/views');
|
|
||||||
app.use(express.static(__dirname + '/public'));
|
|
||||||
app.set('port', (process.env.PORT || 5000));
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
|
||||||
app.use(express.errorHandler({
|
|
||||||
dumpExceptions: true,
|
|
||||||
showStack: true
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Start server */
|
|
||||||
server.listen(app.get('port'), function() {
|
|
||||||
console.log('Express server listening on port %d in %s mode', app.get('port'), app.get('env'));
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = app;
|
|
|
@ -1,87 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var _ = require('underscore')
|
|
||||||
var $ = require('jquery');
|
|
||||||
|
|
||||||
var UserList = React.createClass({
|
|
||||||
render: function(){
|
|
||||||
var sortedUsers = _.sortBy(this.props.data.users, function(users){
|
|
||||||
//Show higher scorers at top of board
|
|
||||||
return 1 - users.score;
|
|
||||||
});
|
|
||||||
var users = sortedUsers.map(function(user) {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<User username = {user.username} score = {user.score} key = {user.id}></User>
|
|
||||||
)
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<div>{users}</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var GameBoard = React.createClass({
|
|
||||||
loadDataFromServer: function(data) {
|
|
||||||
$.ajax({
|
|
||||||
url: this.props.url,
|
|
||||||
dataType: 'json',
|
|
||||||
cache: false,
|
|
||||||
success: function(data) {
|
|
||||||
this.setState({data: data});
|
|
||||||
}.bind(this),
|
|
||||||
error: function(xhr, status, err) {
|
|
||||||
console.error(this.props.url, status, err.toString());
|
|
||||||
}.bind(this)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getInitialState: function() {
|
|
||||||
return {data: {users: []}};
|
|
||||||
},
|
|
||||||
componentDidMount: function() {
|
|
||||||
this.loadDataFromServer();
|
|
||||||
//set up web socket
|
|
||||||
var path = window.location.hostname + ":" + window.location.port;
|
|
||||||
console.log("LOCATION ", path)
|
|
||||||
var socketClient = new WebSocket("wss://" + path);
|
|
||||||
var self = this;
|
|
||||||
socketClient.onopen = function() {
|
|
||||||
console.log("CONNECTED");
|
|
||||||
socketClient.onmessage = function(data) {
|
|
||||||
console.log("ON MESSAGE");
|
|
||||||
self.setState({data: JSON.parse(data.data)});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
},
|
|
||||||
render: function() {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className = "gameTitle">Kill All The Rats!</div>
|
|
||||||
<div className = "boardHeader">
|
|
||||||
<div className="username">PLAYER</div>
|
|
||||||
<div className="score" > SCORE </div>
|
|
||||||
</div>
|
|
||||||
<UserList data ={this.state.data}/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var User = React.createClass({
|
|
||||||
render: function() {
|
|
||||||
return (
|
|
||||||
<div className = "entry">
|
|
||||||
<div className="username"> {this.props.username} </div>
|
|
||||||
<div className="score" > {this.props.score} </div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
React.render(
|
|
||||||
<GameBoard url = "/users" />,
|
|
||||||
document.getElementById('app')
|
|
||||||
);
|
|
|
@ -1,15 +0,0 @@
|
||||||
var gulp = require('gulp');
|
|
||||||
var exec = require('child_process').exec;
|
|
||||||
|
|
||||||
gulp.task('build', function() {
|
|
||||||
exec('npm run build', function(msg){
|
|
||||||
console.log(msg);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('watch', function() {
|
|
||||||
gulp.watch('client/*.jsx', ['build']);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
gulp.task('default', ['build', 'watch'])
|
|
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"name": "KillAllTheRats",
|
|
||||||
"version": "0.6.9",
|
|
||||||
"scripts": {
|
|
||||||
"build": "browserify ./client/app.jsx -t babelify --outfile ./public/js/app.js",
|
|
||||||
"start": "node app.js"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"express": "^4.13.1",
|
|
||||||
"gulp": "^3.9.0",
|
|
||||||
"jquery": "^2.1.4",
|
|
||||||
"react": "^0.13.3",
|
|
||||||
"shortid": "^2.2.4",
|
|
||||||
"underscore": "^1.8.3",
|
|
||||||
"websocket": "^1.0.22"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"babelify": "^6.1.3",
|
|
||||||
"browserify": "^10.2.6"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
body {
|
|
||||||
font-family: Impact;
|
|
||||||
background-color: #009DC0 ;
|
|
||||||
font-size: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gameTitle {
|
|
||||||
color: #D61010;
|
|
||||||
}
|
|
||||||
|
|
||||||
.entry{
|
|
||||||
width:100%;
|
|
||||||
height:50px;
|
|
||||||
border:1px solid #A9D1E1;
|
|
||||||
color: white;
|
|
||||||
margin-right:10px;
|
|
||||||
padding: 10px;
|
|
||||||
float:left;
|
|
||||||
font-size: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.boardHeader{
|
|
||||||
width:100%;
|
|
||||||
height:50px;
|
|
||||||
border:5px solid #A9D1E1;
|
|
||||||
color: white;
|
|
||||||
margin-right:10px;
|
|
||||||
padding: 10px;
|
|
||||||
float:left;
|
|
||||||
font-size: 40px;
|
|
||||||
}
|
|
||||||
.username{
|
|
||||||
font-weight: bold;
|
|
||||||
float: left;
|
|
||||||
margin-right: 50%;
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
||||||
<link rel="stylesheet" href="css/style.css">
|
|
||||||
<title>Kill The Rats!</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
<script src="js/app.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,31 +0,0 @@
|
||||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
|
|
||||||
var scriptURL = Script.resolvePath("pistolScriptSpawner.js");
|
|
||||||
var modelURL = "http://s3.amazonaws.com/hifi-public/cozza13/gun/m1911-handgun+1.fbx";
|
|
||||||
var pistolSpawnerEntity = Entities.addEntity({
|
|
||||||
type: 'Box',
|
|
||||||
position: center,
|
|
||||||
dimensions: {x: 0.38, y: 1.9, z: 3.02},
|
|
||||||
script: scriptURL,
|
|
||||||
visible: false,
|
|
||||||
collisionless: true
|
|
||||||
});
|
|
||||||
|
|
||||||
var pistol = Entities.addEntity({
|
|
||||||
type: 'Model',
|
|
||||||
modelURL: modelURL,
|
|
||||||
position: center,
|
|
||||||
dimensions: {x: 0.38, y: 1.9, z: 3.02},
|
|
||||||
script: scriptURL,
|
|
||||||
color: {red: 200, green: 0, blue: 20},
|
|
||||||
collisionless: true
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function cleanup() {
|
|
||||||
Entities.deleteEntity(pistolSpawnerEntity);
|
|
||||||
Entities.deleteEntity(pistol);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Script.update.connect(update);
|
|
||||||
Script.scriptEnding.connect(cleanup);
|
|
|
@ -22,14 +22,37 @@ if (scripts.length >= 2) {
|
||||||
// Set up the qml ui
|
// Set up the qml ui
|
||||||
var qml = Script.resolvePath('debugWindow.qml');
|
var qml = Script.resolvePath('debugWindow.qml');
|
||||||
|
|
||||||
|
var HMD_DEBUG_WINDOW_GEOMETRY_KEY = 'hmdDebugWindowGeometry';
|
||||||
|
var hmdDebugWindowGeometryValue = Settings.getValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY)
|
||||||
|
|
||||||
|
var windowWidth = 400;
|
||||||
|
var windowHeight = 900;
|
||||||
|
|
||||||
|
var hasPosition = false;
|
||||||
|
var windowX = 0;
|
||||||
|
var windowY = 0;
|
||||||
|
|
||||||
|
if (hmdDebugWindowGeometryValue !== '') {
|
||||||
|
var geometry = JSON.parse(hmdDebugWindowGeometryValue);
|
||||||
|
|
||||||
|
windowWidth = geometry.width
|
||||||
|
windowHeight = geometry.height
|
||||||
|
windowX = geometry.x
|
||||||
|
windowY = geometry.y
|
||||||
|
hasPosition = true;
|
||||||
|
}
|
||||||
|
|
||||||
var window = new OverlayWindow({
|
var window = new OverlayWindow({
|
||||||
title: 'Debug Window',
|
title: 'Debug Window',
|
||||||
source: qml,
|
source: qml,
|
||||||
width: 400, height: 900,
|
width: windowWidth, height: windowHeight,
|
||||||
});
|
});
|
||||||
|
|
||||||
window.setPosition(25, 50);
|
if (hasPosition) {
|
||||||
window.closed.connect(function() { Script.stop(); });
|
window.setPosition(windowX, windowY);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.closed.connect(function () { Script.stop(); });
|
||||||
|
|
||||||
var getFormattedDate = function() {
|
var getFormattedDate = function() {
|
||||||
var date = new Date();
|
var date = new Date();
|
||||||
|
@ -65,6 +88,14 @@ ScriptDiscoveryService.clearDebugWindow.connect(function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
|
var geometry = JSON.stringify({
|
||||||
|
x: window.position.x,
|
||||||
|
y: window.position.y,
|
||||||
|
width: window.size.x,
|
||||||
|
height: window.size.y
|
||||||
|
})
|
||||||
|
|
||||||
|
Settings.setValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY, geometry);
|
||||||
window.close();
|
window.close();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function getAvailableConnections(domain, callback) { // callback([{usename, location}...]) if successful. (Logs otherwise)
|
function getAvailableConnections(domain, callback) { // callback([{usename, location}...]) if successful. (Logs otherwise)
|
||||||
url = METAVERSE_BASE + '/api/v1/users?'
|
url = METAVERSE_BASE + '/api/v1/users?per_page=400&'
|
||||||
if (domain) {
|
if (domain) {
|
||||||
url += 'status=' + domain.slice(1, -1); // without curly braces
|
url += 'status=' + domain.slice(1, -1); // without curly braces
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
getControllerJointIndex, enableDispatcherModule, disableDispatcherModule,
|
getControllerJointIndex, enableDispatcherModule, disableDispatcherModule,
|
||||||
Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions,
|
Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions,
|
||||||
Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable,
|
Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable,
|
||||||
cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE
|
cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE, Uuid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Script.include("/~/system/libraries/Xform.js");
|
Script.include("/~/system/libraries/Xform.js");
|
||||||
|
@ -269,6 +269,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
||||||
this.grabEntityProps = null;
|
this.grabEntityProps = null;
|
||||||
this.shouldSendStart = false;
|
this.shouldSendStart = false;
|
||||||
this.equipedWithSecondary = false;
|
this.equipedWithSecondary = false;
|
||||||
|
this.handHasBeenRightsideUp = false;
|
||||||
|
|
||||||
this.parameters = makeDispatcherModuleParameters(
|
this.parameters = makeDispatcherModuleParameters(
|
||||||
300,
|
300,
|
||||||
|
@ -486,15 +487,17 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
||||||
var grabbedProperties = Entities.getEntityProperties(this.targetEntityID);
|
var grabbedProperties = Entities.getEntityProperties(this.targetEntityID);
|
||||||
|
|
||||||
// if an object is "equipped" and has a predefined offset, use it.
|
// if an object is "equipped" and has a predefined offset, use it.
|
||||||
var offsets = getAttachPointForHotspotFromSettings(this.grabbedHotspot, this.hand);
|
if (this.grabbedHotspot) {
|
||||||
if (offsets) {
|
var offsets = getAttachPointForHotspotFromSettings(this.grabbedHotspot, this.hand);
|
||||||
this.offsetPosition = offsets[0];
|
if (offsets) {
|
||||||
this.offsetRotation = offsets[1];
|
this.offsetPosition = offsets[0];
|
||||||
} else {
|
this.offsetRotation = offsets[1];
|
||||||
var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
|
} else {
|
||||||
if (this.grabbedHotspot.joints[handJointName]) {
|
var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
|
||||||
this.offsetPosition = this.grabbedHotspot.joints[handJointName][0];
|
if (this.grabbedHotspot.joints[handJointName]) {
|
||||||
this.offsetRotation = this.grabbedHotspot.joints[handJointName][1];
|
this.offsetPosition = this.grabbedHotspot.joints[handJointName][0];
|
||||||
|
this.offsetRotation = this.grabbedHotspot.joints[handJointName][1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,7 +552,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
||||||
// 100 ms seems to be sufficient time to force the check even occur after the object has been initialized.
|
// 100 ms seems to be sufficient time to force the check even occur after the object has been initialized.
|
||||||
Script.setTimeout(grabEquipCheck, 100);
|
Script.setTimeout(grabEquipCheck, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.endEquipEntity = function () {
|
this.endEquipEntity = function () {
|
||||||
|
@ -624,7 +626,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
||||||
this.grabbedHotspot = potentialEquipHotspot;
|
this.grabbedHotspot = potentialEquipHotspot;
|
||||||
this.targetEntityID = this.grabbedHotspot.entityID;
|
this.targetEntityID = this.grabbedHotspot.entityID;
|
||||||
this.startEquipEntity(controllerData);
|
this.startEquipEntity(controllerData);
|
||||||
this.messageGrabEnity = false;
|
this.messageGrabEntity = false;
|
||||||
this.equipedWithSecondary = this.secondarySmoothedSqueezed();
|
this.equipedWithSecondary = this.secondarySmoothedSqueezed();
|
||||||
return makeRunningValues(true, [potentialEquipHotspot.entityID], []);
|
return makeRunningValues(true, [potentialEquipHotspot.entityID], []);
|
||||||
} else {
|
} else {
|
||||||
|
@ -640,6 +642,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
||||||
this.isReady = function (controllerData, deltaTime) {
|
this.isReady = function (controllerData, deltaTime) {
|
||||||
var timestamp = Date.now();
|
var timestamp = Date.now();
|
||||||
this.updateInputs(controllerData);
|
this.updateInputs(controllerData);
|
||||||
|
this.handHasBeenRightsideUp = false;
|
||||||
return this.checkNearbyHotspots(controllerData, deltaTime, timestamp);
|
return this.checkNearbyHotspots(controllerData, deltaTime, timestamp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -671,7 +674,14 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
||||||
return makeRunningValues(false, [], []);
|
return makeRunningValues(false, [], []);
|
||||||
}
|
}
|
||||||
|
|
||||||
var dropDetected = this.dropGestureProcess(deltaTime);
|
var handIsUpsideDown = this.dropGestureProcess(deltaTime);
|
||||||
|
var dropDetected = false;
|
||||||
|
if (this.handHasBeenRightsideUp) {
|
||||||
|
dropDetected = handIsUpsideDown;
|
||||||
|
}
|
||||||
|
if (!handIsUpsideDown) {
|
||||||
|
this.handHasBeenRightsideUp = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.triggerSmoothedReleased() || this.secondaryReleased()) {
|
if (this.triggerSmoothedReleased() || this.secondaryReleased()) {
|
||||||
if (this.shouldSendStart) {
|
if (this.shouldSendStart) {
|
||||||
|
@ -692,7 +702,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
||||||
}
|
}
|
||||||
|
|
||||||
// highlight the grabbed hotspot when the dropGesture is detected.
|
// highlight the grabbed hotspot when the dropGesture is detected.
|
||||||
if (dropDetected) {
|
if (dropDetected && this.grabbedHotspot) {
|
||||||
equipHotspotBuddy.updateHotspot(this.grabbedHotspot, timestamp);
|
equipHotspotBuddy.updateHotspot(this.grabbedHotspot, timestamp);
|
||||||
equipHotspotBuddy.highlightHotspot(this.grabbedHotspot);
|
equipHotspotBuddy.highlightHotspot(this.grabbedHotspot);
|
||||||
}
|
}
|
||||||
|
|
|
@ -469,7 +469,7 @@ var toolBar = (function () {
|
||||||
|
|
||||||
// tablet version of new-model dialog
|
// tablet version of new-model dialog
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
tablet.pushOntoStack("NewModelDialog.qml");
|
tablet.pushOntoStack("hifi/tablet/NewModelDialog.qml");
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newCubeButton", "cube-01.svg", function () {
|
addButton("newCubeButton", "cube-01.svg", function () {
|
||||||
|
@ -1344,7 +1344,7 @@ function recursiveDelete(entities, childrenList, deletedIDs) {
|
||||||
var entityID = entities[i];
|
var entityID = entities[i];
|
||||||
var children = Entities.getChildrenIDs(entityID);
|
var children = Entities.getChildrenIDs(entityID);
|
||||||
var grandchildrenList = [];
|
var grandchildrenList = [];
|
||||||
recursiveDelete(children, grandchildrenList);
|
recursiveDelete(children, grandchildrenList, deletedIDs);
|
||||||
var initialProperties = Entities.getEntityProperties(entityID);
|
var initialProperties = Entities.getEntityProperties(entityID);
|
||||||
childrenList.push({
|
childrenList.push({
|
||||||
entityID: entityID,
|
entityID: entityID,
|
||||||
|
|
|
@ -26,6 +26,7 @@ colpick Color Picker / colpick.com
|
||||||
/*Color selection box with gradients*/
|
/*Color selection box with gradients*/
|
||||||
.colpick_color {
|
.colpick_color {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
left: 7px;
|
left: 7px;
|
||||||
top: 7px;
|
top: 7px;
|
||||||
width: 156px;
|
width: 156px;
|
||||||
|
@ -84,6 +85,7 @@ colpick Color Picker / colpick.com
|
||||||
/*Vertical hue bar*/
|
/*Vertical hue bar*/
|
||||||
.colpick_hue {
|
.colpick_hue {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
top: 6px;
|
top: 6px;
|
||||||
left: 175px;
|
left: 175px;
|
||||||
width: 19px;
|
width: 19px;
|
||||||
|
@ -94,6 +96,7 @@ colpick Color Picker / colpick.com
|
||||||
/*Hue bar sliding indicator*/
|
/*Hue bar sliding indicator*/
|
||||||
.colpick_hue_arrs {
|
.colpick_hue_arrs {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
left: -8px;
|
left: -8px;
|
||||||
width: 35px;
|
width: 35px;
|
||||||
height: 7px;
|
height: 7px;
|
||||||
|
@ -101,6 +104,7 @@ colpick Color Picker / colpick.com
|
||||||
}
|
}
|
||||||
.colpick_hue_larr {
|
.colpick_hue_larr {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
|
touch-action: none;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-top: 6px solid transparent;
|
border-top: 6px solid transparent;
|
||||||
|
@ -109,6 +113,7 @@ colpick Color Picker / colpick.com
|
||||||
}
|
}
|
||||||
.colpick_hue_rarr {
|
.colpick_hue_rarr {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
|
touch-action: none;
|
||||||
right:0;
|
right:0;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
|
@ -119,6 +124,7 @@ colpick Color Picker / colpick.com
|
||||||
/*New color box*/
|
/*New color box*/
|
||||||
.colpick_new_color {
|
.colpick_new_color {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
left: 207px;
|
left: 207px;
|
||||||
top: 6px;
|
top: 6px;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
|
@ -129,6 +135,7 @@ colpick Color Picker / colpick.com
|
||||||
/*Current color box*/
|
/*Current color box*/
|
||||||
.colpick_current_color {
|
.colpick_current_color {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
left: 277px;
|
left: 277px;
|
||||||
top: 6px;
|
top: 6px;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
|
@ -139,6 +146,7 @@ colpick Color Picker / colpick.com
|
||||||
/*Input field containers*/
|
/*Input field containers*/
|
||||||
.colpick_field, .colpick_hex_field {
|
.colpick_field, .colpick_hex_field {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
overflow:hidden;
|
overflow:hidden;
|
||||||
|
@ -198,6 +206,7 @@ colpick Color Picker / colpick.com
|
||||||
/*Text inputs*/
|
/*Text inputs*/
|
||||||
.colpick_field input, .colpick_hex_field input {
|
.colpick_field input, .colpick_hex_field input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
right: 11px;
|
right: 11px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -217,6 +226,7 @@ colpick Color Picker / colpick.com
|
||||||
/*Field up/down arrows*/
|
/*Field up/down arrows*/
|
||||||
.colpick_field_arrs {
|
.colpick_field_arrs {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 9px;
|
width: 9px;
|
||||||
|
@ -225,6 +235,7 @@ colpick Color Picker / colpick.com
|
||||||
}
|
}
|
||||||
.colpick_field_uarr {
|
.colpick_field_uarr {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
|
@ -234,6 +245,7 @@ colpick Color Picker / colpick.com
|
||||||
}
|
}
|
||||||
.colpick_field_darr {
|
.colpick_field_darr {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
bottom:5px;
|
bottom:5px;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
|
@ -244,6 +256,7 @@ colpick Color Picker / colpick.com
|
||||||
/*Submit/Select button*/
|
/*Submit/Select button*/
|
||||||
.colpick_submit {
|
.colpick_submit {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
touch-action: none;
|
||||||
left: 207px;
|
left: 207px;
|
||||||
top: 149px;
|
top: 149px;
|
||||||
width: 130px;
|
width: 130px;
|
||||||
|
|
|
@ -653,16 +653,16 @@ function loaded() {
|
||||||
var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y");
|
var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y");
|
||||||
|
|
||||||
// Skybox
|
// Skybox
|
||||||
var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit");
|
var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit");
|
||||||
var elZoneSkyboxModeDisabled = document.getElementById("property-zone-skybox-mode-disabled");
|
var elZoneSkyboxModeDisabled = document.getElementById("property-zone-skybox-mode-disabled");
|
||||||
var elZoneSkyboxModeEnabled = document.getElementById("property-zone-skybox-mode-enabled");
|
var elZoneSkyboxModeEnabled = document.getElementById("property-zone-skybox-mode-enabled");
|
||||||
|
|
||||||
// Ambient light
|
// Ambient light
|
||||||
var elCopySkyboxURLToAmbientURL = document.getElementById("copy-skybox-url-to-ambient-url");
|
var elCopySkyboxURLToAmbientURL = document.getElementById("copy-skybox-url-to-ambient-url");
|
||||||
|
|
||||||
var elZoneAmbientLightModeInherit = document.getElementById("property-zone-ambient-light-mode-inherit");
|
var elZoneAmbientLightModeInherit = document.getElementById("property-zone-ambient-light-mode-inherit");
|
||||||
var elZoneAmbientLightModeDisabled = document.getElementById("property-zone-ambient-light-mode-disabled");
|
var elZoneAmbientLightModeDisabled = document.getElementById("property-zone-ambient-light-mode-disabled");
|
||||||
var elZoneAmbientLightModeEnabled = document.getElementById("property-zone-ambient-light-mode-enabled");
|
var elZoneAmbientLightModeEnabled = document.getElementById("property-zone-ambient-light-mode-enabled");
|
||||||
|
|
||||||
var elZoneAmbientLightIntensity = document.getElementById("property-zone-key-ambient-intensity");
|
var elZoneAmbientLightIntensity = document.getElementById("property-zone-key-ambient-intensity");
|
||||||
var elZoneAmbientLightURL = document.getElementById("property-zone-key-ambient-url");
|
var elZoneAmbientLightURL = document.getElementById("property-zone-key-ambient-url");
|
||||||
|
@ -1013,9 +1013,9 @@ function loaded() {
|
||||||
|
|
||||||
} else if (properties.type === "Zone") {
|
} else if (properties.type === "Zone") {
|
||||||
// Key light
|
// Key light
|
||||||
elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit');
|
elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit');
|
||||||
elZoneKeyLightModeDisabled.checked = (properties.keyLightMode === 'disabled');
|
elZoneKeyLightModeDisabled.checked = (properties.keyLightMode === 'disabled');
|
||||||
elZoneKeyLightModeEnabled.checked = (properties.keyLightMode === 'enabled');
|
elZoneKeyLightModeEnabled.checked = (properties.keyLightMode === 'enabled');
|
||||||
|
|
||||||
elZoneKeyLightColor.style.backgroundColor = "rgb(" + properties.keyLight.color.red + "," +
|
elZoneKeyLightColor.style.backgroundColor = "rgb(" + properties.keyLight.color.red + "," +
|
||||||
properties.keyLight.color.green + "," + properties.keyLight.color.blue + ")";
|
properties.keyLight.color.green + "," + properties.keyLight.color.blue + ")";
|
||||||
|
@ -1027,22 +1027,22 @@ function loaded() {
|
||||||
elZoneKeyLightDirectionY.value = properties.keyLight.direction.y.toFixed(2);
|
elZoneKeyLightDirectionY.value = properties.keyLight.direction.y.toFixed(2);
|
||||||
|
|
||||||
// Skybox
|
// Skybox
|
||||||
elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit');
|
elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit');
|
||||||
elZoneSkyboxModeDisabled.checked = (properties.skyboxMode === 'disabled');
|
elZoneSkyboxModeDisabled.checked = (properties.skyboxMode === 'disabled');
|
||||||
elZoneSkyboxModeEnabled.checked = (properties.skyboxMode === 'enabled');
|
elZoneSkyboxModeEnabled.checked = (properties.skyboxMode === 'enabled');
|
||||||
|
|
||||||
// Ambient light
|
// Ambient light
|
||||||
elZoneAmbientLightModeInherit.checked = (properties.ambientLightMode === 'inherit');
|
elZoneAmbientLightModeInherit.checked = (properties.ambientLightMode === 'inherit');
|
||||||
elZoneAmbientLightModeDisabled.checked = (properties.ambientLightMode === 'disabled');
|
elZoneAmbientLightModeDisabled.checked = (properties.ambientLightMode === 'disabled');
|
||||||
elZoneAmbientLightModeEnabled.checked = (properties.ambientLightMode === 'enabled');
|
elZoneAmbientLightModeEnabled.checked = (properties.ambientLightMode === 'enabled');
|
||||||
|
|
||||||
elZoneAmbientLightIntensity.value = properties.ambientLight.ambientIntensity.toFixed(2);
|
elZoneAmbientLightIntensity.value = properties.ambientLight.ambientIntensity.toFixed(2);
|
||||||
elZoneAmbientLightURL.value = properties.ambientLight.ambientURL;
|
elZoneAmbientLightURL.value = properties.ambientLight.ambientURL;
|
||||||
|
|
||||||
// Haze
|
// Haze
|
||||||
elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit');
|
elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit');
|
||||||
elZoneHazeModeDisabled.checked = (properties.hazeMode === 'disabled');
|
elZoneHazeModeDisabled.checked = (properties.hazeMode === 'disabled');
|
||||||
elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled');
|
elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled');
|
||||||
|
|
||||||
elZoneHazeRange.value = properties.haze.hazeRange.toFixed(0);
|
elZoneHazeRange.value = properties.haze.hazeRange.toFixed(0);
|
||||||
elZoneHazeColor.style.backgroundColor = "rgb(" +
|
elZoneHazeColor.style.backgroundColor = "rgb(" +
|
||||||
|
@ -1308,15 +1308,15 @@ function loaded() {
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
layout: 'hex',
|
layout: 'hex',
|
||||||
color: '000000',
|
color: '000000',
|
||||||
|
submit: false, // We don't want to have a submission button
|
||||||
onShow: function(colpick) {
|
onShow: function(colpick) {
|
||||||
$('#property-color-control2').attr('active', 'true');
|
$('#property-color-control2').attr('active', 'true');
|
||||||
},
|
},
|
||||||
onHide: function(colpick) {
|
onHide: function(colpick) {
|
||||||
$('#property-color-control2').attr('active', 'false');
|
$('#property-color-control2').attr('active', 'false');
|
||||||
},
|
},
|
||||||
onSubmit: function(hsb, hex, rgb, el) {
|
onChange: function(hsb, hex, rgb, el) {
|
||||||
$(el).css('background-color', '#' + hex);
|
$(el).css('background-color', '#' + hex);
|
||||||
$(el).colpickHide();
|
|
||||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
|
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -1332,15 +1332,15 @@ function loaded() {
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
layout: 'hex',
|
layout: 'hex',
|
||||||
color: '000000',
|
color: '000000',
|
||||||
|
submit: false, // We don't want to have a submission button
|
||||||
onShow: function(colpick) {
|
onShow: function(colpick) {
|
||||||
$('#property-light-color').attr('active', 'true');
|
$('#property-light-color').attr('active', 'true');
|
||||||
},
|
},
|
||||||
onHide: function(colpick) {
|
onHide: function(colpick) {
|
||||||
$('#property-light-color').attr('active', 'false');
|
$('#property-light-color').attr('active', 'false');
|
||||||
},
|
},
|
||||||
onSubmit: function(hsb, hex, rgb, el) {
|
onChange: function(hsb, hex, rgb, el) {
|
||||||
$(el).css('background-color', '#' + hex);
|
$(el).css('background-color', '#' + hex);
|
||||||
$(el).colpickHide();
|
|
||||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
|
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -1387,15 +1387,15 @@ function loaded() {
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
layout: 'hex',
|
layout: 'hex',
|
||||||
color: '000000',
|
color: '000000',
|
||||||
|
submit: false, // We don't want to have a submission button
|
||||||
onShow: function(colpick) {
|
onShow: function(colpick) {
|
||||||
$('#property-text-text-color').attr('active', 'true');
|
$('#property-text-text-color').attr('active', 'true');
|
||||||
},
|
},
|
||||||
onHide: function(colpick) {
|
onHide: function(colpick) {
|
||||||
$('#property-text-text-color').attr('active', 'false');
|
$('#property-text-text-color').attr('active', 'false');
|
||||||
},
|
},
|
||||||
onSubmit: function(hsb, hex, rgb, el) {
|
onChange: function(hsb, hex, rgb, el) {
|
||||||
$(el).css('background-color', '#' + hex);
|
$(el).css('background-color', '#' + hex);
|
||||||
$(el).colpickHide();
|
|
||||||
$(el).attr('active', 'false');
|
$(el).attr('active', 'false');
|
||||||
emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b);
|
emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b);
|
||||||
}
|
}
|
||||||
|
@ -1411,15 +1411,15 @@ function loaded() {
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
layout: 'hex',
|
layout: 'hex',
|
||||||
color: '000000',
|
color: '000000',
|
||||||
|
submit: false, // We don't want to have a submission button
|
||||||
onShow: function(colpick) {
|
onShow: function(colpick) {
|
||||||
$('#property-text-background-color').attr('active', 'true');
|
$('#property-text-background-color').attr('active', 'true');
|
||||||
},
|
},
|
||||||
onHide: function(colpick) {
|
onHide: function(colpick) {
|
||||||
$('#property-text-background-color').attr('active', 'false');
|
$('#property-text-background-color').attr('active', 'false');
|
||||||
},
|
},
|
||||||
onSubmit: function(hsb, hex, rgb, el) {
|
onChange: function(hsb, hex, rgb, el) {
|
||||||
$(el).css('background-color', '#' + hex);
|
$(el).css('background-color', '#' + hex);
|
||||||
$(el).colpickHide();
|
|
||||||
emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b);
|
emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -1436,15 +1436,15 @@ function loaded() {
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
layout: 'hex',
|
layout: 'hex',
|
||||||
color: '000000',
|
color: '000000',
|
||||||
|
submit: false, // We don't want to have a submission button
|
||||||
onShow: function(colpick) {
|
onShow: function(colpick) {
|
||||||
$('#property-zone-key-light-color').attr('active', 'true');
|
$('#property-zone-key-light-color').attr('active', 'true');
|
||||||
},
|
},
|
||||||
onHide: function(colpick) {
|
onHide: function(colpick) {
|
||||||
$('#property-zone-key-light-color').attr('active', 'false');
|
$('#property-zone-key-light-color').attr('active', 'false');
|
||||||
},
|
},
|
||||||
onSubmit: function(hsb, hex, rgb, el) {
|
onChange: function(hsb, hex, rgb, el) {
|
||||||
$(el).css('background-color', '#' + hex);
|
$(el).css('background-color', '#' + hex);
|
||||||
$(el).colpickHide();
|
|
||||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight');
|
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight');
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -1505,15 +1505,15 @@ function loaded() {
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
layout: 'hex',
|
layout: 'hex',
|
||||||
color: '000000',
|
color: '000000',
|
||||||
|
submit: false, // We don't want to have a submission button
|
||||||
onShow: function(colpick) {
|
onShow: function(colpick) {
|
||||||
$('#property-zone-haze-color').attr('active', 'true');
|
$('#property-zone-haze-color').attr('active', 'true');
|
||||||
},
|
},
|
||||||
onHide: function(colpick) {
|
onHide: function(colpick) {
|
||||||
$('#property-zone-haze-color').attr('active', 'false');
|
$('#property-zone-haze-color').attr('active', 'false');
|
||||||
},
|
},
|
||||||
onSubmit: function(hsb, hex, rgb, el) {
|
onChange: function(hsb, hex, rgb, el) {
|
||||||
$(el).css('background-color', '#' + hex);
|
$(el).css('background-color', '#' + hex);
|
||||||
$(el).colpickHide();
|
|
||||||
emitColorPropertyUpdate('hazeColor', rgb.r, rgb.g, rgb.b, 'haze');
|
emitColorPropertyUpdate('hazeColor', rgb.r, rgb.g, rgb.b, 'haze');
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -1530,15 +1530,15 @@ function loaded() {
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
layout: 'hex',
|
layout: 'hex',
|
||||||
color: '000000',
|
color: '000000',
|
||||||
|
submit: false, // We don't want to have a submission button
|
||||||
onShow: function(colpick) {
|
onShow: function(colpick) {
|
||||||
$('#property-zone-haze-glare-color').attr('active', 'true');
|
$('#property-zone-haze-glare-color').attr('active', 'true');
|
||||||
},
|
},
|
||||||
onHide: function(colpick) {
|
onHide: function(colpick) {
|
||||||
$('#property-zone-haze-glare-color').attr('active', 'false');
|
$('#property-zone-haze-glare-color').attr('active', 'false');
|
||||||
},
|
},
|
||||||
onSubmit: function(hsb, hex, rgb, el) {
|
onChange: function(hsb, hex, rgb, el) {
|
||||||
$(el).css('background-color', '#' + hex);
|
$(el).css('background-color', '#' + hex);
|
||||||
$(el).colpickHide();
|
|
||||||
emitColorPropertyUpdate('hazeGlareColor', rgb.r, rgb.g, rgb.b, 'haze');
|
emitColorPropertyUpdate('hazeGlareColor', rgb.r, rgb.g, rgb.b, 'haze');
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -1572,15 +1572,15 @@ function loaded() {
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
layout: 'hex',
|
layout: 'hex',
|
||||||
color: '000000',
|
color: '000000',
|
||||||
|
submit: false, // We don't want to have a submission button
|
||||||
onShow: function(colpick) {
|
onShow: function(colpick) {
|
||||||
$('#property-zone-skybox-color').attr('active', 'true');
|
$('#property-zone-skybox-color').attr('active', 'true');
|
||||||
},
|
},
|
||||||
onHide: function(colpick) {
|
onHide: function(colpick) {
|
||||||
$('#property-zone-skybox-color').attr('active', 'false');
|
$('#property-zone-skybox-color').attr('active', 'false');
|
||||||
},
|
},
|
||||||
onSubmit: function(hsb, hex, rgb, el) {
|
onChange: function(hsb, hex, rgb, el) {
|
||||||
$(el).css('background-color', '#' + hex);
|
$(el).css('background-color', '#' + hex);
|
||||||
$(el).colpickHide();
|
|
||||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox');
|
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox');
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -361,7 +361,7 @@ function getProfilePicture(username, callback) { // callback(url) if successfull
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function getAvailableConnections(domain, callback) { // callback([{usename, location}...]) if successfull. (Logs otherwise)
|
function getAvailableConnections(domain, callback) { // callback([{usename, location}...]) if successfull. (Logs otherwise)
|
||||||
url = METAVERSE_BASE + '/api/v1/users?'
|
url = METAVERSE_BASE + '/api/v1/users?per_page=400&'
|
||||||
if (domain) {
|
if (domain) {
|
||||||
url += 'status=' + domain.slice(1, -1); // without curly braces
|
url += 'status=' + domain.slice(1, -1); // without curly braces
|
||||||
} else {
|
} else {
|
||||||
|
@ -493,7 +493,7 @@ function populateNearbyUserList(selectData, oldAudioData) {
|
||||||
data.push(avatarPalDatum);
|
data.push(avatarPalDatum);
|
||||||
print('PAL data:', JSON.stringify(avatarPalDatum));
|
print('PAL data:', JSON.stringify(avatarPalDatum));
|
||||||
});
|
});
|
||||||
getConnectionData(false, location.domainId); // Even admins don't get relationship data in requestUsernameFromID (which is still needed for admin status, which comes from domain).
|
getConnectionData(false, location.domainID); // Even admins don't get relationship data in requestUsernameFromID (which is still needed for admin status, which comes from domain).
|
||||||
conserveResources = Object.keys(avatarsOfInterest).length > 20;
|
conserveResources = Object.keys(avatarsOfInterest).length > 20;
|
||||||
sendToQml({ method: 'nearbyUsers', params: data });
|
sendToQml({ method: 'nearbyUsers', params: data });
|
||||||
if (selectData) {
|
if (selectData) {
|
||||||
|
|
|
@ -35,4 +35,5 @@
|
||||||
button.editProperties({isActive: true});
|
button.editProperties({isActive: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(cleanup);
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -337,7 +337,7 @@ function fillImageDataFromPrevious() {
|
||||||
containsGif: previousAnimatedSnapPath !== "",
|
containsGif: previousAnimatedSnapPath !== "",
|
||||||
processingGif: false,
|
processingGif: false,
|
||||||
shouldUpload: false,
|
shouldUpload: false,
|
||||||
canBlast: location.domainId === Settings.getValue("previousSnapshotDomainID"),
|
canBlast: location.domainID === Settings.getValue("previousSnapshotDomainID"),
|
||||||
isLoggedIn: isLoggedIn
|
isLoggedIn: isLoggedIn
|
||||||
};
|
};
|
||||||
imageData = [];
|
imageData = [];
|
||||||
|
@ -416,7 +416,7 @@ function snapshotUploaded(isError, reply) {
|
||||||
}
|
}
|
||||||
isUploadingPrintableStill = false;
|
isUploadingPrintableStill = false;
|
||||||
}
|
}
|
||||||
var href, domainId;
|
var href, domainID;
|
||||||
function takeSnapshot() {
|
function takeSnapshot() {
|
||||||
tablet.emitScriptEvent(JSON.stringify({
|
tablet.emitScriptEvent(JSON.stringify({
|
||||||
type: "snapshot",
|
type: "snapshot",
|
||||||
|
@ -443,11 +443,11 @@ function takeSnapshot() {
|
||||||
MyAvatar.setClearOverlayWhenMoving(false);
|
MyAvatar.setClearOverlayWhenMoving(false);
|
||||||
|
|
||||||
// We will record snapshots based on the starting location. That could change, e.g., when recording a .gif.
|
// We will record snapshots based on the starting location. That could change, e.g., when recording a .gif.
|
||||||
// Even the domainId could change (e.g., if the user falls into a teleporter while recording).
|
// Even the domainID could change (e.g., if the user falls into a teleporter while recording).
|
||||||
href = location.href;
|
href = location.href;
|
||||||
Settings.setValue("previousSnapshotHref", href);
|
Settings.setValue("previousSnapshotHref", href);
|
||||||
domainId = location.domainId;
|
domainID = location.domainID;
|
||||||
Settings.setValue("previousSnapshotDomainID", domainId);
|
Settings.setValue("previousSnapshotDomainID", domainID);
|
||||||
|
|
||||||
maybeDeleteSnapshotStories();
|
maybeDeleteSnapshotStories();
|
||||||
|
|
||||||
|
@ -548,7 +548,7 @@ function stillSnapshotTaken(pathStillSnapshot, notify) {
|
||||||
}
|
}
|
||||||
HMD.openTablet();
|
HMD.openTablet();
|
||||||
|
|
||||||
isDomainOpen(domainId, function (canShare) {
|
isDomainOpen(domainID, function (canShare) {
|
||||||
snapshotOptions = {
|
snapshotOptions = {
|
||||||
containsGif: false,
|
containsGif: false,
|
||||||
processingGif: false,
|
processingGif: false,
|
||||||
|
@ -594,7 +594,7 @@ function processingGifStarted(pathStillSnapshot) {
|
||||||
}
|
}
|
||||||
HMD.openTablet();
|
HMD.openTablet();
|
||||||
|
|
||||||
isDomainOpen(domainId, function (canShare) {
|
isDomainOpen(domainID, function (canShare) {
|
||||||
snapshotOptions = {
|
snapshotOptions = {
|
||||||
containsGif: true,
|
containsGif: true,
|
||||||
processingGif: true,
|
processingGif: true,
|
||||||
|
@ -622,13 +622,13 @@ function processingGifCompleted(pathAnimatedSnapshot) {
|
||||||
|
|
||||||
Settings.setValue("previousAnimatedSnapPath", pathAnimatedSnapshot);
|
Settings.setValue("previousAnimatedSnapPath", pathAnimatedSnapshot);
|
||||||
|
|
||||||
isDomainOpen(domainId, function (canShare) {
|
isDomainOpen(domainID, function (canShare) {
|
||||||
snapshotOptions = {
|
snapshotOptions = {
|
||||||
containsGif: true,
|
containsGif: true,
|
||||||
processingGif: false,
|
processingGif: false,
|
||||||
canShare: canShare,
|
canShare: canShare,
|
||||||
isLoggedIn: isLoggedIn,
|
isLoggedIn: isLoggedIn,
|
||||||
canBlast: location.domainId === Settings.getValue("previousSnapshotDomainID"),
|
canBlast: location.domainID === Settings.getValue("previousSnapshotDomainID"),
|
||||||
};
|
};
|
||||||
imageData = [{ localPath: pathAnimatedSnapshot, href: href }];
|
imageData = [{ localPath: pathAnimatedSnapshot, href: href }];
|
||||||
tablet.emitScriptEvent(JSON.stringify({
|
tablet.emitScriptEvent(JSON.stringify({
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue