From 4278d7b20dd903422734b316049d1a0dee7c7b23 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 11:05:27 -0800 Subject: [PATCH 01/46] download and link oculus platform for oculus plugin --- cmake/externals/LibOVRPlatform/CMakeLists.txt | 32 +++++++++++++++ cmake/modules/FindLibOVRPlatform.cmake | 41 +++++++++++++++++++ plugins/oculus/CMakeLists.txt | 36 +++++++++------- 3 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 cmake/externals/LibOVRPlatform/CMakeLists.txt create mode 100644 cmake/modules/FindLibOVRPlatform.cmake diff --git a/cmake/externals/LibOVRPlatform/CMakeLists.txt b/cmake/externals/LibOVRPlatform/CMakeLists.txt new file mode 100644 index 0000000000..75338ce041 --- /dev/null +++ b/cmake/externals/LibOVRPlatform/CMakeLists.txt @@ -0,0 +1,32 @@ +include(ExternalProject) +include(SelectLibraryConfigurations) + +set(EXTERNAL_NAME LibOVRPlatform) + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +if (WIN32) + + ExternalProject_Add( + ${EXTERNAL_NAME} + URL http://hifi-public.s3.amazonaws.com/dependencies/OVRPlatformSDK_v1.10.0.zip + URL_MD5 e6c8264af16d904e6506acd5172fa0a9 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 + ) + + ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(${EXTERNAL_NAME_UPPER}_LIB ${SOURCE_DIR}/Windows/LibOVRPlatform64_1.lib CACHE TYPE INTERNAL) + else() + set(${EXTERNAL_NAME_UPPER}_LIB ${SOURCE_DIR}/Windows/LibOVRPlatform32_1.lib CACHE TYPE INTERNAL) + endif() + + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/Include CACHE TYPE INTERNAL) +endif () + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") diff --git a/cmake/modules/FindLibOVRPlatform.cmake b/cmake/modules/FindLibOVRPlatform.cmake new file mode 100644 index 0000000000..e09fa21895 --- /dev/null +++ b/cmake/modules/FindLibOVRPlatform.cmake @@ -0,0 +1,41 @@ +# +# FindLibOVRPlatform.cmake +# +# Try to find the LibOVRPlatform library to use the Oculus Platform SDK +# +# You must provide a LIBOVRPLATFORM_ROOT_DIR which contains Windows and Include directories +# +# Once done this will define +# +# LIBOVRPLATFORM_FOUND - system found Oculus Platform SDK +# LIBOVRPLATFORM_INCLUDE_DIRS - the Oculus Platform include directory +# LIBOVRPLATFORM_LIBRARIES - Link this to use Oculus Platform +# +# Created on December 16, 2016 by Stephen Birarda +# 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) + # setup hints for LIBOVRPLATFORM search + include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") + hifi_library_search_hints("LibOVRPlatform") + + find_path(LIBOVRPLATFORM_INCLUDE_DIRS OVR_Platform.h PATH_SUFFIXES Include HINTS ${LIBOVRPLATFORM_SEARCH_DIRS}) + + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(_LIB_NAME LibOVRPlatform64_1.lib) + else() + set(_LIB_NAME LibOVRPlatform32_1.lib) + endif() + + find_library(LIBOVRPLATFORM_LIBRARY_RELEASE NAMES ${_LIB_NAME} PATH_SUFFIXES Windows HINTS ${LIBOVRPLATFORM_SEARCH_DIRS}) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(LIBOVRPLATFORM DEFAULT_MSG LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES) + + mark_as_advanced(LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES LIBOVRPLATFORM_SEARCH_DIRS) +endif () diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index a768af932e..7ee0228616 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -8,21 +8,27 @@ if (WIN32) - # we're using static GLEW, so define GLEW_STATIC - add_definitions(-DGLEW_STATIC) + # we're using static GLEW, so define GLEW_STATIC + add_definitions(-DGLEW_STATIC) - set(TARGET_NAME oculus) - setup_hifi_plugin(Multimedia) - link_hifi_libraries(shared gl gpu gpu-gl controllers ui - plugins ui-plugins display-plugins input-plugins - audio-client networking render-utils) - - include_hifi_library_headers(octree) - - add_dependency_external_projects(LibOVR) - find_package(LibOVR REQUIRED) - target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) - target_link_libraries(${TARGET_NAME} Winmm.lib) + set(TARGET_NAME oculus) + setup_hifi_plugin(Multimedia) + link_hifi_libraries( + shared gl gpu gpu-gl controllers ui + plugins ui-plugins display-plugins input-plugins + audio-client networking render-utils + ) + include_hifi_library_headers(octree) + + add_dependency_external_projects(LibOVR) + find_package(LibOVR REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) + target_link_libraries(${TARGET_NAME} Winmm.lib) + + add_dependency_external_projects(LibOVRPlatform) + find_package(LibOVRPlatform REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVRPLATFORM_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${LIBOVRPLATFORM_LIBRARIES}) endif() From ac7637f8ff897e9d9133a327b9a16e485b8dbd88 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 13:10:49 -0800 Subject: [PATCH 02/46] use _LIBRARY_RELEASE for LibOVRPlatform external --- cmake/externals/LibOVRPlatform/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/externals/LibOVRPlatform/CMakeLists.txt b/cmake/externals/LibOVRPlatform/CMakeLists.txt index 75338ce041..3622972a13 100644 --- a/cmake/externals/LibOVRPlatform/CMakeLists.txt +++ b/cmake/externals/LibOVRPlatform/CMakeLists.txt @@ -20,9 +20,9 @@ if (WIN32) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") - set(${EXTERNAL_NAME_UPPER}_LIB ${SOURCE_DIR}/Windows/LibOVRPlatform64_1.lib CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/Windows/LibOVRPlatform64_1.lib CACHE TYPE INTERNAL) else() - set(${EXTERNAL_NAME_UPPER}_LIB ${SOURCE_DIR}/Windows/LibOVRPlatform32_1.lib CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/Windows/LibOVRPlatform32_1.lib CACHE TYPE INTERNAL) endif() set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/Include CACHE TYPE INTERNAL) From 1a50a1174125b0ed2257d1c0563e510435e47a2c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 13:15:14 -0800 Subject: [PATCH 03/46] have FindLibOVRPlatform produce LIBOVRPLATFORM_LIBRARY --- cmake/modules/FindLibOVRPlatform.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/modules/FindLibOVRPlatform.cmake b/cmake/modules/FindLibOVRPlatform.cmake index e09fa21895..fd07ff6f06 100644 --- a/cmake/modules/FindLibOVRPlatform.cmake +++ b/cmake/modules/FindLibOVRPlatform.cmake @@ -9,7 +9,7 @@ # # LIBOVRPLATFORM_FOUND - system found Oculus Platform SDK # LIBOVRPLATFORM_INCLUDE_DIRS - the Oculus Platform include directory -# LIBOVRPLATFORM_LIBRARIES - Link this to use Oculus Platform +# LIBOVRPLATFORM_LIBRARY - Link this to use Oculus Platform # # Created on December 16, 2016 by Stephen Birarda # Copyright 2016 High Fidelity, Inc. @@ -35,7 +35,7 @@ if (WIN32) find_library(LIBOVRPLATFORM_LIBRARY_RELEASE NAMES ${_LIB_NAME} PATH_SUFFIXES Windows HINTS ${LIBOVRPLATFORM_SEARCH_DIRS}) include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(LIBOVRPLATFORM DEFAULT_MSG LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES) + find_package_handle_standard_args(LIBOVRPLATFORM DEFAULT_MSG LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARY) - mark_as_advanced(LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES LIBOVRPLATFORM_SEARCH_DIRS) + mark_as_advanced(LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARY LIBOVRPLATFORM_SEARCH_DIRS) endif () From d0236af33468d251317d54443ec0c4c76db3b380 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 13:25:35 -0800 Subject: [PATCH 04/46] use select_library_configurations for LibOVRPlatform --- cmake/modules/FindLibOVRPlatform.cmake | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cmake/modules/FindLibOVRPlatform.cmake b/cmake/modules/FindLibOVRPlatform.cmake index fd07ff6f06..e9caa2cb98 100644 --- a/cmake/modules/FindLibOVRPlatform.cmake +++ b/cmake/modules/FindLibOVRPlatform.cmake @@ -9,7 +9,7 @@ # # LIBOVRPLATFORM_FOUND - system found Oculus Platform SDK # LIBOVRPLATFORM_INCLUDE_DIRS - the Oculus Platform include directory -# LIBOVRPLATFORM_LIBRARY - Link this to use Oculus Platform +# LIBOVRPLATFORM_LIBRARIES - Link this to use Oculus Platform # # Created on December 16, 2016 by Stephen Birarda # Copyright 2016 High Fidelity, Inc. @@ -34,8 +34,11 @@ if (WIN32) find_library(LIBOVRPLATFORM_LIBRARY_RELEASE NAMES ${_LIB_NAME} PATH_SUFFIXES Windows HINTS ${LIBOVRPLATFORM_SEARCH_DIRS}) - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(LIBOVRPLATFORM DEFAULT_MSG LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARY) + include(SelectLibraryConfigurations) + select_library_configurations(LIBOVRPLATFORM) - mark_as_advanced(LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARY LIBOVRPLATFORM_SEARCH_DIRS) + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(LIBOVRPLATFORM DEFAULT_MSG LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES) + + mark_as_advanced(LIBOVRPLATFORM_INCLUDE_DIRS LIBOVRPLATFORM_LIBRARIES LIBOVRPLATFORM_SEARCH_DIRS) endif () From ea3e5f702a26e80c3653d70a39a7c7853a8a3ef2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 13:44:06 -0800 Subject: [PATCH 05/46] add popping of messages for entitlement check --- plugins/oculus/src/OculusHelpers.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 8a160b67ff..7cdf5cfeef 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -15,6 +15,9 @@ #include #include +#define OVRPL_DISABLED +#include + #include #include #include @@ -27,6 +30,7 @@ static ovrSession session { nullptr }; static bool _quitRequested { false }; static bool _reorientRequested { false }; +static bool _entitlementCheckFailed { false }; inline ovrErrorInfo getError() { ovrErrorInfo error; @@ -125,6 +129,20 @@ void handleOVREvents() { return; } + // pop messages to see if we got a return for an entitlement check + while ((message = ovr_PopMessage()) != nullptr) { + switch (ovr_Message_GetType(message)) { + case ovrMessage_Entitlement_GetIsViewerEntitled: { + if (!ovr_Message_IsError(message)) { + // this viewer is entitled, no need to flag anything + } else { + // we failed the entitlement check, set our flag so the app can stop + _entitlementCheckFailed = true; + } + } + } + } + _quitRequested = status.ShouldQuit; _reorientRequested = status.ShouldRecenter; } @@ -217,4 +235,4 @@ controller::Pose ovrControllerPoseToHandPose( pose.velocity = toGlm(handPose.LinearVelocity); pose.valid = true; return pose; -} \ No newline at end of file +} From b87a1b2b2bb3afe0090e01adfc48849e8011a35f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 14:53:48 -0800 Subject: [PATCH 06/46] only fire the entitlement check if OCULUS_APP_ID is set --- plugins/oculus/CMakeLists.txt | 6 ++++- plugins/oculus/src/OculusHelpers.cpp | 35 +++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 7ee0228616..6b8d1a2ff9 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -11,6 +11,11 @@ if (WIN32) # we're using static GLEW, so define GLEW_STATIC add_definitions(-DGLEW_STATIC) + # if we were passed an Oculus App ID for entitlement checks, send that along + if (DEFINED ENV{OCULUS_APP_ID}) + add_definitions(-DOCULUS_APP_ID="\\"$ENV{OCULUS_APP_ID}\\"") + endif () + set(TARGET_NAME oculus) setup_hifi_plugin(Multimedia) link_hifi_libraries( @@ -18,7 +23,6 @@ if (WIN32) plugins ui-plugins display-plugins input-plugins audio-client networking render-utils ) - include_hifi_library_headers(octree) add_dependency_external_projects(LibOVR) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 7cdf5cfeef..ef9b667342 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -30,7 +30,6 @@ static ovrSession session { nullptr }; static bool _quitRequested { false }; static bool _reorientRequested { false }; -static bool _entitlementCheckFailed { false }; inline ovrErrorInfo getError() { ovrErrorInfo error; @@ -92,6 +91,18 @@ ovrSession acquireOculusSession() { logWarning("Failed to initialize Oculus SDK"); return session; } + +#ifdef OCULUS_APP_ID + if (true) { + if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { + // we were unable to initialize the platform for entitlement check - fail the check + _quitRequested = true; + } else { + qCDebug(oculus) << "Performing Oculus Platform entitlement check"; + ovr_Entitlement_GetIsViewerEntitled(); + } + } +#endif Q_ASSERT(0 == refCount); ovrGraphicsLuid luid; @@ -129,22 +140,34 @@ void handleOVREvents() { return; } + _quitRequested = status.ShouldQuit; + _reorientRequested = status.ShouldRecenter; + + #ifdef OCULUS_APP_ID // pop messages to see if we got a return for an entitlement check - while ((message = ovr_PopMessage()) != nullptr) { + ovrMessageHandle message = ovr_PopMessage(); + + while (message) { switch (ovr_Message_GetType(message)) { case ovrMessage_Entitlement_GetIsViewerEntitled: { if (!ovr_Message_IsError(message)) { // this viewer is entitled, no need to flag anything + qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally"; } else { // we failed the entitlement check, set our flag so the app can stop - _entitlementCheckFailed = true; + qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID; + _quitRequested = true; } } } - } - _quitRequested = status.ShouldQuit; - _reorientRequested = status.ShouldRecenter; + // free the message handle to cleanup and not leak + ovr_FreeMessage(message); + + // pop the next message to check, if there is one + message = ovr_PopMessage(); + } +#endif } bool quitRequested() { From f592d8d894fa7abe6c3072397061d857b7070481 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 15:19:26 -0800 Subject: [PATCH 07/46] force entitlement check for all builds with OCULUS_APP_ID --- plugins/oculus/src/OculusHelpers.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index ef9b667342..92cfbcc5bd 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -93,14 +93,13 @@ ovrSession acquireOculusSession() { } #ifdef OCULUS_APP_ID - if (true) { - if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { - // we were unable to initialize the platform for entitlement check - fail the check - _quitRequested = true; - } else { - qCDebug(oculus) << "Performing Oculus Platform entitlement check"; - ovr_Entitlement_GetIsViewerEntitled(); - } + if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { + // we were unable to initialize the platform for entitlement check - fail the check + _quitRequested = true; + } + else { + qCDebug(oculus) << "Performing Oculus Platform entitlement check"; + ovr_Entitlement_GetIsViewerEntitled(); } #endif From 2ec9b81aa6880a13d83269df2c8fa0b37960365e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Dec 2016 15:48:16 -0800 Subject: [PATCH 08/46] fix passing of OCULUS_APP_ID to platform SDK initialization --- plugins/oculus/CMakeLists.txt | 2 +- plugins/oculus/src/OculusHelpers.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 6b8d1a2ff9..55eb9c7b85 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -13,7 +13,7 @@ if (WIN32) # if we were passed an Oculus App ID for entitlement checks, send that along if (DEFINED ENV{OCULUS_APP_ID}) - add_definitions(-DOCULUS_APP_ID="\\"$ENV{OCULUS_APP_ID}\\"") + add_definitions(-DOCULUS_APP_ID="$ENV{OCULUS_APP_ID}") endif () set(TARGET_NAME oculus) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 92cfbcc5bd..7cafe9a1d4 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -96,8 +96,7 @@ ovrSession acquireOculusSession() { if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { // we were unable to initialize the platform for entitlement check - fail the check _quitRequested = true; - } - else { + } else { qCDebug(oculus) << "Performing Oculus Platform entitlement check"; ovr_Entitlement_GetIsViewerEntitled(); } From 46086cdcceb4b25a1e8cbf73e03a787f2a56fc39 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 5 Jan 2017 13:50:45 -0800 Subject: [PATCH 09/46] set the OCULUS_STORE property with oculus store arg --- interface/src/Application.cpp | 41 ++++++++++--------- .../shared/src/shared/GlobalAppProperties.cpp | 1 + .../shared/src/shared/GlobalAppProperties.h | 1 + plugins/oculus/src/OculusHelpers.cpp | 17 ++++---- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 832419a75c..75290f77d5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -250,7 +250,7 @@ public: static const unsigned long MAX_HEARTBEAT_AGE_USECS = 30 * USECS_PER_SECOND; static const int WARNING_ELAPSED_HEARTBEAT = 500 * USECS_PER_MSEC; // warn if elapsed heartbeat average is large static const int HEARTBEAT_SAMPLES = 100000; // ~5 seconds worth of samples - + // Set the heartbeat on launch DeadlockWatchdogThread() { setObjectName("Deadlock Watchdog"); @@ -613,7 +613,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _window->setWindowTitle("Interface"); Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us - + auto nodeList = DependencyManager::get(); // Set up a watchdog thread to intentionally crash the application on deadlocks @@ -634,6 +634,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qCDebug(interfaceapp) << "[VERSION] We will use DEVELOPMENT global services."; #endif + // set the OCULUS_STORE property so the oculus plugin can know if we ran from the Oculus Store + static const QString OCULUS_STORE_ARG = "--oculus-store"; + setProperty(hifi::properties::OCULUS_STORE, arguments().indexOf(OCULUS_STORE_ARG) != -1); static const QString NO_UPDATER_ARG = "--no-updater"; static const bool noUpdater = arguments().indexOf(NO_UPDATER_ARG) != -1; @@ -694,7 +697,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo audioIO->setPositionGetter([]{ auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; - + return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO; }); audioIO->setOrientationGetter([]{ @@ -877,7 +880,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo #ifdef Q_OS_MAC auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget #else - // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the + // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the // window menu, which is a pain, so only hide it for the GL surface auto cursorTarget = _glWidget; #endif @@ -1122,7 +1125,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo loadSettings(); // Now that we've loaded the menu and thus switched to the previous display plugin - // we can unlock the desktop repositioning code, since all the positions will be + // we can unlock the desktop repositioning code, since all the positions will be // relative to the desktop size for this plugin auto offscreenUi = DependencyManager::get(); offscreenUi->getDesktop()->setProperty("repositionLocked", false); @@ -1595,7 +1598,7 @@ void Application::checkChangeCursor() { #ifdef Q_OS_MAC auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget #else - // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the + // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the // window menu, which is a pain, so only hide it for the GL surface auto cursorTarget = _glWidget; #endif @@ -1782,7 +1785,7 @@ Application::~Application() { #endif // The window takes ownership of the menu, so this has the side effect of destroying it. _window->setMenuBar(nullptr); - + _window->deleteLater(); // Can't log to file passed this point, FileLogger about to be deleted @@ -1808,10 +1811,10 @@ void Application::initializeGL() { _glWidget->makeCurrent(); gpu::Context::init(); - qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK, + qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK, QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram))); _gpuContext = std::make_shared(); - // The gpu context can make child contexts for transfers, so + // The gpu context can make child contexts for transfers, so // we need to restore primary rendering context _glWidget->makeCurrent(); @@ -2027,7 +2030,7 @@ void Application::paintGL() { // FIXME not needed anymore? _offscreenContext->makeCurrent(); - // If a display plugin loses it's underlying support, it + // If a display plugin loses it's underlying support, it // needs to be able to signal us to not use it if (!displayPlugin->beginFrameRender(_frameCount)) { _inPaint = false; @@ -2839,7 +2842,7 @@ void Application::keyPressEvent(QKeyEvent* event) { if (isMirrorChecked) { // if we got here without coming in from a non-Full Screen mirror case, then our - // _returnFromFullScreenMirrorTo is unknown. In that case we'll go to the old + // _returnFromFullScreenMirrorTo is unknown. In that case we'll go to the old // behavior of returning to ThirdPerson if (_returnFromFullScreenMirrorTo.isEmpty()) { _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; @@ -3013,7 +3016,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { maybeToggleMenuVisible(event); auto& compositor = getApplicationCompositor(); - // if this is a real mouse event, and we're in HMD mode, then we should use it to move the + // if this is a real mouse event, and we're in HMD mode, then we should use it to move the // compositor reticle // handleRealMouseMoveEvent() will return true, if we shouldn't process the event further if (!compositor.fakeEventActive() && compositor.handleRealMouseMoveEvent()) { @@ -4027,7 +4030,7 @@ void Application::setKeyboardFocusEntity(EntityItemID entityItemID) { } _lastAcceptedKeyPress = usecTimestampNow(); - setKeyboardFocusHighlight(entity->getPosition(), entity->getRotation(), + setKeyboardFocusHighlight(entity->getPosition(), entity->getRotation(), entity->getDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR); } } @@ -4618,7 +4621,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node _octreeQuery.setMaxQueryPacketsPerSecond(0); } - // if asked to forceResend, then set the query's position/orientation to be degenerate in a manner + // if asked to forceResend, then set the query's position/orientation to be degenerate in a manner // that will cause our next query to be guarenteed to be different and the server will resend to us if (forceResend) { _octreeQuery.setCameraPosition(glm::vec3(-0.1, -0.1, -0.1)); @@ -5751,7 +5754,7 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin mapping = mapping.insert(mapping.lastIndexOf("."), "-" + QString::number(copy)); addAssetToWorldWithNewMapping(filePath, mapping, copy); } else { - QString errorInfo = "Too many copies of asset name: " + QString errorInfo = "Too many copies of asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); qWarning(interfaceapp) << "Error downloading asset: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); @@ -5818,7 +5821,7 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { // Note: Model dimensions are not available here; model is scaled per FBX mesh in RenderableModelEntityItem::update() later // on. But FBX dimensions may be in cm, so we monitor for the dimension change and rescale again if warranted. - + if (entityID == QUuid()) { QString errorInfo = "Could not add asset " + mapping + " to world."; qWarning(interfaceapp) << "Could not add asset to world: " + errorInfo; @@ -6283,7 +6286,7 @@ glm::uvec2 Application::getCanvasSize() const { } QRect Application::getRenderingGeometry() const { - auto geometry = _glWidget->geometry(); + auto geometry = _glWidget->geometry(); auto topLeft = geometry.topLeft(); auto topLeftScreen = _glWidget->mapToGlobal(topLeft); geometry.moveTopLeft(topLeftScreen); @@ -6646,8 +6649,8 @@ bool Application::makeRenderingContextCurrent() { return _offscreenContext->makeCurrent(); } -bool Application::isForeground() const { - return _isForeground && !_window->isMinimized(); +bool Application::isForeground() const { + return _isForeground && !_window->isMinimized(); } void Application::sendMousePressOnEntity(QUuid id, PointerEvent event) { diff --git a/libraries/shared/src/shared/GlobalAppProperties.cpp b/libraries/shared/src/shared/GlobalAppProperties.cpp index a8a38457f2..f2d8990708 100644 --- a/libraries/shared/src/shared/GlobalAppProperties.cpp +++ b/libraries/shared/src/shared/GlobalAppProperties.cpp @@ -13,6 +13,7 @@ namespace hifi { namespace properties { const char* CRASHED = "com.highfidelity.crashed"; const char* STEAM = "com.highfidelity.launchedFromSteam"; const char* LOGGER = "com.highfidelity.logger"; + const char* OCULUS_STORE = "com.highfidelity.oculusStore"; const char* TEST = "com.highfidelity.test"; const char* TRACING = "com.highfidelity.tracing"; diff --git a/libraries/shared/src/shared/GlobalAppProperties.h b/libraries/shared/src/shared/GlobalAppProperties.h index 92d8388f09..609f2afd94 100644 --- a/libraries/shared/src/shared/GlobalAppProperties.h +++ b/libraries/shared/src/shared/GlobalAppProperties.h @@ -15,6 +15,7 @@ namespace hifi { namespace properties { extern const char* CRASHED; extern const char* STEAM; extern const char* LOGGER; + extern const char* OCULUS_STORE; extern const char* TEST; extern const char* TRACING; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 7cafe9a1d4..be4866a71e 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -20,6 +20,7 @@ #include #include +#include #include Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display") @@ -91,14 +92,16 @@ ovrSession acquireOculusSession() { logWarning("Failed to initialize Oculus SDK"); return session; } - + #ifdef OCULUS_APP_ID - if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { - // we were unable to initialize the platform for entitlement check - fail the check - _quitRequested = true; - } else { - qCDebug(oculus) << "Performing Oculus Platform entitlement check"; - ovr_Entitlement_GetIsViewerEntitled(); + if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) { + if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { + // we were unable to initialize the platform for entitlement check - fail the check + _quitRequested = true; + } else { + qCDebug(oculus) << "Performing Oculus Platform entitlement check"; + ovr_Entitlement_GetIsViewerEntitled(); + } } #endif From 8f279ce1f7db4367bfce1d6362cad4768d8f0439 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 5 Jan 2017 14:21:35 -0800 Subject: [PATCH 10/46] only pop to check entitlements if oculus store build --- plugins/oculus/src/OculusHelpers.cpp | 39 +++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index be4866a71e..340b804404 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -145,28 +145,31 @@ void handleOVREvents() { _reorientRequested = status.ShouldRecenter; #ifdef OCULUS_APP_ID - // pop messages to see if we got a return for an entitlement check - ovrMessageHandle message = ovr_PopMessage(); - while (message) { - switch (ovr_Message_GetType(message)) { - case ovrMessage_Entitlement_GetIsViewerEntitled: { - if (!ovr_Message_IsError(message)) { - // this viewer is entitled, no need to flag anything - qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally"; - } else { - // we failed the entitlement check, set our flag so the app can stop - qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID; - _quitRequested = true; + if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) { + // pop messages to see if we got a return for an entitlement check + ovrMessageHandle message = ovr_PopMessage(); + + while (message) { + switch (ovr_Message_GetType(message)) { + case ovrMessage_Entitlement_GetIsViewerEntitled: { + if (!ovr_Message_IsError(message)) { + // this viewer is entitled, no need to flag anything + qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally"; + } else { + // we failed the entitlement check, set our flag so the app can stop + qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID; + _quitRequested = true; + } } } + + // free the message handle to cleanup and not leak + ovr_FreeMessage(message); + + // pop the next message to check, if there is one + message = ovr_PopMessage(); } - - // free the message handle to cleanup and not leak - ovr_FreeMessage(message); - - // pop the next message to check, if there is one - message = ovr_PopMessage(); } #endif } From 8bb200902f3b1c496afadfba0cc9ecb249f70857 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 10 Jan 2017 16:40:48 -0800 Subject: [PATCH 11/46] First pass --- assignment-client/src/audio/AudioMixer.cpp | 18 ++++++++-- assignment-client/src/audio/AudioMixer.h | 1 + .../src/audio/AudioMixerClientData.h | 6 ++++ .../src/audio/AudioMixerSlave.cpp | 7 ++-- assignment-client/src/audio/AudioMixerSlave.h | 2 +- interface/resources/qml/hifi/NameCard.qml | 33 ++++++++++++++++++- interface/resources/qml/hifi/Pal.qml | 2 ++ libraries/networking/src/NodeList.cpp | 23 +++++++++++++ libraries/networking/src/NodeList.h | 1 + libraries/networking/src/udt/PacketHeaders.h | 3 +- .../src/UsersScriptingInterface.cpp | 5 +++ .../src/UsersScriptingInterface.h | 8 +++++ scripts/system/pal.js | 4 +++ 13 files changed, 105 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 19ebd4ea87..fddd2d641e 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -68,7 +68,8 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListener(PacketType::NodeMuteRequest, this, "handleNodeMuteRequestPacket"); packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket"); - packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); + packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); + packetReceiver.registerListener(PacketType::PerAvatarGainSet, this, "handlePerAvatarGainSetDataPacket"); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); } @@ -186,7 +187,9 @@ void AudioMixer::handleNodeKilled(SharedNodePointer killedNode) { nodeList->eachNode([&killedNode](const SharedNodePointer& node) { auto clientData = dynamic_cast(node->getLinkedData()); if (clientData) { - clientData->removeHRTFsForNode(killedNode->getUUID()); + QUuid killedUUID = killedNode->getUUID(); + clientData->removePerAvatarGain(killedUUID); + clientData->removeHRTFsForNode(killedUUID); } }); } @@ -240,6 +243,17 @@ void AudioMixer::handleNodeIgnoreRequestPacket(QSharedPointer p sendingNode->parseIgnoreRequestMessage(packet); } +void AudioMixer::handlePerAvatarGainSetDataPacket(QSharedPointer packet, SharedNodePointer sendingNode) { + auto clientData = dynamic_cast(sendingNode->getLinkedData()); + if (clientData) { + // parse the UUID from the packet + QUuid ignoredUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + float gain; + packet->readPrimitive(&gain); + clientData->setPerAvatarGain(ignoredUUID, gain); + } +} + void AudioMixer::handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode) { sendingNode->parseIgnoreRadiusRequestMessage(packet); } diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index d9759653fb..d88bc3b917 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -66,6 +66,7 @@ private slots: void handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleKillAvatarPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleNodeMuteRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void handlePerAvatarGainSetDataPacket(QSharedPointer packet, SharedNodePointer sendingNode); void start(); void removeHRTFsForFinishedInjector(const QUuid& streamID); diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index e637fd0409..d7fbfe5112 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -95,6 +95,10 @@ public: bool getRequestsDomainListData() { return _requestsDomainListData; } void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; } + float getPerAvatarGain(const QUuid& avatarID) { return (_perAvatarGain.count(avatarID) ? _perAvatarGain.at(avatarID) : 1.0f); } + void setPerAvatarGain(const QUuid& avatarID, float gain) { _perAvatarGain[avatarID] = gain; } + void removePerAvatarGain(const QUuid& avatarID) { _perAvatarGain.erase(avatarID); } + signals: void injectorStreamFinished(const QUuid& streamIdentifier); @@ -125,6 +129,8 @@ private: bool _shouldMuteClient { false }; bool _requestsDomainListData { false }; + + std::unordered_map _perAvatarGain; }; #endif // hifi_AudioMixerClientData_h diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 28d3358eb5..90037b7187 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -252,12 +252,13 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& node) { // Enumerate the audio streams attached to the otherNode auto streamsCopy = otherData->getAudioStreams(); + float thisAvatarGain = nodeData->getPerAvatarGain(otherNode->getUUID()); for (auto& streamPair : streamsCopy) { auto otherNodeStream = streamPair.second; bool isSelfWithEcho = ((*otherNode == *node) && (otherNodeStream->shouldLoopbackForNode())); // Add all audio streams that should be added to the mix if (isSelfWithEcho || (!isSelfWithEcho && !insideIgnoreRadius)) { - addStreamToMix(*nodeData, otherNode->getUUID(), *nodeAudioStream, *otherNodeStream); + addStreamToMix(*nodeData, otherNode->getUUID(), *nodeAudioStream, *otherNodeStream, thisAvatarGain); } } } @@ -278,7 +279,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& node) { } void AudioMixerSlave::addStreamToMix(AudioMixerClientData& listenerNodeData, const QUuid& sourceNodeID, - const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd) { + const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, float perAvatarGain) { // to reduce artifacts we calculate the gain and azimuth for every source for this listener // even if we are not going to end up mixing in this source @@ -295,7 +296,7 @@ void AudioMixerSlave::addStreamToMix(AudioMixerClientData& listenerNodeData, con float distance = glm::max(glm::length(relativePosition), EPSILON); // figure out the gain for this source at the listener - float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho); + float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho) + (perAvatarGain - 1.0f); // figure out the azimuth to this source at the listener float azimuth = isEcho ? 0.0f : azimuthForSource(listeningNodeStream, listeningNodeStream, relativePosition); diff --git a/assignment-client/src/audio/AudioMixerSlave.h b/assignment-client/src/audio/AudioMixerSlave.h index c4aabfbb4a..89aa70f99a 100644 --- a/assignment-client/src/audio/AudioMixerSlave.h +++ b/assignment-client/src/audio/AudioMixerSlave.h @@ -43,7 +43,7 @@ private: bool prepareMix(const SharedNodePointer& node); // add a stream to the mix void addStreamToMix(AudioMixerClientData& listenerData, const QUuid& streamerID, - const AvatarAudioStream& listenerStream, const PositionalAudioStream& streamer); + const AvatarAudioStream& listenerStream, const PositionalAudioStream& streamer, float perAvatarGain); float gainForSource(const AvatarAudioStream& listener, const PositionalAudioStream& streamer, const glm::vec3& relativePosition, bool isEcho); diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index a0dde8bacc..0a0b662193 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -10,6 +10,7 @@ // import QtQuick 2.5 +import QtQuick.Controls 1.4 import QtGraphicalEffects 1.0 import "../styles-uit" @@ -27,12 +28,14 @@ Row { } // Properties - property int contentHeight: 50 + property int contentHeight: isMyCard ? 50 : 70 + property string uuid: "" property string displayName: "" property string userName: "" property int displayTextHeight: 18 property int usernameTextHeight: 12 property real audioLevel: 0.0 + property bool isMyCard: false /* User image commented out for now - will probably be re-introduced later. Column { @@ -138,5 +141,33 @@ Row { } } } + + // Per-Avatar Gain Slider Spacer + Item { + width: parent.width + height: 4 + visible: !isMyCard + } + // Per-Avatar Gain Slider + Slider { + id: gainSlider + visible: !isMyCard + width: parent.width + height: 16 + value: 1.0 + minimumValue: 0.0 + maximumValue: 1.5 + stepSize: 0.1 + updateValueWhileDragging: false + onValueChanged: updateGainFromQML(uuid, value) + } + } + + function updateGainFromQML(avatarUuid, gainValue) { + var data = { + sessionId: avatarUuid, + gain: (Math.exp(gainValue) - 1) / (Math.E - 1) + }; + pal.sendToScript({method: 'updateGain', params: data}); } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 66dce622ff..4f65497da5 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -65,6 +65,7 @@ Rectangle { displayName: myData.displayName userName: myData.userName audioLevel: myData.audioLevel + isMyCard: true // Size width: nameCardWidth height: parent.height @@ -206,6 +207,7 @@ Rectangle { userName: model && model.userName audioLevel: model && model.audioLevel visible: !isCheckBox && !isButton + uuid: model && model.sessionId // Size width: nameCardWidth height: parent.height diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index d890431a45..00f13dff3d 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -951,6 +951,29 @@ void NodeList::maybeSendIgnoreSetToNode(SharedNodePointer newNode) { } } +void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { + // cannot set gain of yourself or nobody + if (!nodeID.isNull() && _sessionUUID != nodeID) { + auto audioMixer = soloNodeOfType(NodeType::AudioMixer); + if (audioMixer) { + // setup the packet + auto setAvatarGainPacket = NLPacket::create(PacketType::PerAvatarGainSet, NUM_BYTES_RFC4122_UUID + sizeof(float), true); + + // write the node ID to the packet + setAvatarGainPacket->write(nodeID.toRfc4122()); + setAvatarGainPacket->writePrimitive((gain < 5.0f ? gain : 5.0f)); + + qCDebug(networking) << "Sending Set Avatar Gain packet UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; + + sendPacket(std::move(setAvatarGainPacket), *audioMixer); + } else { + qWarning() << "Couldn't find audio mixer to send set gain request"; + } + } else { + qWarning() << "NodeList::setAvatarGain called with an invalid ID or an ID which matches the current session ID:" << nodeID; + } +} + void NodeList::kickNodeBySessionID(const QUuid& nodeID) { // send a request to domain-server to kick the node with the given session ID // the domain-server will handle the persistence of the kick (via username or IP) diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 8e285629dc..5c477303e2 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -82,6 +82,7 @@ public: bool isIgnoringNode(const QUuid& nodeID) const; void personalMuteNodeBySessionID(const QUuid& nodeID, bool muteEnabled); bool isPersonalMutingNode(const QUuid& nodeID) const; + void setAvatarGain(const QUuid& nodeID, float gain); void kickNodeBySessionID(const QUuid& nodeID); void muteNodeBySessionID(const QUuid& nodeID); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index e4c4937622..0328037eb3 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -106,7 +106,8 @@ public: ViewFrustum, RequestsDomainListData, ExitingSpaceBubble, - LAST_PACKET_TYPE = ExitingSpaceBubble + PerAvatarGainSet, + LAST_PACKET_TYPE = ExitingSpaceBubble // FIXME!!! }; }; diff --git a/libraries/script-engine/src/UsersScriptingInterface.cpp b/libraries/script-engine/src/UsersScriptingInterface.cpp index d0ad699846..3a3225ec75 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.cpp +++ b/libraries/script-engine/src/UsersScriptingInterface.cpp @@ -42,6 +42,11 @@ bool UsersScriptingInterface::getPersonalMuteStatus(const QUuid& nodeID) { return DependencyManager::get()->isPersonalMutingNode(nodeID); } +void UsersScriptingInterface::setAvatarGain(const QUuid& nodeID, float gain) { + // ask the NodeList to set the gain of the specified avatar + DependencyManager::get()->setAvatarGain(nodeID, gain); +} + void UsersScriptingInterface::kick(const QUuid& nodeID) { // ask the NodeList to kick the user with the given session ID DependencyManager::get()->kickNodeBySessionID(nodeID); diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 341285a742..d2d77a6796 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -61,6 +61,14 @@ public slots: */ bool getPersonalMuteStatus(const QUuid& nodeID); + /**jsdoc + * Sets an avatar's gain for you and you only. + * @function Users.setAvatarGain + * @param {nodeID} nodeID The node or session ID of the user whose gain you want to modify. + * @param {float} gain The gain of the avatar you'd like to set. + */ + void setAvatarGain(const QUuid& nodeID, float gain); + /**jsdoc * Kick another user. * @function Users.kick diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 48f44570fd..12f0793b97 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -233,6 +233,10 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like removeOverlays(); populateUserList(); break; + case 'updateGain': + data = message.params; + Users.setAvatarGain(data['sessionId'], data['gain']); + break; default: print('Unrecognized message from Pal.qml:', JSON.stringify(message)); } From dcff873cd46d4747c53539a728c3717c774453fa Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 10 Jan 2017 16:50:38 -0800 Subject: [PATCH 12/46] Modify slider function --- assignment-client/src/audio/AudioMixerSlave.cpp | 2 +- interface/resources/qml/hifi/NameCard.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 90037b7187..d502239341 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -296,7 +296,7 @@ void AudioMixerSlave::addStreamToMix(AudioMixerClientData& listenerNodeData, con float distance = glm::max(glm::length(relativePosition), EPSILON); // figure out the gain for this source at the listener - float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho) + (perAvatarGain - 1.0f); + float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho) * perAvatarGain; // figure out the azimuth to this source at the listener float azimuth = isEcho ? 0.0f : azimuthForSource(listeningNodeStream, listeningNodeStream, relativePosition); diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 0a0b662193..18dbaf1fe1 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -166,7 +166,7 @@ Row { function updateGainFromQML(avatarUuid, gainValue) { var data = { sessionId: avatarUuid, - gain: (Math.exp(gainValue) - 1) / (Math.E - 1) + gain: (Math.pow(20, gainValue) - 1) / (20 - 1) }; pal.sendToScript({method: 'updateGain', params: data}); } From 503468e49b865f341ffdcfd7a965b12b1a959f39 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 10 Jan 2017 17:20:25 -0800 Subject: [PATCH 13/46] Style changes --- interface/resources/qml/hifi/NameCard.qml | 19 +++++++++++++++++-- interface/resources/qml/hifi/Pal.qml | 6 +++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 18dbaf1fe1..1f4ef07131 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -11,6 +11,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 import "../styles-uit" @@ -28,7 +29,7 @@ Row { } // Properties - property int contentHeight: isMyCard ? 50 : 70 + property int contentHeight: 70 property string uuid: "" property string displayName: "" property string userName: "" @@ -153,13 +154,27 @@ Row { id: gainSlider visible: !isMyCard width: parent.width - height: 16 + height: 18 value: 1.0 minimumValue: 0.0 maximumValue: 1.5 stepSize: 0.1 updateValueWhileDragging: false onValueChanged: updateGainFromQML(uuid, value) + style: SliderStyle { + groove: Rectangle { + color: "#dbdbdb" + implicitWidth: gainSlider.width + implicitHeight: 4 + radius: 2 + } + handle: Rectangle { + anchors.centerIn: parent + color: (control.pressed || control.hovered) ? "#00b4ef" : "#8F8F8F" + implicitWidth: 10 + implicitHeight: 18 + } + } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 4f65497da5..2cc07bf90d 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -24,8 +24,8 @@ Rectangle { // Style color: "#E3E3E3" // Properties - property int myCardHeight: 70 - property int rowHeight: 70 + property int myCardHeight: 90 + property int rowHeight: 90 property int actionButtonWidth: 75 property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4 : 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth property var myData: ({displayName: "", userName: "", audioLevel: 0.0}) // valid dummy until set @@ -51,7 +51,7 @@ Rectangle { id: myInfo // Size width: palContainer.width - height: myCardHeight + 20 + height: myCardHeight // Style color: pal.color // Anchors From 8c3766dfe81d26192b0f1447f55d511041e73f58 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 10 Jan 2017 17:21:51 -0800 Subject: [PATCH 14/46] Fixme --- libraries/networking/src/udt/PacketHeaders.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 0328037eb3..c012ed8f67 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -107,7 +107,7 @@ public: RequestsDomainListData, ExitingSpaceBubble, PerAvatarGainSet, - LAST_PACKET_TYPE = ExitingSpaceBubble // FIXME!!! + LAST_PACKET_TYPE = PerAvatarGainSet }; }; From b9cddc31a941f940067692537b2117449244ee52 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 11 Jan 2017 11:56:35 -0800 Subject: [PATCH 15/46] Checkpoint before implementing Ken's suggestions --- interface/resources/qml/hifi/NameCard.qml | 3 ++- interface/resources/qml/hifi/Pal.qml | 4 +++- scripts/system/pal.js | 12 ++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 1f4ef07131..4b8ee6cbc3 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -155,7 +155,7 @@ Row { visible: !isMyCard width: parent.width height: 18 - value: 1.0 + value: pal.gain[uuid] ? pal.gain[uuid] : 1.0 minimumValue: 0.0 maximumValue: 1.5 stepSize: 0.1 @@ -179,6 +179,7 @@ Row { } function updateGainFromQML(avatarUuid, gainValue) { + pal.gain[avatarUuid] = gainValue; var data = { sessionId: avatarUuid, gain: (Math.pow(20, gainValue) - 1) / (20 - 1) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 2cc07bf90d..039ab78baf 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -32,6 +32,7 @@ Rectangle { property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring. property var userModelData: [] // This simple list is essentially a mirror of the userModel listModel without all the extra complexities. property bool iAmAdmin: false + property var gain: ({}); // Keep a local list of per-avatar gain. Far faster than keeping this data on the server. // This is the container for the PAL Rectangle { @@ -494,8 +495,9 @@ Rectangle { } } break; - case 'clearIgnored': + case 'clearLocalQMLData': ignored = {}; + gain = {}; break; default: console.log('Unrecognized message:', JSON.stringify(message)); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 12f0793b97..6b3fd00c3b 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -586,14 +586,14 @@ button.clicked.connect(onClicked); pal.visibleChanged.connect(onVisibleChanged); pal.closed.connect(off); Users.usernameFromIDReply.connect(usernameFromIDReply); -function clearIgnoredInQMLAndClosePAL() { - pal.sendToQml({ method: 'clearIgnored' }); +function clearLocalQMLDataAndClosePAL() { + pal.sendToQml({ method: 'clearLocalQMLData' }); if (pal.visible) { onClicked(); // Close the PAL } } -Window.domainChanged.connect(clearIgnoredInQMLAndClosePAL); -Window.domainConnectionRefused.connect(clearIgnoredInQMLAndClosePAL); +Window.domainChanged.connect(clearLocalQMLDataAndClosePAL); +Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL); // // Cleanup. @@ -604,8 +604,8 @@ Script.scriptEnding.connect(function () { pal.visibleChanged.disconnect(onVisibleChanged); pal.closed.disconnect(off); Users.usernameFromIDReply.disconnect(usernameFromIDReply); - Window.domainChanged.disconnect(clearIgnoredInQMLAndClosePAL); - Window.domainConnectionRefused.disconnect(clearIgnoredInQMLAndClosePAL); + Window.domainChanged.disconnect(clearLocalQMLDataAndClosePAL); + Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL); Messages.unsubscribe(CHANNEL); Messages.messageReceived.disconnect(receiveMessage); off(); From b0b6aeac6c0eba9331eaa4f837803032acb93944 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 11 Jan 2017 16:16:35 -0800 Subject: [PATCH 16/46] Ken's feedback --- assignment-client/src/audio/AudioMixer.cpp | 13 ++++---- .../src/audio/AudioMixerClientData.h | 6 ---- .../src/audio/AudioMixerSlave.cpp | 7 ++--- assignment-client/src/audio/AudioMixerSlave.h | 2 +- interface/resources/qml/hifi/NameCard.qml | 30 ++++++++++++------- interface/resources/qml/hifi/Pal.qml | 6 ++-- libraries/audio/src/AudioHRTF.h | 2 +- libraries/networking/src/NodeList.cpp | 4 ++- .../src/UsersScriptingInterface.h | 3 +- 9 files changed, 41 insertions(+), 32 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index fddd2d641e..07639867eb 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -28,6 +28,7 @@ #include #include +#include "AudioHelpers.h" #include "AudioRingBuffer.h" #include "AudioMixerClientData.h" #include "AvatarAudioStream.h" @@ -188,7 +189,6 @@ void AudioMixer::handleNodeKilled(SharedNodePointer killedNode) { auto clientData = dynamic_cast(node->getLinkedData()); if (clientData) { QUuid killedUUID = killedNode->getUUID(); - clientData->removePerAvatarGain(killedUUID); clientData->removeHRTFsForNode(killedUUID); } }); @@ -246,11 +246,14 @@ void AudioMixer::handleNodeIgnoreRequestPacket(QSharedPointer p void AudioMixer::handlePerAvatarGainSetDataPacket(QSharedPointer packet, SharedNodePointer sendingNode) { auto clientData = dynamic_cast(sendingNode->getLinkedData()); if (clientData) { + QUuid listeningNodeUUID = sendingNode->getUUID(); // parse the UUID from the packet - QUuid ignoredUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - float gain; - packet->readPrimitive(&gain); - clientData->setPerAvatarGain(ignoredUUID, gain); + QUuid audioSourceUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + uint8_t packedGain; + packet->readPrimitive(&packedGain); + float gain = unpackFloatGainFromByte(packedGain); + clientData->hrtfForStream(audioSourceUUID, QUuid()).setGainAdjustment(gain); + qDebug() << "Setting gain adjustment for hrtf[" << listeningNodeUUID << "][" << audioSourceUUID << "] to " << gain; } } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index d7fbfe5112..e637fd0409 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -95,10 +95,6 @@ public: bool getRequestsDomainListData() { return _requestsDomainListData; } void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; } - float getPerAvatarGain(const QUuid& avatarID) { return (_perAvatarGain.count(avatarID) ? _perAvatarGain.at(avatarID) : 1.0f); } - void setPerAvatarGain(const QUuid& avatarID, float gain) { _perAvatarGain[avatarID] = gain; } - void removePerAvatarGain(const QUuid& avatarID) { _perAvatarGain.erase(avatarID); } - signals: void injectorStreamFinished(const QUuid& streamIdentifier); @@ -129,8 +125,6 @@ private: bool _shouldMuteClient { false }; bool _requestsDomainListData { false }; - - std::unordered_map _perAvatarGain; }; #endif // hifi_AudioMixerClientData_h diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index d502239341..28d3358eb5 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -252,13 +252,12 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& node) { // Enumerate the audio streams attached to the otherNode auto streamsCopy = otherData->getAudioStreams(); - float thisAvatarGain = nodeData->getPerAvatarGain(otherNode->getUUID()); for (auto& streamPair : streamsCopy) { auto otherNodeStream = streamPair.second; bool isSelfWithEcho = ((*otherNode == *node) && (otherNodeStream->shouldLoopbackForNode())); // Add all audio streams that should be added to the mix if (isSelfWithEcho || (!isSelfWithEcho && !insideIgnoreRadius)) { - addStreamToMix(*nodeData, otherNode->getUUID(), *nodeAudioStream, *otherNodeStream, thisAvatarGain); + addStreamToMix(*nodeData, otherNode->getUUID(), *nodeAudioStream, *otherNodeStream); } } } @@ -279,7 +278,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& node) { } void AudioMixerSlave::addStreamToMix(AudioMixerClientData& listenerNodeData, const QUuid& sourceNodeID, - const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, float perAvatarGain) { + const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd) { // to reduce artifacts we calculate the gain and azimuth for every source for this listener // even if we are not going to end up mixing in this source @@ -296,7 +295,7 @@ void AudioMixerSlave::addStreamToMix(AudioMixerClientData& listenerNodeData, con float distance = glm::max(glm::length(relativePosition), EPSILON); // figure out the gain for this source at the listener - float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho) * perAvatarGain; + float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho); // figure out the azimuth to this source at the listener float azimuth = isEcho ? 0.0f : azimuthForSource(listeningNodeStream, listeningNodeStream, relativePosition); diff --git a/assignment-client/src/audio/AudioMixerSlave.h b/assignment-client/src/audio/AudioMixerSlave.h index 89aa70f99a..c4aabfbb4a 100644 --- a/assignment-client/src/audio/AudioMixerSlave.h +++ b/assignment-client/src/audio/AudioMixerSlave.h @@ -43,7 +43,7 @@ private: bool prepareMix(const SharedNodePointer& node); // add a stream to the mix void addStreamToMix(AudioMixerClientData& listenerData, const QUuid& streamerID, - const AvatarAudioStream& listenerStream, const PositionalAudioStream& streamer, float perAvatarGain); + const AvatarAudioStream& listenerStream, const PositionalAudioStream& streamer); float gainForSource(const AvatarAudioStream& listener, const PositionalAudioStream& streamer, const glm::vec3& relativePosition, bool isEcho); diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 4b8ee6cbc3..3e8ee355c8 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -155,10 +155,10 @@ Row { visible: !isMyCard width: parent.width height: 18 - value: pal.gain[uuid] ? pal.gain[uuid] : 1.0 - minimumValue: 0.0 - maximumValue: 1.5 - stepSize: 0.1 + value: pal.gainSliderValueDB[uuid] ? pal.gainSliderValueDB[uuid] : 0.0 + minimumValue: -60.0 + maximumValue: 20.0 + stepSize: 2 updateValueWhileDragging: false onValueChanged: updateGainFromQML(uuid, value) style: SliderStyle { @@ -167,6 +167,12 @@ Row { implicitWidth: gainSlider.width implicitHeight: 4 radius: 2 + MouseArea { + anchors.fill: parent + onDoubleClicked: { + gainSlider.value = 0.0 + } + } } handle: Rectangle { anchors.centerIn: parent @@ -178,12 +184,14 @@ Row { } } - function updateGainFromQML(avatarUuid, gainValue) { - pal.gain[avatarUuid] = gainValue; - var data = { - sessionId: avatarUuid, - gain: (Math.pow(20, gainValue) - 1) / (20 - 1) - }; - pal.sendToScript({method: 'updateGain', params: data}); + function updateGainFromQML(avatarUuid, sliderValue) { + if (pal.gainSliderValueDB[avatarUuid] !== sliderValue) { + pal.gainSliderValueDB[avatarUuid] = sliderValue; + var data = { + sessionId: avatarUuid, + gain: sliderValue + }; + pal.sendToScript({method: 'updateGain', params: data}); + } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 039ab78baf..c74d8757f7 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -32,7 +32,9 @@ Rectangle { property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring. property var userModelData: [] // This simple list is essentially a mirror of the userModel listModel without all the extra complexities. property bool iAmAdmin: false - property var gain: ({}); // Keep a local list of per-avatar gain. Far faster than keeping this data on the server. + // Keep a local list of per-avatar gainSliderValueDBs. Far faster than fetching this data from the server. + // NOTE: if another script modifies the per-avatar gain, this value won't be accurate! + property var gainSliderValueDB: ({}); // This is the container for the PAL Rectangle { @@ -497,7 +499,7 @@ Rectangle { break; case 'clearLocalQMLData': ignored = {}; - gain = {}; + gainSliderValueDB = {}; break; default: console.log('Unrecognized message:', JSON.stringify(message)); diff --git a/libraries/audio/src/AudioHRTF.h b/libraries/audio/src/AudioHRTF.h index c9d053bec4..6a17a2d3cc 100644 --- a/libraries/audio/src/AudioHRTF.h +++ b/libraries/audio/src/AudioHRTF.h @@ -45,7 +45,7 @@ public: void renderSilent(int16_t* input, float* output, int index, float azimuth, float distance, float gain, int numFrames); // - // HRTF local gain adjustment + // HRTF local gain adjustment in amplitude (1.0 == unity) // void setGainAdjustment(float gain) { _gainAdjust = HRTF_GAIN * gain; }; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 00f13dff3d..98a563c4e5 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -26,6 +26,7 @@ #include "AccountManager.h" #include "AddressManager.h" #include "Assignment.h" +#include "AudioHelpers.h" #include "HifiSockAddr.h" #include "FingerprintUtils.h" @@ -961,7 +962,8 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { // write the node ID to the packet setAvatarGainPacket->write(nodeID.toRfc4122()); - setAvatarGainPacket->writePrimitive((gain < 5.0f ? gain : 5.0f)); + // We need to convert the gain in dB (from the script) to an amplitude before packing it. + setAvatarGainPacket->writePrimitive(packFloatGainToByte(fastExp2f(gain / 6.0206f))); qCDebug(networking) << "Sending Set Avatar Gain packet UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index d2d77a6796..0b6b7855b5 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -63,9 +63,10 @@ public slots: /**jsdoc * Sets an avatar's gain for you and you only. + * Units are Decibels (dB) * @function Users.setAvatarGain * @param {nodeID} nodeID The node or session ID of the user whose gain you want to modify. - * @param {float} gain The gain of the avatar you'd like to set. + * @param {float} gain The gain of the avatar you'd like to set. Units are dB. */ void setAvatarGain(const QUuid& nodeID, float gain); From a9226e303c666e72bdb3b1b67b7b601cbf4b4025 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 12 Jan 2017 11:18:43 -0800 Subject: [PATCH 17/46] Pull out visual changess & move them to other PR --- interface/resources/qml/controls-uit/CheckBox.qml | 1 + interface/resources/qml/hifi/LetterboxMessage.qml | 6 +++--- interface/resources/qml/hifi/NameCard.qml | 8 ++++---- interface/resources/qml/hifi/Pal.qml | 1 - 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index 09a0e04148..d3cbb87e5b 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -16,6 +16,7 @@ import "../styles-uit" Original.CheckBox { id: checkBox + HifiConstants { id: hifi } property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index c8adcdcb74..290cff6634 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -15,7 +15,7 @@ import "../styles-uit" Item { property alias text: popupText.text - property real popupRadius: hifi.dimensions.borderRadius + property real radius: hifi.dimensions.borderRadius visible: false id: letterbox anchors.fill: parent @@ -23,13 +23,13 @@ Item { anchors.fill: parent color: "black" opacity: 0.5 - radius: popupRadius + radius: radius } Rectangle { width: Math.max(parent.width * 0.75, 400) height: popupText.contentHeight*1.5 anchors.centerIn: parent - radius: popupRadius + radius: radius color: "white" FiraSansSemiBold { id: popupText diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 3e8ee355c8..7892e0755e 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 @@ -135,10 +136,9 @@ Row { start: Qt.point(0, 0) end: Qt.point(parent.width, 0) gradient: Gradient { - GradientStop { position: 0.0; color: "#2c8e72" } - GradientStop { position: 0.9; color: "#1fc6a6" } - GradientStop { position: 0.91; color: "#ea4c5f" } - GradientStop { position: 1.0; color: "#ea4c5f" } + GradientStop { position: 0.05; color: "#00CFEF" } + GradientStop { position: 0.5; color: "#9450A5" } + GradientStop { position: 0.95; color: "#EA4C5F" } } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index c74d8757f7..fe0c25d803 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -451,7 +451,6 @@ Rectangle { if (selected) { table.selection.clear(); // for now, no multi-select table.selection.select(userIndex); - table.positionViewAtRow(userIndex, ListView.Visible); } else { table.selection.deselect(userIndex); } From a69a10b8e4dd687c107d7732661ba3d0734b865b Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 13 Jan 2017 13:15:01 -0800 Subject: [PATCH 18/46] Cleanup after rebase --- interface/resources/qml/controls-uit/CheckBox.qml | 1 - interface/resources/qml/hifi/LetterboxMessage.qml | 6 +++--- interface/resources/qml/hifi/NameCard.qml | 8 ++++---- interface/resources/qml/hifi/Pal.qml | 1 + 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index d3cbb87e5b..09a0e04148 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -16,7 +16,6 @@ import "../styles-uit" Original.CheckBox { id: checkBox - HifiConstants { id: hifi } property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index 290cff6634..c8adcdcb74 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -15,7 +15,7 @@ import "../styles-uit" Item { property alias text: popupText.text - property real radius: hifi.dimensions.borderRadius + property real popupRadius: hifi.dimensions.borderRadius visible: false id: letterbox anchors.fill: parent @@ -23,13 +23,13 @@ Item { anchors.fill: parent color: "black" opacity: 0.5 - radius: radius + radius: popupRadius } Rectangle { width: Math.max(parent.width * 0.75, 400) height: popupText.contentHeight*1.5 anchors.centerIn: parent - radius: radius + radius: popupRadius color: "white" FiraSansSemiBold { id: popupText diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 7892e0755e..3e8ee355c8 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -9,7 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 @@ -136,9 +135,10 @@ Row { start: Qt.point(0, 0) end: Qt.point(parent.width, 0) gradient: Gradient { - GradientStop { position: 0.05; color: "#00CFEF" } - GradientStop { position: 0.5; color: "#9450A5" } - GradientStop { position: 0.95; color: "#EA4C5F" } + GradientStop { position: 0.0; color: "#2c8e72" } + GradientStop { position: 0.9; color: "#1fc6a6" } + GradientStop { position: 0.91; color: "#ea4c5f" } + GradientStop { position: 1.0; color: "#ea4c5f" } } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index fe0c25d803..c74d8757f7 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -451,6 +451,7 @@ Rectangle { if (selected) { table.selection.clear(); // for now, no multi-select table.selection.select(userIndex); + table.positionViewAtRow(userIndex, ListView.Visible); } else { table.selection.deselect(userIndex); } From 8343769352f8a94d941ce15535aab88caa914257 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 13 Jan 2017 15:25:07 -0800 Subject: [PATCH 19/46] NameCard improvements & user feedback --- interface/resources/qml/hifi/NameCard.qml | 41 +++++++++++++---------- interface/resources/qml/hifi/Pal.qml | 2 +- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 3e8ee355c8..b5bd0a88f8 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -20,16 +20,13 @@ Row { // Spacing spacing: 10 // Anchors - anchors.top: parent.top anchors { - topMargin: (parent.height - contentHeight)/2 - bottomMargin: (parent.height - contentHeight)/2 + verticalCenter: parent.verticalCenter leftMargin: 10 rightMargin: 10 } // Properties - property int contentHeight: 70 property string uuid: "" property string displayName: "" property string userName: "" @@ -42,7 +39,7 @@ Row { Column { id: avatarImage // Size - height: contentHeight + height: parent.height width: height Image { id: userImage @@ -56,9 +53,8 @@ Row { Column { id: textContainer // Size - width: parent.width - /*avatarImage.width - */parent.anchors.leftMargin - parent.anchors.rightMargin - parent.spacing - height: contentHeight - + width: parent.width - /*avatarImage.width - parent.spacing - */parent.anchors.leftMargin - parent.anchors.rightMargin + anchors.verticalCenter: parent.verticalCenter // DisplayName Text FiraSansSemiBold { id: displayNameText @@ -94,7 +90,7 @@ Row { // Spacer Item { - height: 4 + height: 3 width: parent.width } @@ -146,7 +142,7 @@ Row { // Per-Avatar Gain Slider Spacer Item { width: parent.width - height: 4 + height: 3 visible: !isMyCard } // Per-Avatar Gain Slider @@ -159,20 +155,31 @@ Row { minimumValue: -60.0 maximumValue: 20.0 stepSize: 2 - updateValueWhileDragging: false + updateValueWhileDragging: true onValueChanged: updateGainFromQML(uuid, value) + MouseArea { + anchors.fill: parent + onWheel: { + // Do nothing. + } + onDoubleClicked: { + gainSlider.value = 0.0 + } + onPressed: { + // Pass through to Slider + mouse.accepted = false + } + onReleased: { + // Pass through to Slider + mouse.accepted = false + } + } style: SliderStyle { groove: Rectangle { color: "#dbdbdb" implicitWidth: gainSlider.width implicitHeight: 4 radius: 2 - MouseArea { - anchors.fill: parent - onDoubleClicked: { - gainSlider.value = 0.0 - } - } } handle: Rectangle { anchors.centerIn: parent diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index c74d8757f7..0b093ed430 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -25,7 +25,7 @@ Rectangle { color: "#E3E3E3" // Properties property int myCardHeight: 90 - property int rowHeight: 90 + property int rowHeight: 80 property int actionButtonWidth: 75 property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4 : 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth property var myData: ({displayName: "", userName: "", audioLevel: 0.0}) // valid dummy until set From a89868dcad7cf23c27396d861e6bdcedf3d9678f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 13 Jan 2017 15:41:17 -0800 Subject: [PATCH 20/46] Make sliders appear only when row is selected --- interface/resources/qml/hifi/NameCard.qml | 5 +++-- interface/resources/qml/hifi/Pal.qml | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index b5bd0a88f8..10afee2e6a 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -34,6 +34,7 @@ Row { property int usernameTextHeight: 12 property real audioLevel: 0.0 property bool isMyCard: false + property bool selected: false /* User image commented out for now - will probably be re-introduced later. Column { @@ -143,12 +144,12 @@ Row { Item { width: parent.width height: 3 - visible: !isMyCard + visible: !isMyCard && selected } // Per-Avatar Gain Slider Slider { id: gainSlider - visible: !isMyCard + visible: !isMyCard && selected width: parent.width height: 18 value: pal.gainSliderValueDB[uuid] ? pal.gainSliderValueDB[uuid] : 0.0 diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 0b093ed430..052c953316 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -25,7 +25,7 @@ Rectangle { color: "#E3E3E3" // Properties property int myCardHeight: 90 - property int rowHeight: 80 + property int rowHeight: 70 property int actionButtonWidth: 75 property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4 : 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth property var myData: ({displayName: "", userName: "", audioLevel: 0.0}) // valid dummy until set @@ -190,7 +190,7 @@ Rectangle { // This Rectangle refers to each Row in the table. rowDelegate: Rectangle { // The only way I know to specify a row height. // Size - height: rowHeight + height: rowHeight + (styleData.selected ? 20 : 0) color: styleData.selected ? hifi.colors.orangeHighlight : styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd @@ -211,6 +211,7 @@ Rectangle { audioLevel: model && model.audioLevel visible: !isCheckBox && !isButton uuid: model && model.sessionId + selected: styleData.selected // Size width: nameCardWidth height: parent.height From a5343d9aa9104e1c9117ef26d1cc1e9224e24c4d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 13 Jan 2017 17:20:29 -0800 Subject: [PATCH 21/46] Final tweaks before PR! --- interface/resources/qml/hifi/NameCard.qml | 73 ++++++++++++++++------- interface/resources/qml/hifi/Pal.qml | 2 +- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 10afee2e6a..c6daf53b9a 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -15,10 +15,8 @@ import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 import "../styles-uit" -Row { +Item { id: thisNameCard - // Spacing - spacing: 10 // Anchors anchors { verticalCenter: parent.verticalCenter @@ -51,10 +49,11 @@ Row { } } */ - Column { + Item { id: textContainer // Size width: parent.width - /*avatarImage.width - parent.spacing - */parent.anchors.leftMargin - parent.anchors.rightMargin + height: childrenRect.height anchors.verticalCenter: parent.verticalCenter // DisplayName Text FiraSansSemiBold { @@ -64,6 +63,8 @@ Row { elide: Text.ElideRight // Size width: parent.width + // Anchors + anchors.top: parent.top // Text Size size: thisNameCard.displayTextHeight // Text Positioning @@ -81,6 +82,8 @@ Row { visible: thisNameCard.displayName // Size width: parent.width + // Anchors + anchors.top: displayNameText.bottom // Text Size size: thisNameCard.usernameTextHeight // Text Positioning @@ -91,25 +94,56 @@ Row { // Spacer Item { - height: 3 + id: spacer + height: 4 width: parent.width + // Anchors + anchors.top: userNameText.bottom } // VU Meter - Rectangle { // CHANGEME to the appropriate type! + Rectangle { id: nameCardVUMeter // Size - width: parent.width + width: ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width height: 8 + // Anchors + anchors.top: spacer.bottom // Style radius: 4 + color: "#c5c5c5" + // Rectangle for the zero-gain point on the VU meter + Rectangle { + id: vuMeterZeroGain + visible: gainSlider.visible + // Size + width: 4 + height: 18 + // Style + color: hifi.colors.darkGray + // Anchors + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: (-gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue) * gainSlider.width - 4 + } + // Rectangle for the VU meter line + Rectangle { + id: vuMeterLine + width: gainSlider.width + visible: gainSlider.visible + // Style + color: vuMeterBase.color + radius: nameCardVUMeter.radius + height: nameCardVUMeter.height / 2 + anchors.verticalCenter: nameCardVUMeter.verticalCenter + } // Rectangle for the VU meter base Rectangle { id: vuMeterBase // Anchors anchors.fill: parent // Style - color: "#c5c5c5" + color: parent.color radius: parent.radius } // Rectangle for the VU meter audio level @@ -118,7 +152,7 @@ Row { // Size width: (thisNameCard.audioLevel) * parent.width // Style - color: "#c5c5c5" + color: parent.color radius: parent.radius // Anchors anchors.bottom: parent.bottom @@ -140,22 +174,20 @@ Row { } } - // Per-Avatar Gain Slider Spacer - Item { - width: parent.width - height: 3 - visible: !isMyCard && selected - } // Per-Avatar Gain Slider Slider { id: gainSlider - visible: !isMyCard && selected + // Size width: parent.width - height: 18 + height: 14 + // Anchors + anchors.verticalCenter: nameCardVUMeter.verticalCenter + // Properties + visible: !isMyCard && selected value: pal.gainSliderValueDB[uuid] ? pal.gainSliderValueDB[uuid] : 0.0 minimumValue: -60.0 maximumValue: 20.0 - stepSize: 2 + stepSize: 5 updateValueWhileDragging: true onValueChanged: updateGainFromQML(uuid, value) MouseArea { @@ -177,16 +209,17 @@ Row { } style: SliderStyle { groove: Rectangle { - color: "#dbdbdb" + color: "#c5c5c5" implicitWidth: gainSlider.width implicitHeight: 4 radius: 2 + opacity: 0 } handle: Rectangle { anchors.centerIn: parent color: (control.pressed || control.hovered) ? "#00b4ef" : "#8F8F8F" implicitWidth: 10 - implicitHeight: 18 + implicitHeight: 16 } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 052c953316..3438baa217 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -190,7 +190,7 @@ Rectangle { // This Rectangle refers to each Row in the table. rowDelegate: Rectangle { // The only way I know to specify a row height. // Size - height: rowHeight + (styleData.selected ? 20 : 0) + height: rowHeight color: styleData.selected ? hifi.colors.orangeHighlight : styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd From baed3bc3b3493ad9c75a3b808378bd2437751ad2 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Sat, 14 Jan 2017 12:57:00 -0700 Subject: [PATCH 22/46] Manage audio interval timer in PAL Now, it is only running when PAL is up. Was running (but doing nothing before. Somewhat more efficient this way. --- scripts/system/pal.js | 121 ++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 57 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 48f44570fd..f65fa10d88 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -448,50 +448,6 @@ triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Cont triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand)); triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand)); triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand)); -// -// Manage the connection between the button and the window. -// -var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); -var buttonName = "pal"; -var button = toolBar.addButton({ - objectName: buttonName, - imageURL: Script.resolvePath("assets/images/tools/people.svg"), - visible: true, - hoverState: 2, - defaultState: 1, - buttonState: 1, - alpha: 0.9 -}); -var isWired = false; -function off() { - if (isWired) { // It is not ok to disconnect these twice, hence guard. - Script.update.disconnect(updateOverlays); - Controller.mousePressEvent.disconnect(handleMouseEvent); - Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); - isWired = false; - } - triggerMapping.disable(); // It's ok if we disable twice. - triggerPressMapping.disable(); // see above - removeOverlays(); - Users.requestsDomainListData = false; -} -function onClicked() { - if (!pal.visible) { - Users.requestsDomainListData = true; - populateUserList(); - pal.raise(); - isWired = true; - Script.update.connect(updateOverlays); - Controller.mousePressEvent.connect(handleMouseEvent); - Controller.mouseMoveEvent.connect(handleMouseMoveEvent); - triggerMapping.enable(); - triggerPressMapping.enable(); - } else { - off(); - } - pal.setVisible(!pal.visible); -} - // // Message from other scripts, such as edit.js // @@ -523,6 +479,7 @@ var LOUDNESS_SCALE = 2.8 / 5.0; var LOG2 = Math.log(2.0); var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too) var myData = {}; // we're not includied in ExtendedOverlay.get. +var audioInterval; function getAudioLevel(id) { // the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged @@ -555,21 +512,71 @@ function getAudioLevel(id) { return audioLevel; } +function createAudioInterval() { + // we will update the audioLevels periodically + // TODO: tune for efficiency - expecially with large numbers of avatars + return Script.setInterval(function () { + if (pal.visible) { + var param = {}; + AvatarList.getAvatarIdentifiers().forEach(function (id) { + var level = getAudioLevel(id); + // qml didn't like an object with null/empty string for a key, so... + var userId = id || 0; + param[userId] = level; + }); + pal.sendToQml({method: 'updateAudioLevel', params: param}); + } + }, AUDIO_LEVEL_UPDATE_INTERVAL_MS); +} -// we will update the audioLevels periodically -// TODO: tune for efficiency - expecially with large numbers of avatars -Script.setInterval(function () { - if (pal.visible) { - var param = {}; - AvatarList.getAvatarIdentifiers().forEach(function (id) { - var level = getAudioLevel(id); - // qml didn't like an object with null/empty string for a key, so... - var userId = id || 0; - param[userId] = level; - }); - pal.sendToQml({method: 'updateAudioLevel', params: param}); +// +// Manage the connection between the button and the window. +// +var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); +var buttonName = "pal"; +var button = toolBar.addButton({ + objectName: buttonName, + imageURL: Script.resolvePath("assets/images/tools/people.svg"), + visible: true, + hoverState: 2, + defaultState: 1, + buttonState: 1, + alpha: 0.9 +}); +var isWired = false; +function off() { + if (isWired) { // It is not ok to disconnect these twice, hence guard. + Script.update.disconnect(updateOverlays); + Controller.mousePressEvent.disconnect(handleMouseEvent); + Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); + isWired = false; } -}, AUDIO_LEVEL_UPDATE_INTERVAL_MS); + triggerMapping.disable(); // It's ok if we disable twice. + triggerPressMapping.disable(); // see above + removeOverlays(); + Users.requestsDomainListData = false; + if (audioInterval) { + Script.clearInterval(audioInterval); + } +} +function onClicked() { + if (!pal.visible) { + Users.requestsDomainListData = true; + populateUserList(); + pal.raise(); + isWired = true; + Script.update.connect(updateOverlays); + Controller.mousePressEvent.connect(handleMouseEvent); + Controller.mouseMoveEvent.connect(handleMouseMoveEvent); + triggerMapping.enable(); + triggerPressMapping.enable(); + createAudioInterval(); + } else { + off(); + } + pal.setVisible(!pal.visible); +} + // // Button state. // From 050a7e87d24acd499601abee1b98b9220f9dd7b0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 15 Jan 2017 17:04:51 -0800 Subject: [PATCH 23/46] load entity models that don't yet need to be rendered but are close enough to keep physics from being enabled. --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index b901db38e7..55c766c267 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -646,6 +646,12 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { // the model is still being downloaded. return false; } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) { + if (!_model) { + EntityTreePointer tree = getTree(); + if (tree) { + QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID())); + } + } return (_model && _model->isLoaded()); } return true; From bd67715cd2ff44c8f16c6d7966e37bb637559222 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 16 Jan 2017 08:54:56 -0800 Subject: [PATCH 24/46] don't early-exit from the loop that checks for loaded collision hulls because the check is what causes the hulls to be constructed --- interface/src/Application.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b056a8e378..28f4d54594 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5294,15 +5294,17 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { if (_nearbyEntitiesStabilityCount >= MINIMUM_NEARBY_ENTITIES_STABILITY_COUNT) { // We've seen the same number of nearby entities for several stats packets in a row. assume we've got all // the local entities. + bool result = true; foreach (EntityItemPointer entity, entities) { if (entity->shouldBePhysical() && !entity->isReadyToComputeShape()) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("Physics disabled until entity loads: .*"); qCDebug(interfaceapp) << "Physics disabled until entity loads: " << entity->getID() << entity->getName(); - return false; + // don't break here because we want all the relevant entities to start their downloads + result = false; } } - return true; + return result; } return false; } From 67ce5040ec66a03d3db0041bd9a811048f0582cb Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 16 Jan 2017 10:09:47 -0800 Subject: [PATCH 25/46] Fix bug in FBX parse changes --- libraries/fbx/src/FBXReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 5272969e6b..42922ce226 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -972,7 +972,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS static const QVariant EMISSIVE = QByteArray("Emissive"); static const QVariant AMBIENT_FACTOR = QByteArray("AmbientFactor"); static const QVariant SHININESS = QByteArray("Shininess"); - static const QVariant OPACITY = QByteArray("Shininess"); + static const QVariant OPACITY = QByteArray("Opacity"); static const QVariant MAYA_USE_NORMAL_MAP = QByteArray("Maya|use_normal_map"); static const QVariant MAYA_BASE_COLOR = QByteArray("Maya|base_color"); static const QVariant MAYA_USE_COLOR_MAP = QByteArray("Maya|use_color_map"); From 117e302b2af7400b5694bb3fd7898ad2d08d1ab6 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 12 Jan 2017 15:40:37 -0800 Subject: [PATCH 26/46] First pass --- interface/resources/qml/hifi/NameCard.qml | 72 ++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index c6daf53b9a..c1b93b92ca 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -55,12 +55,82 @@ Item { width: parent.width - /*avatarImage.width - parent.spacing - */parent.anchors.leftMargin - parent.anchors.rightMargin height: childrenRect.height anchors.verticalCenter: parent.verticalCenter - // DisplayName Text + + // DisplayName field for my card + Rectangle { + id: myDisplayName + visible: isMyCard + color: "#C5C5C5" + anchors.left: parent.left + anchors.leftMargin: -10 + width: parent.width + 70 + height: 35 + TextInput { + id: myDisplayNameText + // Properties + text: thisNameCard.displayName + autoScroll: false + maximumLength: 64 + width: parent.width + height: parent.height + wrapMode: TextInput.Wrap + // Anchors + anchors.fill: parent + anchors.leftMargin: 10 + // Text Positioning + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + // Style + color: hifi.colors.darkGray + FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } + font.family: firaSansSemiBold.name + font.pointSize: thisNameCard.displayTextHeight + // Signals + onEditingFinished: { + console.log("New displayName: ", text) + } + } + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + hoverEnabled: true + propagateComposedEvents: true + onClicked: { + myDisplayNameText.selectAll(); + myDisplayNameText.focus = true; + } + onEntered: myDisplayName.color = hifi.colors.lightGrayText + onExited: myDisplayName.color = "#C5C5C5" + } + // Edit pencil glyph + HiFiGlyphs { + text: hifi.glyphs.edit + // Size + size: thisNameCard.displayTextHeight + // Anchors + anchors.right: parent.right + anchors.rightMargin: size/2 + anchors.verticalCenter: parent.verticalCenter + // Style + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: hifi.colors.baseGray + } + } + // Spacer for DisplayName for my card + Rectangle { + width: myDisplayName.width + height: 5 + visible: isMyCard + opacity: 0 + } + // DisplayName Text for others' cards FiraSansSemiBold { id: displayNameText // Properties text: thisNameCard.displayName elide: Text.ElideRight + visible: !isMyCard // Size width: parent.width // Anchors From 6e4a4da92ab2ec2920ac135493d935b73d62f5f3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 12 Jan 2017 16:40:47 -0800 Subject: [PATCH 27/46] Checkpoint --- interface/resources/qml/hifi/NameCard.qml | 18 ++++++++++-------- scripts/system/pal.js | 6 ++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index c1b93b92ca..906e81a08d 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -69,17 +69,15 @@ Item { id: myDisplayNameText // Properties text: thisNameCard.displayName - autoScroll: false maximumLength: 64 - width: parent.width - height: parent.height - wrapMode: TextInput.Wrap + clip: true // Anchors anchors.fill: parent anchors.leftMargin: 10 + anchors.rightMargin: editGlyph.implicitWidth + editGlyph.anchors.rightMargin // Text Positioning - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignLeft + verticalAlignment: TextInput.AlignVCenter + horizontalAlignment: TextInput.AlignLeft // Style color: hifi.colors.darkGray FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } @@ -87,15 +85,18 @@ Item { font.pointSize: thisNameCard.displayTextHeight // Signals onEditingFinished: { - console.log("New displayName: ", text) + pal.sendToScript({method: 'displayNameUpdate', params: text}) } } MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton hoverEnabled: true - propagateComposedEvents: true onClicked: { + myDisplayNameText.focus ? myDisplayNameText.cursorPosition = myDisplayNameText.positionAt(mouseX, mouseY, TextInput.CursorOnCharacter) : myDisplayNameText.selectAll(); + myDisplayNameText.focus = true; + } + onDoubleClicked: { myDisplayNameText.selectAll(); myDisplayNameText.focus = true; } @@ -104,6 +105,7 @@ Item { } // Edit pencil glyph HiFiGlyphs { + id: editGlyph text: hifi.glyphs.edit // Size size: thisNameCard.displayTextHeight diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 6b3fd00c3b..c6ac1056de 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -237,6 +237,12 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like data = message.params; Users.setAvatarGain(data['sessionId'], data['gain']); break; + case 'displayNameUpdate': + if (MyAvatar.displayName != message.params) { + MyAvatar.displayName = message.params; + } + break; + default: default: print('Unrecognized message from Pal.qml:', JSON.stringify(message)); } From 2f176f50fae4ff06d9ab2e92b92acdf81b63e38c Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 13 Jan 2017 12:56:59 -0800 Subject: [PATCH 28/46] Another checkpoint --- interface/resources/fonts/hifi-glyphs.ttf | Bin 24580 -> 24772 bytes interface/resources/qml/hifi/NameCard.qml | 13 +++++++++---- interface/resources/qml/hifi/Pal.qml | 13 +++++++++++-- .../qml/styles-uit/HifiConstants.qml | 3 ++- libraries/avatars/src/AvatarData.cpp | 1 + 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/interface/resources/fonts/hifi-glyphs.ttf b/interface/resources/fonts/hifi-glyphs.ttf index 09aefffdfef007aa94f3cbdfd02a61612c0ee9e7..c139a196d0f70536b980d7cbbad81c416d237e0b 100644 GIT binary patch delta 684 zcmX|;O-Phs5Xb-XywCf*>%Q(6$S&oZx@9eHv}!B62_*z(6xCL4;;xpy=;jLh1+Jh( z>Y;-|hw`~Z*sVi>V9P>>2uv~|=n@!tkdO}2rArZH1jc^Qz|8y(GsFC6?!BS)HJSwh zuwf1guJ-gqFHcTK2Z7;d0F3k9=X$UN0SwOrXo~cQqI-(GC(KMSZ&foL?DFh{Mi9}57s0fdst#H`8NXa}G=0L{sC ze(Jz(-5NkI0PLo+Bj%l^hur{Q2e6Yir*il}w*Wd-S}0?t6W_wG`heJPfQq^7MBZ}$ z>nbp?4DgR-aRiK-7nX+{r+-0bDB0$dt&K`%TN{gXhO)AYZjwzd(Oz({T%rJFH_9_W z%}~l@fRm*p4i;2~&Ft9ZI{QhP;!DLr@-6?&{QlySTIiisFo+nf&y? zVy4k%5F@MqxvQY7cFh^-AZZBA>D4M7hyAs@)MEA3Qw?Wa+-3QK`kR zDeVZ#SUkYmgK|DTDgVa3l$8ww+l*4hKLhU+yPg;w&!5O8G9%+DK&}ooP)2?ks@MPj HXlvsiT0xGP delta 494 zcmX|+Pe>GT6vsbrW_Gp4>>>-+5?hq(sSUw@UQl~C_V^eb z5-UJuYW%_I)Aqmn;9G#$Qab63obA}G1$Kd^bUK-Hj2p5CQUhE~yVJ9^&udmemVlq* z6T{BKQ0f90%fNTnna%Q520>c9hcb?v91A~s5B*Uulbx8F{?oob3GpK^J{IK!=6Zj0 zCeF7VU}|`^t*m@$YF7S*+?0&EB?D5W7UVF3Cs6EQF^^n9FH#Ug{GJ$D=U6E9HrGeVw}Msz}qtW z2(VRVKLP%$+x9h8i1$dNs<5w1qiVKi)Ehe_8MSHe7GB@~tgGD6C2`f_&_(mq(#oFz Dg()->killNodeWithUUID(getSessionUUID()); qCDebug(avatars) << "Changing display name for avatar to" << displayName; } From 32e330320e0e50d84d8d7bb1a03d0831732fcb17 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 11:26:57 -0800 Subject: [PATCH 29/46] Cleanup after rebase --- interface/resources/qml/hifi/NameCard.qml | 17 ++++++++++++----- interface/resources/qml/hifi/Pal.qml | 8 -------- libraries/avatars/src/AvatarData.cpp | 2 +- scripts/system/pal.js | 1 - 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 250dad7f7f..b389891255 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -60,11 +60,15 @@ Item { Rectangle { id: myDisplayName visible: isMyCard - color: "#C5C5C5" - anchors.left: parent.left - anchors.leftMargin: -10 + // Size width: parent.width + 70 height: 35 + // Anchors + anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: -10 + // Style + color: "#C5C5C5" border.color: hifi.colors.blueHighlight border.width: 0 TextInput { @@ -126,7 +130,10 @@ Item { } // Spacer for DisplayName for my card Rectangle { + id: myDisplayNameSpacer width: myDisplayName.width + // Anchors + anchors.top: myDisplayName.bottom height: 5 visible: isMyCard opacity: 0 @@ -160,7 +167,7 @@ Item { // Size width: parent.width // Anchors - anchors.top: displayNameText.bottom + anchors.top: isMyCard ? myDisplayNameSpacer.bottom : displayNameText.bottom // Text Size size: thisNameCard.usernameTextHeight // Text Positioning @@ -182,7 +189,7 @@ Item { Rectangle { id: nameCardVUMeter // Size - width: ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width + width: isMyCard ? gainSlider.width : ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width height: 8 // Anchors anchors.top: spacer.bottom diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 8fa8fe8514..68ad3f811c 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -346,11 +346,6 @@ Rectangle { visible: iAmAdmin color: hifi.colors.lightGrayText } - function letterbox(message) { - letterboxMessage.text = message; - letterboxMessage.visible = true - - } // This Rectangle refers to the [?] popup button next to "NAMES" Rectangle { color: hifi.colors.tableBackgroundLight @@ -411,9 +406,6 @@ Rectangle { onExited: adminHelpText.color = hifi.colors.redHighlight } } - LetterboxMessage { - id: letterboxMessage - } } function findSessionIndex(sessionId, optionalData) { // no findIndex in .qml diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 0381363ef3..0350e73d2e 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1094,7 +1094,7 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { void AvatarData::setDisplayName(const QString& displayName) { _displayName = displayName; - DependencyManager::get()->killNodeWithUUID(getSessionUUID()); + DependencyManager::get()->getDomainHandler().softReset(); qCDebug(avatars) << "Changing display name for avatar to" << displayName; } diff --git a/scripts/system/pal.js b/scripts/system/pal.js index c6ac1056de..6fd386b00f 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -242,7 +242,6 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like MyAvatar.displayName = message.params; } break; - default: default: print('Unrecognized message from Pal.qml:', JSON.stringify(message)); } From e22c1ac30e35b376bfe28b0309536f9e1c5de911 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 11:48:51 -0800 Subject: [PATCH 30/46] Fix the bug --- .../src/DomainServerSettingsManager.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index c8895839ff..c6bcc5af34 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -780,12 +780,12 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer message, SharedNodePointer sendingNode) { - // Before we do any processing on this packet, make sure it comes from a node that is allowed to kick (is an admin) - if (sendingNode->getCanKick()) { - // From the packet, pull the UUID we're identifying - QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - - if (!nodeUUID.isNull()) { + // From the packet, pull the UUID we're identifying + QUuid nodeUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + if (!nodeUUID.isNull()) { + // Before we do any processing on this packet, make sure it comes from a node that is allowed to kick (is an admin) + // OR from a node whose UUID matches the one in the packet + if (sendingNode->getCanKick() || nodeUUID == sendingNode->getUUID()) { // First, make sure we actually have a node with this UUID auto limitedNodeList = DependencyManager::get(); auto matchingNode = limitedNodeList->nodeWithUUID(nodeUUID); @@ -813,12 +813,12 @@ void DomainServerSettingsManager::processUsernameFromIDRequestPacket(QSharedPoin qWarning() << "Node username request received for unknown node. Refusing to process."; } } else { - qWarning() << "Node username request received for invalid node ID. Refusing to process."; + qWarning() << "Refusing to process a username request packet from node" << uuidStringWithoutCurlyBraces(sendingNode->getUUID()) + << ". Either node doesn't have kick permissions or is requesting a username not from their UUID."; } } else { - qWarning() << "Refusing to process a username request packet from node" << uuidStringWithoutCurlyBraces(sendingNode->getUUID()) - << "that does not have kick permissions."; + qWarning() << "Node username request received for invalid node ID. Refusing to process."; } } From 3b56f46206a3267c8016c9959c90958f343f5fb3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 13:18:24 -0800 Subject: [PATCH 31/46] Style changes --- interface/resources/qml/hifi/NameCard.qml | 34 ++++++++++++++--------- libraries/avatars/src/AvatarData.cpp | 3 +- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index b389891255..367ef3b25b 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -28,7 +28,7 @@ Item { property string uuid: "" property string displayName: "" property string userName: "" - property int displayTextHeight: 18 + property real displayNameTextPixelSize: 18 property int usernameTextHeight: 12 property real audioLevel: 0.0 property bool isMyCard: false @@ -68,7 +68,7 @@ Item { anchors.left: parent.left anchors.leftMargin: -10 // Style - color: "#C5C5C5" + color: hifi.colors.textFieldLightBackground border.color: hifi.colors.blueHighlight border.width: 0 TextInput { @@ -77,23 +77,30 @@ Item { text: thisNameCard.displayName maximumLength: 64 clip: true + // Size + width: parent.width + height: parent.height // Anchors - anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left anchors.leftMargin: 10 anchors.rightMargin: editGlyph.implicitWidth + editGlyph.anchors.rightMargin - // Text Positioning - verticalAlignment: TextInput.AlignVCenter - horizontalAlignment: TextInput.AlignLeft // Style color: hifi.colors.darkGray FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } font.family: firaSansSemiBold.name - font.pointSize: thisNameCard.displayTextHeight + font.pixelSize: displayNameTextPixelSize + selectionColor: hifi.colors.blueHighlight + selectedTextColor: "black" + // Text Positioning + verticalAlignment: TextInput.AlignVCenter + horizontalAlignment: TextInput.AlignLeft // Signals onEditingFinished: { pal.sendToScript({method: 'displayNameUpdate', params: text}) focus = false myDisplayName.border.width = 0 + color = hifi.colors.darkGray } } MouseArea { @@ -101,23 +108,24 @@ Item { acceptedButtons: Qt.LeftButton hoverEnabled: true onClicked: { - myDisplayName.border.width = 3 + myDisplayName.border.width = 1 myDisplayNameText.focus ? myDisplayNameText.cursorPosition = myDisplayNameText.positionAt(mouseX, mouseY, TextInput.CursorOnCharacter) : myDisplayNameText.selectAll(); myDisplayNameText.focus = true + myDisplayNameText.color = "black" } onDoubleClicked: { myDisplayNameText.selectAll(); myDisplayNameText.focus = true; } onEntered: myDisplayName.color = hifi.colors.lightGrayText - onExited: myDisplayName.color = "#C5C5C5" + onExited: myDisplayName.color = hifi.colors.textFieldLightBackground } // Edit pencil glyph HiFiGlyphs { id: editGlyph text: hifi.glyphs.editPencil - // Size - size: thisNameCard.displayTextHeight*1.5 + // Text Size + size: displayNameTextPixelSize*1.5 // Anchors anchors.right: parent.right anchors.rightMargin: 5 @@ -150,7 +158,7 @@ Item { // Anchors anchors.top: parent.top // Text Size - size: thisNameCard.displayTextHeight + size: displayNameTextPixelSize // Text Positioning verticalAlignment: Text.AlignVCenter // Style @@ -189,7 +197,7 @@ Item { Rectangle { id: nameCardVUMeter // Size - width: isMyCard ? gainSlider.width : ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width + width: isMyCard ? myDisplayName.width - 20 : ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width height: 8 // Anchors anchors.top: spacer.bottom diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 0350e73d2e..3d09be0679 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1047,7 +1047,7 @@ bool AvatarData::processAvatarIdentity(const Identity& identity) { } if (identity.displayName != _displayName) { - setDisplayName(identity.displayName); + _displayName = identity.displayName; hasIdentityChanged = true; } maybeUpdateSessionDisplayNameFromTransport(identity.sessionDisplayName); @@ -1094,6 +1094,7 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { void AvatarData::setDisplayName(const QString& displayName) { _displayName = displayName; + DependencyManager::get()->getDomainHandler().softReset(); qCDebug(avatars) << "Changing display name for avatar to" << displayName; From e98a40c30e287897fddef8be2fe20f256f7a8485 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 14:43:30 -0800 Subject: [PATCH 32/46] Does this work? --- assignment-client/src/avatars/AvatarMixer.cpp | 12 +++++++++--- .../src/avatars/AvatarMixerClientData.h | 6 +++--- libraries/avatars/src/AvatarData.cpp | 3 ++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 11cbd73970..8ac2f3922b 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -262,8 +262,13 @@ void AvatarMixer::broadcastAvatarData() { // setup a PacketList for the avatarPackets auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData); - if (avatar.getSessionDisplayName().isEmpty() && // We haven't set it yet... - nodeData->getReceivedIdentity()) { // ... but we have processed identity (with possible displayName). + if (nodeData->getAvatarSessionDisplayNameMustChange()) { // ... but we have processed identity (with possible displayName). + const QString& existingBaseDisplayName = nodeData->getBaseDisplayName(); + // No sense guarding against very rare case of a node with no entry, as this will work without the guard and do one less lookup in the common case. + if (--_sessionDisplayNames[existingBaseDisplayName].second <= 0) { + _sessionDisplayNames.remove(existingBaseDisplayName); + } + QString baseName = avatar.getDisplayName().trimmed(); const QRegularExpression curses{ "fuck|shit|damn|cock|cunt" }; // POC. We may eventually want something much more elaborate (subscription?). baseName = baseName.replace(curses, "*"); // Replace rather than remove, so that people have a clue that the person's a jerk. @@ -280,6 +285,7 @@ void AvatarMixer::broadcastAvatarData() { highWater++; soFar.second++; // refcount nodeData->flagIdentityChange(); + nodeData->setAvatarSessionDisplayNameMustChange(false); sendIdentityPacket(nodeData, node); // Tell new node about its sessionUUID. Others will find out below. } @@ -584,7 +590,7 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer mes if (avatar.processAvatarIdentity(identity)) { QMutexLocker nodeDataLocker(&nodeData->getMutex()); nodeData->flagIdentityChange(); - nodeData->setReceivedIdentity(); + nodeData->setAvatarSessionDisplayNameMustChange(); } } } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index f18cfdde1b..38db2e74d2 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -53,8 +53,8 @@ public: HRCTime getIdentityChangeTimestamp() const { return _identityChangeTimestamp; } void flagIdentityChange() { _identityChangeTimestamp = p_high_resolution_clock::now(); } - bool getReceivedIdentity() const { return _gotIdentity; } - void setReceivedIdentity() { _gotIdentity = true; } + bool getAvatarSessionDisplayNameMustChange() const { return _avatarSessionDisplayNameMustChange; } + void setAvatarSessionDisplayNameMustChange(bool set = true) { _avatarSessionDisplayNameMustChange = set; } void setFullRateDistance(float fullRateDistance) { _fullRateDistance = fullRateDistance; } float getFullRateDistance() const { return _fullRateDistance; } @@ -112,7 +112,7 @@ private: std::unordered_set _hasReceivedFirstPacketsFrom; HRCTime _identityChangeTimestamp; - bool _gotIdentity { false }; + bool _avatarSessionDisplayNameMustChange{ false }; float _fullRateDistance = FLT_MAX; float _maxAvatarDistance = FLT_MAX; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 3d09be0679..1fb68fce14 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1094,8 +1094,9 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { void AvatarData::setDisplayName(const QString& displayName) { _displayName = displayName; + _sessionDisplayName = ""; - DependencyManager::get()->getDomainHandler().softReset(); + sendIdentityPacket(); qCDebug(avatars) << "Changing display name for avatar to" << displayName; } From 0a3236dcc91d7ec0c0a392ed10e788094ed93e27 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 16 Jan 2017 14:54:32 -0800 Subject: [PATCH 33/46] handControllerGrab update loop change --- scripts/system/controllers/handControllerGrab.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 2ed09232e6..57698bd0dc 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -3082,7 +3082,7 @@ var handleHandMessages = function(channel, message, sender) { Messages.messageReceived.connect(handleHandMessages); -var TARGET_UPDATE_HZ = 50; // 50hz good enough (no change in logic) +var TARGET_UPDATE_HZ = 60; // 50hz good enough, but we're using update var BASIC_TIMER_INTERVAL_MS = 1000 / TARGET_UPDATE_HZ; var lastInterval = Date.now(); @@ -3095,7 +3095,7 @@ var updateTotalWork = 0; var UPDATE_PERFORMANCE_DEBUGGING = false; -var updateIntervalTimer = Script.setInterval(function(){ +function updateWrapper(){ intervalCount++; var thisInterval = Date.now(); @@ -3141,11 +3141,12 @@ var updateIntervalTimer = Script.setInterval(function(){ updateTotalWork = 0; } -}, BASIC_TIMER_INTERVAL_MS); +} +Script.update.connect(updateWrapper); function cleanup() { Menu.removeMenuItem("Developer", "Show Grab Sphere"); - Script.clearInterval(updateIntervalTimer); + Script.update.disconnect(updateWrapper); rightController.cleanup(); leftController.cleanup(); Controller.disableMapping(MAPPING_NAME); From fd284578073e665df4d9f1b9fd5fd0da4b772c59 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 16 Jan 2017 15:13:28 -0800 Subject: [PATCH 34/46] fix cauterization hack --- .../render-utils/src/MeshPartPayload.cpp | 19 ++++++++++++++++--- libraries/render-utils/src/MeshPartPayload.h | 5 ++++- libraries/render-utils/src/Model.cpp | 2 +- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 5c4c0890a7..e3b2527e67 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -359,8 +359,11 @@ void ModelMeshPartPayload::notifyLocationChanged() { } -void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, const QVector& clusterMatrices) { +void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, + const QVector& clusterMatrices, + const QVector& cauterizedClusterMatrices) { _transform = transform; + _cauterizedTransform = transform; if (clusterMatrices.size() > 0) { _worldBound = AABox(); @@ -373,6 +376,11 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transf _worldBound.transform(transform); if (clusterMatrices.size() == 1) { _transform = _transform.worldTransform(Transform(clusterMatrices[0])); + if (cauterizedClusterMatrices.size() != 0) { + _cauterizedTransform = _cauterizedTransform.worldTransform(Transform(cauterizedClusterMatrices[0])); + } else { + _cauterizedTransform = _transform; + } } } } @@ -527,9 +535,14 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline: } else { batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.clusterBuffer); } + batch.setModelTransform(_transform); + } else { + if (canCauterize && _model->getCauterizeBones()) { + batch.setModelTransform(_cauterizedTransform); + } else { + batch.setModelTransform(_transform); + } } - - batch.setModelTransform(_transform); } void ModelMeshPartPayload::startFade() { diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index b048dc903f..b7a8cf63f0 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -85,7 +85,9 @@ public: typedef Payload::DataPointer Pointer; void notifyLocationChanged() override; - void updateTransformForSkinnedMesh(const Transform& transform, const QVector& clusterMatrices); + void updateTransformForSkinnedMesh(const Transform& transform, + const QVector& clusterMatrices, + const QVector& cauterizedClusterMatrices); // Entity fade in void startFade(); @@ -106,6 +108,7 @@ public: Model* _model; + Transform _cauterizedTransform; int _meshIndex; int _shapeID; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7c1a6e14d0..3a3095458c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -238,7 +238,7 @@ void Model::updateRenderItems() { // update the model transform and bounding box for this render item. const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); - data.updateTransformForSkinnedMesh(modelTransform, state.clusterMatrices); + data.updateTransformForSkinnedMesh(modelTransform, state.clusterMatrices, state.cauterizedClusterMatrices); } } }); From e72c25736e804bbd625c5855b6d85e7b15086eff Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 15:21:18 -0800 Subject: [PATCH 35/46] Cleanup --- assignment-client/src/avatars/AvatarMixer.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 8ac2f3922b..4127719b7b 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -262,9 +262,8 @@ void AvatarMixer::broadcastAvatarData() { // setup a PacketList for the avatarPackets auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData); - if (nodeData->getAvatarSessionDisplayNameMustChange()) { // ... but we have processed identity (with possible displayName). + if (nodeData->getAvatarSessionDisplayNameMustChange()) { const QString& existingBaseDisplayName = nodeData->getBaseDisplayName(); - // No sense guarding against very rare case of a node with no entry, as this will work without the guard and do one less lookup in the common case. if (--_sessionDisplayNames[existingBaseDisplayName].second <= 0) { _sessionDisplayNames.remove(existingBaseDisplayName); } @@ -286,7 +285,7 @@ void AvatarMixer::broadcastAvatarData() { soFar.second++; // refcount nodeData->flagIdentityChange(); nodeData->setAvatarSessionDisplayNameMustChange(false); - sendIdentityPacket(nodeData, node); // Tell new node about its sessionUUID. Others will find out below. + sendIdentityPacket(nodeData, node); // Tell node whose name changed about its new session display name. Others will find out below. } // this is an AGENT we have received head data from @@ -590,7 +589,7 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer mes if (avatar.processAvatarIdentity(identity)) { QMutexLocker nodeDataLocker(&nodeData->getMutex()); nodeData->flagIdentityChange(); - nodeData->setAvatarSessionDisplayNameMustChange(); + nodeData->setAvatarSessionDisplayNameMustChange(true); } } } From 1e8effdcc42d85b6326b0c4d240088e23b36cee1 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 15:28:53 -0800 Subject: [PATCH 36/46] Packet verison bump --- libraries/networking/src/udt/PacketHeaders.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index c012ed8f67..9bbd139138 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -211,7 +211,8 @@ enum class AvatarMixerPacketVersion : PacketVersion { HandControllerJoints, HasKillAvatarReason, SessionDisplayName, - Unignore + Unignore, + ImmediateSessionDisplayNameUpdates }; enum class DomainConnectRequestVersion : PacketVersion { From 6c701bb0f0124002fb8e57c6a1cec8cfec1394ab Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 16 Jan 2017 18:22:53 -0800 Subject: [PATCH 37/46] remove ignored avatars from PAL when they disconnect --- interface/resources/qml/hifi/Pal.qml | 4 ++++ interface/src/avatar/AvatarManager.cpp | 5 +++++ libraries/networking/src/NodeList.cpp | 12 ++++++++++++ libraries/networking/src/NodeList.h | 2 ++ .../script-engine/src/UsersScriptingInterface.h | 6 ++++++ scripts/system/pal.js | 8 +++++++- 6 files changed, 36 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 3438baa217..a57e76f864 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -502,6 +502,10 @@ Rectangle { ignored = {}; gainSliderValueDB = {}; break; + case 'avatarDisconnected': + var sessionID = message.params[0]; + delete ignored[sessionID]; + break; default: console.log('Unrecognized message:', JSON.stringify(message)); } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 1f5726acba..848218a27e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -261,6 +261,11 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble || removalReason == YourAvatarEnteredTheirBubble) { DependencyManager::get()->radiusIgnoreNodeBySessionID(avatar->getSessionUUID(), true); } + if (removalReason == KillAvatarReason::AvatarDisconnected) { + // remove from node sets, if present + DependencyManager::get()->maintainIgnoreMuteSets(avatar->getSessionUUID()); + DependencyManager::get()->avatarDisconnected(avatar->getSessionUUID()); + } _avatarFades.push_back(removedAvatar); } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 98a563c4e5..0ad31b70fe 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -847,6 +847,18 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { } } +// removes this UUID from ignore and mute lists. +void NodeList::maintainIgnoreMuteSets(const QUuid& nodeID) { + // don't remove yourself, or nobody + if (!nodeID.isNull() && _sessionUUID != nodeID) { + QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; + QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; + _ignoredNodeIDs.unsafe_erase(nodeID); + _personalMutedNodeIDs.unsafe_erase(nodeID); + qCDebug(networking) << "removed" << nodeID.toString() << "from ignore/mute sets (if present)"; + } +} + bool NodeList::isIgnoringNode(const QUuid& nodeID) const { QReadLocker ignoredSetLocker{ &_ignoredSetLock }; return _ignoredNodeIDs.find(nodeID) != _ignoredNodeIDs.cend(); diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 5c477303e2..4cbe3b1c3b 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -90,6 +90,8 @@ public: bool getRequestsDomainListData() { return _requestsDomainListData; } void setRequestsDomainListData(bool isRequesting); + void maintainIgnoreMuteSets(const QUuid& nodeID); + public slots: void reset(); void sendDomainServerCheckIn(); diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 0b6b7855b5..2dcff02c77 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -139,6 +139,12 @@ signals: */ void usernameFromIDReply(const QString& nodeID, const QString& username, const QString& machineFingerprint); + /**jsdoc + * Notifies scripts that a user has disconnected from the domain + * @function Users.avatar.avatarDisconnected + */ + void avatarDisconnected(const QUuid& nodeID); + private: bool getRequestsDomainListData(); void setRequestsDomainListData(bool requests); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 5c5b84e3e8..ad7d2bd7b5 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -580,7 +580,11 @@ function onClicked() { } pal.setVisible(!pal.visible); } - +function avatarDisconnected(nodeID) { + // remove from the pal list + print("got avatarDisconnected for " + nodeID); + pal.sendToQml({method: 'avatarDisconnected', params: [nodeID]}); +} // // Button state. // @@ -593,6 +597,8 @@ button.clicked.connect(onClicked); pal.visibleChanged.connect(onVisibleChanged); pal.closed.connect(off); Users.usernameFromIDReply.connect(usernameFromIDReply); +Users.avatarDisconnected.connect(avatarDisconnected); + function clearLocalQMLDataAndClosePAL() { pal.sendToQml({ method: 'clearLocalQMLData' }); if (pal.visible) { From 6c07a9aece6920794cc0d69a5f60d585911877ae Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 16 Jan 2017 19:06:36 -0800 Subject: [PATCH 38/46] remove debuggng logspam --- libraries/networking/src/NodeList.cpp | 1 - scripts/system/pal.js | 1 - 2 files changed, 2 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 0ad31b70fe..8451b2c4a0 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -855,7 +855,6 @@ void NodeList::maintainIgnoreMuteSets(const QUuid& nodeID) { QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; _ignoredNodeIDs.unsafe_erase(nodeID); _personalMutedNodeIDs.unsafe_erase(nodeID); - qCDebug(networking) << "removed" << nodeID.toString() << "from ignore/mute sets (if present)"; } } diff --git a/scripts/system/pal.js b/scripts/system/pal.js index ad7d2bd7b5..7ecce80480 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -582,7 +582,6 @@ function onClicked() { } function avatarDisconnected(nodeID) { // remove from the pal list - print("got avatarDisconnected for " + nodeID); pal.sendToQml({method: 'avatarDisconnected', params: [nodeID]}); } // From 5e49e8025ab84d11a8363e058ee5b837961e5b68 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 16 Jan 2017 21:06:38 -0600 Subject: [PATCH 39/46] improve comment in domain settings --- domain-server/resources/describe-settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index dd0e4ad4a1..c813ffc54c 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -40,7 +40,7 @@ { "name": "local_port", "label": "Local UDP Port", - "help": "This is the local port your domain-server binds to for UDP connections.
Depending on your router, this may need to be changed to run multiple full automatic networking domain-servers in the same network.", + "help": "This is the local port your domain-server binds to for UDP connections.
Depending on your router, this may need to be changed to unique values for each domain-server in order to run multiple full automatic networking domain-servers in the same network. You can use the value 0 to have the domain-server select a random port, which will help in preventing port collisions.", "default": "40102", "type": "int", "advanced": true From 2460e89a574613ab615c05c0d2ba283a6d2a5d71 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 17 Jan 2017 09:53:04 -0800 Subject: [PATCH 40/46] CR feedback --- interface/src/avatar/AvatarManager.cpp | 2 +- libraries/networking/src/NodeList.cpp | 3 +-- libraries/networking/src/NodeList.h | 2 +- scripts/system/pal.js | 1 + 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 848218a27e..ef08a463f4 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -263,7 +263,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar } if (removalReason == KillAvatarReason::AvatarDisconnected) { // remove from node sets, if present - DependencyManager::get()->maintainIgnoreMuteSets(avatar->getSessionUUID()); + DependencyManager::get()->removeFromIgnoreMuteSets(avatar->getSessionUUID()); DependencyManager::get()->avatarDisconnected(avatar->getSessionUUID()); } _avatarFades.push_back(removedAvatar); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 8451b2c4a0..0fcd207b94 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -847,8 +847,7 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { } } -// removes this UUID from ignore and mute lists. -void NodeList::maintainIgnoreMuteSets(const QUuid& nodeID) { +void NodeList::removeFromIgnoreMuteSets(const QUuid& nodeID) { // don't remove yourself, or nobody if (!nodeID.isNull() && _sessionUUID != nodeID) { QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 4cbe3b1c3b..c4564c0889 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -90,7 +90,7 @@ public: bool getRequestsDomainListData() { return _requestsDomainListData; } void setRequestsDomainListData(bool isRequesting); - void maintainIgnoreMuteSets(const QUuid& nodeID); + void removeFromIgnoreMuteSets(const QUuid& nodeID); public slots: void reset(); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 7ecce80480..fb0d2b310b 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -620,6 +620,7 @@ Script.scriptEnding.connect(function () { Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL); Messages.unsubscribe(CHANNEL); Messages.messageReceived.disconnect(receiveMessage); + Users.avatarDisconnected.disconnect(avatarDisconnected); off(); }); From 1e04aebb8d33e9e9bb4a4e072690dc7d5b7f381f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 17 Jan 2017 11:25:40 -0800 Subject: [PATCH 41/46] add --fast-hearbeat command line switch for 1s stats --- interface/src/Application.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ceda6c6598..4f35b10a1b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1238,8 +1238,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Add periodic checks to send user activity data static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000; - static int SEND_STATS_INTERVAL_MS = 10000; static int NEARBY_AVATAR_RADIUS_METERS = 10; + + // setup the stats interval depending on if the 1s faster hearbeat was requested + static const QString FAST_STATS_ARG = "--fast-heartbeat"; + static int SEND_STATS_INTERVAL_MS = arguments().indexOf(FAST_STATS_ARG) != -1 ? 1000 : 10000; static glm::vec3 lastAvatarPosition = myAvatar->getPosition(); static glm::mat4 lastHMDHeadPose = getHMDSensorPose(); From 246f5fb7f5da02172c45e8c8032bb8274ffd8ef0 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 17 Jan 2017 11:51:09 -0800 Subject: [PATCH 42/46] Add log; fix whitespace --- assignment-client/src/avatars/AvatarMixer.cpp | 4 +++- libraries/networking/src/udt/PacketHeaders.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 4127719b7b..cd866cecb2 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -280,12 +280,14 @@ void AvatarMixer::broadcastAvatarData() { QPair& soFar = _sessionDisplayNames[baseName]; // Inserts and answers 0, 0 if not already present, which is what we want. int& highWater = soFar.first; nodeData->setBaseDisplayName(baseName); - avatar.setSessionDisplayName((highWater > 0) ? baseName + "_" + QString::number(highWater) : baseName); + QString sessionDisplayName = (highWater > 0) ? baseName + "_" + QString::number(highWater) : baseName; + avatar.setSessionDisplayName(sessionDisplayName); highWater++; soFar.second++; // refcount nodeData->flagIdentityChange(); nodeData->setAvatarSessionDisplayNameMustChange(false); sendIdentityPacket(nodeData, node); // Tell node whose name changed about its new session display name. Others will find out below. + qDebug() << "Giving session display name" << sessionDisplayName << "to node with ID" << node->getUUID(); } // this is an AGENT we have received head data from diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 9bbd139138..5cef6013d9 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -212,7 +212,7 @@ enum class AvatarMixerPacketVersion : PacketVersion { HasKillAvatarReason, SessionDisplayName, Unignore, - ImmediateSessionDisplayNameUpdates + ImmediateSessionDisplayNameUpdates }; enum class DomainConnectRequestVersion : PacketVersion { From 9b1aaf3bfeb9a136a79396f75565eb02abd110a0 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 17 Jan 2017 12:09:47 -0800 Subject: [PATCH 43/46] CR feedback --- interface/src/avatar/AvatarManager.cpp | 3 +-- libraries/script-engine/src/UsersScriptingInterface.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index ef08a463f4..b0dc9922ff 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -260,8 +260,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar } if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble || removalReason == YourAvatarEnteredTheirBubble) { DependencyManager::get()->radiusIgnoreNodeBySessionID(avatar->getSessionUUID(), true); - } - if (removalReason == KillAvatarReason::AvatarDisconnected) { + } else if (removalReason == KillAvatarReason::AvatarDisconnected) { // remove from node sets, if present DependencyManager::get()->removeFromIgnoreMuteSets(avatar->getSessionUUID()); DependencyManager::get()->avatarDisconnected(avatar->getSessionUUID()); diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 2dcff02c77..758868ac63 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -142,6 +142,7 @@ signals: /**jsdoc * Notifies scripts that a user has disconnected from the domain * @function Users.avatar.avatarDisconnected + * @param {nodeID} NodeID The session ID of the avatar that has disconnected */ void avatarDisconnected(const QUuid& nodeID); From 59ff970d5b400867506418da8761442fdca6dc3d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 17 Jan 2017 15:01:02 -0800 Subject: [PATCH 44/46] CR feedback --- interface/resources/qml/hifi/NameCard.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 367ef3b25b..2725ea1617 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -75,7 +75,7 @@ Item { id: myDisplayNameText // Properties text: thisNameCard.displayName - maximumLength: 64 + maximumLength: 256 clip: true // Size width: parent.width @@ -84,7 +84,8 @@ Item { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 10 - anchors.rightMargin: editGlyph.implicitWidth + editGlyph.anchors.rightMargin + anchors.right: parent.right + anchors.rightMargin: editGlyph.width + editGlyph.anchors.rightMargin // Style color: hifi.colors.darkGray FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } @@ -98,6 +99,7 @@ Item { // Signals onEditingFinished: { pal.sendToScript({method: 'displayNameUpdate', params: text}) + cursorPosition = 0 focus = false myDisplayName.border.width = 0 color = hifi.colors.darkGray From cbc89e77ab11a9d1a0d0657b4eb9405e6b641618 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 17 Jan 2017 09:32:58 -0800 Subject: [PATCH 45/46] Consume fewer resources in AssetServer when interface is running locally --- assignment-client/src/assets/AssetServer.cpp | 48 +++++++++++++++++ interface/src/main.cpp | 2 +- libraries/shared/src/SharedUtil.cpp | 54 +++++++++++++++++++- libraries/shared/src/SharedUtil.h | 4 ++ 4 files changed, 106 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2fbe2f6dfe..69f3d83583 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -12,6 +12,8 @@ #include "AssetServer.h" +#include + #include #include #include @@ -21,6 +23,7 @@ #include #include +#include #include #include "NetworkLogging.h" @@ -30,6 +33,37 @@ const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; +bool interfaceRunning() { + bool result = false; + +#ifdef Q_OS_WIN + QSharedMemory sharedMemory { getInterfaceSharedMemoryName() }; + result = sharedMemory.attach(QSharedMemory::ReadOnly); + if (result) { + sharedMemory.detach(); + } +#endif + return result; +} + +void updateConsumedCores() { + static bool wasInterfaceRunning = false; + bool isInterfaceRunning = interfaceRunning(); + // If state is unchanged, return early + if (isInterfaceRunning == wasInterfaceRunning) { + return; + } + + wasInterfaceRunning = isInterfaceRunning; + auto coreCount = std::thread::hardware_concurrency(); + if (isInterfaceRunning) { + coreCount = coreCount > 4 ? 2 : 1; + } + qDebug() << "Setting max consumed cores to " << coreCount; + setMaxCores(coreCount); +} + + AssetServer::AssetServer(ReceivedMessage& message) : ThreadedAssignment(message), _taskPool(this) @@ -45,6 +79,20 @@ AssetServer::AssetServer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation"); + +#ifdef Q_OS_WIN + updateConsumedCores(); + QTimer* timer = new QTimer(this); + auto timerConnection = connect(timer, &QTimer::timeout, [] { + updateConsumedCores(); + }); + connect(qApp, &QCoreApplication::aboutToQuit, [this, timerConnection] { + disconnect(timerConnection); + }); + timer->setInterval(1000); + timer->setTimerType(Qt::CoarseTimer); + timer->start(); +#endif } void AssetServer::run() { diff --git a/interface/src/main.cpp b/interface/src/main.cpp index c83f7a989c..d33dba535e 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -56,7 +56,7 @@ int main(int argc, const char* argv[]) { QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN); QCoreApplication::setApplicationVersion(BuildInfo::VERSION); - QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME"); + const QString& applicationName = getInterfaceSharedMemoryName(); bool instanceMightBeRunning = true; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 89116aa924..4b8699befd 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include @@ -1022,4 +1024,54 @@ bool getProcessorInfo(ProcessorInfo& info) { #endif return false; -} \ No newline at end of file +} + + +const QString& getInterfaceSharedMemoryName() { + static const QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME"); + return applicationName; +} + +const std::vector& getAvailableCores() { + static std::vector availableCores; +#ifdef Q_OS_WIN + static std::once_flag once; + std::call_once(once, [&] { + DWORD_PTR defaultProcessAffinity = 0, defaultSystemAffinity = 0; + HANDLE process = GetCurrentProcess(); + GetProcessAffinityMask(process, &defaultProcessAffinity, &defaultSystemAffinity); + for (uint64_t i = 0; i < sizeof(DWORD_PTR) * 8; ++i) { + DWORD_PTR coreMask = 1; + coreMask <<= i; + if (0 != (defaultSystemAffinity & coreMask)) { + availableCores.push_back(i); + } + } + }); +#endif + return availableCores; +} + +void setMaxCores(uint8_t maxCores) { +#ifdef Q_OS_WIN + HANDLE process = GetCurrentProcess(); + auto availableCores = getAvailableCores(); + if (availableCores.size() <= maxCores) { + DWORD_PTR currentProcessAffinity = 0, currentSystemAffinity = 0; + GetProcessAffinityMask(process, ¤tProcessAffinity, ¤tSystemAffinity); + SetProcessAffinityMask(GetCurrentProcess(), currentSystemAffinity); + return; + } + + DWORD_PTR newProcessAffinity = 0; + while (maxCores) { + int index = randIntInRange(0, (int)availableCores.size() - 1); + DWORD_PTR coreMask = 1; + coreMask <<= availableCores[index]; + newProcessAffinity |= coreMask; + availableCores.erase(availableCores.begin() + index); + maxCores--; + } + SetProcessAffinityMask(process, newProcessAffinity); +#endif +} diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 77204c9608..0f30842f47 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -231,4 +231,8 @@ struct ProcessorInfo { bool getProcessorInfo(ProcessorInfo& info); +const QString& getInterfaceSharedMemoryName(); + +void setMaxCores(uint8_t maxCores); + #endif // hifi_SharedUtil_h From a593a2116a069bc8625e8ad2ca57f9d629f56000 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 17 Jan 2017 13:40:19 -0800 Subject: [PATCH 46/46] Removing magic numbers --- assignment-client/src/assets/AssetServer.cpp | 9 +++++++-- libraries/shared/src/SharedUtil.cpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 69f3d83583..2498af8010 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -31,6 +31,11 @@ #include "SendAssetTask.h" #include "UploadAssetTask.h" +static const uint8_t MIN_CORES_FOR_MULTICORE = 4; +static const uint8_t CPU_AFFINITY_COUNT_HIGH = 2; +static const uint8_t CPU_AFFINITY_COUNT_LOW = 1; +static const int INTERFACE_RUNNING_CHECK_FREQUENCY_MS = 1000; + const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; bool interfaceRunning() { @@ -57,7 +62,7 @@ void updateConsumedCores() { wasInterfaceRunning = isInterfaceRunning; auto coreCount = std::thread::hardware_concurrency(); if (isInterfaceRunning) { - coreCount = coreCount > 4 ? 2 : 1; + coreCount = coreCount > MIN_CORES_FOR_MULTICORE ? CPU_AFFINITY_COUNT_HIGH : CPU_AFFINITY_COUNT_LOW; } qDebug() << "Setting max consumed cores to " << coreCount; setMaxCores(coreCount); @@ -89,7 +94,7 @@ AssetServer::AssetServer(ReceivedMessage& message) : connect(qApp, &QCoreApplication::aboutToQuit, [this, timerConnection] { disconnect(timerConnection); }); - timer->setInterval(1000); + timer->setInterval(INTERFACE_RUNNING_CHECK_FREQUENCY_MS); timer->setTimerType(Qt::CoarseTimer); timer->start(); #endif diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 4b8699befd..a7e251f0e0 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -1040,7 +1040,7 @@ const std::vector& getAvailableCores() { DWORD_PTR defaultProcessAffinity = 0, defaultSystemAffinity = 0; HANDLE process = GetCurrentProcess(); GetProcessAffinityMask(process, &defaultProcessAffinity, &defaultSystemAffinity); - for (uint64_t i = 0; i < sizeof(DWORD_PTR) * 8; ++i) { + for (uint64_t i = 0; i < sizeof(DWORD_PTR) * BITS_IN_BYTE; ++i) { DWORD_PTR coreMask = 1; coreMask <<= i; if (0 != (defaultSystemAffinity & coreMask)) {