From 90b77030d5c7da0e88454b503de783bb7e85a080 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 7 Mar 2018 02:55:47 +0100 Subject: [PATCH 001/380] MyAvatar.hasScriptedBlendshapes property --- interface/src/avatar/MyAvatar.h | 4 ++++ interface/src/avatar/MyHead.cpp | 7 ++++--- libraries/avatars/src/AvatarData.cpp | 3 ++- libraries/avatars/src/AvatarData.h | 2 ++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fa5206e128..f2d1baf0aa 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -133,6 +133,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(AudioListenerMode audioListenerModeHead READ getAudioListenerModeHead) Q_PROPERTY(AudioListenerMode audioListenerModeCamera READ getAudioListenerModeCamera) Q_PROPERTY(AudioListenerMode audioListenerModeCustom READ getAudioListenerModeCustom) + Q_PROPERTY(bool hasScriptedBlendshapes READ getHasScriptedBlendshapes WRITE setHasScriptedBlendshapes) //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity) Q_PROPERTY(glm::vec3 leftHandPosition READ getLeftHandPosition) @@ -654,6 +655,8 @@ private: virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override; void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; setEnableMeshVisible(shouldRender); } bool getShouldRenderLocally() const { return _shouldRender; } + void setHasScriptedBlendshapes(bool hasScriptedBlendshapes) { _hasScriptedBlendShapes = hasScriptedBlendshapes; } + bool getHasScriptedBlendshapes() const override { return _hasScriptedBlendShapes; } bool isMyAvatar() const override { return true; } virtual int parseDataFromBuffer(const QByteArray& buffer) override; virtual glm::vec3 getSkeletonPosition() const override; @@ -764,6 +767,7 @@ private: bool _hmdRollControlEnabled { true }; float _hmdRollControlDeadZone { ROLL_CONTROL_DEAD_ZONE_DEFAULT }; float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT }; + bool _hasScriptedBlendShapes { false }; // working copy -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access glm::mat4 _sensorToWorldMatrix { glm::mat4() }; diff --git a/interface/src/avatar/MyHead.cpp b/interface/src/avatar/MyHead.cpp index cad2f9e5d0..b7b8aa5e52 100644 --- a/interface/src/avatar/MyHead.cpp +++ b/interface/src/avatar/MyHead.cpp @@ -46,9 +46,10 @@ void MyHead::simulate(float deltaTime) { auto player = DependencyManager::get(); // Only use face trackers when not playing back a recording. if (!player->isPlaying()) { - FaceTracker* faceTracker = qApp->getActiveFaceTracker(); - _isFaceTrackerConnected = faceTracker != nullptr && !faceTracker->isMuted(); - if (_isFaceTrackerConnected) { + auto faceTracker = qApp->getActiveFaceTracker(); + bool hasActualFaceTrackerConnected = faceTracker && !faceTracker->isMuted(); + _isFaceTrackerConnected = hasActualFaceTrackerConnected || _owningAvatar->getHasScriptedBlendshapes(); + if (hasActualFaceTrackerConnected) { _transientBlendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); if (typeid(*faceTracker) == typeid(DdeFaceTracker)) { diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1bbc8cc1a5..dcaae59a38 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -300,7 +300,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent tranlationChangedSince(lastSentTime) || parentInfoChangedSince(lastSentTime)); - hasFaceTrackerInfo = !dropFaceTracking && hasFaceTracker() && (sendAll || faceTrackerInfoChangedSince(lastSentTime)); + hasFaceTrackerInfo = !dropFaceTracking && (hasFaceTracker() || getHasScriptedBlendshapes()) && + (sendAll || faceTrackerInfoChangedSince(lastSentTime)); hasJointData = sendAll || !sendMinimum; hasJointDefaultPoseFlags = hasJointData; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index e927120b07..1f6d2e3630 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -497,6 +497,8 @@ public: float getDomainLimitedScale() const; + virtual bool getHasScriptedBlendshapes() const { return false; } + /**jsdoc * returns the minimum scale allowed for this avatar in the current domain. * This value can change as the user changes avatars or when changing domains. From a896e9872cb27a4077120e8d3addc5e1f8f5a54d Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 14 Mar 2018 17:09:23 -0700 Subject: [PATCH 002/380] adressing the avatar vissibility switch --- interface/src/avatar/MyAvatar.cpp | 3 ++- .../avatars-renderer/src/avatars-renderer/Avatar.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9620a2dcec..f18b2ed42c 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1114,7 +1114,8 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) { } void MyAvatar::setEnableMeshVisible(bool isEnabled) { - _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); + // TODO: This should tell the main MetaRenderItem of the Avatar to be hidden to control vsisiblity since the model is culled by the MetaRI. + _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1, true); } void MyAvatar::setEnableInverseKinematics(bool isEnabled) { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 65145d4c88..f90f3660a0 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -52,7 +52,13 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f); namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) { - return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1).withMetaCullGroup(); + ItemKey::Builder keyBuilder = ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1).withMetaCullGroup(); + auto avatarPtr = static_pointer_cast(avatar); + auto model = avatarPtr->getSkeletonModel(); + if (model && !model->isVisible()) { + keyBuilder.withInvisible(); + } + return keyBuilder.build(); } template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) { return static_pointer_cast(avatar)->getBounds(); From 2fc23d799ad8fbca48e795835546662e90744c26 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 15 Mar 2018 18:05:58 -0700 Subject: [PATCH 003/380] adding the correct flag maybe? --- libraries/render-utils/src/CauterizedModel.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 1596f7ba83..3c6a0df850 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -220,6 +220,7 @@ void CauterizedModel::updateRenderItems() { bool isLayeredInFront = self->isLayeredInFront(); bool isLayeredInHUD = self->isLayeredInHUD(); bool enableCauterization = self->getEnableCauterization(); + bool isGroupCulled = self->isGroupCulled(); render::Transaction transaction; for (int i = 0; i < (int)self->_modelMeshRenderItemIDs.size(); i++) { @@ -234,7 +235,7 @@ void CauterizedModel::updateRenderItems() { bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, - isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, canCastShadow, enableCauterization](CauterizedMeshPartPayload& data) { + isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, canCastShadow, enableCauterization, isGroupCulled](CauterizedMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions, cauterizedMeshState.clusterDualQuaternions); @@ -276,7 +277,7 @@ void CauterizedModel::updateRenderItems() { data.updateTransformForCauterizedMesh(renderTransform); data.setEnableCauterization(enableCauterization); - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, render::ItemKey::TAG_BITS_ALL); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, render::ItemKey::TAG_BITS_ALL, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); }); From 5cdcf1c53e6b158d3619a71903b4476a9d20164a Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Tue, 17 Apr 2018 11:53:37 +0300 Subject: [PATCH 004/380] Eliminated spurious "resolved_item" warnings in CMake Previously, building the project produced many warnings with this message: "resolved_item == resolved_embedded_item - not copying..." These warnings are distracting as they make it difficult to see actual warnings. This commit changes the warnings to status messages. This fix was copied from: https://github.com/jherico/OculusMinimalExample/blob/master/cmake/templates/FixupBundlePostBuild.cmake.in --- cmake/templates/FixupBundlePostBuild.cmake.in | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/cmake/templates/FixupBundlePostBuild.cmake.in b/cmake/templates/FixupBundlePostBuild.cmake.in index 57379bb48b..4ebb0ea1a6 100644 --- a/cmake/templates/FixupBundlePostBuild.cmake.in +++ b/cmake/templates/FixupBundlePostBuild.cmake.in @@ -11,6 +11,36 @@ include(BundleUtilities) +# replace copy_resolved_item_into_bundle +# +# The official version of copy_resolved_item_into_bundle will print out a "warning:" when +# the resolved item matches the resolved embedded item. This not not really an issue that +# should rise to the level of a "warning" so we replace this message with a "status:" +# +# Source: https://github.com/jherico/OculusMinimalExample/blob/master/cmake/templates/FixupBundlePostBuild.cmake.in +# +function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item) + if (WIN32) + # ignore case on Windows + string(TOLOWER "${resolved_item}" resolved_item_compare) + string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) + else() + set(resolved_item_compare "${resolved_item}") + set(resolved_embedded_item_compare "${resolved_embedded_item}") + endif() + + if ("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") + # this is our only change from the original version + message(STATUS "status: resolved_item == resolved_embedded_item - not copying...") + else() + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") + if(UNIX AND NOT APPLE) + file(RPATH_REMOVE FILE "${resolved_embedded_item}") + endif() + endif() +endfunction() + function(gp_resolved_file_type_override resolved_file type_var) if( file MATCHES ".*VCRUNTIME140.*" ) set(type "system" PARENT_SCOPE) From 50eaf3e166bbe76cac76214788be2c4120cd1e9b Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Tue, 17 Apr 2018 12:14:45 +0300 Subject: [PATCH 005/380] Fixed CMakeLists.txt for 'oven' to work in Linux --- tools/oven/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/oven/CMakeLists.txt b/tools/oven/CMakeLists.txt index 71bb997303..1b77a2585f 100644 --- a/tools/oven/CMakeLists.txt +++ b/tools/oven/CMakeLists.txt @@ -11,7 +11,7 @@ if (WIN32) elseif (UNIX AND NOT APPLE) find_package(Threads REQUIRED) if(THREADS_HAVE_PTHREAD_ARG) - target_compile_options(PUBLIC oven "-pthread") + target_compile_options(oven PUBLIC "-pthread") endif() elseif (APPLE) # Fix up the rpath so macdeployqt works From cd06067030ad1d7ab791361df35aa41fd456bf11 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Wed, 18 Apr 2018 10:18:29 +0300 Subject: [PATCH 006/380] Fixed based on PR review --- cmake/templates/FixupBundlePostBuild.cmake.in | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmake/templates/FixupBundlePostBuild.cmake.in b/cmake/templates/FixupBundlePostBuild.cmake.in index 4ebb0ea1a6..bb96fe49f3 100644 --- a/cmake/templates/FixupBundlePostBuild.cmake.in +++ b/cmake/templates/FixupBundlePostBuild.cmake.in @@ -33,10 +33,9 @@ function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item) # this is our only change from the original version message(STATUS "status: resolved_item == resolved_embedded_item - not copying...") else() - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") - if(UNIX AND NOT APPLE) - file(RPATH_REMOVE FILE "${resolved_embedded_item}") + if (UNIX AND NOT APPLE) + file(RPATH_REMOVE FILE "${resolved_embedded_item}") endif() endif() endfunction() From b0187ecfd3dfdceb084884a72cc1a432f6018ebf Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 24 Apr 2018 19:24:23 +0200 Subject: [PATCH 007/380] add MyAvatar.hasAudioEnabledFaceMovement API property which is enabled by default --- interface/src/avatar/MyAvatar.h | 4 +++ interface/src/avatar/MyHead.cpp | 45 ++++++++++++++++-------------- libraries/avatars/src/AvatarData.h | 1 + 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index b8c9e4d595..537b5de8d8 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -134,6 +134,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(AudioListenerMode audioListenerModeCamera READ getAudioListenerModeCamera) Q_PROPERTY(AudioListenerMode audioListenerModeCustom READ getAudioListenerModeCustom) Q_PROPERTY(bool hasScriptedBlendshapes READ getHasScriptedBlendshapes WRITE setHasScriptedBlendshapes) + Q_PROPERTY(bool hasAudioEnabledFaceMovement READ getHasAudioEnabledFaceMovement WRITE setHasAudioEnabledFaceMovement) //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity) Q_PROPERTY(glm::vec3 leftHandPosition READ getLeftHandPosition) @@ -684,6 +685,8 @@ private: bool getShouldRenderLocally() const { return _shouldRender; } void setHasScriptedBlendshapes(bool hasScriptedBlendshapes) { _hasScriptedBlendShapes = hasScriptedBlendshapes; } bool getHasScriptedBlendshapes() const override { return _hasScriptedBlendShapes; } + void setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement) { _hasAudioEnabledFaceMovement = hasAudioEnabledFaceMovement; } + bool getHasAudioEnabledFaceMovement() const override { return _hasAudioEnabledFaceMovement; } bool isMyAvatar() const override { return true; } virtual int parseDataFromBuffer(const QByteArray& buffer) override; virtual glm::vec3 getSkeletonPosition() const override; @@ -793,6 +796,7 @@ private: float _hmdRollControlDeadZone { ROLL_CONTROL_DEAD_ZONE_DEFAULT }; float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT }; bool _hasScriptedBlendShapes { false }; + bool _hasAudioEnabledFaceMovement { true }; // working copy -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access glm::mat4 _sensorToWorldMatrix { glm::mat4() }; diff --git a/interface/src/avatar/MyHead.cpp b/interface/src/avatar/MyHead.cpp index b7b8aa5e52..ed38fdd004 100644 --- a/interface/src/avatar/MyHead.cpp +++ b/interface/src/avatar/MyHead.cpp @@ -47,29 +47,32 @@ void MyHead::simulate(float deltaTime) { // Only use face trackers when not playing back a recording. if (!player->isPlaying()) { auto faceTracker = qApp->getActiveFaceTracker(); - bool hasActualFaceTrackerConnected = faceTracker && !faceTracker->isMuted(); + const bool hasActualFaceTrackerConnected = faceTracker && !faceTracker->isMuted(); _isFaceTrackerConnected = hasActualFaceTrackerConnected || _owningAvatar->getHasScriptedBlendshapes(); - if (hasActualFaceTrackerConnected) { - _transientBlendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); - - if (typeid(*faceTracker) == typeid(DdeFaceTracker)) { - - if (Menu::getInstance()->isOptionChecked(MenuOption::UseAudioForMouth)) { - calculateMouthShapes(deltaTime); - - const int JAW_OPEN_BLENDSHAPE = 21; - const int MMMM_BLENDSHAPE = 34; - const int FUNNEL_BLENDSHAPE = 40; - const int SMILE_LEFT_BLENDSHAPE = 28; - const int SMILE_RIGHT_BLENDSHAPE = 29; - _transientBlendshapeCoefficients[JAW_OPEN_BLENDSHAPE] += _audioJawOpen; - _transientBlendshapeCoefficients[SMILE_LEFT_BLENDSHAPE] += _mouth4; - _transientBlendshapeCoefficients[SMILE_RIGHT_BLENDSHAPE] += _mouth4; - _transientBlendshapeCoefficients[MMMM_BLENDSHAPE] += _mouth2; - _transientBlendshapeCoefficients[FUNNEL_BLENDSHAPE] += _mouth3; - } - applyEyelidOffset(getFinalOrientationInWorldFrame()); + if (_isFaceTrackerConnected) { + if (hasActualFaceTrackerConnected) { + _transientBlendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); + } else { + _transientBlendshapeCoefficients.fill(0, _blendshapeCoefficients.size()); } + + if (_owningAvatar->getHasAudioEnabledFaceMovement() || (faceTracker && (typeid(*faceTracker) == typeid(DdeFaceTracker)) + && Menu::getInstance()->isOptionChecked(MenuOption::UseAudioForMouth))) { + + calculateMouthShapes(deltaTime); + + const int JAW_OPEN_BLENDSHAPE = 21; + const int MMMM_BLENDSHAPE = 34; + const int FUNNEL_BLENDSHAPE = 40; + const int SMILE_LEFT_BLENDSHAPE = 28; + const int SMILE_RIGHT_BLENDSHAPE = 29; + _transientBlendshapeCoefficients[JAW_OPEN_BLENDSHAPE] += _audioJawOpen; + _transientBlendshapeCoefficients[SMILE_LEFT_BLENDSHAPE] += _mouth4; + _transientBlendshapeCoefficients[SMILE_RIGHT_BLENDSHAPE] += _mouth4; + _transientBlendshapeCoefficients[MMMM_BLENDSHAPE] += _mouth2; + _transientBlendshapeCoefficients[FUNNEL_BLENDSHAPE] += _mouth3; + } + applyEyelidOffset(getFinalOrientationInWorldFrame()); } auto eyeTracker = DependencyManager::get(); _isEyeTrackerConnected = eyeTracker->isTracking(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index fbef083dcd..fe4ff364ae 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -503,6 +503,7 @@ public: float getDomainLimitedScale() const; virtual bool getHasScriptedBlendshapes() const { return false; } + virtual bool getHasAudioEnabledFaceMovement() const { return false; } /**jsdoc * returns the minimum scale allowed for this avatar in the current domain. From 192e48a376026b565ce89b39992b6060fc48d1c6 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 25 Apr 2018 13:47:00 +0200 Subject: [PATCH 008/380] style fix + JSDocs --- interface/src/avatar/MyAvatar.h | 2 ++ interface/src/avatar/MyHead.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 537b5de8d8..9bccc93fbf 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -80,6 +80,8 @@ class MyAvatar : public Avatar { * MyAvatar.audioListenerModeCamera - the listener is relative to the camera. * MyAvatar.audioListenerModeCustom - the listener is at a custom location specified by the MyAvatar.customListenPosition * and MyAvatar.customListenOrientation properties. + * @property hasScriptedBlendshapes {bool} Blendshapes will be transmitted over the network if set to true. + * @property hasAudioEnabledFaceMovement {bool} If set to true, voice audio will move the mouth Blendshapes while MyAvatar.hasScriptedBlendshapes is enabled. * @property customListenPosition {Vec3} If MyAvatar.audioListenerMode == MyAvatar.audioListenerModeHead, then this determines the position * of audio spatialization listener. * @property customListenOrientation {Quat} If MyAvatar.audioListenerMode == MyAvatar.audioListenerModeHead, then this determines the orientation diff --git a/interface/src/avatar/MyHead.cpp b/interface/src/avatar/MyHead.cpp index ed38fdd004..44d679f3f8 100644 --- a/interface/src/avatar/MyHead.cpp +++ b/interface/src/avatar/MyHead.cpp @@ -72,7 +72,7 @@ void MyHead::simulate(float deltaTime) { _transientBlendshapeCoefficients[MMMM_BLENDSHAPE] += _mouth2; _transientBlendshapeCoefficients[FUNNEL_BLENDSHAPE] += _mouth3; } - applyEyelidOffset(getFinalOrientationInWorldFrame()); + applyEyelidOffset(getFinalOrientationInWorldFrame()); } auto eyeTracker = DependencyManager::get(); _isEyeTrackerConnected = eyeTracker->isTracking(); From 484e20ea55dc6027b06447e6ca56baeabed88f52 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 25 Apr 2018 19:01:18 +0200 Subject: [PATCH 009/380] JSDOC - change bool type to boolean, to match JS type --- interface/src/avatar/MyAvatar.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9bccc93fbf..23faff88ee 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -80,8 +80,8 @@ class MyAvatar : public Avatar { * MyAvatar.audioListenerModeCamera - the listener is relative to the camera. * MyAvatar.audioListenerModeCustom - the listener is at a custom location specified by the MyAvatar.customListenPosition * and MyAvatar.customListenOrientation properties. - * @property hasScriptedBlendshapes {bool} Blendshapes will be transmitted over the network if set to true. - * @property hasAudioEnabledFaceMovement {bool} If set to true, voice audio will move the mouth Blendshapes while MyAvatar.hasScriptedBlendshapes is enabled. + * @property hasScriptedBlendshapes {boolean} Blendshapes will be transmitted over the network if set to true. + * @property hasAudioEnabledFaceMovement {boolean} If set to true, voice audio will move the mouth Blendshapes while MyAvatar.hasScriptedBlendshapes is enabled. * @property customListenPosition {Vec3} If MyAvatar.audioListenerMode == MyAvatar.audioListenerModeHead, then this determines the position * of audio spatialization listener. * @property customListenOrientation {Quat} If MyAvatar.audioListenerMode == MyAvatar.audioListenerModeHead, then this determines the orientation From bbd31d590bb5f465fa5f906ac7dbf756abf7af53 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 26 Apr 2018 03:12:44 +0200 Subject: [PATCH 010/380] defaults --- interface/src/avatar/MyAvatar.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index ef2b0cd042..512273aee6 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -82,8 +82,8 @@ class MyAvatar : public Avatar { * @property {number} audioListenerModeCamera=1 - The audio listening position is at the camera. Read-only. * @property {number} audioListenerModeCustom=2 - The audio listening position is at a the position specified by set by the * customListenPosition and customListenOrientation property values. Read-only. - * @property hasScriptedBlendshapes {boolean} Blendshapes will be transmitted over the network if set to true. - * @property hasAudioEnabledFaceMovement {boolean} If set to true, voice audio will move the mouth Blendshapes while MyAvatar.hasScriptedBlendshapes is enabled. + * @property {boolean} hasScriptedBlendshapes=false - Blendshapes will be transmitted over the network if set to true. + * @property {boolean} hasAudioEnabledFaceMovement=true - If set to true, voice audio will move the mouth Blendshapes while MyAvatar.hasScriptedBlendshapes is enabled. * @property {Vec3} customListenPosition=Vec3.ZERO - The listening position used when the audioListenerMode * property value is audioListenerModeCustom. * @property {Quat} customListenOrientation=Quat.IDENTITY - The listening orientation used when the From 6d251c4cd3e661242962b7a0ea399eba2c1a62ec Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 3 May 2018 17:46:50 -0700 Subject: [PATCH 011/380] Bringing the work and refinment done in workload branch to master branch --- .../render-utils/src/AmbientOcclusionEffect.h | 2 +- libraries/render-utils/src/LightClusters.h | 2 +- .../render-utils/src/SubsurfaceScattering.h | 2 +- libraries/render/src/render/Item.h | 1 + libraries/task/src/task/Config.h | 35 ++++++++++++--- libraries/task/src/task/Task.h | 45 +++++++++++++++++-- 6 files changed, 74 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 3643e608ed..b3a93ab1de 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -181,7 +181,7 @@ class DebugAmbientOcclusionConfig : public render::Job::Config { Q_PROPERTY(bool showCursorPixel MEMBER showCursorPixel NOTIFY dirty) Q_PROPERTY(glm::vec2 debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty) public: - DebugAmbientOcclusionConfig() : render::Job::Config(true) {} + DebugAmbientOcclusionConfig() : render::Job::Config(false) {} bool showCursorPixel{ false }; glm::vec2 debugCursorTexcoord{ 0.5f, 0.5f }; diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index f495dabebb..fa054c304a 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -195,7 +195,7 @@ class DebugLightClustersConfig : public render::Job::Config { Q_PROPERTY(bool doDrawClusterFromDepth MEMBER doDrawClusterFromDepth NOTIFY dirty) Q_PROPERTY(bool doDrawContent MEMBER doDrawContent NOTIFY dirty) public: - DebugLightClustersConfig() : render::Job::Config(true){} + DebugLightClustersConfig() : render::Job::Config(false){} bool doDrawGrid{ false }; diff --git a/libraries/render-utils/src/SubsurfaceScattering.h b/libraries/render-utils/src/SubsurfaceScattering.h index 30021fae40..780ce34d7f 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.h +++ b/libraries/render-utils/src/SubsurfaceScattering.h @@ -149,7 +149,7 @@ class DebugSubsurfaceScatteringConfig : public render::Job::Config { Q_PROPERTY(bool showCursorPixel MEMBER showCursorPixel NOTIFY dirty) Q_PROPERTY(glm::vec2 debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty) public: - DebugSubsurfaceScatteringConfig() : render::Job::Config(true) {} + DebugSubsurfaceScatteringConfig() : render::Job::Config(false) {} bool showProfile{ false }; bool showLUT{ false }; diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index e4dcc7ee03..b8a3fbf0f8 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -122,6 +122,7 @@ public: Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); } Builder& withDeformed() { _flags.set(DEFORMED); return (*this); } Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); } + Builder& withVisible() { _flags.reset(INVISIBLE); return (*this); } Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); } Builder& withLayered() { _flags.set(LAYERED); return (*this); } Builder& withMetaCullGroup() { _flags.set(META_CULL_GROUP); return (*this); } diff --git a/libraries/task/src/task/Config.h b/libraries/task/src/task/Config.h index 36dfb35f25..4ba1934643 100644 --- a/libraries/task/src/task/Config.h +++ b/libraries/task/src/task/Config.h @@ -12,6 +12,8 @@ #ifndef hifi_task_Config_h #define hifi_task_Config_h +#include + #include #include #include @@ -108,11 +110,19 @@ public: Q_INVOKABLE QString toJSON() { return QJsonDocument(toJsonValue(*this).toObject()).toJson(QJsonDocument::Compact); } Q_INVOKABLE void load(const QVariantMap& map) { qObjectFromJsonValue(QJsonObject::fromVariantMap(map), *this); emit loaded(); } + Q_INVOKABLE QObject* getConfig(const QString& name) { return nullptr; } + // Running Time measurement // The new stats signal is emitted once per run time of a job when stats (cpu runtime) are updated - void setCPURunTime(double mstime) { _msCPURunTime = mstime; emit newStats(); } + void setCPURunTime(const std::chrono::nanoseconds& runtime) { _msCPURunTime = std::chrono::duration(runtime).count(); emit newStats(); } double getCPURunTime() const { return _msCPURunTime; } + // Describe the node graph data connections of the associated Job/Task + Q_INVOKABLE virtual bool isTask() const { return false; } + Q_INVOKABLE virtual QObjectList getSubConfigs() const { return QObjectList(); } + Q_INVOKABLE virtual int getNumSubs() const { return 0; } + Q_INVOKABLE virtual QObject* getSubConfig(int i) const { return nullptr; } + public slots: void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); emit loaded(); } @@ -122,6 +132,8 @@ signals: void dirtyEnabled(); }; +using QConfigPointer = std::shared_ptr; + class TConfigProxy { public: using Config = JobConfig; @@ -134,11 +146,9 @@ public: using Persistent = PersistentConfig; - TaskConfig() = default ; + TaskConfig() = default; TaskConfig(bool enabled) : JobConfig(enabled) {} - - // Get a sub job config through task.getConfig(path) // where path can be: // - search for the first job named job_name traversing the the sub graph of task and jobs (from this task as root) @@ -170,6 +180,21 @@ public: return root->findChild(tokens.front()); } + Q_INVOKABLE bool isTask() const override { return true; } + Q_INVOKABLE QObjectList getSubConfigs() const override { + auto list = findChildren(QRegExp(".*"), Qt::FindDirectChildrenOnly); + QObjectList returned; + for (int i = 0; i < list.size(); i++) { + returned.push_back(list[i]); + } + return returned; + } + Q_INVOKABLE int getNumSubs() const override { return getSubConfigs().size(); } + Q_INVOKABLE QObject* getSubConfig(int i) const override { + auto subs = getSubConfigs(); + return ((i < 0 || i >= subs.size()) ? nullptr : subs[i]); + } + void connectChildConfig(QConfigPointer childConfig, const std::string& name); void transferChildrenConfigs(QConfigPointer source); @@ -179,8 +204,6 @@ public slots: void refresh(); }; -using QConfigPointer = std::shared_ptr; - } #endif // hifi_task_Config_h diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index 022dd99200..93dfdd85f4 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -80,10 +80,11 @@ public: virtual const Varying getInput() const { return Varying(); } virtual const Varying getOutput() const { return Varying(); } + virtual Varying& editInput() = 0; virtual QConfigPointer& getConfiguration() { return _config; } virtual void applyConfiguration() = 0; - void setCPURunTime(double mstime) { std::static_pointer_cast(_config)->setCPURunTime(mstime); } + void setCPURunTime(const std::chrono::nanoseconds& runtime) { std::static_pointer_cast(_config)->setCPURunTime(runtime); } QConfigPointer _config; protected: @@ -143,6 +144,10 @@ public: const Varying getInput() const override { return _input; } const Varying getOutput() const override { return _output; } + Varying& editInput() override { return _input; } + + template void feedInput(const I& in) { _concept->editInput().template edit() = in; } + template void feedInput(int index, const S& inS) { (_concept->editInput().template editN(index)).template edit() = inS; } template Model(const std::string& name, const Varying& input, QConfigPointer config, A&&... args) : @@ -201,11 +206,12 @@ public: PerformanceTimer perfTimer(getName().c_str()); // NOTE: rather than use the PROFILE_RANGE macro, we create a Duration manually Duration profileRange(jobContext->profileCategory, ("run::" + getName()).c_str()); - auto start = usecTimestampNow(); + + auto startTime = std::chrono::high_resolution_clock::now(); _concept->run(jobContext); - _concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0); + _concept->setCPURunTime((std::chrono::high_resolution_clock::now() - startTime)); } protected: @@ -242,6 +248,8 @@ public: const Varying getInput() const override { return _input; } const Varying getOutput() const override { return _output; } + Varying& editInput() override { return _input; } + typename Jobs::iterator editJob(std::string name) { typename Jobs::iterator jobIt; for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) { @@ -370,8 +378,36 @@ public: protected: }; -} +template +class Engine : public Task { +public: + using Context = JC; + using ContextPointer = std::shared_ptr; + using Config = TaskConfig; + using TaskType = Task; + using ConceptPointer = typename TaskType::ConceptPointer; + + Engine(ConceptPointer concept) : TaskType(concept) {} + ~Engine() = default; + + void reset(const ContextPointer& context) { _context = context; } + + void run() { + if (_context) { + run(_context); + } + } + +protected: + void run(const ContextPointer& jobContext) override { + TaskType::run(_context); + } + + ContextPointer _context; +}; + +} #define Task_DeclareTypeAliases(ContextType) \ using JobConfig = task::JobConfig; \ @@ -379,6 +415,7 @@ protected: template using PersistentConfig = task::PersistentConfig; \ using Job = task::Job; \ using Task = task::Task; \ + using _Engine = task::Engine; \ using Varying = task::Varying; \ template < typename T0, typename T1 > using VaryingSet2 = task::VaryingSet2; \ template < typename T0, typename T1, typename T2 > using VaryingSet3 = task::VaryingSet3; \ From e1d063e90880f1e885b29c2612fabb5172a9de70 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 4 May 2018 00:01:48 -0700 Subject: [PATCH 012/380] Adding the scripts for Jet --- scripts/developer/utilities/lib/jet/jet.js | 73 +++++++++++++++++++ .../utilities/lib/jet/qml/TaskList.qml | 48 ++++++++++++ .../developer/utilities/lib/jet/qml/qmldir | 1 + .../render/configSlider/ConfigSlider.qml | 40 ++++++---- .../utilities/render/deferredLighting.qml | 10 +++ 5 files changed, 159 insertions(+), 13 deletions(-) create mode 100644 scripts/developer/utilities/lib/jet/jet.js create mode 100644 scripts/developer/utilities/lib/jet/qml/TaskList.qml create mode 100644 scripts/developer/utilities/lib/jet/qml/qmldir diff --git a/scripts/developer/utilities/lib/jet/jet.js b/scripts/developer/utilities/lib/jet/jet.js new file mode 100644 index 0000000000..39da9b6d90 --- /dev/null +++ b/scripts/developer/utilities/lib/jet/jet.js @@ -0,0 +1,73 @@ +// +// Job Engine & Task... +// jet.js +// +// Created by Sam Gateau, 2018/03/28 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +"use strict"; + + // traverse task tree +function task_traverse(root, functor, depth) { + // if (root.isTask()) { + depth++; + for (var i = 0; i Date: Fri, 4 May 2018 17:58:21 -0700 Subject: [PATCH 013/380] Templatizing the timeProfiler for the task --- libraries/render/src/render/Engine.h | 6 +- libraries/task/src/task/Task.cpp | 4 +- libraries/task/src/task/Task.h | 63 ++++++++++--------- .../utilities/render/deferredLighting.qml | 16 ++--- 4 files changed, 46 insertions(+), 43 deletions(-) diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 0271c71529..f444416a3f 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -25,7 +25,7 @@ namespace render { class RenderContext : public task::JobContext { public: - RenderContext() : task::JobContext(trace_render()) {} + RenderContext() : task::JobContext() {} virtual ~RenderContext() {} RenderArgs* args; @@ -33,7 +33,9 @@ namespace render { }; using RenderContextPointer = std::shared_ptr; - Task_DeclareTypeAliases(RenderContext) + Task_DeclareCategoryTimeProfilerClass(RenderTimeProfiler, trace_render); + + Task_DeclareTypeAliases(RenderContext, RenderTimeProfiler) // Versions of the COnfig integrating a gpu & batch timer class GPUJobConfig : public JobConfig { diff --git a/libraries/task/src/task/Task.cpp b/libraries/task/src/task/Task.cpp index 621d77d7bf..9123ef8b04 100644 --- a/libraries/task/src/task/Task.cpp +++ b/libraries/task/src/task/Task.cpp @@ -12,9 +12,7 @@ using namespace task; -JobContext::JobContext(const QLoggingCategory& category) : - profileCategory(category) { - assert(&category); +JobContext::JobContext() { } JobContext::~JobContext() { diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index 93dfdd85f4..c9a3285443 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -15,20 +15,15 @@ #include "Config.h" #include "Varying.h" -#include "SettingHandle.h" - -#include -#include - namespace task { class JobConcept; -template class JobT; -template class TaskT; +template class JobT; +template class TaskT; class JobNoIO {}; // Task Flow control class is a simple per value object used to communicate flow control commands trhough the graph of tasks. -// From within the Job::Run function, you can access it from the JobCOntext and issue commands which will be picked up by the Task calling for the Job run. +// From within the Job::Run function, you can access it from the JobContext and issue commands which will be picked up by the Task calling for the Job run. // This is first introduced to provide a way to abort all the work from within a task job. see the "abortTask" call class TaskFlow { public: @@ -55,11 +50,10 @@ protected: // The JobContext can be derived to add more global state to it that Jobs can access class JobContext { public: - JobContext(const QLoggingCategory& category); + JobContext(); virtual ~JobContext(); std::shared_ptr jobConfig { nullptr }; - const QLoggingCategory& profileCategory; // Task flow control TaskFlow taskFlow{}; @@ -115,10 +109,11 @@ template void jobRun(T& data, const JC& jo data.run(jobContext, input, output); } -template +template class Job { public: using Context = JC; + using TimeProfiler = TP; using ContextPointer = std::shared_ptr; using Config = JobConfig; using None = JobNoIO; @@ -165,7 +160,7 @@ public: void applyConfiguration() override { - Duration profileRange(trace_render(), ("configure::" + JobConcept::getName()).c_str()); + TimeProfiler probe(("configure::" + JobConcept::getName())); jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); } @@ -203,14 +198,9 @@ public: } virtual void run(const ContextPointer& jobContext) { - PerformanceTimer perfTimer(getName().c_str()); - // NOTE: rather than use the PROFILE_RANGE macro, we create a Duration manually - Duration profileRange(jobContext->profileCategory, ("run::" + getName()).c_str()); - + TimeProfiler probe(getName()); auto startTime = std::chrono::high_resolution_clock::now(); - _concept->run(jobContext); - _concept->setCPURunTime((std::chrono::high_resolution_clock::now() - startTime)); } @@ -226,13 +216,14 @@ protected: // The build method is where child Jobs can be added internally to the task // where the input of the task can be setup to feed the child jobs // and where the output of the task is defined -template -class Task : public Job { +template +class Task : public Job { public: using Context = JC; + using TimeProfiler = TP; using ContextPointer = std::shared_ptr; using Config = TaskConfig; - using JobType = Job; + using JobType = Job; using None = typename JobType::None; using Concept = typename JobType::Concept; using ConceptPointer = typename JobType::ConceptPointer; @@ -303,7 +294,7 @@ public: auto model = std::make_shared(name, input, std::make_shared()); { - Duration profileRange(trace_render(), ("build::" + model->getName()).c_str()); + TimeProfiler probe("build::" + model->getName()); model->_data.build(*(model), model->_input, model->_output, std::forward(args)...); } // Recreate the Config to use the templated type @@ -338,7 +329,7 @@ public: } void applyConfiguration() override { - Duration profileRange(trace_render(), ("configure::" + JobConcept::getName()).c_str()); + TimeProfiler probe("configure::" + JobConcept::getName()); jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); for (auto& job : TaskConcept::_jobs) { job.applyConfiguration(); @@ -379,13 +370,13 @@ public: protected: }; -template -class Engine : public Task { +template +class Engine : public Task { public: using Context = JC; using ContextPointer = std::shared_ptr; using Config = TaskConfig; - using TaskType = Task; + using TaskType = Task; using ConceptPointer = typename TaskType::ConceptPointer; Engine(ConceptPointer concept) : TaskType(concept) {} @@ -409,13 +400,13 @@ protected: } -#define Task_DeclareTypeAliases(ContextType) \ +#define Task_DeclareTypeAliases(ContextType, TimeProfiler) \ using JobConfig = task::JobConfig; \ using TaskConfig = task::TaskConfig; \ template using PersistentConfig = task::PersistentConfig; \ - using Job = task::Job; \ - using Task = task::Task; \ - using _Engine = task::Engine; \ + using Job = task::Job; \ + using Task = task::Task; \ + using _Engine = task::Engine; \ using Varying = task::Varying; \ template < typename T0, typename T1 > using VaryingSet2 = task::VaryingSet2; \ template < typename T0, typename T1, typename T2 > using VaryingSet3 = task::VaryingSet3; \ @@ -426,4 +417,16 @@ protected: template < typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7 > using VaryingSet8 = task::VaryingSet8; \ template < class T, int NUM > using VaryingArray = task::VaryingArray; + + +#include +#include + +#define Task_DeclareCategoryTimeProfilerClass(className, category) \ + class className : public PerformanceTimer { \ + public: \ + className(const std::string& label) : PerformanceTimer(label.c_str()), profileRange(category(), label.c_str()) {} \ + Duration profileRange; \ + }; + #endif // hifi_task_Task_h diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 160ec26be0..dc81df48cb 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -37,9 +37,9 @@ Rectangle { anchors.left: parent.left anchors.right: parent.right - spacing: 20 + spacing: 5 Column { - spacing: 10 + spacing: 5 // padding: 10 Repeater { model: [ @@ -61,7 +61,7 @@ Rectangle { Column { - spacing: 10 + spacing: 5 Repeater { model: [ "Obscurance:LightingModel:enableObscurance", @@ -81,7 +81,7 @@ Rectangle { } Column { - spacing: 10 + spacing: 5 Repeater { model: [ "Ambient:LightingModel:enableAmbientLight", @@ -105,7 +105,7 @@ Rectangle { Column { anchors.left: parent.left anchors.right: parent.right - spacing: 10 + spacing: 5 Repeater { model: [ "Tone Mapping Exposure:ToneMapping:exposure:5.0:-5.0" ] @@ -211,9 +211,9 @@ Rectangle { Separator {} Row { - spacing: 10 + spacing: 5 Column { - spacing: 10 + spacing: 5 HifiControls.CheckBox { boxSize: 20 @@ -254,7 +254,7 @@ Rectangle { } Column { - spacing: 10 + spacing: 5 HifiControls.CheckBox { boxSize: 20 text: "Metas" From d8257dcfd3ca497898e8a198aa15816616ca985a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 May 2018 11:45:17 -0700 Subject: [PATCH 014/380] Add 010 fbx template --- tools/010-templates/fbx.bt | 102 +++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 tools/010-templates/fbx.bt diff --git a/tools/010-templates/fbx.bt b/tools/010-templates/fbx.bt new file mode 100644 index 0000000000..dcb620066e --- /dev/null +++ b/tools/010-templates/fbx.bt @@ -0,0 +1,102 @@ +// +// fbx.bt +// tools/010-templates +// +// Created by Ryan Huffman +// Copyright 2018 High Fidelity, Inc. +// +// FBX file template +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +local char use64BitAddresses = 1; + +struct Header { + char prefix[23]; + int32 version; +}; + +struct Property { + char type; + if (type == 'Y') { + int16 value; + } else if (type == 'C') { + char value; + } else if (type == 'I') { + int32 value; + } else if (type == 'F') { + float value; + } else if (type == 'D') { + double value; + } else if (type == 'L') { + int64 value; + } else if (type == 'S' || type == 'R') { + uint32 size; + char value[size]; + } else { + uint32 length; + uint32 encoding; + uint32 compressedLength; + if (encoding == 1) { + char compressedData[compressedLength]; + } else if (type == 'f') { + float values[this.length]; + } else if (type == 'd') { + double values[this.length]; + } else if (type == 'l') { + int64 values[this.length]; + } else if (type == 'i') { + int32 values[this.length]; + } else if (type == 'b') { + char values[this.length]; + } else { + Printf("%c", type); + Assert(false, "Error, unknown property type"); + } + } +}; + +struct Node; + +string nodeName(Node& node) { + if (!exists(node.name)) { + return "Node ----- "; + } + local string s; + SPrintf(s, "Node (%s) ", node.name); + return s; +} + +struct Node { + if (use64BitAddresses) { + int64 endOffset; + uint64 propertyCount; + uint64 propertyListLength; + } else { + int32 endOffset; + uint32 propertyCount; + uint32 propertyListLength; + } + uchar nameLength; + char name[this.nameLength]; + Property properties[this.propertyCount]; + while (FTell() < endOffset) { + Node children; + } +}; + +struct File { + Header header; + use64BitAddresses = header.version >= 7500; + local int i = 0; + Node node; + local string name = node.name; + while (name != "") { + Node node; + i++; + name = exists(node[i].name) ? node[i].name : ""; + } + +} file; From b9fb9875a7462f3262237c8ead48feac565324a5 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 May 2018 11:48:50 -0700 Subject: [PATCH 015/380] Add 010 ktx template --- tools/010-templates/ktx.bt | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tools/010-templates/ktx.bt diff --git a/tools/010-templates/ktx.bt b/tools/010-templates/ktx.bt new file mode 100644 index 0000000000..9690dbb391 --- /dev/null +++ b/tools/010-templates/ktx.bt @@ -0,0 +1,52 @@ +// +// ktx.bt +// tools/010-templates +// +// Created by Ryan Huffman +// Copyright 2018 High Fidelity, Inc. +// +// KTX file template +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +struct Header { + char identifier[12]; + uint32 endianness; + uint32 glType; + uint32 glTypeSize; + uint32 glFormat; + uint32 glInternalFormat; + uint32 glBaseInternalFormat; + uint32 pixelWidth; + uint32 pixelHeight; + uint32 pixelDepth; + uint32 numberOfArrayElements; + uint32 numberOfFaces; + uint32 numberOfMipmapLevels; + uint32 bytesOfKeyValueData; +}; + +struct KV { + uint32 byteSize; + local uint32 keyLength = ReadStringLength(FTell()); + char key[keyLength]; + char value[byteSize - keyLength] ; + char padding[3 - ((byteSize + 3) % 4)]; +}; + +string kvName(KV& kv) { + local string s; + SPrintf(s, "KeyValue (%s) ", kv.key); + return s; +} + +struct File { + Header header; + local uint32 endOfKV = FTell() + header.bytesOfKeyValueData; + while (FTell() < endOfKV) { + KV keyValue ; + } + char imageData[FileSize() - FTell()]; +} file; From 894cd3ed76b3d870e391a406f3173d9f8f833b3d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 May 2018 11:52:29 -0700 Subject: [PATCH 016/380] Add 010-templates/README.md --- tools/010-templates/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 tools/010-templates/README.md diff --git a/tools/010-templates/README.md b/tools/010-templates/README.md new file mode 100644 index 0000000000..df3ce6d0e5 --- /dev/null +++ b/tools/010-templates/README.md @@ -0,0 +1 @@ +This directory contains [010 editor](https://www.sweetscape.com/010editor/) templates for parsing and inspecting different file types. From 3a10cacec003d840cf7bd283d70cacec2ac8e2cb Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 19 Apr 2018 14:04:54 -0700 Subject: [PATCH 017/380] 1.added the swing twist code to update the follow rotation in MyAvatar.cpp 2.added step.js and cg_lean.js to the developer folder 3.added menu item for toggling the hips following between head and hips 4.added new function to return true if the root of MyAvatar is translating to be under the head. Used to smooth the path of the hips 5.added computeCounterBalance to MyAvatar.h and cpp 6.added the menu item under developer/avatar to enable debug draw of the base of support in menu.h menu.cpp MyAvatar.h MyAvatar.cpp 7.added head yaw into the calculation of the hip rotation for the center of gravity. This is already was happening in the deriveBodyFromHMD code that is default 8.Changed Constants in Avatar constants for the base of support 9.fixed the over rotation of the shoulders 10.fixed scaling problem in cg computation 11.added room for going up on the toes without stretching --- interface/src/Menu.cpp | 4 + interface/src/Menu.h | 2 + interface/src/avatar/MyAvatar.cpp | 276 ++++++++++- interface/src/avatar/MyAvatar.h | 52 ++- interface/src/avatar/MySkeletonModel.cpp | 16 +- libraries/shared/src/AvatarConstants.h | 4 + scripts/defaultScripts.js | 4 +- scripts/developer/cg_lean.js | 553 +++++++++++++++++++++++ tests/animation/src/data/avatar.json | 2 +- 9 files changed, 902 insertions(+), 11 deletions(-) create mode 100644 scripts/developer/cg_lean.js diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index bf0fc05350..41831bf3c5 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -600,6 +600,10 @@ Menu::Menu() { }); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::FixGaze, 0, false); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ToggleHipsFollowing, 0, false, + avatar.get(), SLOT(setToggleHips(bool))); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawBaseOfSupport, 0, false, + avatar.get(), SLOT(setEnableDebugDrawBaseOfSupport(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawDefaultPose, 0, false, avatar.get(), SLOT(setEnableDebugDrawDefaultPose(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawAnimPose, 0, false, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 20375a71b2..936062b960 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -30,6 +30,7 @@ namespace MenuOption { const QString AddressBar = "Show Address Bar"; const QString Animations = "Animations..."; const QString AnimDebugDrawAnimPose = "Debug Draw Animation"; + const QString AnimDebugDrawBaseOfSupport = "Debug Draw Base of Support"; const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose"; const QString AnimDebugDrawPosition= "Debug Draw Position"; const QString AskToResetSettings = "Ask To Reset Settings"; @@ -203,6 +204,7 @@ namespace MenuOption { const QString ThirdPerson = "Third Person"; const QString ThreePointCalibration = "3 Point Calibration"; const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp + const QString ToggleHipsFollowing = "Toggle Hips Following"; const QString ToolWindow = "Tool Window"; const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 15b220c63b..c3df9f6143 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1068,6 +1068,22 @@ float loadSetting(Settings& settings, const QString& name, float defaultValue) { return value; } +void MyAvatar::setToggleHips(bool followHead) { + _follow.setToggleHipsFollowing(followHead); +} + +void MyAvatar::FollowHelper::setToggleHipsFollowing(bool followHead) { + _toggleHipsFollowing = followHead; +} + +bool MyAvatar::FollowHelper::getToggleHipsFollowing() const { + return _toggleHipsFollowing; +} + +void MyAvatar::setEnableDebugDrawBaseOfSupport(bool isEnabled) { + _enableDebugDrawBaseOfSupport = isEnabled; +} + void MyAvatar::setEnableDebugDrawDefaultPose(bool isEnabled) { _enableDebugDrawDefaultPose = isEnabled; @@ -1195,6 +1211,8 @@ void MyAvatar::loadData() { settings.endGroup(); setEnableMeshVisible(Menu::getInstance()->isOptionChecked(MenuOption::MeshVisible)); + _follow.setToggleHipsFollowing (Menu::getInstance()->isOptionChecked(MenuOption::ToggleHipsFollowing)); + setEnableDebugDrawBaseOfSupport(Menu::getInstance()->isOptionChecked(MenuOption::AnimDebugDrawBaseOfSupport)); setEnableDebugDrawDefaultPose(Menu::getInstance()->isOptionChecked(MenuOption::AnimDebugDrawDefaultPose)); setEnableDebugDrawAnimPose(Menu::getInstance()->isOptionChecked(MenuOption::AnimDebugDrawAnimPose)); setEnableDebugDrawPosition(Menu::getInstance()->isOptionChecked(MenuOption::AnimDebugDrawPosition)); @@ -2829,6 +2847,245 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { return createMatFromQuatAndPos(headOrientationYawOnly, bodyPos); } +float slope(float num) { + float constantK = 1.0; + float ret = 1.0f; + if (num > 0.0f) { + ret = 1.0f - (1.0f / (1.0f + constantK * num)); + } + return ret; +} + +glm::vec3 dampenCgMovement(glm::vec3 rawCg, float baseOfSupportScale) { + float distanceFromCenterZ = rawCg.z; + float distanceFromCenterX = rawCg.x; + + // The dampening scale factors makes the slope function soft clamp the + // cg at the edge of the base of support of the feet, in the lateral and posterior directions. + // In the forward direction we need a different scale because forward is in + // the direction of the hip extensor joint, which means bending usually happens + // well before reaching the edge of the base of support. + // The scale of the base of support reflects the size of the user in real life. + float forwardDampeningFactor = 0.5f; + float lateralAndBackDampeningScaleFactor = 2.0f; + float clampFront = DEFAULT_AVATAR_SUPPORT_BASE_FRONT * forwardDampeningFactor * baseOfSupportScale; + float clampBack = DEFAULT_AVATAR_SUPPORT_BASE_BACK * lateralAndBackDampeningScaleFactor * baseOfSupportScale; + float clampLeft = DEFAULT_AVATAR_SUPPORT_BASE_LEFT * lateralAndBackDampeningScaleFactor * baseOfSupportScale; + float clampRight = DEFAULT_AVATAR_SUPPORT_BASE_RIGHT * lateralAndBackDampeningScaleFactor * baseOfSupportScale; + glm::vec3 dampedCg = {0.0f,0.0f,0.0f}; + + // find the damped z coord of the cg + if (rawCg.z < 0.0f) { + // forward displacement + float inputFront; + inputFront = fabs(distanceFromCenterZ / clampFront); + float scaleFrontNew = slope(inputFront); + dampedCg.z = scaleFrontNew * clampFront; + } else { + // backwards displacement + float inputBack; + inputBack = fabs(distanceFromCenterZ / clampBack); + float scaleBackNew = slope(inputBack); + dampedCg.z = scaleBackNew * clampBack; + } + + // find the damped x coord of the cg + if (rawCg.x > 0.0f) { + // right of center + float inputRight; + inputRight = fabs(distanceFromCenterX / clampRight); + float scaleRightNew = slope(inputRight); + dampedCg.x = scaleRightNew * clampRight; + } else { + // left of center + float inputLeft; + inputLeft = fabs(distanceFromCenterX / clampLeft); + float scaleLeftNew = slope(inputLeft); + dampedCg.x = scaleLeftNew * clampLeft; + } + return dampedCg; +} + +glm::vec3 MyAvatar::computeCounterBalance() const { + struct jointMass { + QString name; + float weight; + glm::vec3 position; + } cgMasses[3]; + // init the body part weights + cgMasses[0].name = "Head"; + cgMasses[0].weight = 20.0f; + cgMasses[0].position = { 0.0f, 0.0f, 0.0f }; + cgMasses[1].name = "LeftHand"; + cgMasses[1].weight = 2.0f; + cgMasses[1].position = { 0.0f, 0.0f, 0.0f }; + cgMasses[2].name = "RightHand"; + cgMasses[2].weight = 2.0f; + cgMasses[2].position = { 0.0f, 0.0f, 0.0f }; + // find the current center of gravity position based on head and hand moments + float hipsMass = 40.0f; + float totalMass = 0.0f; + glm::vec3 sumOfMoments = { 0.0f, 0.0f, 0.0f }; + for (int i = 0; i < 3; i++) { + const QString jointName = cgMasses[i].name; + cgMasses[i].position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(jointName)); + sumOfMoments += cgMasses[i].weight * cgMasses[i].position; + totalMass += cgMasses[i].weight; + } + glm::vec3 currentCg = (1 / totalMass) * sumOfMoments; + currentCg.y = 0.0f; + // dampening the center of gravity, in effect, limits the value to the perimeter of the base of support + float baseScale = 1.0f; + if (getUserEyeHeight() > 0.0f) { + baseScale = getUserEyeHeight() / DEFAULT_AVATAR_EYE_HEIGHT; + } + glm::vec3 desiredCg = dampenCgMovement(currentCg, baseScale); + + // compute hips position to maintain desiredCg + glm::vec3 counterBalancedForHead = ((totalMass + hipsMass) * desiredCg) - (cgMasses[0].position * cgMasses[0].weight); + glm::vec3 counterBalancedForLeftHand = counterBalancedForHead - (cgMasses[1].weight * cgMasses[1].position); + glm::vec3 counterBalancedForRightHand = counterBalancedForLeftHand - (cgMasses[2].weight * cgMasses[2].position); + glm::vec3 counterBalancedCg = (1.0f / hipsMass) * counterBalancedForRightHand; + + // find the height of the hips + glm::vec3 currentHead = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("Head")); + glm::vec3 tposeHead = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("Head")); + glm::vec3 tposeHips = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("Hips")); + glm::vec3 xzDiff = {(currentHead.x - counterBalancedCg.x), 0.0f, (currentHead.z - counterBalancedCg.z)}; + float headMinusHipXz = glm::length(xzDiff); + float headHipDefault = glm::length(tposeHead - tposeHips); + float hipHeight = 0.0f; + if (headHipDefault > headMinusHipXz) { + hipHeight = sqrtf((headHipDefault * headHipDefault) - (headMinusHipXz * headMinusHipXz)); + } + counterBalancedCg.y = (currentHead.y - hipHeight); + + // this is to be sure that the feet don't lift off the floor. + // add 5 centimeters to allow for going up on the toes. + if (counterBalancedCg.y > (tposeHips.y + 0.05f)) { + // if the height is higher than default hips, clamp to default hips + counterBalancedCg.y = tposeHips.y + 0.05f; + } + return counterBalancedCg; +} + +glm::quat computeNewHipsRotation(glm::quat hipYawRot, glm::vec3 curHead, glm::vec3 hipPos) { + glm::vec3 spineVec = curHead - hipPos; + glm::quat finalRot = Quaternions::IDENTITY; + + if (spineVec.y > 0.0f) { + + glm::vec3 newYaxisHips = glm::normalize(spineVec); + glm::vec3 forward = { 0.0f, 0.0f, 1.0f }; + glm::vec3 oldZaxisHips = glm::normalize(forward); + glm::vec3 newXaxisHips = glm::normalize(glm::cross(newYaxisHips, oldZaxisHips)); + glm::vec3 newZaxisHips = glm::normalize(glm::cross(newXaxisHips, newYaxisHips)); + + // create mat4 with the new axes + glm::vec4 left = { newXaxisHips.x, newXaxisHips.y, newXaxisHips.z, 0.0f }; + glm::vec4 up = { newYaxisHips.x, newYaxisHips.y, newYaxisHips.z, 0.0f }; + glm::vec4 view = { newZaxisHips.x, newZaxisHips.y, newZaxisHips.z, 0.0f }; + glm::vec4 translation = { 0.0f, 0.0f, 0.0f, 1.0f }; + glm::mat4 newRotHips(left, up, view, translation); + finalRot = glm::toQuat(newRotHips); + } else if (spineVec.y < 0.0f) { + + glm::vec3 newYaxisHips = glm::normalize(-spineVec); + glm::vec3 forward = { 0.0f, 0.0f, 1.0f }; + glm::vec3 oldZaxisHips = glm::normalize(forward); + glm::vec3 newXaxisHips = glm::normalize(glm::cross(newYaxisHips, oldZaxisHips)); + glm::vec3 newZaxisHips = glm::normalize(glm::cross(newXaxisHips, newYaxisHips)); + + // create mat4 with the new axes + glm::vec4 left = { newXaxisHips.x, newXaxisHips.y, newXaxisHips.z, 0.0f }; + glm::vec4 up = { newYaxisHips.x, newYaxisHips.y, newYaxisHips.z, 0.0f }; + glm::vec4 view = { newZaxisHips.x, newZaxisHips.y, newZaxisHips.z, 0.0f }; + glm::vec4 translation = { 0.0f, 0.0f, 0.0f, 1.0f }; + glm::mat4 newRotHips(left, up, view, translation); + finalRot = glm::toQuat(newRotHips); + } else { + + //y equals zero. + if (glm::length(spineVec) > 0.0f) { + glm::vec3 newYaxisHips = glm::normalize(spineVec); + glm::vec3 forward = { 0.0f, 1.0f, 0.0f }; + glm::vec3 oldZaxisHips = forward; + glm::vec3 newXaxisHips = glm::normalize(glm::cross(newYaxisHips, oldZaxisHips)); + glm::vec3 newZaxisHips = oldZaxisHips; + + // create mat4 with the new axes + glm::vec4 left = { newXaxisHips.x, newXaxisHips.y, newXaxisHips.z, 0.0f }; + glm::vec4 up = { newYaxisHips.x, newYaxisHips.y, newYaxisHips.z, 0.0f }; + glm::vec4 view = { newZaxisHips.x, newZaxisHips.y, newZaxisHips.z, 0.0f }; + glm::vec4 translation = { 0.0f, 0.0f, 0.0f, 1.0f }; + glm::mat4 newRotHips(left, up, view, translation); + finalRot = glm::toQuat(newRotHips); + } + // otherwise, head and hips are equal so leave finalRot identity + } + glm::quat hipsRotation = hipYawRot*finalRot; + return hipsRotation; +} + +void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::mat4 avatarToWorld) { + // scale the base of support based on user height + float clampFront = DEFAULT_AVATAR_SUPPORT_BASE_FRONT * baseOfSupportScale; + float clampBack = DEFAULT_AVATAR_SUPPORT_BASE_BACK * baseOfSupportScale; + float clampLeft = DEFAULT_AVATAR_SUPPORT_BASE_LEFT * baseOfSupportScale; + float clampRight = DEFAULT_AVATAR_SUPPORT_BASE_RIGHT * baseOfSupportScale; + float floor = footLocal + 0.05f; + + // transform the base of support corners to world space + glm::vec3 frontRight = transformPoint(avatarToWorld, { clampRight, floor, clampFront }); + glm::vec3 frontLeft = transformPoint(avatarToWorld, { clampLeft, floor, clampFront }); + glm::vec3 backRight = transformPoint(avatarToWorld, { clampRight, floor, clampBack }); + glm::vec3 backLeft = transformPoint(avatarToWorld, { clampLeft, floor, clampBack }); + + // draw the borders + const glm::vec4 rayColor = { 1.0f, 0.0f, 0.0f, 1.0f }; + DebugDraw::getInstance().drawRay(backLeft, frontLeft, rayColor); + DebugDraw::getInstance().drawRay(backLeft, backRight, rayColor); + DebugDraw::getInstance().drawRay(backRight, frontRight, rayColor); + DebugDraw::getInstance().drawRay(frontLeft, frontRight, rayColor); +} + +glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { + glm::mat4 worldToSensorMat = glm::inverse(getSensorToWorldMatrix()); + glm::mat4 avatarToWorldMat = getTransform().getMatrix(); + glm::mat4 avatarToSensorMat = worldToSensorMat * avatarToWorldMat; + + glm::vec3 headPosition; + glm::quat headOrientation; + auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD); + if (headPose.isValid()) { + headPosition = headPose.translation; + // rotate by 180 Y to put the head in same frame as the avatar + headOrientation = headPose.rotation * Quaternions::Y_180; + } + const glm::quat headOrientationYawOnly = cancelOutRollAndPitch(headOrientation); + const float MIX_RATIO = 0.15f; + // here we mix in some of the head yaw into the hip yaw + glm::quat hipYawRot = glm::normalize(glm::lerp(glmExtractRotation(avatarToSensorMat), headOrientationYawOnly, MIX_RATIO)); + glm::quat deltaRot = glm::inverse(glmExtractRotation(avatarToSensorMat))*hipYawRot; + glm::vec3 headPositionLocal = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("Head")); + glm::vec3 headLocalAfterDelta = glm::inverse(deltaRot)*headPositionLocal; + + if (_enableDebugDrawBaseOfSupport) { + // default height is ~ 1.64 meters + float scaleBaseOfSupport = getUserEyeHeight() / DEFAULT_AVATAR_EYE_HEIGHT; + glm::vec3 rightFootPositionLocal = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("RightFoot")); + drawBaseOfSupport(scaleBaseOfSupport, rightFootPositionLocal.y, avatarToWorldMat); + } + + // get the new center of gravity + const glm::vec3 cgHipsPosition = computeCounterBalance(); + glm::vec3 hipsPositionFinal = transformPoint(avatarToSensorMat, cgHipsPosition); + + //find the new hips rotation using the new head-hips axis as the up axis + glm::quat newHipsRotation = computeNewHipsRotation( hipYawRot, headLocalAfterDelta, cgHipsPosition); + return createMatFromQuatAndPos(newHipsRotation, hipsPositionFinal); +} + float MyAvatar::getUserHeight() const { return _userHeight.get(); } @@ -3066,11 +3323,24 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat AnimPose followWorldPose(currentWorldMatrix); + glm::quat currentHipsLocal = myAvatar.getAbsoluteJointRotationInObjectFrame(myAvatar.getJointIndex("Hips")); + const glm::quat hipsinWorldSpace = followWorldPose.rot() * (Quaternions::Y_180 * (currentHipsLocal)); + const glm::vec3 avatarUpWorld = glm::normalize(followWorldPose.rot()*(Vectors::UP)); + glm::quat resultingSwingInWorld; + glm::quat resultingTwistInWorld; + swingTwistDecomposition(hipsinWorldSpace, avatarUpWorld, resultingSwingInWorld, resultingTwistInWorld); + // remove scale present from sensorToWorldMatrix followWorldPose.scale() = glm::vec3(1.0f); if (isActive(Rotation)) { - followWorldPose.rot() = glmExtractRotation(desiredWorldMatrix); + if (getToggleHipsFollowing()) { + //use the hmd reading for the hips follow + followWorldPose.rot() = glmExtractRotation(desiredWorldMatrix); + } else { + //use the hips as changed by the arms azimuth for the hips to follow. + followWorldPose.rot() = resultingTwistInWorld; + } } if (isActive(Horizontal)) { glm::vec3 desiredTranslation = extractTranslation(desiredWorldMatrix); @@ -3466,6 +3736,10 @@ void MyAvatar::updateHoldActions(const AnimPose& prePhysicsPose, const AnimPose& } } +bool MyAvatar::isRecenteringHorizontally() const { + return _follow.isActive(FollowHelper::Horizontal); +} + const MyHead* MyAvatar::getMyHead() const { return static_cast(getHead()); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index ac3d3cd2f4..3293109004 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -105,6 +105,9 @@ class MyAvatar : public Avatar { * by 30cm. Read-only. * @property {Pose} rightHandTipPose - The pose of the right hand as determined by the hand controllers, with the position * by 30cm. Read-only. + * @property {boolean} centerOfGravityModelEnabled=true - If true then the avatar hips are placed according to the center of + * gravity model that balance the center of gravity over the base of support of the feet. Setting the value false + * will result in the default behaviour where the hips are placed under the head. * @property {boolean} hmdLeanRecenterEnabled=true - If true then the avatar is re-centered to be under the * head's position. In room-scale VR, this behavior is what causes your avatar to follow your HMD as you walk around * the room. Setting the value false is useful if you want to pin the avatar to a fixed position. @@ -199,6 +202,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float energy READ getEnergy WRITE setEnergy) Q_PROPERTY(bool isAway READ getIsAway WRITE setAway) + Q_PROPERTY(bool centerOfGravityModelEnabled READ getCenterOfGravityModelEnabled WRITE setCenterOfGravityModelEnabled) Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled) Q_PROPERTY(bool collisionsEnabled READ getCollisionsEnabled WRITE setCollisionsEnabled) Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled) @@ -480,7 +484,16 @@ public: */ Q_INVOKABLE QString getDominantHand() const { return _dominantHand; } - + /**jsdoc + * @function MyAvatar.setCenterOfGravityModelEnabled + * @param {boolean} enabled + */ + Q_INVOKABLE void setCenterOfGravityModelEnabled(bool value) { _centerOfGravityModelEnabled = value; } + /**jsdoc + * @function MyAvatar.getCenterOfGravityModelEnabled + * @returns {boolean} + */ + Q_INVOKABLE bool getCenterOfGravityModelEnabled() const { return _centerOfGravityModelEnabled; } /**jsdoc * @function MyAvatar.setHMDLeanRecenterEnabled * @param {boolean} enabled @@ -564,6 +577,13 @@ public: */ Q_INVOKABLE void triggerRotationRecenter(); + /**jsdoc + *The isRecenteringHorizontally function returns true if MyAvatar + *is translating the root of the Avatar to keep the center of gravity under the head. + *isActive(Horizontal) is returned. + *@function MyAvatar.isRecenteringHorizontally + */ + Q_INVOKABLE bool isRecenteringHorizontally() const; eyeContactTarget getEyeContactTarget(); @@ -956,10 +976,18 @@ public: void removeHoldAction(AvatarActionHold* holdAction); // thread-safe void updateHoldActions(const AnimPose& prePhysicsPose, const AnimPose& postUpdatePose); + // derive avatar body position and orientation from the current HMD Sensor location. // results are in HMD frame glm::mat4 deriveBodyFromHMDSensor() const; + glm::vec3 computeCounterBalance() const; + + // derive avatar body position and orientation from using the current HMD Sensor location in relation to the previous + // location of the base of support of the avatar. + // results are in HMD frame + glm::mat4 deriveBodyUsingCgModel() const; + /**jsdoc * @function MyAvatar.isUp * @param {Vec3} direction @@ -1107,7 +1135,16 @@ public slots: */ Q_INVOKABLE void updateMotionBehaviorFromMenu(); - + /**jsdoc + * @function MyAvatar.setToggleHips + * @param {boolean} enabled + */ + void setToggleHips(bool followHead); + /**jsdoc + * @function MyAvatar.setEnableDebugDrawBaseOfSupport + * @param {boolean} enabled + */ + void setEnableDebugDrawBaseOfSupport(bool isEnabled); /**jsdoc * @function MyAvatar.setEnableDebugDrawDefaultPose * @param {boolean} enabled @@ -1495,9 +1532,12 @@ private: void setForceActivateVertical(bool val); bool getForceActivateHorizontal() const; void setForceActivateHorizontal(bool val); - std::atomic _forceActivateRotation{ false }; - std::atomic _forceActivateVertical{ false }; - std::atomic _forceActivateHorizontal{ false }; + bool getToggleHipsFollowing() const; + void setToggleHipsFollowing(bool followHead); + std::atomic _forceActivateRotation { false }; + std::atomic _forceActivateVertical { false }; + std::atomic _forceActivateHorizontal { false }; + std::atomic _toggleHipsFollowing { true }; }; FollowHelper _follow; @@ -1510,6 +1550,7 @@ private: bool _prevShouldDrawHead; bool _rigEnabled { true }; + bool _enableDebugDrawBaseOfSupport { false }; bool _enableDebugDrawDefaultPose { false }; bool _enableDebugDrawAnimPose { false }; bool _enableDebugDrawHandControllers { false }; @@ -1532,6 +1573,7 @@ private: std::map _controllerPoseMap; mutable std::mutex _controllerPoseMapMutex; + bool _centerOfGravityModelEnabled { true }; bool _hmdLeanRecenterEnabled { true }; bool _sprint { false }; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index fd57657d33..f7f55db369 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -45,7 +45,14 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { return result; } - glm::mat4 hipsMat = myAvatar->deriveBodyFromHMDSensor(); + glm::mat4 hipsMat; + if (myAvatar->getCenterOfGravityModelEnabled()) { + // then we use center of gravity model + hipsMat = myAvatar->deriveBodyUsingCgModel(); + } else { + // otherwise use the default of putting the hips under the head + hipsMat = myAvatar->deriveBodyFromHMDSensor(); + } glm::vec3 hipsPos = extractTranslation(hipsMat); glm::quat hipsRot = glmExtractRotation(hipsMat); @@ -53,8 +60,11 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { glm::mat4 avatarToSensorMat = worldToSensorMat * avatarToWorldMat; // dampen hips rotation, by mixing it with the avatar orientation in sensor space - const float MIX_RATIO = 0.5f; - hipsRot = safeLerp(glmExtractRotation(avatarToSensorMat), hipsRot, MIX_RATIO); + // turning this off for center of gravity model because it is already mixed in there + if (!(myAvatar->getCenterOfGravityModelEnabled())) { + const float MIX_RATIO = 0.5f; + hipsRot = safeLerp(glmExtractRotation(avatarToSensorMat), hipsRot, MIX_RATIO); + } if (isFlying) { // rotate the hips back to match the flying animation. diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index 930da6a494..9f0c789b9d 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -20,6 +20,10 @@ const float DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD = 0.11f; // meters const float DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD = 0.185f; // meters const float DEFAULT_AVATAR_NECK_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD; const float DEFAULT_AVATAR_EYE_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD; +const float DEFAULT_AVATAR_SUPPORT_BASE_LEFT = -0.25f; +const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f; +const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f; +const float DEFAULT_AVATAR_SUPPORT_BASE_BACK = 0.10f; // Used when avatar is missing joints... (avatar space) const glm::quat DEFAULT_AVATAR_MIDDLE_EYE_ROT { Quaternions::Y_180 }; diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 71755e3abb..eec9d8eda6 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -33,7 +33,9 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/emote.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ - "system/controllers/controllerScripts.js" + "system/controllers/controllerScripts.js", + //"developer/step.js", + //"developer/cg_lean.js" //"system/chat.js" ]; diff --git a/scripts/developer/cg_lean.js b/scripts/developer/cg_lean.js new file mode 100644 index 0000000000..a4ca56d6d6 --- /dev/null +++ b/scripts/developer/cg_lean.js @@ -0,0 +1,553 @@ + +/* global Script, Vec3, MyAvatar Tablet Messages Quat DebugDraw Mat4 Xform*/ + + +Script.include("/~/system/libraries/Xform.js"); + +var MESSAGE_CHANNEL = "Hifi-Step-Cg"; + +var ANIM_VARS = [ + "isTalking", + "isNotMoving", + "isMovingForward", + "isMovingBackward", + "isMovingRight", + "isMovingLeft", + "isTurningRight", + "isTurningLeft", + "isFlying", + "isTakeoffStand", + "isTakeoffRun", + "isInAirStand", + "isInAirRun", + "hipsPosition", + "hipsRotation", + "hipsType", + "headWeight", + "headType" +]; + +var DEBUGDRAWING; +var YELLOW; +var BLUE; +var GREEN; +var RED; + +var ROT_Y90; +var ROT_Y180; +var FLOOR_Y; +var IDENT_QUAT; + +var TABLET_BUTTON_NAME; +var RECENTER; +var JOINT_MASSES; + +var hipsUnderHead; + +var armsHipRotation; +var hipsPosition; +var filteredHipsPosition; +var hipsRotation; + +var jointList; +var rightFootName; +var leftFootName; +var rightToeName; +var leftToeName; +var leftToeEnd; +var rightToeEnd; +var leftFoot; +var rightFoot; +var base; + +var clampFront; +var clampBack; +var clampLeft; +var clampRight; + +var tablet; +var tabletButton; + +function initCg() { + + DEBUGDRAWING = false; + + YELLOW = { r: 1, g: 1, b: 0, a: 1 }; + BLUE = { r: 0, g: 0, b: 1, a: 1 }; + GREEN = { r: 0, g: 1, b: 0, a: 1 }; + RED = { r: 1, g: 0, b: 0, a: 1 }; + + ROT_Y90 = { x: 0, y: 0.7071067811865475, z: 0, w: 0.7071067811865476 }; + ROT_Y180 = { x: 0, y: 1, z: 0, w: 0 }; + FLOOR_Y = -0.9; + IDENT_QUAT = { x: 0, y: 0, z: 0, w: 1 }; + + JOINT_MASSES = [{ joint: "Head", mass: 20.0, pos: { x: 0, y: 0, z: 0 } }, + { joint: "LeftHand", mass: 2.0, pos: { x: 0, y: 0, z: 0 } }, + { joint: "RightHand", mass: 2.0, pos: { x: 0, y: 0, z: 0 } }]; + + TABLET_BUTTON_NAME = "CG"; + RECENTER = false; + + MyAvatar.hmdLeanRecenterEnabled = RECENTER; + hipsUnderHead; + + armsHipRotation = { x: 0, y: 1, z: 0, w: 0 }; + hipsPosition = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); + filteredHipsPosition = MyAvatar.position; + hipsRotation = { x: 0, y: 0, z: 0, w: 1 }; + + jointList = MyAvatar.getJointNames(); + // print(JSON.stringify(jointList)); + + rightFootName = null; + leftFootName = null; + rightToeName = null; + leftToeName = null; + leftToeEnd = null; + rightToeEnd = null; + leftFoot; + rightFoot; + + clampFront = -0.10; + clampBack = 0.17; + clampLeft = -0.50; + clampRight = 0.50; + + getFeetAndToeNames(); + base = computeBase(); + mirrorPoints(); + + + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + + tabletButton = tablet.addButton({ + text: TABLET_BUTTON_NAME, + icon: "icons/tablet-icons/avatar-record-i.svg" + }); + + tabletButton.clicked.connect(function () { + print("recenter is: " + RECENTER); + MyAvatar.hmdLeanRecenterEnabled = RECENTER; + RECENTER = !RECENTER; + + // messageSend("clicked button in cg"); + }); + + + var handlerId = MyAvatar.addAnimationStateHandler(function (props) { + + var result = {}; + + // prevent animations from ever leaving the idle state + result.isTalking = false; + result.isFlying = false; + result.isTakeoffStand = false; + result.isTakeoffRun = false; + result.isInAirStand = false; + result.isInAirRun = false; + result.hipsPosition = hipsPosition; + result.hipsRotation = hipsRotation; + result.hipsType = 0; + result.headWeight = 4; + result.headType = 4; + + return result; + }, ANIM_VARS); + + Messages.subscribe(MESSAGE_CHANNEL); + Messages.messageReceived.connect(messageHandler); + Script.update.connect(update); + MyAvatar.skeletonChanged.connect(function () { + Script.setTimeout(function () { + // stop logic if needed + MyAvatar.clearJointsData(); + // reset logic + }, 200); + }); + HMD.displayModeChanged.connect(function () { + Script.setTimeout(function () { + // stop logic if needed + MyAvatar.clearJointsData(); + // reset logic + }, 200); + }); + + +} + +function messageSend(message) { + Messages.sendLocalMessage(MESSAGE_CHANNEL, message); +} + +function messageHandler(channel, messageString, senderID) { + if (channel !== MESSAGE_CHANNEL) { + return; + } + + var hipquat = JSON.parse(messageString); + armsHipRotation = Quat.multiply(ROT_Y180,hipquat); + +} + +function getFeetAndToeNames() { + + for (var i = 0; i < jointList.length; i++) { + if ((jointList[i].indexOf('Right') !== -1) && (jointList[i].indexOf('Foot') !== -1)) { + print(JSON.stringify(jointList[i])); + rightFootName = jointList[i]; + } + if ((jointList[i].indexOf('Left') !== -1) && (jointList[i].indexOf('Foot') !== -1)) { + print(JSON.stringify(jointList[i])); + leftFootName = jointList[i]; + } + if ((jointList[i].indexOf('Right') !== -1) && (jointList[i].indexOf('Toe') !== -1) && (jointList[i].indexOf('End') !== -1)) { + print(JSON.stringify(jointList[i])); + rightToeName = jointList[i]; + } + if ((jointList[i].indexOf('Left') !== -1) && (jointList[i].indexOf('Toe') !== -1) && (jointList[i].indexOf('End') !== -1)) { + print(JSON.stringify(jointList[i])); + leftToeName = jointList[i]; + } + } +} + +function computeBase() { + + if (rightFootName === null || leftFootName === null) { + // if the feet names aren't found then use our best guess of the base. + leftToeEnd = {x: 0.12, y: 0.0, z: 0.12}; + rightToeEnd = {x: -0.18, y: 0.0, z: 0.12}; + leftFoot = {x: 0.15, y: 0.0, z: -0.17}; + rightFoot = {x: -0.20, y: 0.0, z: -0.17}; + } else { + // else we at least found the feet in the skeleton. + var leftFootIndex = MyAvatar.getJointIndex(leftFootName); + var rightFootIndex = MyAvatar.getJointIndex(rightFootName); + var leftFoot = MyAvatar.getAbsoluteJointTranslationInObjectFrame(leftFootIndex); + var rightFoot = MyAvatar.getAbsoluteJointTranslationInObjectFrame(rightFootIndex); + + if (rightToeName === null || leftToeName === null) { + // the toe ends were not found then we use a guess for the length and width of the feet. + leftToeEnd = {x: (leftFoot.x + 0.02), y: 0.0, z: (leftFoot.z - 0.2)}; + rightToeEnd = {x: (rightFoot.x - 0.02), y: 0.0, z: (rightFoot.z - 0.2)}; + } else { + // else we found the toe ends and now we can really compute the base. + var leftToeIndex = MyAvatar.getJointIndex(leftToeName); + var rightToeIndex = MyAvatar.getJointIndex(rightToeName); + leftToeEnd = MyAvatar.getAbsoluteJointTranslationInObjectFrame(leftToeIndex); + rightToeEnd = MyAvatar.getAbsoluteJointTranslationInObjectFrame(rightToeIndex); + } + + } + + // project each point into the FLOOR plane. + var points = [{x: leftToeEnd.x, y: FLOOR_Y, z: leftToeEnd.z}, + {x: rightToeEnd.x, y: FLOOR_Y, z: rightToeEnd.z}, + {x: rightFoot.x, y: FLOOR_Y, z: rightFoot.z}, + {x: leftFoot.x, y: FLOOR_Y, z: rightFoot.z}]; + + // compute normals for each plane + var normal, normals = []; + var n = points.length; + var next, prev; + for (next = 0, prev = n - 1; next < n; prev = next, next++) { + normal = Vec3.multiplyQbyV(ROT_Y90, Vec3.normalize(Vec3.subtract(points[next], points[prev]))); + normals.push(normal); + } + + var TOE_FORWARD_RADIUS = 0.01; + var TOE_SIDE_RADIUS = 0.05; + var HEEL_FORWARD_RADIUS = 0.01; + var HEEL_SIDE_RADIUS = 0.03; + var radii = [ + TOE_SIDE_RADIUS, TOE_FORWARD_RADIUS, TOE_FORWARD_RADIUS, TOE_SIDE_RADIUS, + HEEL_SIDE_RADIUS, HEEL_FORWARD_RADIUS, HEEL_FORWARD_RADIUS, HEEL_SIDE_RADIUS + ]; + + // subdivide base and extrude by the toe and heel radius. + var newPoints = []; + for (next = 0, prev = n - 1; next < n; prev = next, next++) { + newPoints.push(Vec3.sum(points[next], Vec3.multiply(radii[2 * next], normals[next]))); + newPoints.push(Vec3.sum(points[next], Vec3.multiply(radii[(2 * next) + 1], normals[(next + 1) % n]))); + } + + // compute newNormals + var newNormals = []; + n = newPoints.length; + for (next = 0, prev = n - 1; next < n; prev = next, next++) { + normal = Vec3.multiplyQbyV(ROT_Y90, Vec3.normalize(Vec3.subtract(newPoints[next], newPoints[prev]))); + newNormals.push(normal); + } + + for (var j = 0;j Math.abs(base.points[3].x)) { + base.points[3].x = -base.points[0].x; + base.points[2].x = -base.points[1].x; + } else { + base.points[0].x = -base.points[3].x; + base.points[1].x = -base.points[2].x; + } + + if (Math.abs(base.points[4].x) > Math.abs(base.points[7].x)) { + base.points[7].x = -base.points[4].x; + base.points[6].x = -base.points[5].x; + } else { + base.points[4].x = -base.points[7].x; + base.points[5].x = -base.points[6].x; + } + + if (Math.abs(base.points[0].z) > Math.abs(base.points[0].z)) { + base.points[3].z = base.points[0].z; + base.points[2].z = base.points[1].z; + } else { + base.points[0].z = base.points[3].z; + base.points[1].z = base.points[2].z; + } + + if (Math.abs(base.points[4].z) > Math.abs(base.points[7].z)) { + base.points[7].z = base.points[4].z; + base.points[6].z = base.points[5].z; + } else { + base.points[4].z = base.points[7].z; + base.points[5].z = base.points[6].z; + } + + for (var i = 0; i < base.points.length; i++) { + + print("point: " + i + " " + JSON.stringify(base.points[i])); + } + for (var j = 0; j < base.normals.length; j++) { + print("normal: " + j + " " + JSON.stringify(base.normals[j])); + } +} + + +function drawBase(base) { + // transform corners into world space, for rendering. + var xform = new Xform(MyAvatar.orientation, MyAvatar.position); + var worldPoints = base.points.map(function (point) { + return xform.xformPoint(point); + }); + var worldNormals = base.normals.map(function (normal) { + return xform.xformVector(normal); + }); + + var n = worldPoints.length; + var next, prev; + for (next = 0, prev = n - 1; next < n; prev = next, next++) { + if (DEBUGDRAWING) { + // draw border + DebugDraw.drawRay(worldPoints[prev], worldPoints[next], GREEN); + DebugDraw.drawRay(worldPoints[next], worldPoints[prev], GREEN); + + // draw normal + var midPoint = Vec3.multiply(0.5, Vec3.sum(worldPoints[prev], worldPoints[next])); + DebugDraw.drawRay(midPoint, Vec3.sum(midPoint, worldNormals[next]), YELLOW); + DebugDraw.drawRay(midPoint, Vec3.sum(midPoint, worldNormals[next+1]), YELLOW); + } + } +} + +function computeCg() { + // point mass. + var n = JOINT_MASSES.length; + var moments = {x: 0, y: 0, z: 0}; + var masses = 0; + for (var i = 0; i < n; i++) { + var pos = MyAvatar.getAbsoluteJointTranslationInObjectFrame(MyAvatar.getJointIndex(JOINT_MASSES[i].joint)); + JOINT_MASSES[i].pos = pos; + moments = Vec3.sum(moments, Vec3.multiply(JOINT_MASSES[i].mass, pos)); + masses += JOINT_MASSES[i].mass; + } + return Vec3.multiply(1 / masses, moments); +} + + +function clamp(val, min, max) { + return Math.max(min, Math.min(max, val)); +} + +function distancetoline(p1,p2,cg) { + var numerator = Math.abs((p2.z - p1.z)*(cg.x) - (p2.x - p1.x)*(cg.z) + (p2.x)*(p1.z) - (p2.z)*(p1.x)); + var denominator = Math.sqrt( Math.pow((p2.z - p1.z),2) + Math.pow((p2.x - p1.x),2)); + + return numerator/denominator; +} + +function isLeft(a, b, c) { + return (((b.x - a.x)*(c.z - a.z) - (b.z - a.z)*(c.x - a.x)) > 0); +} + +function slope(num) { + var constant = 1.0; + return 1 - ( 1/(1+constant*num)); +} + +function dampenCgMovement(rawCg) { + + var distanceFromCenterZ = rawCg.z; + var distanceFromCenterX = rawCg.x; + + // clampFront = -0.10; + // clampBack = 0.17; + // clampLeft = -0.50; + // clampRight = 0.50; + + var dampedCg = { x: 0, y: 0, z: 0 }; + + if (rawCg.z < 0.0) { + var inputFront; + inputFront = Math.abs(distanceFromCenterZ / clampFront); + var scaleFrontNew = slope(inputFront); + dampedCg.z = scaleFrontNew * clampFront; + } else { + // cg.z > 0.0 + var inputBack; + inputBack = Math.abs(distanceFromCenterZ / clampBack); + var scaleBackNew = slope(inputBack); + dampedCg.z = scaleBackNew * clampBack; + } + + if (rawCg.x > 0.0) { + var inputRight; + inputRight = Math.abs(distanceFromCenterX / clampRight); + var scaleRightNew = slope(inputRight); + dampedCg.x = scaleRightNew * clampRight; + } else { + // left of center + var inputLeft; + inputLeft = Math.abs(distanceFromCenterX / clampLeft); + var scaleLeftNew = slope(inputLeft); + dampedCg.x = scaleLeftNew * clampLeft; + } + return dampedCg; +} + +function computeCounterBalance(desiredCgPos) { + // compute hips position to maintain desiredCg + var HIPS_MASS = 40; + var totalMass = JOINT_MASSES.reduce(function (accum, obj) { + return accum + obj.mass; + }, 0); + var temp1 = Vec3.subtract(Vec3.multiply(totalMass + HIPS_MASS, desiredCgPos), + Vec3.multiply(JOINT_MASSES[0].mass, JOINT_MASSES[0].pos)); + var temp2 = Vec3.subtract(temp1, + Vec3.multiply(JOINT_MASSES[1].mass, JOINT_MASSES[1].pos)); + var temp3 = Vec3.subtract(temp2, + Vec3.multiply(JOINT_MASSES[2].mass, JOINT_MASSES[2].pos)); + var temp4 = Vec3.multiply(1 / HIPS_MASS, temp3); + + + var currentHead = MyAvatar.getAbsoluteJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); + var tposeHead = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); + var tposeHips = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); + + var xzDiff = { x: (currentHead.x - temp4.x), y: 0, z: (currentHead.z - temp4.z) }; + var headMinusHipXz = Vec3.length(xzDiff); + + var headHipDefault = Vec3.length(Vec3.subtract(tposeHead, tposeHips)); + + var hipHeight = Math.sqrt((headHipDefault * headHipDefault) - (headMinusHipXz * headMinusHipXz)); + + temp4.y = (currentHead.y - hipHeight); + if (temp4.y > tposeHips.y) { + temp4.y = 0.0; + } + return temp4; +} + +function update(dt) { + + var cg = computeCg(); + // print("time elapsed " + dt); + + var desiredCg = { x: 0, y: 0, z: 0 }; + // print("the raw cg " + cg.x + " " + cg.y + " " + cg.z); + + desiredCg.x = cg.x; + desiredCg.y = 0; + desiredCg.z = cg.z; + + desiredCg = dampenCgMovement(cg); + + cg.y = FLOOR_Y; + + // after the dampening above it might be right to clamp the desiredcg to the edge of the base + // of support. + + if (DEBUGDRAWING) { + DebugDraw.addMyAvatarMarker("left toe", IDENT_QUAT, leftToeEnd, BLUE); + DebugDraw.addMyAvatarMarker("right toe", IDENT_QUAT, rightToeEnd, BLUE); + DebugDraw.addMyAvatarMarker("cg", IDENT_QUAT, cg, BLUE); + DebugDraw.addMyAvatarMarker("desiredCg", IDENT_QUAT, desiredCg, GREEN); + drawBase(base); + } + + var currentHeadPos = MyAvatar.getAbsoluteJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); + var localHipsPos = computeCounterBalance(desiredCg); + // print("current hips " + cg.x + " " + cg.y + " " + cg.z); + // print("dampened hips " + desiredCg.x + " " + desiredCg.y + " " + desiredCg.z) + + var globalPosRoot = MyAvatar.position; + var globalRotRoot = Quat.normalize(MyAvatar.orientation); + var inverseGlobalRotRoot = Quat.normalize(Quat.inverse(globalRotRoot)); + var globalPosHips = Vec3.sum(globalPosRoot, Vec3.multiplyQbyV(globalRotRoot, localHipsPos)); + var unRotatedHipsPosition; + + if (!MyAvatar.isRecenteringHorizontally()) { + + filteredHipsPosition = Vec3.mix(filteredHipsPosition, globalPosHips, 0.1); + unRotatedHipsPosition = Vec3.multiplyQbyV(inverseGlobalRotRoot, Vec3.subtract(filteredHipsPosition, globalPosRoot)); + hipsPosition = Vec3.multiplyQbyV(ROT_Y180, unRotatedHipsPosition); + } else { + // DebugDraw.addMarker("hipsunder", IDENT_QUAT, hipsUnderHead, GREEN); + filteredHipsPosition = Vec3.mix(filteredHipsPosition, globalPosHips, 0.1); + unRotatedHipsPosition = Vec3.multiplyQbyV(inverseGlobalRotRoot, Vec3.subtract(filteredHipsPosition, globalPosRoot)); + hipsPosition = Vec3.multiplyQbyV(ROT_Y180, unRotatedHipsPosition); + } + + var newYaxisHips = Vec3.normalize(Vec3.subtract(currentHeadPos, unRotatedHipsPosition)); + var forward = { x: 0.0, y: 0.0, z: 1.0 }; + + // arms hip rotation is sent from the step script + var oldZaxisHips = Vec3.normalize(Vec3.multiplyQbyV(armsHipRotation, forward)); + var newXaxisHips = Vec3.normalize(Vec3.cross(newYaxisHips, oldZaxisHips)); + var newZaxisHips = Vec3.normalize(Vec3.cross(newXaxisHips, newYaxisHips)); + + // var beforeHips = MyAvatar.getAbsoluteJointRotationInObjectFrame(MyAvatar.getJointIndex("Hips")); + var left = { x: newXaxisHips.x, y: newXaxisHips.y, z: newXaxisHips.z, w: 0.0 }; + var up = { x: newYaxisHips.x, y: newYaxisHips.y, z: newYaxisHips.z, w: 0.0 }; + var view = { x: newZaxisHips.x, y: newZaxisHips.y, z: newZaxisHips.z, w: 0.0 }; + + var translation = { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }; + var newRotHips = Mat4.createFromColumns(left, up, view, translation); + var finalRot = Mat4.extractRotation(newRotHips); + + hipsRotation = Quat.multiply(ROT_Y180, finalRot); + print("final rot" + finalRot.x + " " + finalRot.y + " " + finalRot.z + " " + finalRot.w); + + if (DEBUGDRAWING) { + DebugDraw.addMyAvatarMarker("hipsPos", IDENT_QUAT, hipsPosition, RED); + } +} + + +Script.setTimeout(initCg, 10); +Script.scriptEnding.connect(function () { + Script.update.disconnect(update); + if (tablet) { + tablet.removeButton(tabletButton); + } + Messages.messageReceived.disconnect(messageHandler); + Messages.unsubscribe(MESSAGE_CHANNEL); + +}); diff --git a/tests/animation/src/data/avatar.json b/tests/animation/src/data/avatar.json index 550a95e980..3b80ff6d77 100644 --- a/tests/animation/src/data/avatar.json +++ b/tests/animation/src/data/avatar.json @@ -363,7 +363,7 @@ { "id": "idle", "interpTarget": 6, - "interpDuration": 6, + "interpDuration": 3, "transitions": [ { "var": "isMovingForward", "state": "walkFwd" }, { "var": "isMovingBackward", "state": "walkBwd" }, From bbf8c7357248cca8c83ab1dd99f1a7bd4b754645 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 8 May 2018 10:52:28 -0700 Subject: [PATCH 018/380] code review changes to declare functions static --- interface/src/avatar/MyAvatar.cpp | 39 ++++++++++++++++++------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c3df9f6143..c78fc1c11b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2847,32 +2847,37 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { return createMatFromQuatAndPos(headOrientationYawOnly, bodyPos); } -float slope(float num) { - float constantK = 1.0; +// ease in function for dampening cg movement +static float slope(float num) { + const float CURVE_CONSTANT = 1.0f; float ret = 1.0f; if (num > 0.0f) { - ret = 1.0f - (1.0f / (1.0f + constantK * num)); + ret = 1.0f - (1.0f / (1.0f + CURVE_CONSTANT * num)); } return ret; } -glm::vec3 dampenCgMovement(glm::vec3 rawCg, float baseOfSupportScale) { +// This function gives a soft clamp at the edge of the base of support +// dampenCgMovement returns the cg value in Avatar space. +// rawCg is also in Avatar space +// baseOfSupportScale is based on the height of the user +static glm::vec3 dampenCgMovement(glm::vec3 rawCg, float baseOfSupportScale) { float distanceFromCenterZ = rawCg.z; float distanceFromCenterX = rawCg.x; - // The dampening scale factors makes the slope function soft clamp the - // cg at the edge of the base of support of the feet, in the lateral and posterior directions. - // In the forward direction we need a different scale because forward is in - // the direction of the hip extensor joint, which means bending usually happens + // The dampening scale factors makes the slope function soft clamp the + // cg at the edge of the base of support of the feet, in the lateral and posterior directions. + // In the forward direction we need a different scale because forward is in + // the direction of the hip extensor joint, which means bending usually happens // well before reaching the edge of the base of support. // The scale of the base of support reflects the size of the user in real life. - float forwardDampeningFactor = 0.5f; - float lateralAndBackDampeningScaleFactor = 2.0f; - float clampFront = DEFAULT_AVATAR_SUPPORT_BASE_FRONT * forwardDampeningFactor * baseOfSupportScale; + const float forwardDampeningFactor = 0.5f; + const float lateralAndBackDampeningScaleFactor = 2.0f; + const float clampFront = DEFAULT_AVATAR_SUPPORT_BASE_FRONT * forwardDampeningFactor * baseOfSupportScale; float clampBack = DEFAULT_AVATAR_SUPPORT_BASE_BACK * lateralAndBackDampeningScaleFactor * baseOfSupportScale; float clampLeft = DEFAULT_AVATAR_SUPPORT_BASE_LEFT * lateralAndBackDampeningScaleFactor * baseOfSupportScale; float clampRight = DEFAULT_AVATAR_SUPPORT_BASE_RIGHT * lateralAndBackDampeningScaleFactor * baseOfSupportScale; - glm::vec3 dampedCg = {0.0f,0.0f,0.0f}; + glm::vec3 dampedCg(0.0f, 0.0f, 0.0f); // find the damped z coord of the cg if (rawCg.z < 0.0f) { @@ -2906,8 +2911,9 @@ glm::vec3 dampenCgMovement(glm::vec3 rawCg, float baseOfSupportScale) { return dampedCg; } +// computeCounterBalance returns the center of gravity in Avatar space glm::vec3 MyAvatar::computeCounterBalance() const { - struct jointMass { + struct JointMass { QString name; float weight; glm::vec3 position; @@ -2925,14 +2931,14 @@ glm::vec3 MyAvatar::computeCounterBalance() const { // find the current center of gravity position based on head and hand moments float hipsMass = 40.0f; float totalMass = 0.0f; - glm::vec3 sumOfMoments = { 0.0f, 0.0f, 0.0f }; + glm::vec3 sumOfMoments(0.0f, 0.0f, 0.0f); for (int i = 0; i < 3; i++) { const QString jointName = cgMasses[i].name; cgMasses[i].position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(jointName)); sumOfMoments += cgMasses[i].weight * cgMasses[i].position; totalMass += cgMasses[i].weight; } - glm::vec3 currentCg = (1 / totalMass) * sumOfMoments; + glm::vec3 currentCg = (1.0f / totalMass) * sumOfMoments; currentCg.y = 0.0f; // dampening the center of gravity, in effect, limits the value to the perimeter of the base of support float baseScale = 1.0f; @@ -2969,7 +2975,8 @@ glm::vec3 MyAvatar::computeCounterBalance() const { return counterBalancedCg; } -glm::quat computeNewHipsRotation(glm::quat hipYawRot, glm::vec3 curHead, glm::vec3 hipPos) { +// this function matches the hips rotation to the new cg head axis +static glm::quat computeNewHipsRotation(glm::quat hipYawRot, glm::vec3 curHead, glm::vec3 hipPos) { glm::vec3 spineVec = curHead - hipPos; glm::quat finalRot = Quaternions::IDENTITY; From 544967ef3bbeb5835333c91729a99306b7645853 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 8 May 2018 10:55:10 -0700 Subject: [PATCH 019/380] added test function to cancel out roll and pitch --- interface/src/avatar/MyAvatar.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c3df9f6143..b9fa8d2ac6 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3049,6 +3049,30 @@ void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::mat4 avat DebugDraw::getInstance().drawRay(frontLeft, frontRight, rayColor); } +// cancel out roll and pitch test fix +glm::quat cancelOutRollAndPitch2(const glm::quat& q) { + glm::vec3 zAxis = q * glm::vec3(0.0f, 0.0f, 1.0f); + glm::vec3 newZ; + glm::vec3 newX; + glm::vec3 newY; + // cancel out the roll and pitch + if (zAxis.x == 0 && zAxis.z == 0.0f) { + if (fabs(zAxis.y) > 0.0) { + // new z is the up axis, that is the direction the body is pointing + newZ = glm::normalize(q * glm::vec3(0.0f, 1.0f, 0.0f)); + } + newX = glm::cross(vec3(0.0f, 1.0f, 0.0f), newZ); + newY = glm::cross(newZ, newX); + } + else { + newZ = glm::normalize(vec3(zAxis.x, 0.0f, zAxis.z)); + newX = glm::cross(vec3(0.0f, 1.0f, 0.0f), newZ); + newY = glm::cross(newZ, newX); + } + glm::mat4 temp(glm::vec4(newX, 0.0f), glm::vec4(newY, 0.0f), glm::vec4(newZ, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + return glm::quat_cast(temp); +} + glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { glm::mat4 worldToSensorMat = glm::inverse(getSensorToWorldMatrix()); glm::mat4 avatarToWorldMat = getTransform().getMatrix(); @@ -3062,7 +3086,7 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { // rotate by 180 Y to put the head in same frame as the avatar headOrientation = headPose.rotation * Quaternions::Y_180; } - const glm::quat headOrientationYawOnly = cancelOutRollAndPitch(headOrientation); + const glm::quat headOrientationYawOnly = cancelOutRollAndPitch2(headOrientation); const float MIX_RATIO = 0.15f; // here we mix in some of the head yaw into the hip yaw glm::quat hipYawRot = glm::normalize(glm::lerp(glmExtractRotation(avatarToSensorMat), headOrientationYawOnly, MIX_RATIO)); From 07600f2a81b98c8c3317fa53b02dfb7acd731529 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 3 May 2018 20:21:05 -0400 Subject: [PATCH 020/380] add etc2comp dependency on desktop and android --- android/build.gradle | 45 ++++++++++++++----------- cmake/externals/etc2comp/CMakeLists.txt | 44 ++++++++++++++++++++++++ cmake/macros/TargetEtc2Comp.cmake | 22 ++++++++++++ cmake/modules/FindEtc2Comp.cmake | 37 ++++++++++++++++++++ libraries/image/CMakeLists.txt | 1 + libraries/image/src/image/Image.cpp | 6 ++++ 6 files changed, 136 insertions(+), 19 deletions(-) create mode 100644 cmake/externals/etc2comp/CMakeLists.txt create mode 100644 cmake/macros/TargetEtc2Comp.cmake create mode 100644 cmake/modules/FindEtc2Comp.cmake diff --git a/android/build.gradle b/android/build.gradle index 1dfef97f91..e041142282 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,7 +14,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.0' } } @@ -66,19 +66,19 @@ ext { def baseFolder = new File(HIFI_ANDROID_PRECOMPILED) def appDir = new File(projectDir, 'app') def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a') -def baseUrl = 'https://hifi-public.s3.amazonaws.com/austin/android/' +def baseUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/android/' def qtFile='qt-5.9.3_linux_armv8-libcpp_openssl.tgz' def qtChecksum='04599670ccca84bd2b15f6915568eb2d' -def qtVersionId='PeoqzN31n.YvLfs9JE2SgHgZ4.IaKAlt' +def qtVersionId='8QbCma4ryEPgBYn_8kgYgB10IvNx9I1W' if (Os.isFamily(Os.FAMILY_MAC)) { qtFile = 'qt-5.9.3_osx_armv8-libcpp_openssl.tgz' qtChecksum='4b02de9d67d6bfb202355a808d2d9c59' - qtVersionId='HygCmtMLPYioyil0DfXckGVzhw2SXZA9' + qtVersionId='2gfgoYCggJGyXxKiazaPGsMs1Gn9j4og' } else if (Os.isFamily(Os.FAMILY_WINDOWS)) { qtFile = 'qt-5.9.3_win_armv8-libcpp_openssl.tgz' qtChecksum='c3e25db64002d0f43cf565e0ef708911' - qtVersionId='HeVObSVLCBoc7yY7He1oBMvPIH0VkClT' + qtVersionId='xKIteC6HO0xrmcWeMmhQcmKyPEsnUrcZ' } def packages = [ @@ -89,61 +89,66 @@ def packages = [ ], bullet: [ file: 'bullet-2.83_armv8-libcpp.tgz', - versionId: 'ljb7v.1IjVRqyopUKVDbVnLA4z88J8Eo', + versionId: 'L6MqTwt24yZAx0cHgLyN.GPky1kVGsq3', checksum: '2c558d604fce337f5eba3eb7ec1252fd', ], draco: [ file: 'draco_armv8-libcpp.tgz', - versionId: 'cA3tVJSmkvb1naA3l6D_Jv2Noh.4yc4m', + versionId: '3.B.uBj31kWlgND3_R2xwQzT_TP6Dz_8', checksum: '617a80d213a5ec69fbfa21a1f2f738cd', ], glad: [ file: 'glad_armv8-libcpp.zip', - versionId: 'Q9szthzeye8fFyAA.cY26Lgn2B8kezEE', + versionId: 'r5Zran.JSCtvrrB6Q4KaqfIoALPw3lYY', checksum: 'a8ee8584cf1ccd34766c7ddd9d5e5449', ], glm: [ file: 'glm-0.9.8.tgz', - versionId: 'BlkJNwaYV2Gfy5XwMeU7K0uzPDRKFMt2', + versionId: 'CHPAk.Un_8MC4v8cIqkEJ468Y4_RQDmd', checksum: 'd2b42cee31d2bc17bab6ce69e6b3f30a', ], gvr: [ file: 'gvrsdk_v1.101.0.tgz', - versionId: 'UTberAIFraEfF9IVjoV66u1DTPTopgeY', + versionId: 'nqBV_j81Uc31rC7bKIrlya_Hah4v3y5r', checksum: '57fd02baa069176ba18597a29b6b4fc7', ], nvtt: [ file: 'nvtt_armv8-libcpp.zip', - versionId: 'vLqrqThvpq4gp75BHMAqO6HhfTXaa0An', + versionId: 'lmkBVR5t4UF1UUwMwEirnk9H_8Nt90IO', checksum: 'eb46d0b683e66987190ed124aabf8910', sharedLibFolder: 'lib', includeLibs: ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so'], ], openssl: [ file: 'openssl-1.1.0g_armv8.tgz', - versionId: 'DmahmSGFS4ltpHyTdyQvv35WOeUOiib9', + versionId: 'AiiPjmgUZTgNj7YV1EEx2lL47aDvvvAW', checksum: 'cabb681fbccd79594f65fcc266e02f32', ], polyvox: [ file: 'polyvox_armv8-libcpp.tgz', - versionId: 'LDJtzMTvdm4SAc2KYg8Cg6uwWk4Vq3e3', - checksum: '349ad5b72aaf2749ca95d847e60c5314', + versionId: 'UmHp.EOFiepdXnv2YxwNXNO3J6nVsBkE', + checksum: '5c918288741ee754c16aeb12bb46b9e1', sharedLibFolder: 'lib', includeLibs: ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'], ], tbb: [ file: 'tbb-2018_U1_armv8_libcpp.tgz', - versionId: 'YZliDD8.Menh1IVXKEuLPeO3xAjJ1UdF', + versionId: 'mrRbWnv4O4evcM1quRH43RJqimlRtaKB', checksum: '20768f298f53b195e71b414b0ae240c4', sharedLibFolder: 'lib/release', includeLibs: ['libtbb.so', 'libtbbmalloc.so'], ], hifiAC: [ file: 'libplugins_libhifiCodec.zip', - versionId: 'mzKhsRCgVmloqq5bvE.0IwYK1NjGQc_G', + versionId: 'i31pW.qNbvFOXRxbyiJUxg3sphaFNmZU', checksum: '9412a8e12c88a4096c1fc843bb9fe52d', sharedLibFolder: '', includeLibs: ['libplugins_libhifiCodec.so'] + ], + etc2comp: [ + file: 'etc2comp-armv8-libcpp.tgz', + versionId: '1WfqJYWLOP0g22eikYjBzn62gza7MKE6', + checksum: '0b4c2e6de728546845f0e471dfdeb604' ] ] @@ -152,15 +157,15 @@ def scribeLocalFile='scribe' + EXEC_SUFFIX def scribeFile='scribe_linux_x86_64' def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6' -def scribeVersion='wgpf4dB2Ltzg4Lb2jJ4nPFsHoDkmK_OO' +def scribeVersion='u_iTrJDaE95i2abTPXOpPZckGBIim53G' if (Os.isFamily(Os.FAMILY_MAC)) { scribeFile = 'scribe_osx_x86_64' scribeChecksum='72db9d32d4e1e50add755570ac5eb749' - scribeVersion='o_NbPrktzEYtBkQf3Tn7zc1nZWzM52w6' + scribeVersion='DAW0DmnjCRib4MD8x93bgc2Z2MpPojZC' } else if (Os.isFamily(Os.FAMILY_WINDOWS)) { scribeFile = 'scribe_win32_x86_64.exe' scribeChecksum='678e43d290c90fda670c6fefe038a06d' - scribeVersion='GCCJxlmd2irvNOFWfZR0U1UCLHndHQrC' + scribeVersion='PuullrA_bPlO9kXZRt8rLe536X1UI.m7' } def options = [ @@ -361,6 +366,7 @@ task verifyOpenSSL(type: Verify) { def p = packages['openssl']; src new File(bas task verifyPolyvox(type: Verify) { def p = packages['polyvox']; src new File(baseFolder, p['file']); checksum p['checksum'] } task verifyTBB(type: Verify) { def p = packages['tbb']; src new File(baseFolder, p['file']); checksum p['checksum'] } task verifyHifiAC(type: Verify) { def p = packages['hifiAC']; src new File(baseFolder, p['file']); checksum p['checksum'] } +task verifyEtc2Comp(type: Verify) { def p = packages['etc2comp']; src new File(baseFolder, p['file']); checksum p['checksum'] } task verifyDependencyDownloads(dependsOn: downloadDependencies) { } verifyDependencyDownloads.dependsOn verifyQt @@ -371,6 +377,7 @@ verifyDependencyDownloads.dependsOn verifyOpenSSL verifyDependencyDownloads.dependsOn verifyPolyvox verifyDependencyDownloads.dependsOn verifyTBB verifyDependencyDownloads.dependsOn verifyHifiAC +verifyDependencyDownloads.dependsOn verifyEtc2Comp task extractDependencies(dependsOn: verifyDependencyDownloads) { doLast { diff --git a/cmake/externals/etc2comp/CMakeLists.txt b/cmake/externals/etc2comp/CMakeLists.txt new file mode 100644 index 0000000000..9cee0652bc --- /dev/null +++ b/cmake/externals/etc2comp/CMakeLists.txt @@ -0,0 +1,44 @@ +set(EXTERNAL_NAME etc2comp) + +if (ANDROID) + set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19") +endif () + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://hifi-public.s3.amazonaws.com/dependencies/etc2comp-master.zip + URL_MD5 d0969e14af6b10b3306f880c8e2b1184 + CMAKE_ARGS ${ANDROID_CMAKE_ARGS} + BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +if (WIN32) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/build/EtcLib/Debug/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp debug library") + + # use generator expression to ensure the correct library is found when building different configurations in VS + set(_LIB_FOLDER "$<$:build/EtcLib/RelWithDebInfo>") + set(_LIB_FOLDER "${_LIB_FOLDER}$<$:build/EtcLib/MinSizeRel>") + set(_LIB_FOLDER "${_LIB_FOLDER}$<$,$>:build/EtcLib/Release>") + + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/${_LIB_FOLDER}/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp release library") +else () + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Path to EtcLib debug library") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/build/EtcLib/libEtcLib.a CACHE FILEPATH "Path to EtcLib release library") +endif () + +set(ETC_INCLUDE_DIR ${SOURCE_DIR}/EtcLib/Etc CACHE FILEPATH "Path to Etc2Comp/Etc include directory") +set(ETCCODEC_INCLUDE_DIR ${SOURCE_DIR}/EtcLib/EtcCodec CACHE FILEPATH "Path to Etc2Comp/EtcCodec include directory") +# ETC2COMP_INCLUDE_DIRS will be set later by FindEtc2Comp \ No newline at end of file diff --git a/cmake/macros/TargetEtc2Comp.cmake b/cmake/macros/TargetEtc2Comp.cmake new file mode 100644 index 0000000000..8dfae175a9 --- /dev/null +++ b/cmake/macros/TargetEtc2Comp.cmake @@ -0,0 +1,22 @@ +# +# Copyright 2018 High Fidelity, Inc. +# Created by Sam Gondelman on 5/2/2018 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_ETC2COMP) + if (ANDROID) + set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/etc2comp) + set(ETC2COMP_INCLUDE_DIRS "${INSTALL_DIR}/include/Etc" "${INSTALL_DIR}/include/EtcCodec") + set(ETC2COMP_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libEtcLib.a) + set(ETC2COMP_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libEtcLib.a) + select_library_configurations(ETC2COMP) + else() + add_dependency_external_projects(etc2comp) + find_package(ETC2COMP REQUIRED) + endif() + + target_include_directories(${TARGET_NAME} PRIVATE ${ETC2COMP_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${ETC2COMP_LIBRARIES}) +endmacro() diff --git a/cmake/modules/FindEtc2Comp.cmake b/cmake/modules/FindEtc2Comp.cmake new file mode 100644 index 0000000000..1b990368fd --- /dev/null +++ b/cmake/modules/FindEtc2Comp.cmake @@ -0,0 +1,37 @@ +# +# FindEtc2Comp.cmake +# +# Try to find the Etc2Comp compression library. +# +# Once done this will define +# +# ETC2COMP_FOUND - system found Etc2Comp +# ETC2COMP_INCLUDE_DIRS - the Etc2Comp include directory +# ETC2COMP_LIBRARIES - link to this to use Etc2Comp +# +# Created on 5/2/2018 by Sam Gondelman +# Copyright 2018 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") +hifi_library_search_hints("etc2comp") + +find_path(ETC_INCLUDE_DIR NAMES Etc.h HINTS ${ETC2COMP_SEARCH_DIRS}) +find_path(ETCCODEC_INCLUDE_DIR NAMES EtcBlock4x4.h HINTS ${ETC2COMP_SEARCH_DIRS}) +set(ETC2COMP_INCLUDE_DIRS "${ETC_INCLUDE_DIR}" "${ETCCODEC_INCLUDE_DIR}") + +find_library(ETC2COMP_LIBRARY_DEBUG NAMES ETC2COMP ETC2COMP_LIB PATH_SUFFIXES EtcLib/Debug HINTS ${ETC2COMP_SEARCH_DIRS}) +find_library(ETC2COMP_LIBRARY_RELEASE NAMES ETC2COMP ETC2COMP_LIB PATH_SUFFIXES EtcLib/Release EtcLib HINTS ${ETC2COMP_SEARCH_DIRS}) + +include(SelectLibraryConfigurations) +select_library_configurations(ETC2COMP) + +set(ETC2COMP_LIBRARIES ${ETC2COMP_LIBRARY}) + +find_package_handle_standard_args(ETC2COMP "Could NOT find ETC2COMP, try to set the path to ETC2COMP root folder in the system variable ETC2COMP_ROOT_DIR or create a directory etc2comp in HIFI_LIB_DIR and paste the necessary files there" + ETC2COMP_INCLUDE_DIRS ETC2COMP_LIBRARIES) + +mark_as_advanced(ETC2COMP_INCLUDE_DIRS ETC2COMP_LIBRARIES ETC2COMP_SEARCH_DIRS) diff --git a/libraries/image/CMakeLists.txt b/libraries/image/CMakeLists.txt index 8073cc2b5e..6bc5c762f5 100644 --- a/libraries/image/CMakeLists.txt +++ b/libraries/image/CMakeLists.txt @@ -2,3 +2,4 @@ set(TARGET_NAME image) setup_hifi_library() link_hifi_libraries(shared gpu) target_nvtt() +target_etc2comp() diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index c1c07838c7..1639dde246 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -31,8 +31,14 @@ using namespace gpu; #define CPU_MIPMAPS 1 #include +#include + static const glm::uvec2 SPARSE_PAGE_SIZE(128); +#ifdef Q_OS_ANDROID +static const glm::uvec2 MAX_TEXTURE_SIZE(1024); +#else static const glm::uvec2 MAX_TEXTURE_SIZE(4096); +#endif bool DEV_DECIMATE_TEXTURES = false; std::atomic DECIMATED_TEXTURE_COUNT{ 0 }; std::atomic RECTIFIED_TEXTURE_COUNT{ 0 }; From 8000bcd272fc907df4ffee73dcd6f93a3e8cfb1f Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 8 May 2018 18:12:53 -0700 Subject: [PATCH 021/380] cleaned up cg code ie computeNewHipsRotation --- interface/src/avatar/MyAvatar.cpp | 205 ++++++++++--------------- libraries/shared/src/AvatarConstants.h | 7 + 2 files changed, 91 insertions(+), 121 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5faebb0789..941aecc58b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2858,55 +2858,38 @@ static float slope(float num) { } // This function gives a soft clamp at the edge of the base of support -// dampenCgMovement returns the cg value in Avatar space. -// rawCg is also in Avatar space +// dampenCgMovement returns the damped cg value in Avatar space. +// cgUnderHeadHandsAvatarSpace is also in Avatar space // baseOfSupportScale is based on the height of the user -static glm::vec3 dampenCgMovement(glm::vec3 rawCg, float baseOfSupportScale) { - float distanceFromCenterZ = rawCg.z; - float distanceFromCenterX = rawCg.x; +static glm::vec3 dampenCgMovement(glm::vec3 cgUnderHeadHandsAvatarSpace, float baseOfSupportScale) { + float distanceFromCenterZ = cgUnderHeadHandsAvatarSpace.z; + float distanceFromCenterX = cgUnderHeadHandsAvatarSpace.x; - // The dampening scale factors makes the slope function soft clamp the - // cg at the edge of the base of support of the feet, in the lateral and posterior directions. // In the forward direction we need a different scale because forward is in // the direction of the hip extensor joint, which means bending usually happens // well before reaching the edge of the base of support. - // The scale of the base of support reflects the size of the user in real life. - const float forwardDampeningFactor = 0.5f; - const float lateralAndBackDampeningScaleFactor = 2.0f; - const float clampFront = DEFAULT_AVATAR_SUPPORT_BASE_FRONT * forwardDampeningFactor * baseOfSupportScale; - float clampBack = DEFAULT_AVATAR_SUPPORT_BASE_BACK * lateralAndBackDampeningScaleFactor * baseOfSupportScale; - float clampLeft = DEFAULT_AVATAR_SUPPORT_BASE_LEFT * lateralAndBackDampeningScaleFactor * baseOfSupportScale; - float clampRight = DEFAULT_AVATAR_SUPPORT_BASE_RIGHT * lateralAndBackDampeningScaleFactor * baseOfSupportScale; + const float clampFront = DEFAULT_AVATAR_SUPPORT_BASE_FRONT * DEFAULT_AVATAR_FORWARD_DAMPENING_FACTOR * baseOfSupportScale; + float clampBack = DEFAULT_AVATAR_SUPPORT_BASE_BACK * DEFAULT_AVATAR_LATERAL_DAMPENING_FACTOR * baseOfSupportScale; + float clampLeft = DEFAULT_AVATAR_SUPPORT_BASE_LEFT * DEFAULT_AVATAR_LATERAL_DAMPENING_FACTOR * baseOfSupportScale; + float clampRight = DEFAULT_AVATAR_SUPPORT_BASE_RIGHT * DEFAULT_AVATAR_LATERAL_DAMPENING_FACTOR * baseOfSupportScale; glm::vec3 dampedCg(0.0f, 0.0f, 0.0f); // find the damped z coord of the cg - if (rawCg.z < 0.0f) { + if (cgUnderHeadHandsAvatarSpace.z < 0.0f) { // forward displacement - float inputFront; - inputFront = fabs(distanceFromCenterZ / clampFront); - float scaleFrontNew = slope(inputFront); - dampedCg.z = scaleFrontNew * clampFront; + dampedCg.z = slope(fabs(distanceFromCenterZ / clampFront)) * clampFront; } else { // backwards displacement - float inputBack; - inputBack = fabs(distanceFromCenterZ / clampBack); - float scaleBackNew = slope(inputBack); - dampedCg.z = scaleBackNew * clampBack; + dampedCg.z = slope(fabs(distanceFromCenterZ / clampBack)) * clampBack; } // find the damped x coord of the cg - if (rawCg.x > 0.0f) { + if (cgUnderHeadHandsAvatarSpace.x > 0.0f) { // right of center - float inputRight; - inputRight = fabs(distanceFromCenterX / clampRight); - float scaleRightNew = slope(inputRight); - dampedCg.x = scaleRightNew * clampRight; + dampedCg.x = slope(fabs(distanceFromCenterX / clampRight)) * clampRight; } else { // left of center - float inputLeft; - inputLeft = fabs(distanceFromCenterX / clampLeft); - float scaleLeftNew = slope(inputLeft); - dampedCg.x = scaleLeftNew * clampLeft; + dampedCg.x = slope(fabs(distanceFromCenterX / clampLeft)) * clampLeft; } return dampedCg; } @@ -2917,27 +2900,43 @@ glm::vec3 MyAvatar::computeCounterBalance() const { QString name; float weight; glm::vec3 position; - } cgMasses[3]; + JointMass() {}; + JointMass(QString n, float w, glm::vec3 p) { + name = n; + weight = w; + position = p; + } + }; + // init the body part weights - cgMasses[0].name = "Head"; - cgMasses[0].weight = 20.0f; - cgMasses[0].position = { 0.0f, 0.0f, 0.0f }; - cgMasses[1].name = "LeftHand"; - cgMasses[1].weight = 2.0f; - cgMasses[1].position = { 0.0f, 0.0f, 0.0f }; - cgMasses[2].name = "RightHand"; - cgMasses[2].weight = 2.0f; - cgMasses[2].position = { 0.0f, 0.0f, 0.0f }; - // find the current center of gravity position based on head and hand moments - float hipsMass = 40.0f; - float totalMass = 0.0f; - glm::vec3 sumOfMoments(0.0f, 0.0f, 0.0f); - for (int i = 0; i < 3; i++) { - const QString jointName = cgMasses[i].name; - cgMasses[i].position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(jointName)); - sumOfMoments += cgMasses[i].weight * cgMasses[i].position; - totalMass += cgMasses[i].weight; + JointMass cgHeadMass(QString("Head"), DEFAULT_AVATAR_HEAD_MASS, glm::vec3(0.0f, 0.0f, 0.0f)); + JointMass cgLeftHandMass(QString("LeftHand"), DEFAULT_AVATAR_LEFTHAND_MASS, glm::vec3(0.0f, 0.0f, 0.0f)); + JointMass cgRightHandMass(QString("RightHand"), DEFAULT_AVATAR_RIGHTHAND_MASS, glm::vec3(0.0f, 0.0f, 0.0f)); + glm::vec3 tposeHead = DEFAULT_AVATAR_HEAD_POS; + glm::vec3 tposeHips = glm::vec3(0.0f, 0.0f, 0.0f); + + if (_skeletonModel->getRig().indexOfJoint(cgHeadMass.name) != -1) { + cgHeadMass.position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgHeadMass.name)); + tposeHead = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgHeadMass.name)); } + if (_skeletonModel->getRig().indexOfJoint(cgLeftHandMass.name) != -1) { + cgLeftHandMass.position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgLeftHandMass.name)); + } else { + cgLeftHandMass.position = DEFAULT_AVATAR_LEFTHAND_POS; + } + if (_skeletonModel->getRig().indexOfJoint(cgRightHandMass.name) != -1) { + cgRightHandMass.position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgRightHandMass.name)); + } else { + cgRightHandMass.position = DEFAULT_AVATAR_RIGHTHAND_POS; + } + if (_skeletonModel->getRig().indexOfJoint("Hips") != -1) { + tposeHips = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("Hips")); + } + + // find the current center of gravity position based on head and hand moments + glm::vec3 sumOfMoments = (cgHeadMass.weight * cgHeadMass.position) + (cgLeftHandMass.weight * cgLeftHandMass.position) + (cgRightHandMass.weight * cgRightHandMass.position); + float totalMass = cgHeadMass.weight + cgLeftHandMass.weight + cgRightHandMass.weight; + glm::vec3 currentCg = (1.0f / totalMass) * sumOfMoments; currentCg.y = 0.0f; // dampening the center of gravity, in effect, limits the value to the perimeter of the base of support @@ -2948,23 +2947,19 @@ glm::vec3 MyAvatar::computeCounterBalance() const { glm::vec3 desiredCg = dampenCgMovement(currentCg, baseScale); // compute hips position to maintain desiredCg - glm::vec3 counterBalancedForHead = ((totalMass + hipsMass) * desiredCg) - (cgMasses[0].position * cgMasses[0].weight); - glm::vec3 counterBalancedForLeftHand = counterBalancedForHead - (cgMasses[1].weight * cgMasses[1].position); - glm::vec3 counterBalancedForRightHand = counterBalancedForLeftHand - (cgMasses[2].weight * cgMasses[2].position); - glm::vec3 counterBalancedCg = (1.0f / hipsMass) * counterBalancedForRightHand; + glm::vec3 counterBalancedForHead = (totalMass + DEFAULT_AVATAR_HIPS_MASS) * desiredCg; + counterBalancedForHead -= sumOfMoments; + glm::vec3 counterBalancedCg = (1.0f / DEFAULT_AVATAR_HIPS_MASS) * counterBalancedForHead; // find the height of the hips - glm::vec3 currentHead = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("Head")); - glm::vec3 tposeHead = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("Head")); - glm::vec3 tposeHips = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("Hips")); - glm::vec3 xzDiff = {(currentHead.x - counterBalancedCg.x), 0.0f, (currentHead.z - counterBalancedCg.z)}; + glm::vec3 xzDiff((cgHeadMass.position.x - counterBalancedCg.x), 0.0f, (cgHeadMass.position.z - counterBalancedCg.z)); float headMinusHipXz = glm::length(xzDiff); float headHipDefault = glm::length(tposeHead - tposeHips); float hipHeight = 0.0f; if (headHipDefault > headMinusHipXz) { hipHeight = sqrtf((headHipDefault * headHipDefault) - (headMinusHipXz * headMinusHipXz)); } - counterBalancedCg.y = (currentHead.y - hipHeight); + counterBalancedCg.y = (cgHeadMass.position.y - hipHeight); // this is to be sure that the feet don't lift off the floor. // add 5 centimeters to allow for going up on the toes. @@ -2975,66 +2970,33 @@ glm::vec3 MyAvatar::computeCounterBalance() const { return counterBalancedCg; } -// this function matches the hips rotation to the new cg head axis -static glm::quat computeNewHipsRotation(glm::quat hipYawRot, glm::vec3 curHead, glm::vec3 hipPos) { +// this function matches the hips rotation to the new cghips-head axis +// curHead and hipPos are in Avatar space +// returns the rotation of the hips in Avatar space +static glm::quat computeNewHipsRotation(glm::vec3 curHead, glm::vec3 hipPos) { glm::vec3 spineVec = curHead - hipPos; glm::quat finalRot = Quaternions::IDENTITY; - - if (spineVec.y > 0.0f) { - - glm::vec3 newYaxisHips = glm::normalize(spineVec); - glm::vec3 forward = { 0.0f, 0.0f, 1.0f }; - glm::vec3 oldZaxisHips = glm::normalize(forward); - glm::vec3 newXaxisHips = glm::normalize(glm::cross(newYaxisHips, oldZaxisHips)); - glm::vec3 newZaxisHips = glm::normalize(glm::cross(newXaxisHips, newYaxisHips)); - - // create mat4 with the new axes - glm::vec4 left = { newXaxisHips.x, newXaxisHips.y, newXaxisHips.z, 0.0f }; - glm::vec4 up = { newYaxisHips.x, newYaxisHips.y, newYaxisHips.z, 0.0f }; - glm::vec4 view = { newZaxisHips.x, newZaxisHips.y, newZaxisHips.z, 0.0f }; - glm::vec4 translation = { 0.0f, 0.0f, 0.0f, 1.0f }; - glm::mat4 newRotHips(left, up, view, translation); - finalRot = glm::toQuat(newRotHips); - } else if (spineVec.y < 0.0f) { - - glm::vec3 newYaxisHips = glm::normalize(-spineVec); - glm::vec3 forward = { 0.0f, 0.0f, 1.0f }; - glm::vec3 oldZaxisHips = glm::normalize(forward); - glm::vec3 newXaxisHips = glm::normalize(glm::cross(newYaxisHips, oldZaxisHips)); - glm::vec3 newZaxisHips = glm::normalize(glm::cross(newXaxisHips, newYaxisHips)); - - // create mat4 with the new axes - glm::vec4 left = { newXaxisHips.x, newXaxisHips.y, newXaxisHips.z, 0.0f }; - glm::vec4 up = { newYaxisHips.x, newYaxisHips.y, newYaxisHips.z, 0.0f }; - glm::vec4 view = { newZaxisHips.x, newZaxisHips.y, newZaxisHips.z, 0.0f }; - glm::vec4 translation = { 0.0f, 0.0f, 0.0f, 1.0f }; - glm::mat4 newRotHips(left, up, view, translation); - finalRot = glm::toQuat(newRotHips); - } else { - - //y equals zero. - if (glm::length(spineVec) > 0.0f) { - glm::vec3 newYaxisHips = glm::normalize(spineVec); - glm::vec3 forward = { 0.0f, 1.0f, 0.0f }; - glm::vec3 oldZaxisHips = forward; - glm::vec3 newXaxisHips = glm::normalize(glm::cross(newYaxisHips, oldZaxisHips)); - glm::vec3 newZaxisHips = oldZaxisHips; - - // create mat4 with the new axes - glm::vec4 left = { newXaxisHips.x, newXaxisHips.y, newXaxisHips.z, 0.0f }; - glm::vec4 up = { newYaxisHips.x, newYaxisHips.y, newYaxisHips.z, 0.0f }; - glm::vec4 view = { newZaxisHips.x, newZaxisHips.y, newZaxisHips.z, 0.0f }; - glm::vec4 translation = { 0.0f, 0.0f, 0.0f, 1.0f }; - glm::mat4 newRotHips(left, up, view, translation); - finalRot = glm::toQuat(newRotHips); - } - // otherwise, head and hips are equal so leave finalRot identity + glm::vec3 newYaxisHips = glm::normalize(spineVec); + glm::vec3 forward(0.0f, 0.0f, 1.0f); + if ((fabs(spineVec.y) == 0.0f) && (glm::length(spineVec) > 0.0f)){ + //y equals zero and hips position != head position + forward = glm::vec3(0.0f, 1.0f, 0.0f); } - glm::quat hipsRotation = hipYawRot*finalRot; + glm::vec3 oldZaxisHips = glm::normalize(forward); + glm::vec3 newXaxisHips = glm::normalize(glm::cross(newYaxisHips, oldZaxisHips)); + glm::vec3 newZaxisHips = glm::normalize(glm::cross(newXaxisHips, newYaxisHips)); + // create mat4 with the new axes + glm::vec4 left(newXaxisHips.x, newXaxisHips.y, newXaxisHips.z, 0.0f); + glm::vec4 up(newYaxisHips.x, newYaxisHips.y, newYaxisHips.z, 0.0f); + glm::vec4 view(newZaxisHips.x, newZaxisHips.y, newZaxisHips.z, 0.0f); + glm::vec4 translation(0.0f, 0.0f, 0.0f, 1.0f); + glm::mat4 newRotHips(left, up, view, translation); + finalRot = glm::toQuat(newRotHips); + glm::quat hipsRotation = finalRot; return hipsRotation; } -void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::mat4 avatarToWorld) { +static void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::mat4 avatarToWorld) { // scale the base of support based on user height float clampFront = DEFAULT_AVATAR_SUPPORT_BASE_FRONT * baseOfSupportScale; float clampBack = DEFAULT_AVATAR_SUPPORT_BASE_BACK * baseOfSupportScale; @@ -3080,6 +3042,9 @@ glm::quat cancelOutRollAndPitch2(const glm::quat& q) { return glm::quat_cast(temp); } +// this function finds the hips position using a center of gravity model that +// balances the head and hands with the hips over the base of support +// returns the rotation and position of the Avatar in Sensor space glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { glm::mat4 worldToSensorMat = glm::inverse(getSensorToWorldMatrix()); glm::mat4 avatarToWorldMat = getTransform().getMatrix(); @@ -3094,12 +3059,10 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { headOrientation = headPose.rotation * Quaternions::Y_180; } const glm::quat headOrientationYawOnly = cancelOutRollAndPitch2(headOrientation); - const float MIX_RATIO = 0.15f; + const float MIX_RATIO = 0.5f; // here we mix in some of the head yaw into the hip yaw glm::quat hipYawRot = glm::normalize(glm::lerp(glmExtractRotation(avatarToSensorMat), headOrientationYawOnly, MIX_RATIO)); - glm::quat deltaRot = glm::inverse(glmExtractRotation(avatarToSensorMat))*hipYawRot; - glm::vec3 headPositionLocal = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("Head")); - glm::vec3 headLocalAfterDelta = glm::inverse(deltaRot)*headPositionLocal; + glm::vec3 newLocalHeadPos = glm::inverse(hipYawRot) * (headPosition - extractTranslation(avatarToSensorMat)); if (_enableDebugDrawBaseOfSupport) { // default height is ~ 1.64 meters @@ -3112,9 +3075,9 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { const glm::vec3 cgHipsPosition = computeCounterBalance(); glm::vec3 hipsPositionFinal = transformPoint(avatarToSensorMat, cgHipsPosition); - //find the new hips rotation using the new head-hips axis as the up axis - glm::quat newHipsRotation = computeNewHipsRotation( hipYawRot, headLocalAfterDelta, cgHipsPosition); - return createMatFromQuatAndPos(newHipsRotation, hipsPositionFinal); + // find the new hips rotation using the new head-hips axis as the up axis + glm::quat newHipsRotation = computeNewHipsRotation(newLocalHeadPos, cgHipsPosition); + return createMatFromQuatAndPos(hipYawRot*newHipsRotation, hipsPositionFinal); } float MyAvatar::getUserHeight() const { diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index 9f0c789b9d..bdc54dfeb6 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -24,6 +24,13 @@ const float DEFAULT_AVATAR_SUPPORT_BASE_LEFT = -0.25f; const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f; const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f; const float DEFAULT_AVATAR_SUPPORT_BASE_BACK = 0.10f; +const float DEFAULT_AVATAR_FORWARD_DAMPENING_FACTOR = 0.5f; +const float DEFAULT_AVATAR_LATERAL_DAMPENING_FACTOR = 2.0f; +const float DEFAULT_AVATAR_HIPS_MASS = 40.0f; +const float DEFAULT_AVATAR_HEAD_MASS = 20.0f; +const float DEFAULT_AVATAR_LEFTHAND_MASS = 2.0f; +const float DEFAULT_AVATAR_RIGHTHAND_MASS = 2.0f; + // Used when avatar is missing joints... (avatar space) const glm::quat DEFAULT_AVATAR_MIDDLE_EYE_ROT { Quaternions::Y_180 }; From 859b187db6e3badd5477ea7dc409252fe04e2534 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 8 May 2018 18:17:52 -0700 Subject: [PATCH 022/380] Separate panel for inspecting the engine --- scripts/developer/utilities/lib/jet/jet.js | 15 +++--- .../utilities/lib/jet/qml/TaskList.qml | 7 +-- .../utilities/render/deferredLighting.qml | 15 +++--- .../utilities/render/engineInspector.js | 13 +++++ .../utilities/render/engineInspector.qml | 30 +++++++++++ scripts/developer/utilities/render/luci.js | 53 +++++++++++++++---- 6 files changed, 100 insertions(+), 33 deletions(-) create mode 100644 scripts/developer/utilities/render/engineInspector.js create mode 100644 scripts/developer/utilities/render/engineInspector.qml diff --git a/scripts/developer/utilities/lib/jet/jet.js b/scripts/developer/utilities/lib/jet/jet.js index 39da9b6d90..c326a3a73e 100644 --- a/scripts/developer/utilities/lib/jet/jet.js +++ b/scripts/developer/utilities/lib/jet/jet.js @@ -46,19 +46,20 @@ function job_propKeys(job) { } // Use this function to create a functor that will print the content of the Job visited calling the specified 'printout' function -function job_print_functor(printout, maxDepth) { +function job_print_functor(printout, showProps, maxDepth) { if (maxDepth === undefined) maxDepth = 100 return function (job, depth, index) { var tab = " " var depthTab = ""; for (var d = 0; d < depth; d++) { depthTab += tab } - printout(depthTab + index + " " + job.objectName + " " + (job.enabled ? "on" : "off")) - var keys = job_propKeys(job); - for (var p=0; p < keys.length;p++) { - var prop = job[keys[p]] - printout(depthTab + tab + tab + typeof prop + " " + keys[p] + " " + prop); + printout(depthTab + index + " " + job.objectName + " " + (job.enabled ? "on " : "off ") + job.cpuRunTime + "ms") + if (showProps) { + var keys = job_propKeys(job); + for (var p=0; p < keys.length;p++) { + var prop = job[keys[p]] + printout(depthTab + tab + tab + typeof prop + " " + keys[p] + " " + prop); + } } - return true // return depth < maxDepth; } diff --git a/scripts/developer/utilities/lib/jet/qml/TaskList.qml b/scripts/developer/utilities/lib/jet/qml/TaskList.qml index fa004627a7..bd4b1e6c79 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskList.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskList.qml @@ -32,14 +32,9 @@ Rectangle { Component.onCompleted: { var message = "" - var functor = Jet.job_print_functor(function (line) { message += line + "\n"; }); + var functor = Jet.job_print_functor(function (line) { message += line + "\n"; }, false); Jet.task_traverseTree(rootConfig, functor); textArea.append(message); - } - function fromScript(mope) { - var message ='Received \n'; - message += mope; - textArea.append(message); } function clearWindow() { diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index dc81df48cb..d68b19c513 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -14,7 +14,6 @@ import QtQuick.Layouts 1.3 import "qrc:///qml/styles-uit" import "qrc:///qml/controls-uit" as HifiControls import "configSlider" -import "../lib/jet/qml" as Jet Rectangle { HifiConstants { id: hifi;} @@ -276,14 +275,12 @@ Rectangle { } } Separator {} - - Jet.TaskList { - rootConfig: Render - anchors.left: parent.left - anchors.right: parent.right - - height: 200 + HifiControls.Button { + text: "Engine" + // activeFocusOnPress: false + onClicked: { + sendToScript({method: "openEngineView"}); + } } } - //} } diff --git a/scripts/developer/utilities/render/engineInspector.js b/scripts/developer/utilities/render/engineInspector.js new file mode 100644 index 0000000000..dcf13157b5 --- /dev/null +++ b/scripts/developer/utilities/render/engineInspector.js @@ -0,0 +1,13 @@ + function openEngineTaskView() { + // Set up the qml ui + var qml = Script.resolvePath('engineInspector.qml'); + var window = new OverlayWindow({ + title: 'Render Engine', + source: qml, + width: 300, + height: 400 + }); + window.setPosition(200, 50); + //window.closed.connect(function() { Script.stop(); }); + } + openEngineTaskView(); \ No newline at end of file diff --git a/scripts/developer/utilities/render/engineInspector.qml b/scripts/developer/utilities/render/engineInspector.qml new file mode 100644 index 0000000000..6461e5d834 --- /dev/null +++ b/scripts/developer/utilities/render/engineInspector.qml @@ -0,0 +1,30 @@ +// +// deferredLighting.qml +// +// Created by Sam Gateau on 6/6/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 + +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls + +import "../lib/jet/qml" as Jet + +Item { + HifiConstants { id: hifi;} + id: render; + anchors.fill: parent + + property var mainViewTask: Render.getConfig("RenderMainView") + + Jet.TaskList { + rootConfig: Render + anchors.fill: render + } +} \ No newline at end of file diff --git a/scripts/developer/utilities/render/luci.js b/scripts/developer/utilities/render/luci.js index 6482c884ff..005d96780a 100644 --- a/scripts/developer/utilities/render/luci.js +++ b/scripts/developer/utilities/render/luci.js @@ -64,9 +64,6 @@ button.editProperties({isActive: onLuciScreen}); wireEventBridge(onLuciScreen); } - - function fromQml(message) { - } button.clicked.connect(onClicked); tablet.screenChanged.connect(onScreenChanged); @@ -82,14 +79,6 @@ Controller.mouseMoveEvent.connect(function (e) { if (moveDebugCursor) setDebugCursor(e.x, e.y); }); - Script.scriptEnding.connect(function () { - if (onLuciScreen) { - tablet.gotoHomeScreen(); - } - button.clicked.disconnect(onClicked); - tablet.screenChanged.disconnect(onScreenChanged); - tablet.removeButton(button); - }); function setDebugCursor(x, y) { nx = (x / Window.innerWidth); @@ -98,4 +87,46 @@ Render.getConfig("RenderMainView").getConfig("Antialiasing").debugCursorTexcoord = { x: nx, y: ny }; } + + function fromQml(message) { + switch (message.method) { + case "openEngineView": + openEngineTaskView(); + break; + } + } + + + var engineInspectorView = null + function openEngineTaskView() { + if (engineInspectorView == null) { + var qml = Script.resolvePath('engineInspector.qml'); + var window = new OverlayWindow({ + title: 'Render Engine', + source: qml, + width: 300, + height: 400 + }); + window.setPosition(200, 50); + engineInspectorView = window + window.closed.connect(function() { engineInspectorView = null; }); + } else { + engineInspectorView.setPosition(200, 50); + } + } + + + + Script.scriptEnding.connect(function () { + if (onLuciScreen) { + tablet.gotoHomeScreen(); + } + button.clicked.disconnect(onClicked); + tablet.screenChanged.disconnect(onScreenChanged); + tablet.removeButton(button); + + if (engineInspectorView !== null) { + engineInspectorView.close() + } + }); }()); \ No newline at end of file From 77aedc1512d502bfa9f8e7198722ffba9099b9c8 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 9 May 2018 11:14:13 -0700 Subject: [PATCH 023/380] changed lerp to saferLerp in cg code --- interface/src/avatar/MyAvatar.cpp | 19 +- scripts/developer/cg_lean.js | 553 ------------------------------ 2 files changed, 16 insertions(+), 556 deletions(-) delete mode 100644 scripts/developer/cg_lean.js diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 941aecc58b..c73b99d716 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2978,7 +2978,8 @@ static glm::quat computeNewHipsRotation(glm::vec3 curHead, glm::vec3 hipPos) { glm::quat finalRot = Quaternions::IDENTITY; glm::vec3 newYaxisHips = glm::normalize(spineVec); glm::vec3 forward(0.0f, 0.0f, 1.0f); - if ((fabs(spineVec.y) == 0.0f) && (glm::length(spineVec) > 0.0f)){ + const float EPSILON = 0.0001f; + if ((fabs(spineVec.y) < EPSILON) && (glm::length(spineVec) > 0.0f)) { //y equals zero and hips position != head position forward = glm::vec3(0.0f, 1.0f, 0.0f); } @@ -3042,6 +3043,16 @@ glm::quat cancelOutRollAndPitch2(const glm::quat& q) { return glm::quat_cast(temp); } +static glm::quat saferLerp(const glm::quat& a, const glm::quat& b, float alpha) { + // adjust signs if necessary + glm::quat bTemp = b; + float dot = glm::dot(a, bTemp); + if (dot < 0.0f) { + bTemp = -bTemp; + } + return glm::normalize(glm::lerp(a, bTemp, alpha)); +} + // this function finds the hips position using a center of gravity model that // balances the head and hands with the hips over the base of support // returns the rotation and position of the Avatar in Sensor space @@ -3058,10 +3069,11 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { // rotate by 180 Y to put the head in same frame as the avatar headOrientation = headPose.rotation * Quaternions::Y_180; } - const glm::quat headOrientationYawOnly = cancelOutRollAndPitch2(headOrientation); + const glm::quat headOrientationYawOnly = cancelOutRollAndPitch(headOrientation); const float MIX_RATIO = 0.5f; // here we mix in some of the head yaw into the hip yaw - glm::quat hipYawRot = glm::normalize(glm::lerp(glmExtractRotation(avatarToSensorMat), headOrientationYawOnly, MIX_RATIO)); + glm::quat hipYawRot = glm::normalize(saferLerp(glmExtractRotation(avatarToSensorMat), headOrientationYawOnly, MIX_RATIO)); + // glm::quat hipYawRot = glmExtractRotation(avatarToSensorMat); glm::vec3 newLocalHeadPos = glm::inverse(hipYawRot) * (headPosition - extractTranslation(avatarToSensorMat)); if (_enableDebugDrawBaseOfSupport) { @@ -3078,6 +3090,7 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { // find the new hips rotation using the new head-hips axis as the up axis glm::quat newHipsRotation = computeNewHipsRotation(newLocalHeadPos, cgHipsPosition); return createMatFromQuatAndPos(hipYawRot*newHipsRotation, hipsPositionFinal); + // return createMatFromQuatAndPos(hipYawRot, hipsPositionFinal); } float MyAvatar::getUserHeight() const { diff --git a/scripts/developer/cg_lean.js b/scripts/developer/cg_lean.js deleted file mode 100644 index a4ca56d6d6..0000000000 --- a/scripts/developer/cg_lean.js +++ /dev/null @@ -1,553 +0,0 @@ - -/* global Script, Vec3, MyAvatar Tablet Messages Quat DebugDraw Mat4 Xform*/ - - -Script.include("/~/system/libraries/Xform.js"); - -var MESSAGE_CHANNEL = "Hifi-Step-Cg"; - -var ANIM_VARS = [ - "isTalking", - "isNotMoving", - "isMovingForward", - "isMovingBackward", - "isMovingRight", - "isMovingLeft", - "isTurningRight", - "isTurningLeft", - "isFlying", - "isTakeoffStand", - "isTakeoffRun", - "isInAirStand", - "isInAirRun", - "hipsPosition", - "hipsRotation", - "hipsType", - "headWeight", - "headType" -]; - -var DEBUGDRAWING; -var YELLOW; -var BLUE; -var GREEN; -var RED; - -var ROT_Y90; -var ROT_Y180; -var FLOOR_Y; -var IDENT_QUAT; - -var TABLET_BUTTON_NAME; -var RECENTER; -var JOINT_MASSES; - -var hipsUnderHead; - -var armsHipRotation; -var hipsPosition; -var filteredHipsPosition; -var hipsRotation; - -var jointList; -var rightFootName; -var leftFootName; -var rightToeName; -var leftToeName; -var leftToeEnd; -var rightToeEnd; -var leftFoot; -var rightFoot; -var base; - -var clampFront; -var clampBack; -var clampLeft; -var clampRight; - -var tablet; -var tabletButton; - -function initCg() { - - DEBUGDRAWING = false; - - YELLOW = { r: 1, g: 1, b: 0, a: 1 }; - BLUE = { r: 0, g: 0, b: 1, a: 1 }; - GREEN = { r: 0, g: 1, b: 0, a: 1 }; - RED = { r: 1, g: 0, b: 0, a: 1 }; - - ROT_Y90 = { x: 0, y: 0.7071067811865475, z: 0, w: 0.7071067811865476 }; - ROT_Y180 = { x: 0, y: 1, z: 0, w: 0 }; - FLOOR_Y = -0.9; - IDENT_QUAT = { x: 0, y: 0, z: 0, w: 1 }; - - JOINT_MASSES = [{ joint: "Head", mass: 20.0, pos: { x: 0, y: 0, z: 0 } }, - { joint: "LeftHand", mass: 2.0, pos: { x: 0, y: 0, z: 0 } }, - { joint: "RightHand", mass: 2.0, pos: { x: 0, y: 0, z: 0 } }]; - - TABLET_BUTTON_NAME = "CG"; - RECENTER = false; - - MyAvatar.hmdLeanRecenterEnabled = RECENTER; - hipsUnderHead; - - armsHipRotation = { x: 0, y: 1, z: 0, w: 0 }; - hipsPosition = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); - filteredHipsPosition = MyAvatar.position; - hipsRotation = { x: 0, y: 0, z: 0, w: 1 }; - - jointList = MyAvatar.getJointNames(); - // print(JSON.stringify(jointList)); - - rightFootName = null; - leftFootName = null; - rightToeName = null; - leftToeName = null; - leftToeEnd = null; - rightToeEnd = null; - leftFoot; - rightFoot; - - clampFront = -0.10; - clampBack = 0.17; - clampLeft = -0.50; - clampRight = 0.50; - - getFeetAndToeNames(); - base = computeBase(); - mirrorPoints(); - - - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - - tabletButton = tablet.addButton({ - text: TABLET_BUTTON_NAME, - icon: "icons/tablet-icons/avatar-record-i.svg" - }); - - tabletButton.clicked.connect(function () { - print("recenter is: " + RECENTER); - MyAvatar.hmdLeanRecenterEnabled = RECENTER; - RECENTER = !RECENTER; - - // messageSend("clicked button in cg"); - }); - - - var handlerId = MyAvatar.addAnimationStateHandler(function (props) { - - var result = {}; - - // prevent animations from ever leaving the idle state - result.isTalking = false; - result.isFlying = false; - result.isTakeoffStand = false; - result.isTakeoffRun = false; - result.isInAirStand = false; - result.isInAirRun = false; - result.hipsPosition = hipsPosition; - result.hipsRotation = hipsRotation; - result.hipsType = 0; - result.headWeight = 4; - result.headType = 4; - - return result; - }, ANIM_VARS); - - Messages.subscribe(MESSAGE_CHANNEL); - Messages.messageReceived.connect(messageHandler); - Script.update.connect(update); - MyAvatar.skeletonChanged.connect(function () { - Script.setTimeout(function () { - // stop logic if needed - MyAvatar.clearJointsData(); - // reset logic - }, 200); - }); - HMD.displayModeChanged.connect(function () { - Script.setTimeout(function () { - // stop logic if needed - MyAvatar.clearJointsData(); - // reset logic - }, 200); - }); - - -} - -function messageSend(message) { - Messages.sendLocalMessage(MESSAGE_CHANNEL, message); -} - -function messageHandler(channel, messageString, senderID) { - if (channel !== MESSAGE_CHANNEL) { - return; - } - - var hipquat = JSON.parse(messageString); - armsHipRotation = Quat.multiply(ROT_Y180,hipquat); - -} - -function getFeetAndToeNames() { - - for (var i = 0; i < jointList.length; i++) { - if ((jointList[i].indexOf('Right') !== -1) && (jointList[i].indexOf('Foot') !== -1)) { - print(JSON.stringify(jointList[i])); - rightFootName = jointList[i]; - } - if ((jointList[i].indexOf('Left') !== -1) && (jointList[i].indexOf('Foot') !== -1)) { - print(JSON.stringify(jointList[i])); - leftFootName = jointList[i]; - } - if ((jointList[i].indexOf('Right') !== -1) && (jointList[i].indexOf('Toe') !== -1) && (jointList[i].indexOf('End') !== -1)) { - print(JSON.stringify(jointList[i])); - rightToeName = jointList[i]; - } - if ((jointList[i].indexOf('Left') !== -1) && (jointList[i].indexOf('Toe') !== -1) && (jointList[i].indexOf('End') !== -1)) { - print(JSON.stringify(jointList[i])); - leftToeName = jointList[i]; - } - } -} - -function computeBase() { - - if (rightFootName === null || leftFootName === null) { - // if the feet names aren't found then use our best guess of the base. - leftToeEnd = {x: 0.12, y: 0.0, z: 0.12}; - rightToeEnd = {x: -0.18, y: 0.0, z: 0.12}; - leftFoot = {x: 0.15, y: 0.0, z: -0.17}; - rightFoot = {x: -0.20, y: 0.0, z: -0.17}; - } else { - // else we at least found the feet in the skeleton. - var leftFootIndex = MyAvatar.getJointIndex(leftFootName); - var rightFootIndex = MyAvatar.getJointIndex(rightFootName); - var leftFoot = MyAvatar.getAbsoluteJointTranslationInObjectFrame(leftFootIndex); - var rightFoot = MyAvatar.getAbsoluteJointTranslationInObjectFrame(rightFootIndex); - - if (rightToeName === null || leftToeName === null) { - // the toe ends were not found then we use a guess for the length and width of the feet. - leftToeEnd = {x: (leftFoot.x + 0.02), y: 0.0, z: (leftFoot.z - 0.2)}; - rightToeEnd = {x: (rightFoot.x - 0.02), y: 0.0, z: (rightFoot.z - 0.2)}; - } else { - // else we found the toe ends and now we can really compute the base. - var leftToeIndex = MyAvatar.getJointIndex(leftToeName); - var rightToeIndex = MyAvatar.getJointIndex(rightToeName); - leftToeEnd = MyAvatar.getAbsoluteJointTranslationInObjectFrame(leftToeIndex); - rightToeEnd = MyAvatar.getAbsoluteJointTranslationInObjectFrame(rightToeIndex); - } - - } - - // project each point into the FLOOR plane. - var points = [{x: leftToeEnd.x, y: FLOOR_Y, z: leftToeEnd.z}, - {x: rightToeEnd.x, y: FLOOR_Y, z: rightToeEnd.z}, - {x: rightFoot.x, y: FLOOR_Y, z: rightFoot.z}, - {x: leftFoot.x, y: FLOOR_Y, z: rightFoot.z}]; - - // compute normals for each plane - var normal, normals = []; - var n = points.length; - var next, prev; - for (next = 0, prev = n - 1; next < n; prev = next, next++) { - normal = Vec3.multiplyQbyV(ROT_Y90, Vec3.normalize(Vec3.subtract(points[next], points[prev]))); - normals.push(normal); - } - - var TOE_FORWARD_RADIUS = 0.01; - var TOE_SIDE_RADIUS = 0.05; - var HEEL_FORWARD_RADIUS = 0.01; - var HEEL_SIDE_RADIUS = 0.03; - var radii = [ - TOE_SIDE_RADIUS, TOE_FORWARD_RADIUS, TOE_FORWARD_RADIUS, TOE_SIDE_RADIUS, - HEEL_SIDE_RADIUS, HEEL_FORWARD_RADIUS, HEEL_FORWARD_RADIUS, HEEL_SIDE_RADIUS - ]; - - // subdivide base and extrude by the toe and heel radius. - var newPoints = []; - for (next = 0, prev = n - 1; next < n; prev = next, next++) { - newPoints.push(Vec3.sum(points[next], Vec3.multiply(radii[2 * next], normals[next]))); - newPoints.push(Vec3.sum(points[next], Vec3.multiply(radii[(2 * next) + 1], normals[(next + 1) % n]))); - } - - // compute newNormals - var newNormals = []; - n = newPoints.length; - for (next = 0, prev = n - 1; next < n; prev = next, next++) { - normal = Vec3.multiplyQbyV(ROT_Y90, Vec3.normalize(Vec3.subtract(newPoints[next], newPoints[prev]))); - newNormals.push(normal); - } - - for (var j = 0;j Math.abs(base.points[3].x)) { - base.points[3].x = -base.points[0].x; - base.points[2].x = -base.points[1].x; - } else { - base.points[0].x = -base.points[3].x; - base.points[1].x = -base.points[2].x; - } - - if (Math.abs(base.points[4].x) > Math.abs(base.points[7].x)) { - base.points[7].x = -base.points[4].x; - base.points[6].x = -base.points[5].x; - } else { - base.points[4].x = -base.points[7].x; - base.points[5].x = -base.points[6].x; - } - - if (Math.abs(base.points[0].z) > Math.abs(base.points[0].z)) { - base.points[3].z = base.points[0].z; - base.points[2].z = base.points[1].z; - } else { - base.points[0].z = base.points[3].z; - base.points[1].z = base.points[2].z; - } - - if (Math.abs(base.points[4].z) > Math.abs(base.points[7].z)) { - base.points[7].z = base.points[4].z; - base.points[6].z = base.points[5].z; - } else { - base.points[4].z = base.points[7].z; - base.points[5].z = base.points[6].z; - } - - for (var i = 0; i < base.points.length; i++) { - - print("point: " + i + " " + JSON.stringify(base.points[i])); - } - for (var j = 0; j < base.normals.length; j++) { - print("normal: " + j + " " + JSON.stringify(base.normals[j])); - } -} - - -function drawBase(base) { - // transform corners into world space, for rendering. - var xform = new Xform(MyAvatar.orientation, MyAvatar.position); - var worldPoints = base.points.map(function (point) { - return xform.xformPoint(point); - }); - var worldNormals = base.normals.map(function (normal) { - return xform.xformVector(normal); - }); - - var n = worldPoints.length; - var next, prev; - for (next = 0, prev = n - 1; next < n; prev = next, next++) { - if (DEBUGDRAWING) { - // draw border - DebugDraw.drawRay(worldPoints[prev], worldPoints[next], GREEN); - DebugDraw.drawRay(worldPoints[next], worldPoints[prev], GREEN); - - // draw normal - var midPoint = Vec3.multiply(0.5, Vec3.sum(worldPoints[prev], worldPoints[next])); - DebugDraw.drawRay(midPoint, Vec3.sum(midPoint, worldNormals[next]), YELLOW); - DebugDraw.drawRay(midPoint, Vec3.sum(midPoint, worldNormals[next+1]), YELLOW); - } - } -} - -function computeCg() { - // point mass. - var n = JOINT_MASSES.length; - var moments = {x: 0, y: 0, z: 0}; - var masses = 0; - for (var i = 0; i < n; i++) { - var pos = MyAvatar.getAbsoluteJointTranslationInObjectFrame(MyAvatar.getJointIndex(JOINT_MASSES[i].joint)); - JOINT_MASSES[i].pos = pos; - moments = Vec3.sum(moments, Vec3.multiply(JOINT_MASSES[i].mass, pos)); - masses += JOINT_MASSES[i].mass; - } - return Vec3.multiply(1 / masses, moments); -} - - -function clamp(val, min, max) { - return Math.max(min, Math.min(max, val)); -} - -function distancetoline(p1,p2,cg) { - var numerator = Math.abs((p2.z - p1.z)*(cg.x) - (p2.x - p1.x)*(cg.z) + (p2.x)*(p1.z) - (p2.z)*(p1.x)); - var denominator = Math.sqrt( Math.pow((p2.z - p1.z),2) + Math.pow((p2.x - p1.x),2)); - - return numerator/denominator; -} - -function isLeft(a, b, c) { - return (((b.x - a.x)*(c.z - a.z) - (b.z - a.z)*(c.x - a.x)) > 0); -} - -function slope(num) { - var constant = 1.0; - return 1 - ( 1/(1+constant*num)); -} - -function dampenCgMovement(rawCg) { - - var distanceFromCenterZ = rawCg.z; - var distanceFromCenterX = rawCg.x; - - // clampFront = -0.10; - // clampBack = 0.17; - // clampLeft = -0.50; - // clampRight = 0.50; - - var dampedCg = { x: 0, y: 0, z: 0 }; - - if (rawCg.z < 0.0) { - var inputFront; - inputFront = Math.abs(distanceFromCenterZ / clampFront); - var scaleFrontNew = slope(inputFront); - dampedCg.z = scaleFrontNew * clampFront; - } else { - // cg.z > 0.0 - var inputBack; - inputBack = Math.abs(distanceFromCenterZ / clampBack); - var scaleBackNew = slope(inputBack); - dampedCg.z = scaleBackNew * clampBack; - } - - if (rawCg.x > 0.0) { - var inputRight; - inputRight = Math.abs(distanceFromCenterX / clampRight); - var scaleRightNew = slope(inputRight); - dampedCg.x = scaleRightNew * clampRight; - } else { - // left of center - var inputLeft; - inputLeft = Math.abs(distanceFromCenterX / clampLeft); - var scaleLeftNew = slope(inputLeft); - dampedCg.x = scaleLeftNew * clampLeft; - } - return dampedCg; -} - -function computeCounterBalance(desiredCgPos) { - // compute hips position to maintain desiredCg - var HIPS_MASS = 40; - var totalMass = JOINT_MASSES.reduce(function (accum, obj) { - return accum + obj.mass; - }, 0); - var temp1 = Vec3.subtract(Vec3.multiply(totalMass + HIPS_MASS, desiredCgPos), - Vec3.multiply(JOINT_MASSES[0].mass, JOINT_MASSES[0].pos)); - var temp2 = Vec3.subtract(temp1, - Vec3.multiply(JOINT_MASSES[1].mass, JOINT_MASSES[1].pos)); - var temp3 = Vec3.subtract(temp2, - Vec3.multiply(JOINT_MASSES[2].mass, JOINT_MASSES[2].pos)); - var temp4 = Vec3.multiply(1 / HIPS_MASS, temp3); - - - var currentHead = MyAvatar.getAbsoluteJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); - var tposeHead = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); - var tposeHips = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); - - var xzDiff = { x: (currentHead.x - temp4.x), y: 0, z: (currentHead.z - temp4.z) }; - var headMinusHipXz = Vec3.length(xzDiff); - - var headHipDefault = Vec3.length(Vec3.subtract(tposeHead, tposeHips)); - - var hipHeight = Math.sqrt((headHipDefault * headHipDefault) - (headMinusHipXz * headMinusHipXz)); - - temp4.y = (currentHead.y - hipHeight); - if (temp4.y > tposeHips.y) { - temp4.y = 0.0; - } - return temp4; -} - -function update(dt) { - - var cg = computeCg(); - // print("time elapsed " + dt); - - var desiredCg = { x: 0, y: 0, z: 0 }; - // print("the raw cg " + cg.x + " " + cg.y + " " + cg.z); - - desiredCg.x = cg.x; - desiredCg.y = 0; - desiredCg.z = cg.z; - - desiredCg = dampenCgMovement(cg); - - cg.y = FLOOR_Y; - - // after the dampening above it might be right to clamp the desiredcg to the edge of the base - // of support. - - if (DEBUGDRAWING) { - DebugDraw.addMyAvatarMarker("left toe", IDENT_QUAT, leftToeEnd, BLUE); - DebugDraw.addMyAvatarMarker("right toe", IDENT_QUAT, rightToeEnd, BLUE); - DebugDraw.addMyAvatarMarker("cg", IDENT_QUAT, cg, BLUE); - DebugDraw.addMyAvatarMarker("desiredCg", IDENT_QUAT, desiredCg, GREEN); - drawBase(base); - } - - var currentHeadPos = MyAvatar.getAbsoluteJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); - var localHipsPos = computeCounterBalance(desiredCg); - // print("current hips " + cg.x + " " + cg.y + " " + cg.z); - // print("dampened hips " + desiredCg.x + " " + desiredCg.y + " " + desiredCg.z) - - var globalPosRoot = MyAvatar.position; - var globalRotRoot = Quat.normalize(MyAvatar.orientation); - var inverseGlobalRotRoot = Quat.normalize(Quat.inverse(globalRotRoot)); - var globalPosHips = Vec3.sum(globalPosRoot, Vec3.multiplyQbyV(globalRotRoot, localHipsPos)); - var unRotatedHipsPosition; - - if (!MyAvatar.isRecenteringHorizontally()) { - - filteredHipsPosition = Vec3.mix(filteredHipsPosition, globalPosHips, 0.1); - unRotatedHipsPosition = Vec3.multiplyQbyV(inverseGlobalRotRoot, Vec3.subtract(filteredHipsPosition, globalPosRoot)); - hipsPosition = Vec3.multiplyQbyV(ROT_Y180, unRotatedHipsPosition); - } else { - // DebugDraw.addMarker("hipsunder", IDENT_QUAT, hipsUnderHead, GREEN); - filteredHipsPosition = Vec3.mix(filteredHipsPosition, globalPosHips, 0.1); - unRotatedHipsPosition = Vec3.multiplyQbyV(inverseGlobalRotRoot, Vec3.subtract(filteredHipsPosition, globalPosRoot)); - hipsPosition = Vec3.multiplyQbyV(ROT_Y180, unRotatedHipsPosition); - } - - var newYaxisHips = Vec3.normalize(Vec3.subtract(currentHeadPos, unRotatedHipsPosition)); - var forward = { x: 0.0, y: 0.0, z: 1.0 }; - - // arms hip rotation is sent from the step script - var oldZaxisHips = Vec3.normalize(Vec3.multiplyQbyV(armsHipRotation, forward)); - var newXaxisHips = Vec3.normalize(Vec3.cross(newYaxisHips, oldZaxisHips)); - var newZaxisHips = Vec3.normalize(Vec3.cross(newXaxisHips, newYaxisHips)); - - // var beforeHips = MyAvatar.getAbsoluteJointRotationInObjectFrame(MyAvatar.getJointIndex("Hips")); - var left = { x: newXaxisHips.x, y: newXaxisHips.y, z: newXaxisHips.z, w: 0.0 }; - var up = { x: newYaxisHips.x, y: newYaxisHips.y, z: newYaxisHips.z, w: 0.0 }; - var view = { x: newZaxisHips.x, y: newZaxisHips.y, z: newZaxisHips.z, w: 0.0 }; - - var translation = { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }; - var newRotHips = Mat4.createFromColumns(left, up, view, translation); - var finalRot = Mat4.extractRotation(newRotHips); - - hipsRotation = Quat.multiply(ROT_Y180, finalRot); - print("final rot" + finalRot.x + " " + finalRot.y + " " + finalRot.z + " " + finalRot.w); - - if (DEBUGDRAWING) { - DebugDraw.addMyAvatarMarker("hipsPos", IDENT_QUAT, hipsPosition, RED); - } -} - - -Script.setTimeout(initCg, 10); -Script.scriptEnding.connect(function () { - Script.update.disconnect(update); - if (tablet) { - tablet.removeButton(tabletButton); - } - Messages.messageReceived.disconnect(messageHandler); - Messages.unsubscribe(MESSAGE_CHANNEL); - -}); From a7955b642a791bf138e5f4e19cb7a9192c310e92 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 9 May 2018 11:27:04 -0700 Subject: [PATCH 024/380] removed the follow hips code from pre physics update --- interface/src/avatar/MyAvatar.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c73b99d716..9a30113ca4 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3341,13 +3341,8 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat followWorldPose.scale() = glm::vec3(1.0f); if (isActive(Rotation)) { - if (getToggleHipsFollowing()) { //use the hmd reading for the hips follow - followWorldPose.rot() = glmExtractRotation(desiredWorldMatrix); - } else { - //use the hips as changed by the arms azimuth for the hips to follow. - followWorldPose.rot() = resultingTwistInWorld; - } + followWorldPose.rot() = glmExtractRotation(desiredWorldMatrix); } if (isActive(Horizontal)) { glm::vec3 desiredTranslation = extractTranslation(desiredWorldMatrix); From 50f225777af00698b9f1c34262356716d54c6399 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 9 May 2018 11:31:19 -0700 Subject: [PATCH 025/380] removed debug code from cg code in MyAvatar.cpp --- interface/src/avatar/MyAvatar.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9a30113ca4..778332f65b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3073,7 +3073,6 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { const float MIX_RATIO = 0.5f; // here we mix in some of the head yaw into the hip yaw glm::quat hipYawRot = glm::normalize(saferLerp(glmExtractRotation(avatarToSensorMat), headOrientationYawOnly, MIX_RATIO)); - // glm::quat hipYawRot = glmExtractRotation(avatarToSensorMat); glm::vec3 newLocalHeadPos = glm::inverse(hipYawRot) * (headPosition - extractTranslation(avatarToSensorMat)); if (_enableDebugDrawBaseOfSupport) { @@ -3090,7 +3089,6 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { // find the new hips rotation using the new head-hips axis as the up axis glm::quat newHipsRotation = computeNewHipsRotation(newLocalHeadPos, cgHipsPosition); return createMatFromQuatAndPos(hipYawRot*newHipsRotation, hipsPositionFinal); - // return createMatFromQuatAndPos(hipYawRot, hipsPositionFinal); } float MyAvatar::getUserHeight() const { From 7418fe782cabf2dccc3ea57ba1f79ead926021a1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 9 May 2018 12:22:30 -0700 Subject: [PATCH 026/380] local compression on android --- libraries/image/src/image/Image.cpp | 121 +++++++++++++++++++++------- 1 file changed, 94 insertions(+), 27 deletions(-) diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 1639dde246..55cafe9571 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -31,7 +31,10 @@ using namespace gpu; #define CPU_MIPMAPS 1 #include +#ifdef Q_OS_ANDROID #include +#include +#endif static const glm::uvec2 SPARSE_PAGE_SIZE(128); #ifdef Q_OS_ANDROID @@ -43,6 +46,7 @@ bool DEV_DECIMATE_TEXTURES = false; std::atomic DECIMATED_TEXTURE_COUNT{ 0 }; std::atomic RECTIFIED_TEXTURE_COUNT{ 0 }; +// TODO: pick compressed android hdr format static const auto HDR_FORMAT = gpu::Element::COLOR_R11G11B10; static std::atomic compressColorTextures { false }; @@ -560,7 +564,9 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic(localCopy.constBits()); + auto mipFormat = texture->getStoredMipFormat(); +#ifndef Q_OS_ANDROID nvtt::TextureType textureType = nvtt::TextureType_2D; nvtt::InputFormat inputFormat = nvtt::InputFormat_BGRA_8UB; nvtt::WrapMode wrapMode = nvtt::WrapMode_Mirror; @@ -590,8 +596,6 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomicgetStoredMipFormat(); if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGB) { compressionOptions.setFormat(nvtt::Format_BC1); } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_MASK) { @@ -675,6 +679,78 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic floatData; + floatData.resize(width * height); + for (int y = 0; y < height; y++) { + QRgb *line = (QRgb *) localCopy.scanLine(y); + for (int x = 0; x < width; x++) { + QRgb &pixel = line[x]; + floatData[x + y * width] = vec4(qRed(pixel), qGreen(pixel), qBlue(pixel), qAlpha(pixel)) / 255.0f; + } + } + + Etc::EncodeMipmaps( + (float *)floatData.data(), width, height, + etcFormat, errorMetric, effort, + numEncodeThreads, numEncodeThreads, + numMips, Etc::FILTER_WRAP_X | Etc::FILTER_WRAP_Y, + mipMaps, &encodingTime + ); + + // free up the memory afterward to avoid bloating the heap + data = nullptr; + localCopy = QImage(); // QImage doesn't have a clear function, so override it with an empty one. + + for (int i = 0; i < numMips; i++) { + if (face >= 0) { + texture->assignStoredMipFace(i, face, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); + } else { + texture->assignStoredMip(i, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); + } + } + + delete[] mipMaps; +#endif } #endif @@ -744,7 +820,6 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma gpu::Element formatMip; gpu::Element formatGPU; if (isColorTexturesCompressionEnabled()) { -#ifndef USE_GLES if (validAlpha) { // NOTE: This disables BC1a compression because it was producing odd artifacts on text textures // for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts). @@ -752,23 +827,15 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma } else { formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_SRGB; } -#else - if (validAlpha) { - formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA; - } else { - formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGB; - } -#endif - formatMip = formatGPU; } else { -#ifdef USE_GLES +#ifdef Q_OS_ANDROID // GLES does not support GL_BGRA - formatMip = gpu::Element::COLOR_SRGBA_32; + formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA; #else - formatMip = gpu::Element::COLOR_SBGRA_32; + formatGPU = gpu::Element::COLOR_SBGRA_32; #endif - formatGPU = gpu::Element::COLOR_SRGBA_32; } + formatMip = formatGPU; if (isStrict) { theTexture = gpu::Texture::createStrict(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); @@ -882,16 +949,18 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr gpu::TexturePointer theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - gpu::Element formatMip = gpu::Element::VEC2NU8_XY; - gpu::Element formatGPU = gpu::Element::VEC2NU8_XY; + gpu::Element formatMip; + gpu::Element formatGPU; if (isNormalTexturesCompressionEnabled()) { -#ifndef USE_GLES formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_XY; -#else + } else { +#ifdef Q_OS_ANDROID formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_XY; +#else + formatGPU = gpu::Element::VEC2NU8_XY; #endif - formatMip = formatGPU; } + formatMip = formatGPU; theTexture = gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); theTexture->setSource(srcImageName); @@ -923,16 +992,15 @@ gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& sr gpu::Element formatMip; gpu::Element formatGPU; if (isGrayscaleTexturesCompressionEnabled()) { -#ifndef USE_GLES formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_RED; -#else - formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED; -#endif - formatMip = formatGPU; } else { - formatMip = gpu::Element::COLOR_R_8; +#ifdef Q_OS_ANDROID + formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED; +#else formatGPU = gpu::Element::COLOR_R_8; +#endif } + formatMip = formatGPU; theTexture = gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); theTexture->setSource(srcImageName); @@ -1295,7 +1363,6 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI gpu::Element formatMip; gpu::Element formatGPU; if (isCubeTexturesCompressionEnabled()) { - // TODO: gles: pick HDR ETC format formatMip = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; } else { From eff84de99f12fcf7b0462ae3f363ab2b302a54d0 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 9 May 2018 14:55:10 -0700 Subject: [PATCH 027/380] added more straight forward computation of the hips rotation inMyAvatar.cpp contributed by AJT --- interface/src/avatar/MyAvatar.cpp | 84 +++++++++++-------------------- 1 file changed, 29 insertions(+), 55 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 778332f65b..35247bca20 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -52,6 +52,7 @@ #include "MyHead.h" #include "MySkeletonModel.h" +#include "AnimUtil.h" #include "Application.h" #include "AvatarManager.h" #include "AvatarActionHold.h" @@ -2971,30 +2972,21 @@ glm::vec3 MyAvatar::computeCounterBalance() const { } // this function matches the hips rotation to the new cghips-head axis -// curHead and hipPos are in Avatar space -// returns the rotation of the hips in Avatar space -static glm::quat computeNewHipsRotation(glm::vec3 curHead, glm::vec3 hipPos) { - glm::vec3 spineVec = curHead - hipPos; - glm::quat finalRot = Quaternions::IDENTITY; - glm::vec3 newYaxisHips = glm::normalize(spineVec); - glm::vec3 forward(0.0f, 0.0f, 1.0f); - const float EPSILON = 0.0001f; - if ((fabs(spineVec.y) < EPSILON) && (glm::length(spineVec) > 0.0f)) { - //y equals zero and hips position != head position - forward = glm::vec3(0.0f, 1.0f, 0.0f); - } - glm::vec3 oldZaxisHips = glm::normalize(forward); - glm::vec3 newXaxisHips = glm::normalize(glm::cross(newYaxisHips, oldZaxisHips)); - glm::vec3 newZaxisHips = glm::normalize(glm::cross(newXaxisHips, newYaxisHips)); - // create mat4 with the new axes - glm::vec4 left(newXaxisHips.x, newXaxisHips.y, newXaxisHips.z, 0.0f); - glm::vec4 up(newYaxisHips.x, newYaxisHips.y, newYaxisHips.z, 0.0f); - glm::vec4 view(newZaxisHips.x, newZaxisHips.y, newZaxisHips.z, 0.0f); - glm::vec4 translation(0.0f, 0.0f, 0.0f, 1.0f); - glm::mat4 newRotHips(left, up, view, translation); - finalRot = glm::toQuat(newRotHips); - glm::quat hipsRotation = finalRot; - return hipsRotation; +// headOrientation, headPosition and hipsPosition are in avatar space +// returns the matrix of the hips in Avatar space +static glm::mat4 computeNewHipsMatrix(glm::quat headOrientation, glm::vec3 headPosition, glm::vec3 hipsPosition) { + glm::quat headOrientationYawOnly = cancelOutRollAndPitch(headOrientation); + const float MIX_RATIO = 0.5f; + glm::quat hipsRot = safeLerp(Quaternions::IDENTITY, headOrientationYawOnly, MIX_RATIO); + glm::vec3 hipsFacing = hipsRot * Vectors::UNIT_Z; + + glm::vec3 spineVec = headPosition - hipsPosition; + glm::vec3 u, v, w; + generateBasisVectors(glm::normalize(spineVec), hipsFacing, u, v, w); + return glm::mat4(glm::vec4(w, 0.0f), + glm::vec4(u, 0.0f), + glm::vec4(v, 0.0f), + glm::vec4(hipsPosition, 1.0f)); } static void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::mat4 avatarToWorld) { @@ -3043,40 +3035,21 @@ glm::quat cancelOutRollAndPitch2(const glm::quat& q) { return glm::quat_cast(temp); } -static glm::quat saferLerp(const glm::quat& a, const glm::quat& b, float alpha) { - // adjust signs if necessary - glm::quat bTemp = b; - float dot = glm::dot(a, bTemp); - if (dot < 0.0f) { - bTemp = -bTemp; - } - return glm::normalize(glm::lerp(a, bTemp, alpha)); -} - -// this function finds the hips position using a center of gravity model that +// this function finds the hips position using a center of gravity model that // balances the head and hands with the hips over the base of support // returns the rotation and position of the Avatar in Sensor space glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { - glm::mat4 worldToSensorMat = glm::inverse(getSensorToWorldMatrix()); - glm::mat4 avatarToWorldMat = getTransform().getMatrix(); - glm::mat4 avatarToSensorMat = worldToSensorMat * avatarToWorldMat; - - glm::vec3 headPosition; - glm::quat headOrientation; + glm::mat4 sensorToWorldMat = getSensorToWorldMatrix(); + glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat); auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD); - if (headPose.isValid()) { - headPosition = headPose.translation; - // rotate by 180 Y to put the head in same frame as the avatar - headOrientation = headPose.rotation * Quaternions::Y_180; - } - const glm::quat headOrientationYawOnly = cancelOutRollAndPitch(headOrientation); - const float MIX_RATIO = 0.5f; - // here we mix in some of the head yaw into the hip yaw - glm::quat hipYawRot = glm::normalize(saferLerp(glmExtractRotation(avatarToSensorMat), headOrientationYawOnly, MIX_RATIO)); - glm::vec3 newLocalHeadPos = glm::inverse(hipYawRot) * (headPosition - extractTranslation(avatarToSensorMat)); + + // the Y_180 is to flip the controller pose from -z forward to the head joint which is +z forward. + glm::mat4 sensorHeadMat = createMatFromQuatAndPos(headPose.rotation * Quaternions::Y_180, headPose.translation); + // convert into avatar space + glm::mat4 avatarToWorldMat = getTransform().getMatrix(); + glm::mat4 avatarHeadMat = glm::inverse(avatarToWorldMat) * sensorToWorldMat * sensorHeadMat; if (_enableDebugDrawBaseOfSupport) { - // default height is ~ 1.64 meters float scaleBaseOfSupport = getUserEyeHeight() / DEFAULT_AVATAR_EYE_HEIGHT; glm::vec3 rightFootPositionLocal = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("RightFoot")); drawBaseOfSupport(scaleBaseOfSupport, rightFootPositionLocal.y, avatarToWorldMat); @@ -3084,11 +3057,12 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { // get the new center of gravity const glm::vec3 cgHipsPosition = computeCounterBalance(); - glm::vec3 hipsPositionFinal = transformPoint(avatarToSensorMat, cgHipsPosition); // find the new hips rotation using the new head-hips axis as the up axis - glm::quat newHipsRotation = computeNewHipsRotation(newLocalHeadPos, cgHipsPosition); - return createMatFromQuatAndPos(hipYawRot*newHipsRotation, hipsPositionFinal); + glm::mat4 avatarHipsMat = computeNewHipsMatrix(glmExtractRotation(avatarHeadMat), extractTranslation(avatarHeadMat), cgHipsPosition); + + // convert hips from avatar to sensor space + return worldToSensorMat * avatarToWorldMat * avatarHipsMat; } float MyAvatar::getUserHeight() const { From 20c960c0da5406db331c600eb3af93284241c00d Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 9 May 2018 15:00:20 -0700 Subject: [PATCH 028/380] removed white space in MyAvatar.cpp --- interface/src/avatar/MyAvatar.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 35247bca20..72bb5cc500 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3022,11 +3022,10 @@ glm::quat cancelOutRollAndPitch2(const glm::quat& q) { if (fabs(zAxis.y) > 0.0) { // new z is the up axis, that is the direction the body is pointing newZ = glm::normalize(q * glm::vec3(0.0f, 1.0f, 0.0f)); - } + } newX = glm::cross(vec3(0.0f, 1.0f, 0.0f), newZ); newY = glm::cross(newZ, newX); - } - else { + } else { newZ = glm::normalize(vec3(zAxis.x, 0.0f, zAxis.z)); newX = glm::cross(vec3(0.0f, 1.0f, 0.0f), newZ); newY = glm::cross(newZ, newX); @@ -3057,10 +3056,10 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { // get the new center of gravity const glm::vec3 cgHipsPosition = computeCounterBalance(); - + // find the new hips rotation using the new head-hips axis as the up axis glm::mat4 avatarHipsMat = computeNewHipsMatrix(glmExtractRotation(avatarHeadMat), extractTranslation(avatarHeadMat), cgHipsPosition); - + // convert hips from avatar to sensor space return worldToSensorMat * avatarToWorldMat * avatarHipsMat; } From 3241c182714c2f2bf221d1f910dab38049644406 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 9 May 2018 18:10:40 -0700 Subject: [PATCH 029/380] first pass cloneables WIP --- .../src/entities/EntityServer.cpp | 1 + .../entities/src/EntityEditPacketSender.cpp | 14 ++- .../entities/src/EntityEditPacketSender.h | 1 + libraries/entities/src/EntityItem.cpp | 98 ++++++++++++++++++ libraries/entities/src/EntityItem.h | 23 +++++ .../entities/src/EntityItemProperties.cpp | 97 ++++++++++++++++++ libraries/entities/src/EntityItemProperties.h | 7 ++ .../src/EntityItemPropertiesDefaults.h | 5 + libraries/entities/src/EntityPropertyFlags.h | 5 + .../entities/src/EntityScriptingInterface.cpp | 73 +++++++++----- .../entities/src/EntityScriptingInterface.h | 3 + libraries/entities/src/EntityTree.cpp | 99 +++++++++++++++---- libraries/entities/src/EntityTree.h | 1 + libraries/gpu/src/gpu/Buffer.cpp | 2 +- .../networking/src/udt/PacketHeaders.cpp | 3 +- libraries/networking/src/udt/PacketHeaders.h | 4 +- scripts/system/html/js/entityProperties.js | 75 ++------------ scripts/system/libraries/cloneEntityUtils.js | 60 +++-------- .../libraries/controllerDispatcherUtils.js | 3 +- 19 files changed, 410 insertions(+), 164 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index c108dad6cf..3ca8c1ecd1 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -44,6 +44,7 @@ EntityServer::EntityServer(ReceivedMessage& message) : auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, + PacketType::EntityClone, PacketType::EntityEdit, PacketType::EntityErase, PacketType::EntityPhysics, diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index d89dd4f9d0..0ae4f7ac2b 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -34,7 +34,7 @@ void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer EntityItem::getMaterial } return toReturn; } + +bool EntityItem::getCloneable() const { + bool result; + withReadLock([&] { + result = _cloneable; + }); + return result; +} + +void EntityItem::setCloneable(bool value) { + withWriteLock([&] { + _cloneable = value; + }); +} + +float EntityItem::getCloneableLifetime() const { + float result; + withReadLock([&] { + result = _cloneableLifetime; + }); + return result; +} + +void EntityItem::setCloneableLifetime(float value) { + withWriteLock([&] { + _cloneableLifetime = value; + }); +} + +float EntityItem::getCloneableLimit() const { + float result; + withReadLock([&] { + result = _cloneableLimit; + }); + return result; +} + +void EntityItem::setCloneableLimit(float value) { + withWriteLock([&] { + _cloneableLimit = value; + }); +} + +bool EntityItem::getCloneableDynamic() const { + bool result; + withReadLock([&] { + result = _cloneableDynamic; + }); + return result; +} + +void EntityItem::setCloneableDynamic(const bool value) { + withWriteLock([&] { + _cloneableDynamic = value; + }); +} + +bool EntityItem::addCloneID(const QUuid& cloneID) { + if (!_cloneIDs.contains(cloneID)) { + _cloneIDs.append(cloneID); + return true; + } + return false; +} + +bool EntityItem::removeCloneID(const QUuid& cloneID) { + int index = _cloneIDs.indexOf(cloneID); + if (index > 0) { + _cloneIDs.removeAt(index); + return true; + } + return false; +} \ No newline at end of file diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a88250a133..95cc5f96e1 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -341,6 +341,15 @@ public: quint32 getStaticCertificateVersion() const; void setStaticCertificateVersion(const quint32&); + bool getCloneable() const; + void setCloneable(bool value); + float getCloneableLifetime() const; + void setCloneableLifetime(float value); + float getCloneableLimit() const; + void setCloneableLimit(float value); + bool getCloneableDynamic() const; + void setCloneableDynamic(const bool value); + // TODO: get rid of users of getRadius()... float getRadius() const; @@ -494,6 +503,12 @@ public: void setSimulationOwnershipExpiry(uint64_t expiry) { _simulationOwnershipExpiry = expiry; } uint64_t getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } + bool addCloneID(const QUuid& cloneID); + bool removeCloneID(const QUuid& cloneID); + const QList& getCloneIDs() const { return _cloneIDs; } + void setCloneParent(const QUuid& cloneParentID) { _cloneParentID = cloneParentID; } + const QUuid& getCloneParent() const { return _cloneParentID; } + signals: void requestRenderUpdate(); @@ -648,6 +663,14 @@ protected: bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera + bool _cloneable; + float _cloneableLifetime; + float _cloneableLimit; + bool _cloneableDynamic; + + QList _cloneIDs; + QUuid _cloneParentID; + private: std::unordered_map _materials; std::mutex _materialsLock; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 4d7c114176..93c2eb885e 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -436,6 +436,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_DPI, dpi); CHECK_PROPERTY_CHANGE(PROP_RELAY_PARENT_JOINTS, relayParentJoints); + CHECK_PROPERTY_CHANGE(PROP_CLONEABLE, cloneable); + CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_LIFETIME, cloneableLifetime); + CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_LIMIT, cloneableLimit); + CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_DYNAMIC, cloneableDynamic); + changedProperties += _animation.getChangedProperties(); changedProperties += _keyLight.getChangedProperties(); changedProperties += _ambientLight.getChangedProperties(); @@ -1430,6 +1435,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly); // Gettable but not settable except at entity creation COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); // Gettable but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE, cloneable); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_LIFETIME, cloneableLifetime); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_LIMIT, cloneableLimit); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_DYNAMIC, cloneableDynamic); + // Rendering info if (!skipDefaults && !strictSemantics) { QScriptValue renderInfo = engine->newObject(); @@ -1642,6 +1652,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(dpi, uint16_t, setDPI); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneable, bool, setCloneable); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableLifetime, float, setCloneableLifetime); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableLimit, float, setCloneableLimit); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableDynamic, bool, setCloneableDynamic); + _lastEdited = usecTimestampNow(); } @@ -2017,6 +2032,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_DPI, DPI, dpi, uint16_t); + ADD_PROPERTY_TO_MAP(PROP_CLONEABLE, Cloneable, cloneable, bool); + ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_LIFETIME, CloneableLifetime, cloneableLifetime, float); + ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_LIMIT, CloneableLimit, cloneableLimit, float); + ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_DYNAMIC, CloneableDynamic, cloneableDynamic, bool); + // FIXME - these are not yet handled //ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64); @@ -2331,6 +2351,11 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, properties.getEntityInstanceNumber()); APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, properties.getCertificateID()); APPEND_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, properties.getStaticCertificateVersion()); + + APPEND_ENTITY_PROPERTY(PROP_CLONEABLE, properties.getCloneable()); + APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIFETIME, properties.getCloneableLifetime()); + APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIMIT, properties.getCloneableLimit()); + APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_DYNAMIC, properties.getCloneableDynamic()); } if (propertyCount > 0) { @@ -2701,6 +2726,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CERTIFICATE_ID, QString, setCertificateID); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STATIC_CERTIFICATE_VERSION, quint32, setStaticCertificateVersion); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE, bool, setCloneable); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_LIFETIME, float, setCloneableLifetime); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_LIMIT, float, setCloneableLimit); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_DYNAMIC, bool, setCloneableDynamic); + return valid; } @@ -2780,6 +2810,54 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt return true; } +bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID, QByteArray& buffer) { + + char* copyAt = buffer.data(); + int outputLength = 0; + + if (buffer.size() < (int)(sizeof(NUM_BYTES_RFC4122_UUID) * 2)) { + qCDebug(entities) << "ERROR - encodeCloneEntityMessage() called with buffer that is too small!"; + return false; + } + + memcpy(copyAt, entityIDToClone.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); + copyAt += NUM_BYTES_RFC4122_UUID; + outputLength += NUM_BYTES_RFC4122_UUID; + + memcpy(copyAt, newEntityID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); + copyAt += NUM_BYTES_RFC4122_UUID; + outputLength += NUM_BYTES_RFC4122_UUID; + + buffer.resize(outputLength); + + return true; +} + +bool EntityItemProperties::decodeCloneEntityMessage(const QByteArray& buffer, int& processedBytes, EntityItemID& entityIDToClone, EntityItemID& newEntityID) { + + const unsigned char* packetData = (const unsigned char*)buffer.constData(); + const unsigned char* dataAt = packetData; + size_t packetLength = buffer.size(); + processedBytes = 0; + + if (NUM_BYTES_RFC4122_UUID * 2 > packetLength) { + qCDebug(entities) << "EntityItemProperties::processEraseMessageDetails().... bailing because not enough bytes in buffer"; + return false; // bail to prevent buffer overflow + } + + QByteArray encodedID = buffer.mid((int)processedBytes, NUM_BYTES_RFC4122_UUID); + entityIDToClone = QUuid::fromRfc4122(encodedID); + dataAt += encodedID.size(); + processedBytes += encodedID.size(); + + encodedID = buffer.mid((int)processedBytes, NUM_BYTES_RFC4122_UUID); + newEntityID = QUuid::fromRfc4122(encodedID); + dataAt += encodedID.size(); + processedBytes += encodedID.size(); + + return true; +} + void EntityItemProperties::markAllChanged() { _lastEditedByChanged = true; _simulationOwnerChanged = true; @@ -2941,6 +3019,11 @@ void EntityItemProperties::markAllChanged() { _dpiChanged = true; _relayParentJointsChanged = true; + + _cloneableChanged = true; + _cloneableLifetimeChanged = true; + _cloneableLimitChanged = true; + _cloneableDynamicChanged = true; } // The minimum bounding box for the entity. @@ -3373,6 +3456,20 @@ QList EntityItemProperties::listChangedProperties() { out += "isUVModeStretch"; } + if (cloneableChanged()) { + out += "cloneable"; + } + if (cloneableLifetimeChanged()) { + out += "cloneableLifetime"; + } + if (cloneableLimitChanged()) { + out += "cloneableLimit"; + } + if (cloneableDynamicChanged()) { + out += "cloneableDynamic"; + } + + getAnimation().listChangedProperties(out); getKeyLight().listChangedProperties(out); getAmbientLight().listChangedProperties(out); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 39ea2e0bdd..3ae2186cab 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -272,6 +272,11 @@ public: DEFINE_PROPERTY_REF(PROP_SERVER_SCRIPTS, ServerScripts, serverScripts, QString, ENTITY_ITEM_DEFAULT_SERVER_SCRIPTS); DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS); + DEFINE_PROPERTY(PROP_CLONEABLE, Cloneable, cloneable, bool, ENTITY_ITEM_CLONEABLE); + DEFINE_PROPERTY(PROP_CLONEABLE_LIFETIME, CloneableLifetime, cloneableLifetime, float, ENTITY_ITEM_CLONEABLE_LIFETIME); + DEFINE_PROPERTY(PROP_CLONEABLE_LIMIT, CloneableLimit, cloneableLimit, float, ENTITY_ITEM_CLONEABLE_LIMIT); + DEFINE_PROPERTY(PROP_CLONEABLE_DYNAMIC, CloneableDynamic, cloneableDynamic, bool, ENTITY_ITEM_CLONEABLE_DYNAMIC); + static QString getComponentModeString(uint32_t mode); static QString getComponentModeAsString(uint32_t mode); @@ -294,6 +299,8 @@ public: QByteArray& buffer, EntityPropertyFlags requestedProperties, EntityPropertyFlags& didntFitProperties); static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer); + static bool encodeCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID, QByteArray& buffer); + static bool decodeCloneEntityMessage(const QByteArray& buffer, int& processedBytes, EntityItemID& entityIDToClone, EntityItemID& newEntityID); static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes, EntityItemID& entityID, EntityItemProperties& properties); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index d2ddd687dd..6e46453bda 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -97,4 +97,9 @@ const QUuid ENTITY_ITEM_DEFAULT_LAST_EDITED_BY = QUuid(); const bool ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS = false; +const bool ENTITY_ITEM_CLONEABLE = false; +const float ENTITY_ITEM_CLONEABLE_LIFETIME = 300.0f; +const int ENTITY_ITEM_CLONEABLE_LIMIT = 0; +const bool ENTITY_ITEM_CLONEABLE_DYNAMIC = false; + #endif // hifi_EntityItemPropertiesDefaults_h diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 99a5f287ea..f698739e01 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -242,6 +242,11 @@ enum EntityPropertyList { PROP_MATERIAL_MAPPING_ROT, PROP_MATERIAL_DATA, + PROP_CLONEABLE, + PROP_CLONEABLE_LIFETIME, + PROP_CLONEABLE_LIMIT, + PROP_CLONEABLE_DYNAMIC, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7c16214a78..132fec2c51 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -258,33 +258,9 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties propertiesWithSimID = convertPropertiesFromScriptSemantics(propertiesWithSimID, scalesWithParent); propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); - EntityItemID id = EntityItemID(QUuid::createUuid()); - + EntityItemID id; // If we have a local entity tree set, then also update it. - bool success = true; - if (_entityTree) { - _entityTree->withWriteLock([&] { - EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID); - if (entity) { - if (propertiesWithSimID.queryAACubeRelatedPropertyChanged()) { - // due to parenting, the server may not know where something is in world-space, so include the bounding cube. - bool success; - AACube queryAACube = entity->getQueryAACube(success); - if (success) { - propertiesWithSimID.setQueryAACube(queryAACube); - } - } - - entity->setLastBroadcast(usecTimestampNow()); - // since we're creating this object we will immediately volunteer to own its simulation - entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY); - propertiesWithSimID.setLastEdited(entity->getLastEdited()); - } else { - qCDebug(entities) << "script failed to add new Entity to local Octree"; - success = false; - } - }); - } + bool success = addLocalEntityCopy(propertiesWithSimID, id); // queue the packet if (success) { @@ -295,6 +271,39 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties } } +bool EntityScriptingInterface::addLocalEntityCopy(EntityItemProperties& properties, EntityItemID& id) { + bool success = true; + + id = EntityItemID(QUuid::createUuid()); + + if (_entityTree) { + _entityTree->withWriteLock([&] { + EntityItemPointer entity = _entityTree->addEntity(id, properties); + if (entity) { + if (properties.queryAACubeRelatedPropertyChanged()) { + // due to parenting, the server may not know where something is in world-space, so include the bounding cube. + bool success; + AACube queryAACube = entity->getQueryAACube(success); + if (success) { + properties.setQueryAACube(queryAACube); + } + } + + entity->setLastBroadcast(usecTimestampNow()); + // since we're creating this object we will immediately volunteer to own its simulation + entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY); + properties.setLastEdited(entity->getLastEdited()); + } + else { + qCDebug(entities) << "script failed to add new Entity to local Octree"; + success = false; + } + }); + } + + return success; +} + QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const QString& textures, const QString& shapeType, bool dynamic, bool collisionless, const glm::vec3& position, const glm::vec3& gravity) { @@ -320,6 +329,18 @@ QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QStrin return addEntity(properties); } +QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { + EntityItemID newEntityID; + EntityItemProperties properties = getEntityProperties(entityIDToClone); + if (addLocalEntityCopy(properties, newEntityID)) { + qCDebug(entities) << "DBACK POOPY cloneEntity addLocalEntityCopy" << newEntityID; + getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); + return newEntityID; + } else { + return QUuid(); + } +} + EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) { EntityPropertyFlags noSpecificProperties; return getEntityProperties(identity, noSpecificProperties); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 8adb5138f2..6935c9e8c4 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -224,6 +224,8 @@ public slots: Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const QString& textures, const QString& shapeType, bool dynamic, bool collisionless, const glm::vec3& position, const glm::vec3& gravity); + Q_INVOKABLE QUuid cloneEntity(QUuid entityIDToClone); + /**jsdoc * Get the properties of an entity. * @function Entities.getEntityProperties @@ -1875,6 +1877,7 @@ private: bool polyVoxWorker(QUuid entityID, std::function actor); bool setPoints(QUuid entityID, std::function actor); void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); + bool addLocalEntityCopy(EntityItemProperties& propertiesWithSimID, EntityItemID& id); EntityItemPointer checkForTreeEntityAndTypeMatch(const QUuid& entityID, EntityTypes::EntityType entityType = EntityTypes::Unknown); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 3149527216..1e8055ff46 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -228,6 +228,7 @@ bool EntityTree::handlesEditPacketType(PacketType packetType) const { // we handle these types of "edit" packets switch (packetType) { case PacketType::EntityAdd: + case PacketType::EntityClone: case PacketType::EntityEdit: case PacketType::EntityErase: case PacketType::EntityPhysics: @@ -592,6 +593,7 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign return; } + removeCloneIDFromCloneParent(entityID); unhookChildAvatar(entityID); emit deletingEntity(entityID); emit deletingEntityPointer(existingEntity.get()); @@ -625,6 +627,19 @@ void EntityTree::unhookChildAvatar(const EntityItemID entityID) { }); } +void EntityTree::removeCloneIDFromCloneParent(const EntityItemID& entityID) { + EntityItemPointer entity = findEntityByEntityItemID(entityID); + if (entity) { + const QUuid& cloneParentID = entity->getCloneParent(); + if (!cloneParentID.isNull()) { + EntityItemPointer cloneParent = findEntityByID(cloneParentID); + if (cloneParent) { + cloneParent->removeCloneID(entityID); + } + } + } +} + void EntityTree::deleteEntities(QSet entityIDs, bool force, bool ignoreWarnings) { // NOTE: callers must lock the tree before using this method DeleteEntityOperator theOperator(getThisPointer()); @@ -653,6 +668,7 @@ void EntityTree::deleteEntities(QSet entityIDs, bool force, bool i } // tell our delete operator about this entityID + removeCloneIDFromCloneParent(entityID); unhookChildAvatar(entityID); theOperator.addEntityIDToDeleteList(entityID); emit deletingEntity(entityID); @@ -1392,6 +1408,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c int processedBytes = 0; bool isAdd = false; + bool isClone = false; // we handle these types of "edit" packets switch (message.getType()) { case PacketType::EntityErase: { @@ -1400,8 +1417,10 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c break; } + case PacketType::EntityClone: + isClone = true; // fall through to next case case PacketType::EntityAdd: - isAdd = true; // fall through to next case + isAdd = true; // fall through to next case // FALLTHRU case PacketType::EntityPhysics: case PacketType::EntityEdit: { @@ -1422,8 +1441,21 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c EntityItemProperties properties; startDecode = usecTimestampNow(); - bool validEditPacket = EntityItemProperties::decodeEntityEditPacket(editData, maxLength, processedBytes, - entityItemID, properties); + bool validEditPacket = false; + EntityItemID entityIDToClone; + EntityItemPointer entityToClone; + if (isClone) { + QByteArray buffer = QByteArray::fromRawData(reinterpret_cast(editData), maxLength); + validEditPacket = EntityItemProperties::decodeCloneEntityMessage(buffer, processedBytes, entityIDToClone, entityItemID); + entityToClone = findEntityByEntityItemID(entityIDToClone); + if (entityToClone) { + properties = entityToClone->getProperties(); + } + } + else { + validEditPacket = EntityItemProperties::decodeEntityEditPacket(editData, maxLength, processedBytes, entityItemID, properties); + } + endDecode = usecTimestampNow(); EntityItemPointer existingEntity; @@ -1491,24 +1523,26 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } - if ((isAdd || properties.lifetimeChanged()) && - ((!senderNode->getCanRez() && senderNode->getCanRezTmp()) || - (!senderNode->getCanRezCertified() && senderNode->getCanRezTmpCertified()))) { - // this node is only allowed to rez temporary entities. if need be, cap the lifetime. - if (properties.getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME || - properties.getLifetime() > _maxTmpEntityLifetime) { - properties.setLifetime(_maxTmpEntityLifetime); + if (!isClone) { + if ((isAdd || properties.lifetimeChanged()) && + ((!senderNode->getCanRez() && senderNode->getCanRezTmp()) || + (!senderNode->getCanRezCertified() && senderNode->getCanRezTmpCertified()))) { + // this node is only allowed to rez temporary entities. if need be, cap the lifetime. + if (properties.getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME || + properties.getLifetime() > _maxTmpEntityLifetime) { + properties.setLifetime(_maxTmpEntityLifetime); + bumpTimestamp(properties); + } + } + + if (isAdd && properties.getLocked() && !senderNode->isAllowedEditor()) { + // if a node can't change locks, don't allow it to create an already-locked entity -- automatically + // clear the locked property and allow the unlocked entity to be created. + properties.setLocked(false); bumpTimestamp(properties); } } - if (isAdd && properties.getLocked() && !senderNode->isAllowedEditor()) { - // if a node can't change locks, don't allow it to create an already-locked entity -- automatically - // clear the locked property and allow the unlocked entity to be created. - properties.setLocked(false); - bumpTimestamp(properties); - } - // If we got a valid edit packet, then it could be a new entity or it could be an update to // an existing entity... handle appropriately if (validEditPacket) { @@ -1566,17 +1600,39 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } else if (isAdd) { bool failedAdd = !allowed; bool isCertified = !properties.getCertificateID().isEmpty(); + bool isCloneable = properties.getCloneable(); + int cloneLimit = properties.getCloneableLimit(); if (!allowed) { qCDebug(entities) << "Filtered entity add. ID:" << entityItemID; - } else if (!isCertified && !senderNode->getCanRez() && !senderNode->getCanRezTmp()) { + } else if (!isClone && !isCertified && !senderNode->getCanRez() && !senderNode->getCanRezTmp()) { failedAdd = true; qCDebug(entities) << "User without 'uncertified rez rights' [" << senderNode->getUUID() << "] attempted to add an uncertified entity with ID:" << entityItemID; - } else if (isCertified && !senderNode->getCanRezCertified() && !senderNode->getCanRezTmpCertified()) { + } else if (!isClone && isCertified && !senderNode->getCanRezCertified() && !senderNode->getCanRezTmpCertified()) { failedAdd = true; qCDebug(entities) << "User without 'certified rez rights' [" << senderNode->getUUID() << "] attempted to add a certified entity with ID:" << entityItemID; + } else if (isClone && isCertified) { + failedAdd = true; + qCDebug(entities) << "User attempted to clone certified entity from entity ID:" << entityIDToClone; + } else if (isClone && !isCloneable) { + failedAdd = true; + qCDebug(entities) << "User attempted to clone non-cloneable entity from entity ID:" << entityIDToClone; + } else if (isClone && entityToClone && entityToClone->getCloneIDs().size() >= cloneLimit) { + failedAdd = true; + qCDebug(entities) << "User attempted to clone entity ID:" << entityIDToClone << " which reached it's cloneable limit."; } else { + if (isClone) { + properties.setName(properties.getName() + "-clone-" + entityIDToClone.toString()); + properties.setLocked(false); + properties.setLifetime(properties.getCloneableLifetime()); + properties.setDynamic(properties.getCloneableDynamic()); + properties.setCloneable(ENTITY_ITEM_CLONEABLE); + properties.setCloneableLifetime(ENTITY_ITEM_CLONEABLE_LIFETIME); + properties.setCloneableLimit(ENTITY_ITEM_CLONEABLE_LIMIT); + properties.setCloneableDynamic(ENTITY_ITEM_CLONEABLE_DYNAMIC); + } + // this is a new entity... assign a new entityID properties.setCreated(properties.getLastEdited()); properties.setLastEditedBy(senderNode->getUUID()); @@ -1600,6 +1656,11 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c if (newEntity) { newEntity->markAsChangedOnServer(); notifyNewlyCreatedEntity(*newEntity, senderNode); + if (isClone) { + entityToClone->addCloneID(newEntity->getEntityItemID()); + newEntity->setCloneParent(entityIDToClone); + qCDebug(entities) << "DBACK POOPY addedEntity clone " << newEntity->getEntityItemID(); + } startLogging = usecTimestampNow(); if (wantEditLogging()) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index ee9fb10554..0d7cc54df7 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -117,6 +117,7 @@ public: // check if the avatar is a child of this entity, If so set the avatar parentID to null void unhookChildAvatar(const EntityItemID entityID); + void removeCloneIDFromCloneParent(const EntityItemID& entityID); void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = true); void deleteEntities(QSet entityIDs, bool force = false, bool ignoreWarnings = true); diff --git a/libraries/gpu/src/gpu/Buffer.cpp b/libraries/gpu/src/gpu/Buffer.cpp index ebb768e597..fe3570e7f7 100644 --- a/libraries/gpu/src/gpu/Buffer.cpp +++ b/libraries/gpu/src/gpu/Buffer.cpp @@ -99,7 +99,7 @@ Buffer::Update::Update(const Buffer& parent) : buffer(parent) { void Buffer::Update::apply() const { // Make sure we're loaded in order buffer._applyUpdateCount++; - assert(buffer._applyUpdateCount == updateNumber); + //assert(buffer._applyUpdateCount == updateNumber); const auto pageSize = buffer._pages._pageSize; buffer._renderSysmem.resize(size); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 70880833bf..e84f3ffe7a 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -29,10 +29,11 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::DomainList: return static_cast(DomainListVersion::GetMachineFingerprintFromUUIDSupport); case PacketType::EntityAdd: + case PacketType::EntityClone: case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::MaterialData); + return static_cast(EntityVersion::CloneableData); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 7d374f3625..5cb2d49a53 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -75,6 +75,7 @@ public: EntityData, EntityQuery, EntityAdd, + EntityClone, EntityErase, EntityEdit, DomainServerConnectionToken, @@ -232,7 +233,8 @@ enum class EntityVersion : PacketVersion { SoftEntities, MaterialEntities, ShadowControl, - MaterialData + MaterialData, + CloneableData }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 4b6329db44..f0bcdad708 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1040,12 +1040,12 @@ function loaded() { elWantsTrigger.checked = false; elIgnoreIK.checked = true; - elCloneable.checked = false; - elCloneableDynamic.checked = false; + elCloneable.checked = properties.cloneable; + elCloneableDynamic.checked = properties.cloneableDynamic; elCloneableGroup.style.display = elCloneable.checked ? "block": "none"; - elCloneableLimit.value = 0; - elCloneableLifetime.value = 300; - + elCloneableLimit.value = properties.cloneableLimit; + elCloneableLifetime.value = properties.cloneableLifetime; + var grabbablesSet = false; var parsedUserData = {}; try { @@ -1069,27 +1069,6 @@ function loaded() { } else { elIgnoreIK.checked = true; } - if ("cloneable" in grabbableData) { - elCloneable.checked = grabbableData.cloneable; - elCloneableGroup.style.display = elCloneable.checked ? "block" : "none"; - elCloneableDynamic.checked = - grabbableData.cloneDynamic ? grabbableData.cloneDynamic : properties.dynamic; - if (elCloneable.checked) { - if ("cloneLifetime" in grabbableData) { - elCloneableLifetime.value = - grabbableData.cloneLifetime ? grabbableData.cloneLifetime : 300; - } - if ("cloneLimit" in grabbableData) { - elCloneableLimit.value = grabbableData.cloneLimit ? grabbableData.cloneLimit : 0; - } - if ("cloneAvatarEntity" in grabbableData) { - elCloneableAvatarEntity.checked = - grabbableData.cloneAvatarEntity ? grabbableData.cloneAvatarEntity : false; - } - } - } else { - elCloneable.checked = false; - } } } catch (e) { // TODO: What should go here? @@ -1460,45 +1439,11 @@ function loaded() { } userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, true); }); - elCloneableDynamic.addEventListener('change', function(event) { - userDataChanger("grabbableKey", "cloneDynamic", event.target, elUserData, -1); - }); - - elCloneableAvatarEntity.addEventListener('change', function(event) { - userDataChanger("grabbableKey", "cloneAvatarEntity", event.target, elUserData, -1); - }); - - elCloneable.addEventListener('change', function (event) { - var checked = event.target.checked; - if (checked) { - multiDataUpdater("grabbableKey", { - cloneLifetime: elCloneableLifetime, - cloneLimit: elCloneableLimit, - cloneDynamic: elCloneableDynamic, - cloneAvatarEntity: elCloneableAvatarEntity, - cloneable: event.target, - grabbable: null - }, elUserData, {}); - elCloneableGroup.style.display = "block"; - updateProperty('dynamic', false); - } else { - multiDataUpdater("grabbableKey", { - cloneLifetime: null, - cloneLimit: null, - cloneDynamic: null, - cloneAvatarEntity: null, - cloneable: false - }, elUserData, {}); - elCloneableGroup.style.display = "none"; - } - }); - - var numberListener = function (event) { - userDataChanger("grabbableKey", - event.target.getAttribute("data-user-data-type"), parseInt(event.target.value), elUserData, false); - }; - elCloneableLifetime.addEventListener('change', numberListener); - elCloneableLimit.addEventListener('change', numberListener); + + elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); + elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneableDynamic')); + elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLifetime')); + elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLimit')); elWantsTrigger.addEventListener('change', function() { userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); diff --git a/scripts/system/libraries/cloneEntityUtils.js b/scripts/system/libraries/cloneEntityUtils.js index 63b161eb80..bd33d32342 100644 --- a/scripts/system/libraries/cloneEntityUtils.js +++ b/scripts/system/libraries/cloneEntityUtils.js @@ -33,8 +33,7 @@ if (typeof Object.assign !== 'function') { entityIsCloneable = function(props) { if (props) { - var grabbableData = getGrabbableData(props); - return grabbableData.cloneable; + return props.cloneable; } return false; }; @@ -42,56 +41,19 @@ entityIsCloneable = function(props) { propsAreCloneDynamic = function(props) { var cloneable = entityIsCloneable(props); if (cloneable) { - var grabInfo = getGrabbableData(props); - if (grabInfo.cloneDynamic) { - return true; - } + return props.cloneableDynamic; } return false; }; - cloneEntity = function(props, worldEntityProps) { - // we need all the properties, for this - var cloneableProps = Entities.getEntityProperties(props.id); - - var count = 0; - worldEntityProps.forEach(function(itemWE) { - if (itemWE.name.indexOf('-clone-' + cloneableProps.id) !== -1) { - count++; - } - }); - - var grabInfo = getGrabbableData(cloneableProps); - var limit = grabInfo.cloneLimit ? grabInfo.cloneLimit : 0; - if (count >= limit && limit !== 0) { - return null; - } - - cloneableProps.name = cloneableProps.name + '-clone-' + cloneableProps.id; - var lifetime = grabInfo.cloneLifetime ? grabInfo.cloneLifetime : 300; - var dynamic = grabInfo.cloneDynamic ? grabInfo.cloneDynamic : false; - var triggerable = grabInfo.triggerable ? grabInfo.triggerable : false; - var avatarEntity = grabInfo.cloneAvatarEntity ? grabInfo.cloneAvatarEntity : false; - var cUserData = Object.assign({}, JSON.parse(cloneableProps.userData)); - var cProperties = Object.assign({}, cloneableProps); - - - delete cUserData.grabbableKey.cloneLifetime; - delete cUserData.grabbableKey.cloneable; - delete cUserData.grabbableKey.cloneDynamic; - delete cUserData.grabbableKey.cloneLimit; - delete cUserData.grabbableKey.cloneAvatarEntity; - delete cProperties.id; - - - cProperties.dynamic = dynamic; - cProperties.locked = false; - cUserData.grabbableKey.triggerable = triggerable; - cUserData.grabbableKey.grabbable = true; - cProperties.lifetime = lifetime; - cProperties.userData = JSON.stringify(cUserData); - - var cloneID = Entities.addEntity(cProperties, avatarEntity); - return cloneID; + var entityToClone = props.id; + var certificateID = Entities.getEntityProperties(entityToClone, ['certificateID']).certificateID; + // ensure entity is cloneable and does not have a certificate ID, whereas cloneable limits + // will now be handled by the server where the entity add will fail if limit reached + if (entityIsCloneable(props) && (certificateID === undefined || certificateID.length === 0)) { + var cloneID = Entities.cloneEntity(entityToClone); + return cloneID; + } + return null; }; diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index 71dc5e4273..f3f0e8dd01 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -125,7 +125,8 @@ DISPATCHER_PROPERTIES = [ "dimensions", "userData", "type", - "href" + "href", + "cloneable" ]; // priority -- a lower priority means the module will be asked sooner than one with a higher priority in a given update step From dea588ae4ac1968b0e3f5c070f9c99096fbc2b96 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 9 May 2018 18:12:04 -0700 Subject: [PATCH 030/380] remove prints --- libraries/entities/src/EntityScriptingInterface.cpp | 1 - libraries/entities/src/EntityTree.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 132fec2c51..7b7f35aa09 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -333,7 +333,6 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); if (addLocalEntityCopy(properties, newEntityID)) { - qCDebug(entities) << "DBACK POOPY cloneEntity addLocalEntityCopy" << newEntityID; getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); return newEntityID; } else { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 1e8055ff46..20b3f81f42 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1659,7 +1659,6 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c if (isClone) { entityToClone->addCloneID(newEntity->getEntityItemID()); newEntity->setCloneParent(entityIDToClone); - qCDebug(entities) << "DBACK POOPY addedEntity clone " << newEntity->getEntityItemID(); } startLogging = usecTimestampNow(); From 1aa653c5db6cf05fbb94517c857e4b3958e8563a Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 9 May 2018 18:20:07 -0700 Subject: [PATCH 031/380] tabs --- scripts/system/html/js/entityProperties.js | 12 ++++++------ scripts/system/libraries/cloneEntityUtils.js | 16 ++++++++-------- .../libraries/controllerDispatcherUtils.js | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index f0bcdad708..c81e51d674 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1045,7 +1045,7 @@ function loaded() { elCloneableGroup.style.display = elCloneable.checked ? "block": "none"; elCloneableLimit.value = properties.cloneableLimit; elCloneableLifetime.value = properties.cloneableLifetime; - + var grabbablesSet = false; var parsedUserData = {}; try { @@ -1439,11 +1439,11 @@ function loaded() { } userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, true); }); - - elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); - elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneableDynamic')); - elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLifetime')); - elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLimit')); + + elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); + elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneableDynamic')); + elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLifetime')); + elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLimit')); elWantsTrigger.addEventListener('change', function() { userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); diff --git a/scripts/system/libraries/cloneEntityUtils.js b/scripts/system/libraries/cloneEntityUtils.js index bd33d32342..358bc4a75f 100644 --- a/scripts/system/libraries/cloneEntityUtils.js +++ b/scripts/system/libraries/cloneEntityUtils.js @@ -47,13 +47,13 @@ propsAreCloneDynamic = function(props) { }; cloneEntity = function(props, worldEntityProps) { - var entityToClone = props.id; + var entityToClone = props.id; var certificateID = Entities.getEntityProperties(entityToClone, ['certificateID']).certificateID; - // ensure entity is cloneable and does not have a certificate ID, whereas cloneable limits - // will now be handled by the server where the entity add will fail if limit reached - if (entityIsCloneable(props) && (certificateID === undefined || certificateID.length === 0)) { - var cloneID = Entities.cloneEntity(entityToClone); - return cloneID; - } - return null; + // ensure entity is cloneable and does not have a certificate ID, whereas cloneable limits + // will now be handled by the server where the entity add will fail if limit reached + if (entityIsCloneable(props) && (certificateID === undefined || certificateID.length === 0)) { + var cloneID = Entities.cloneEntity(entityToClone); + return cloneID; + } + return null; }; diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index f3f0e8dd01..43945c6145 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -126,7 +126,7 @@ DISPATCHER_PROPERTIES = [ "userData", "type", "href", - "cloneable" + "cloneable" ]; // priority -- a lower priority means the module will be asked sooner than one with a higher priority in a given update step From f08f77098dc22b8d3e40f199d63184fbec9e144d Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 9 May 2018 18:28:47 -0700 Subject: [PATCH 032/380] Adding a true ListView for the engine --- scripts/developer/utilities/lib/jet/jet.js | 9 +++ .../utilities/lib/jet/qml/TaskList.qml | 4 +- .../utilities/lib/jet/qml/TaskListView.qml | 67 +++++++++++++++++++ .../developer/utilities/lib/jet/qml/qmldir | 3 +- .../utilities/render/engineInspector.qml | 4 +- 5 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 scripts/developer/utilities/lib/jet/qml/TaskListView.qml diff --git a/scripts/developer/utilities/lib/jet/jet.js b/scripts/developer/utilities/lib/jet/jet.js index c326a3a73e..5bebb99068 100644 --- a/scripts/developer/utilities/lib/jet/jet.js +++ b/scripts/developer/utilities/lib/jet/jet.js @@ -45,6 +45,15 @@ function job_propKeys(job) { return propKeys; } +// Use this function to create a functor that will fill the specifed array with one entry name per task and job and it s rank +function job_list_functor(jobList, maxDepth) { + if (maxDepth === undefined) maxDepth = 100 + return function (job, depth, index) { + jobList.push(job.objectName); + return depth < maxDepth; + } +} + // Use this function to create a functor that will print the content of the Job visited calling the specified 'printout' function function job_print_functor(printout, showProps, maxDepth) { if (maxDepth === undefined) maxDepth = 100 diff --git a/scripts/developer/utilities/lib/jet/qml/TaskList.qml b/scripts/developer/utilities/lib/jet/qml/TaskList.qml index bd4b1e6c79..b801b9171d 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskList.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskList.qml @@ -17,7 +17,9 @@ import "qrc:///qml/controls-uit" as HifiControls import "../jet.js" as Jet -Rectangle { +Rectangle { + HifiConstants { id: hifi;} + color: hifi.colors.baseGray; id: root // width: parent ? parent.width : 200 // height: parent ? parent.height : 400 diff --git a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml new file mode 100644 index 0000000000..f8775d56b9 --- /dev/null +++ b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml @@ -0,0 +1,67 @@ +// +// jet/TaskListView.qml +// +// Created by Sam Gateau, 2018/05/09 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7 +import QtQuick.Controls 1.4 as Original +import QtQuick.Controls.Styles 1.4 + +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls + +import "../jet.js" as Jet + +Rectangle { + HifiConstants { id: hifi;} + color: hifi.colors.baseGray; + id: root + + // width: parent ? parent.width : 200 + // height: parent ? parent.height : 400 + property var rootConfig : Workload + property var myArray : [] + + Component.onCompleted: { + var message = "" + var functor = Jet.job_print_functor(function (line) { message += line + "\n"; }, false); + + functor = Jet.job_list_functor(root.myArray); + + Jet.task_traverseTree(rootConfig, functor); + //print(JSON.stringify(root.myArray)) + // theView.model = root.myArray.length + for (var i = 0; i < root.myArray.length; i++) { + jobsModel.append({"on": true, "name": root.myArray[i]}) + } + // theView.model = root.myArray + } + + function getJobName(i) { + return root.myArray[i]; + } + + ListModel { + id: jobsModel + } + + Component { + id: itemDelegate + //HifiControls.Label { text: "I am item number: " + index } + HifiControls.CheckBox { text: name + index; + checked: true; } + } + + ListView { + id: theView + anchors.fill: parent + model: jobsModel + delegate: itemDelegate + } + +} \ No newline at end of file diff --git a/scripts/developer/utilities/lib/jet/qml/qmldir b/scripts/developer/utilities/lib/jet/qml/qmldir index f926d8cc67..3134545625 100644 --- a/scripts/developer/utilities/lib/jet/qml/qmldir +++ b/scripts/developer/utilities/lib/jet/qml/qmldir @@ -1 +1,2 @@ -TaskList 1.0 TaskList.qml \ No newline at end of file +TaskList 1.0 TaskList.qml +TaskViewList 1.0 TaskViewList.qml \ No newline at end of file diff --git a/scripts/developer/utilities/render/engineInspector.qml b/scripts/developer/utilities/render/engineInspector.qml index 6461e5d834..1b9941e64e 100644 --- a/scripts/developer/utilities/render/engineInspector.qml +++ b/scripts/developer/utilities/render/engineInspector.qml @@ -20,10 +20,10 @@ Item { HifiConstants { id: hifi;} id: render; anchors.fill: parent - + property var mainViewTask: Render.getConfig("RenderMainView") - Jet.TaskList { + Jet.TaskListView { rootConfig: Render anchors.fill: render } From 5aab88be06edf0b56fe4b9c6dd690e73ded6b529 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 9 May 2018 19:10:56 -0700 Subject: [PATCH 033/380] assert --- libraries/gpu/src/gpu/Buffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/Buffer.cpp b/libraries/gpu/src/gpu/Buffer.cpp index fe3570e7f7..ebb768e597 100644 --- a/libraries/gpu/src/gpu/Buffer.cpp +++ b/libraries/gpu/src/gpu/Buffer.cpp @@ -99,7 +99,7 @@ Buffer::Update::Update(const Buffer& parent) : buffer(parent) { void Buffer::Update::apply() const { // Make sure we're loaded in order buffer._applyUpdateCount++; - //assert(buffer._applyUpdateCount == updateNumber); + assert(buffer._applyUpdateCount == updateNumber); const auto pageSize = buffer._pages._pageSize; buffer._renderSysmem.resize(size); From bf85034f3618d267f0187fe82ea05dbc6236a450 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 10 May 2018 02:08:19 -0700 Subject: [PATCH 034/380] Tree view comming together for the engine! --- scripts/developer/utilities/lib/jet/jet.js | 6 +- .../utilities/lib/jet/qml/TaskListView.qml | 90 +++++++++++++++---- 2 files changed, 76 insertions(+), 20 deletions(-) diff --git a/scripts/developer/utilities/lib/jet/jet.js b/scripts/developer/utilities/lib/jet/jet.js index 5bebb99068..18027ea4bd 100644 --- a/scripts/developer/utilities/lib/jet/jet.js +++ b/scripts/developer/utilities/lib/jet/jet.js @@ -12,15 +12,15 @@ // traverse task tree function task_traverse(root, functor, depth) { - // if (root.isTask()) { + if (root.isTask()) { depth++; for (var i = 0; i 0 ? "." : "") + node.get(jobTreePath[n]).name + node = node.get(jobTreePath[n]).subNode + } + node.append(newItem) + jobTreePath.push(0); + } else if (jobTreePath.length >= depth) { + var node = jobsRoot; + for (var n = 0; n < (depth - 1); n++) { + newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name + node = node.get(jobTreePath[n]).subNode + } + node.append(newItem) + jobTreePath[depth-1] = index; + while (jobTreePath.length > depth) { + jobTreePath.pop(); + } + } + } + return true; + } Jet.task_traverseTree(rootConfig, functor); - //print(JSON.stringify(root.myArray)) - // theView.model = root.myArray.length - for (var i = 0; i < root.myArray.length; i++) { - jobsModel.append({"on": true, "name": root.myArray[i]}) - } - // theView.model = root.myArray - } - - function getJobName(i) { - return root.myArray[i]; } ListModel { @@ -51,17 +77,47 @@ Rectangle { } Component { - id: itemDelegate - //HifiControls.Label { text: "I am item number: " + index } - HifiControls.CheckBox { text: name + index; - checked: true; } + id: objRecursiveDelegate + Column { + id: objRecursiveColumn + clip: true + visible: model.init + + MouseArea { + width: objRow.implicitWidth + height: objRow.implicitHeight + onDoubleClicked: { + for(var i = 1; i < parent.children.length - 1; ++i) { + parent.children[i].visible = !parent.children[i].visible + } + } + Row { + id: objRow + Item { + height: 1 + width: model.level * 15 + } + HifiControls.CheckBox { + property var config: root.rootConfig.getConfig(model.path + "." + model.name); + text: (objRecursiveColumn.children.length > 2 ? + objRecursiveColumn.children[1].visible ? + qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name + " ms=" + config.cpuRunTime.toFixed(3) + checked: config.enabled + } + } + } + Repeater { + model: subNode + delegate: objRecursiveDelegate + } + } } ListView { id: theView anchors.fill: parent model: jobsModel - delegate: itemDelegate + delegate: objRecursiveDelegate } } \ No newline at end of file From 02be965271154c9b29dbdb3e60aaffdfe14431bf Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 10 May 2018 18:10:01 -0700 Subject: [PATCH 035/380] more stuff fixed --- .../src/procedural/ProceduralSkybox.cpp | 7 +++++- libraries/render/src/render/Engine.cpp | 3 +-- libraries/render/src/render/Engine.h | 14 ++++++----- libraries/task/src/task/Task.h | 2 +- .../utilities/lib/jet/qml/TaskListView.qml | 24 +++++++++---------- 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 0c6501928b..806302d7ef 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -21,6 +21,7 @@ ProceduralSkybox::ProceduralSkybox() : graphics::Skybox() { _procedural._vertexSource = skybox_vert::getSource(); _procedural._opaquefragmentSource = skybox_frag::getSource(); + _procedural._transparentfragmentSource = skybox_frag::getSource(); // Adjust the pipeline state for background using the stencil test _procedural.setDoesFade(false); // Must match PrepareStencil::STENCIL_BACKGROUND @@ -60,9 +61,13 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, batch.setModelTransform(Transform()); // only for Mac auto& procedural = skybox._procedural; - procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat()); + +// procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat()); + procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat(), glm::vec4(glm::vec3(1.0f), 0.9)); + auto textureSlot = procedural.getOpaqueShader()->getTextures().findLocation("cubeMap"); auto bufferSlot = procedural.getOpaqueShader()->getUniformBuffers().findLocation("skyboxBuffer"); + skybox.prepare(batch, textureSlot, bufferSlot); batch.draw(gpu::TRIANGLE_STRIP, 4); } diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index b0842d63cd..de282bed9f 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -36,8 +36,7 @@ public: } }; -Engine::Engine() : Task(EngineTask::JobModel::create("Engine")), - _renderContext(std::make_shared()) +Engine::Engine() : _Engine(EngineTask::JobModel::create("Engine"), std::make_shared()) { } diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index f444416a3f..7a5f7b7ce8 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -82,7 +82,9 @@ namespace render { // The render engine holds all render tasks, and is itself a render task. // State flows through tasks to jobs via the render and scene contexts - // the engine should not be known from its jobs. - class Engine : public Task { + class Engine : public _Engine { + + //class Engine : public Task { public: Engine(); @@ -93,19 +95,19 @@ namespace render { void load(); // Register the scene - void registerScene(const ScenePointer& scene) { _renderContext->_scene = scene; } + void registerScene(const ScenePointer& scene) { _context->_scene = scene; } // acces the RenderContext - RenderContextPointer getRenderContext() const { return _renderContext; } + RenderContextPointer getRenderContext() const { return _context; } // Render a frame // Must have a scene registered and a context set - void run() { assert(_renderContext); Task::run(_renderContext); } + // void run() { assert(_renderContext); Task::run(_renderContext); } protected: - RenderContextPointer _renderContext; + // RenderContextPointer _renderContext; - void run(const RenderContextPointer& context) override { assert(_renderContext); Task::run(_renderContext); } + // void run(const RenderContextPointer& context) override { assert(_renderContext); Task::run(_renderContext); } }; using EnginePointer = std::shared_ptr; diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index c9a3285443..ef1ca60d57 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -379,7 +379,7 @@ public: using TaskType = Task; using ConceptPointer = typename TaskType::ConceptPointer; - Engine(ConceptPointer concept) : TaskType(concept) {} + Engine(const ConceptPointer& concept, const ContextPointer& context) : TaskType(concept), _context(context) {} ~Engine() = default; void reset(const ContextPointer& context) { _context = context; } diff --git a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml index 998abdef0e..eff456d838 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml @@ -20,7 +20,7 @@ import "../jet.js" as Jet Rectangle { HifiConstants { id: hifi;} color: hifi.colors.baseGray; - id: root + id: root; // width: parent ? parent.width : 200 // height: parent ? parent.height : 400 @@ -29,11 +29,7 @@ Rectangle { Component.onCompleted: { var message = "" - // functor = Jet.job_print_functor(function (line) { message += line + "\n"; }, false); - - // functor = Jet.job_list_functor(root.myArray); - - var maxDepth = 4; + var maxDepth = 3; var jobTreePath = [] var jobsRoot; @@ -72,6 +68,7 @@ Rectangle { Jet.task_traverseTree(rootConfig, functor); } + ListModel { id: jobsModel } @@ -101,7 +98,7 @@ Rectangle { property var config: root.rootConfig.getConfig(model.path + "." + model.name); text: (objRecursiveColumn.children.length > 2 ? objRecursiveColumn.children[1].visible ? - qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name + " ms=" + config.cpuRunTime.toFixed(3) + qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name + " ms=" + config.cpuRunTime.toFixed(2) checked: config.enabled } } @@ -113,11 +110,12 @@ Rectangle { } } - ListView { - id: theView - anchors.fill: parent - model: jobsModel - delegate: objRecursiveDelegate + Original.ScrollView { + anchors.fill: parent + ListView { + id: theView + model: jobsModel + delegate: objRecursiveDelegate + } } - } \ No newline at end of file From a57c280813afc5478148db440e3ab1812a5efac0 Mon Sep 17 00:00:00 2001 From: David Back Date: Fri, 11 May 2018 17:54:08 -0700 Subject: [PATCH 036/380] convertToCloneProperties --- libraries/entities/src/EntityEditPacketSender.cpp | 4 ---- libraries/entities/src/EntityItemProperties.cpp | 11 +++++++++++ libraries/entities/src/EntityItemProperties.h | 2 ++ libraries/entities/src/EntityScriptingInterface.cpp | 1 + libraries/entities/src/EntityTree.cpp | 9 +-------- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index a33f9763e7..c2323b0a20 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -156,10 +156,6 @@ void EntityEditPacketSender::queueEraseEntityMessage(const EntityItemID& entityI } void EntityEditPacketSender::queueCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID) { - if (!_shouldSend) { - return; // bail early - } - QByteArray bufferOut(NLPacket::maxPayloadSize(PacketType::EntityClone), 0); if (EntityItemProperties::encodeCloneEntityMessage(entityIDToClone, newEntityID, bufferOut)) { diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 93c2eb885e..7c799a64e1 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -3633,3 +3633,14 @@ bool EntityItemProperties::verifyStaticCertificateProperties() { // I.e., if we can verify that the certificateID was produced by High Fidelity signing the static certificate hash. return verifySignature(EntityItem::_marketplacePublicKey, getStaticCertificateHash(), QByteArray::fromBase64(getCertificateID().toUtf8())); } + +void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityIDToClone) { + setName(getName() + "-clone-" + entityIDToClone.toString()); + setLocked(false); + setLifetime(getCloneableLifetime()); + setDynamic(getCloneableDynamic()); + setCloneable(ENTITY_ITEM_CLONEABLE); + setCloneableLifetime(ENTITY_ITEM_CLONEABLE_LIFETIME); + setCloneableLimit(ENTITY_ITEM_CLONEABLE_LIMIT); + setCloneableDynamic(ENTITY_ITEM_CLONEABLE_DYNAMIC); +} \ No newline at end of file diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 3ae2186cab..12d4bdf919 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -376,6 +376,8 @@ public: bool verifyStaticCertificateProperties(); static bool verifySignature(const QString& key, const QByteArray& text, const QByteArray& signature); + void convertToCloneProperties(const EntityItemID& entityIDToClone); + protected: QString getCollisionMaskAsString() const; void setCollisionMaskFromString(const QString& maskString); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7b7f35aa09..71e7d1c7c0 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -332,6 +332,7 @@ QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QStrin QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); + properties.convertToCloneProperties(entityIDToClone); if (addLocalEntityCopy(properties, newEntityID)) { getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); return newEntityID; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 20b3f81f42..bcea89232e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1623,14 +1623,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c qCDebug(entities) << "User attempted to clone entity ID:" << entityIDToClone << " which reached it's cloneable limit."; } else { if (isClone) { - properties.setName(properties.getName() + "-clone-" + entityIDToClone.toString()); - properties.setLocked(false); - properties.setLifetime(properties.getCloneableLifetime()); - properties.setDynamic(properties.getCloneableDynamic()); - properties.setCloneable(ENTITY_ITEM_CLONEABLE); - properties.setCloneableLifetime(ENTITY_ITEM_CLONEABLE_LIFETIME); - properties.setCloneableLimit(ENTITY_ITEM_CLONEABLE_LIMIT); - properties.setCloneableDynamic(ENTITY_ITEM_CLONEABLE_DYNAMIC); + properties.convertToCloneProperties(entityIDToClone); } // this is a new entity... assign a new entityID From 1cc7eb635fb8a955a0cc211b925aa1f4c3cab61b Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 14 May 2018 09:13:26 -0700 Subject: [PATCH 037/380] Fix ubuntu warning by removing cancelOutRollAndPitch2() --- interface/src/avatar/MyAvatar.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 11395182fa..1e87dca89b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3011,29 +3011,6 @@ static void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::ma DebugDraw::getInstance().drawRay(frontLeft, frontRight, rayColor); } -// cancel out roll and pitch test fix -glm::quat cancelOutRollAndPitch2(const glm::quat& q) { - glm::vec3 zAxis = q * glm::vec3(0.0f, 0.0f, 1.0f); - glm::vec3 newZ; - glm::vec3 newX; - glm::vec3 newY; - // cancel out the roll and pitch - if (zAxis.x == 0 && zAxis.z == 0.0f) { - if (fabs(zAxis.y) > 0.0) { - // new z is the up axis, that is the direction the body is pointing - newZ = glm::normalize(q * glm::vec3(0.0f, 1.0f, 0.0f)); - } - newX = glm::cross(vec3(0.0f, 1.0f, 0.0f), newZ); - newY = glm::cross(newZ, newX); - } else { - newZ = glm::normalize(vec3(zAxis.x, 0.0f, zAxis.z)); - newX = glm::cross(vec3(0.0f, 1.0f, 0.0f), newZ); - newY = glm::cross(newZ, newX); - } - glm::mat4 temp(glm::vec4(newX, 0.0f), glm::vec4(newY, 0.0f), glm::vec4(newZ, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); - return glm::quat_cast(temp); -} - // this function finds the hips position using a center of gravity model that // balances the head and hands with the hips over the base of support // returns the rotation and position of the Avatar in Sensor space From ec638d9d91716dd966cd071af66df19ed57c80b3 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 14 May 2018 13:48:04 -0700 Subject: [PATCH 038/380] Avatar can now look straight down without spinning 180. Also, come code clean up and removal of unnecessary Y_180 flips. --- interface/src/avatar/MyAvatar.cpp | 33 ++++++++++--------- interface/src/avatar/MyAvatar.h | 8 ++--- interface/src/avatar/MySkeletonModel.cpp | 1 + libraries/animation/src/AnimUtil.cpp | 40 +++++++++++++++++++++++- libraries/animation/src/AnimUtil.h | 5 +++ libraries/shared/src/GLMHelpers.cpp | 6 ++-- libraries/shared/src/GLMHelpers.h | 3 ++ 7 files changed, 75 insertions(+), 21 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1e87dca89b..f017ba0527 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -423,12 +423,12 @@ void MyAvatar::update(float deltaTime) { } #ifdef DEBUG_DRAW_HMD_MOVING_AVERAGE - glm::vec3 p = transformPoint(getSensorToWorldMatrix(), getControllerPoseInAvatarFrame(controller::Pose::HEAD) * - glm::vec3(_headControllerFacingMovingAverage.x, 0.0f, _headControllerFacingMovingAverage.y)); - DebugDraw::getInstance().addMarker("facing-avg", getOrientation(), p, glm::vec4(1.0f)); - p = transformPoint(getSensorToWorldMatrix(), getHMDSensorPosition() + - glm::vec3(_headControllerFacing.x, 0.0f, _headControllerFacing.y)); - DebugDraw::getInstance().addMarker("facing", getOrientation(), p, glm::vec4(1.0f)); + auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); + glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation()); + glm::vec3 worldFacingAverage = transformVectorFast(getSensorToWorldMatrix(), glm::vec3(_headControllerFacingMovingAverage.x, 0.0f, _headControllerFacingMovingAverage.y)); + glm::vec3 worldFacing = transformVectorFast(getSensorToWorldMatrix(), glm::vec3(_headControllerFacing.x, 0.0f, _headControllerFacing.y)); + DebugDraw::getInstance().drawRay(worldHeadPos, worldHeadPos + worldFacing, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f)); + DebugDraw::getInstance().drawRay(worldHeadPos, worldHeadPos + worldFacingAverage, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f)); #endif if (_goToPending) { @@ -702,7 +702,8 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { _hmdSensorOrientation = glmExtractRotation(hmdSensorMatrix); auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD); if (headPose.isValid()) { - _headControllerFacing = getFacingDir2D(headPose.rotation); + glm::quat bodyOrientation = computeBodyFacingFromHead(headPose.rotation, Vectors::UNIT_Y); + _headControllerFacing = getFacingDir2D(bodyOrientation); } else { _headControllerFacing = glm::vec2(1.0f, 0.0f); } @@ -2817,6 +2818,7 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD); if (headPose.isValid()) { headPosition = headPose.translation; + // AJT: TODO: can remove this Y_180 headOrientation = headPose.rotation * Quaternions::Y_180; } const glm::quat headOrientationYawOnly = cancelOutRollAndPitch(headOrientation); @@ -2839,6 +2841,8 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { // eyeToNeck offset is relative full HMD orientation. // while neckToRoot offset is only relative to HMDs yaw. // Y_180 is necessary because rig is z forward and hmdOrientation is -z forward + + // AJT: TODO: can remove this Y_180, if we remove the higher level one. glm::vec3 headToNeck = headOrientation * Quaternions::Y_180 * (localNeck - localHead); glm::vec3 neckToRoot = headOrientationYawOnly * Quaternions::Y_180 * -localNeck; @@ -2975,9 +2979,11 @@ glm::vec3 MyAvatar::computeCounterBalance() const { // headOrientation, headPosition and hipsPosition are in avatar space // returns the matrix of the hips in Avatar space static glm::mat4 computeNewHipsMatrix(glm::quat headOrientation, glm::vec3 headPosition, glm::vec3 hipsPosition) { - glm::quat headOrientationYawOnly = cancelOutRollAndPitch(headOrientation); - const float MIX_RATIO = 0.5f; - glm::quat hipsRot = safeLerp(Quaternions::IDENTITY, headOrientationYawOnly, MIX_RATIO); + + glm::quat bodyOrientation = computeBodyFacingFromHead(headOrientation, Vectors::UNIT_Y); + + const float MIX_RATIO = 0.3f; + glm::quat hipsRot = safeLerp(Quaternions::IDENTITY, bodyOrientation, MIX_RATIO); glm::vec3 hipsFacing = hipsRot * Vectors::UNIT_Z; glm::vec3 spineVec = headPosition - hipsPosition; @@ -3013,14 +3019,14 @@ static void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::ma // this function finds the hips position using a center of gravity model that // balances the head and hands with the hips over the base of support -// returns the rotation and position of the Avatar in Sensor space +// returns the rotation (-z forward) and position of the Avatar in Sensor space glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { glm::mat4 sensorToWorldMat = getSensorToWorldMatrix(); glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat); auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD); - // the Y_180 is to flip the controller pose from -z forward to the head joint which is +z forward. glm::mat4 sensorHeadMat = createMatFromQuatAndPos(headPose.rotation * Quaternions::Y_180, headPose.translation); + // convert into avatar space glm::mat4 avatarToWorldMat = getTransform().getMatrix(); glm::mat4 avatarHeadMat = glm::inverse(avatarToWorldMat) * sensorToWorldMat * sensorHeadMat; @@ -3038,6 +3044,7 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const { glm::mat4 avatarHipsMat = computeNewHipsMatrix(glmExtractRotation(avatarHeadMat), extractTranslation(avatarHeadMat), cgHipsPosition); // convert hips from avatar to sensor space + // The Y_180 is to convert from z forward to -z forward. return worldToSensorMat * avatarToWorldMat * avatarHipsMat; } @@ -3205,9 +3212,7 @@ void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) { bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); - return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD; - } bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c7b09f7bc6..0d9fd860b7 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -978,14 +978,14 @@ public: // derive avatar body position and orientation from the current HMD Sensor location. - // results are in HMD frame + // results are in sensor frame (-z forward) glm::mat4 deriveBodyFromHMDSensor() const; glm::vec3 computeCounterBalance() const; // derive avatar body position and orientation from using the current HMD Sensor location in relation to the previous // location of the base of support of the avatar. - // results are in HMD frame + // results are in sensor frame (-z foward) glm::mat4 deriveBodyUsingCgModel() const; /**jsdoc @@ -1495,8 +1495,8 @@ private: glm::quat _hmdSensorOrientation; glm::vec3 _hmdSensorPosition; // cache head controller pose in sensor space - glm::vec2 _headControllerFacing; // facing vector in xz plane - glm::vec2 _headControllerFacingMovingAverage { 0, 0 }; // facing vector in xz plane + glm::vec2 _headControllerFacing; // facing vector in xz plane (sensor space) + glm::vec2 _headControllerFacingMovingAverage { 0.0f, 0.0f }; // facing vector in xz plane (sensor space) // cache of the current body position and orientation of the avatar's body, // in sensor space. diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index f7f55db369..4a7c203f11 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -83,6 +83,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { hipsPos = headPos + tiltRot * (hipsPos - headPos); } + // AJT: TODO can we remove this? return AnimPose(hipsRot * Quaternions::Y_180, hipsPos); } diff --git a/libraries/animation/src/AnimUtil.cpp b/libraries/animation/src/AnimUtil.cpp index 65c605b5ba..ad11623a25 100644 --- a/libraries/animation/src/AnimUtil.cpp +++ b/libraries/animation/src/AnimUtil.cpp @@ -9,7 +9,9 @@ // #include "AnimUtil.h" -#include "GLMHelpers.h" +#include +#include +#include // TODO: use restrict keyword // TODO: excellent candidate for simd vectorization. @@ -107,3 +109,39 @@ AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone) { glm::vec4(bone.trans(), 1.0f)); return AnimPose(lookAt); } + +// This will attempt to determine the proper body facing of a characters body +// assumes headRot is z-forward and y-up. +// and returns a bodyRot that is also z-forward and y-up +glm::quat computeBodyFacingFromHead(const glm::quat& headRot, const glm::vec3& up) { + + glm::vec3 bodyUp = glm::normalize(up); + + // initially take the body facing from the head. + glm::vec3 headUp = headRot * Vectors::UNIT_Y; + glm::vec3 headForward = headRot * Vectors::UNIT_Z; + const float THRESHOLD = cosf(glm::radians(30.0f)); + + glm::vec3 bodyForward = headForward; + + float dot = glm::dot(headForward, bodyUp); + + if (dot < -THRESHOLD) { // head is looking down + // the body should face in the same direction as the top the head. + bodyForward = headUp; + } else if (dot > THRESHOLD) { // head is looking upward + // the body should face away from the top of the head. + bodyForward = -headUp; + } + + // cancel out upward component + bodyForward = glm::normalize(bodyForward - dot * bodyUp); + + glm::vec3 u, v, w; + generateBasisVectors(bodyForward, bodyUp, u, v, w); + + // create matrix from orthogonal basis vectors + glm::mat4 bodyMat(glm::vec4(w, 0.0f), glm::vec4(v, 0.0f), glm::vec4(u, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + + return glmExtractRotation(bodyMat); +} diff --git a/libraries/animation/src/AnimUtil.h b/libraries/animation/src/AnimUtil.h index f2cceb361b..3cd7f4b6fb 100644 --- a/libraries/animation/src/AnimUtil.h +++ b/libraries/animation/src/AnimUtil.h @@ -33,4 +33,9 @@ inline glm::quat safeLerp(const glm::quat& a, const glm::quat& b, float alpha) { AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone); +// This will attempt to determine the proper body facing of a characters body +// assumes headRot is z-forward and y-up. +// and returns a bodyRot that is also z-forward and y-up +glm::quat computeBodyFacingFromHead(const glm::quat& headRot, const glm::vec3& up); + #endif diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 75446754d5..4be8ad0e41 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -574,8 +574,9 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda vAxisOut = glm::cross(wAxisOut, uAxisOut); } +// assumes z-forward and y-up glm::vec2 getFacingDir2D(const glm::quat& rot) { - glm::vec3 facing3D = rot * Vectors::UNIT_NEG_Z; + glm::vec3 facing3D = rot * Vectors::UNIT_Z; glm::vec2 facing2D(facing3D.x, facing3D.z); const float ALMOST_ZERO = 0.0001f; if (glm::length(facing2D) < ALMOST_ZERO) { @@ -585,8 +586,9 @@ glm::vec2 getFacingDir2D(const glm::quat& rot) { } } +// assumes z-forward and y-up glm::vec2 getFacingDir2D(const glm::mat4& m) { - glm::vec3 facing3D = transformVectorFast(m, Vectors::UNIT_NEG_Z); + glm::vec3 facing3D = transformVectorFast(m, Vectors::UNIT_Z); glm::vec2 facing2D(facing3D.x, facing3D.z); const float ALMOST_ZERO = 0.0001f; if (glm::length(facing2D) < ALMOST_ZERO) { diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 0e1af27cd2..7e6ef4cb28 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -250,7 +250,10 @@ glm::vec3 transformVectorFull(const glm::mat4& m, const glm::vec3& v); void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& secondaryAxis, glm::vec3& uAxisOut, glm::vec3& vAxisOut, glm::vec3& wAxisOut); +// assumes z-forward and y-up glm::vec2 getFacingDir2D(const glm::quat& rot); + +// assumes z-forward and y-up glm::vec2 getFacingDir2D(const glm::mat4& m); inline bool isNaN(const glm::vec3& value) { return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } From 986318ccfdfe367c08756dbde6ad9caff03bdf41 Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Mon, 14 May 2018 16:33:28 -0700 Subject: [PATCH 039/380] Adding preliminary scripts to repro getChildren issue. --- scripts/defaultScripts.js | 4 ++- scripts/system/createobject.js | 60 ++++++++++++++++++++++++++++++++++ scripts/system/deleteobject.js | 41 +++++++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 scripts/system/createobject.js create mode 100644 scripts/system/deleteobject.js diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 71755e3abb..13994a7e3c 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -30,7 +30,9 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/dialTone.js", "system/firstPersonHMD.js", "system/tablet-ui/tabletUI.js", - "system/emote.js" + "system/emote.js", + "system/createobject.js", + "system/deleteobject.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ "system/controllers/controllerScripts.js" diff --git a/scripts/system/createobject.js b/scripts/system/createobject.js new file mode 100644 index 0000000000..527bf64315 --- /dev/null +++ b/scripts/system/createobject.js @@ -0,0 +1,60 @@ +(function(){ + var button; + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + + function createEntity(description, position, parent) { + var entity = Entities.addEntity({ + type: "Sphere", + position: position, + dimensions: Vec3.HALF, + dynamic: true, + collisionless: true, + parentID: parent, + lifetime: 300 // Delete after 5 minutes. + }); + print(description + ": " + entity); + return entity; + } + + + function createBabies() { + var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 2, z: -5})); + var root = createEntity("Root", position, Uuid.NULL); + var ctr; + var avatarChildren = []; + // make five children. + for(var ctr = 0; ctr < 5; ctr++) { + avatarChildren.append(CreateEntity("Child" + ctr, Vec3.sum(position, { x: ctr, y: -1, z: ctr }), root)); + }} + + button = tablet.addButton({ + icon: "icons/tablet-icons/clap-i.svg", + text: "Create OBJ", + sortOrder: 1 + }); + + button.clicked.connect(createBabies); + + Script.scriptEnding.connect(function () { + button.clicked.disconnect(createBabies); + if (tablet) { + tablet.removeButton(button); + } + }); + +/* var entityID = Entities.addEntity({*/ + //type: "Box", + //position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })), + //dimensions: { x: 0.5, y: 0.5, z: 0.5 }, + //dynamic: true, + //collisionless: false, + //userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }", + //lifetime: 300 // Delete after 5 minutes. + //}); + + /*var actionID = Entities.addAction("slider", entityID, {*/ + //axis: { x: 0, y: 1, z: 0 }, + //linearLow: 0, + //linearHigh: 0.6 + /*});*/ +}()); diff --git a/scripts/system/deleteobject.js b/scripts/system/deleteobject.js new file mode 100644 index 0000000000..2c366b5546 --- /dev/null +++ b/scripts/system/deleteobject.js @@ -0,0 +1,41 @@ +(function(){ + var button; + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + + function destroyBabies() { + var avatarEntityID = + for(var ctr = 0; ctr < getChildrenIDs(); ctr++) { + avatarChildren.append(CreateEntity("Child" + ctr, Vec3.sum(position, { x: ctr, y: -1, z: ctr }), root)); + }} + + button = tablet.addButton({ + icon: "icons/tablet-icons/clap-i.svg", + text: "Destroy OBJ", + sortOrder: 1 + }); + + button.clicked.connect(createBabies); + + Script.scriptEnding.connect(function () { + button.clicked.disconnect(createBabies); + if (tablet) { + tablet.removeButton(button); + } + }); + +/* var entityID = Entities.addEntity({*/ + //type: "Box", + //position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })), + //dimensions: { x: 0.5, y: 0.5, z: 0.5 }, + //dynamic: true, + //collisionless: false, + //userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }", + //lifetime: 300 // Delete after 5 minutes. + //}); + + /*var actionID = Entities.addAction("slider", entityID, {*/ + //axis: { x: 0, y: 1, z: 0 }, + //linearLow: 0, + //linearHigh: 0.6 + /*});*/ +}()); From acd1721c88376575d289d3e81f01cc7f793a4353 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 14 May 2018 17:26:03 -0700 Subject: [PATCH 040/380] Load handTouch.js as a default script --- scripts/system/controllers/controllerScripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index 8db8e29f37..4c8452c7d4 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -14,6 +14,7 @@ var CONTOLLER_SCRIPTS = [ "controllerDisplayManager.js", "grab.js", "toggleAdvancedMovementForHandControllers.js", + "handTouch.js", "controllerDispatcher.js", "controllerModules/nearParentGrabEntity.js", "controllerModules/nearParentGrabOverlay.js", From bd6905b3d2c73d75d281cd0d0a98db7aa8b943a2 Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Mon, 14 May 2018 18:25:39 -0700 Subject: [PATCH 041/380] Adding possible solution to issue#1934. --- .../entities/src/EntityScriptingInterface.cpp | 28 +++++-- scripts/defaultScripts.js | 3 +- scripts/system/createobject.js | 77 ++++++++++++++----- scripts/system/deleteobject.js | 15 ++-- 4 files changed, 85 insertions(+), 38 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7c16214a78..65bacfec5a 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1660,14 +1660,28 @@ QVector EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) { return result; } - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID); - if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID; - return result; - } - + //EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID); + //if (!entity) { + // qCDebug(entities) << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID; + // return result; + //} _entityTree->withReadLock([&] { - entity->forEachChild([&](SpatiallyNestablePointer child) { + QSharedPointer parentFinder = DependencyManager::get(); + if (!parentFinder) { + return; + } + bool success; + SpatiallyNestableWeakPointer parentWP = parentFinder->find(parentID, success); + if (!success) { + return; + } + SpatiallyNestablePointer parent = parentWP.lock(); + if (!parent) { + return; + } + //_entityTree->withReadLock([&] { + //entity->forEachChild([&](SpatiallyNestablePointer child) { + parent->forEachChild([&](SpatiallyNestablePointer child) { result.push_back(child->getID()); }); }); diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 13994a7e3c..12e9a4fd58 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -31,8 +31,7 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/firstPersonHMD.js", "system/tablet-ui/tabletUI.js", "system/emote.js", - "system/createobject.js", - "system/deleteobject.js" + "system/createobject.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ "system/controllers/controllerScripts.js" diff --git a/scripts/system/createobject.js b/scripts/system/createobject.js index 527bf64315..887313130c 100644 --- a/scripts/system/createobject.js +++ b/scripts/system/createobject.js @@ -3,34 +3,69 @@ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); function createEntity(description, position, parent) { - var entity = Entities.addEntity({ - type: "Sphere", - position: position, - dimensions: Vec3.HALF, - dynamic: true, - collisionless: true, - parentID: parent, - lifetime: 300 // Delete after 5 minutes. - }); - print(description + ": " + entity); - return entity; + var entity = Entities.addEntity({ + type: "Sphere", + position: position, + dimensions: Vec3.HALF, + dynamic: true, + collisionless: true, + parentID: parent, + lifetime: 300 // Delete after 5 minutes. + }); + //print(description + ": " + entity); + return entity; } - function createBabies() { - var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 2, z: -5})); - var root = createEntity("Root", position, Uuid.NULL); - var ctr; - var avatarChildren = []; - // make five children. - for(var ctr = 0; ctr < 5; ctr++) { - avatarChildren.append(CreateEntity("Child" + ctr, Vec3.sum(position, { x: ctr, y: -1, z: ctr }), root)); - }} + var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 2, z: -5})); + //var root = createEntity("Root", position, Uuid.NULL); + var avatarChildren = []; + var overlayChildren = []; + var entityChildren = []; + var avatar = MyAvatar.sessionUUID; + if (avatar === Uuid.NULL) { + avatar = MyAvatar.SELF_ID; + } + var textToWrite = "Avatar UUID: " + avatar + "\n\n"; + // make five children. + for(var ctr = 0; ctr < 5; ctr++) { + var entity = createEntity("AvatarChild" + ctr, Vec3.sum(position, { x: ctr, y: -1, z: ctr }), avatar); + avatarChildren.push(entity); + textToWrite += "AvatarChild" + ctr + " UUID: " + entity + "\n"; + } + var overlay = Overlays.addOverlay("cube", { + position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })), + rotation: MyAvatar.orientation, + dimensions: { x: 0.3, y: 0.3, z: 0.3 }, + solid: true + }); + textToWrite += "\nOverlay UUID: " + overlay + "\n\n"; + for(var ctr = 0; ctr < 5; ctr++) { + var entity = createEntity("OverlayChild" + ctr, Vec3.sum(position, { x: ctr, y: -1, z: ctr }), overlay); + overlayChildren.push(entity); + textToWrite += "OverlayChild" + ctr + " UUID: " + entity + "\n"; + } + var rootEntity = Entities.addEntity({ + type: "Sphere", + position: position, + dimensions: Vec3.HALF, + dynamic: true, + collisionless: true, + lifetime: 300 // Delete after 5 minutes. + }); + textToWrite += "\nEntity UUID: " + rootEntity + "\n\n"; + for(var ctr = 0; ctr < 5; ctr++) { + var entity = createEntity("EntityChild" + ctr, Vec3.sum(position, { x: ctr, y: -1, z: ctr }), rootEntity); + entityChildren.push(entity); + textToWrite += "EntityChild" + ctr + " UUID: " + entity + "\n"; + } + console.log(textToWrite); + } button = tablet.addButton({ icon: "icons/tablet-icons/clap-i.svg", text: "Create OBJ", - sortOrder: 1 + sortOrder: 12 }); button.clicked.connect(createBabies); diff --git a/scripts/system/deleteobject.js b/scripts/system/deleteobject.js index 2c366b5546..ff65762497 100644 --- a/scripts/system/deleteobject.js +++ b/scripts/system/deleteobject.js @@ -3,21 +3,20 @@ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); function destroyBabies() { - var avatarEntityID = - for(var ctr = 0; ctr < getChildrenIDs(); ctr++) { - avatarChildren.append(CreateEntity("Child" + ctr, Vec3.sum(position, { x: ctr, y: -1, z: ctr }), root)); - }} + // TODO: destroy babies + } + button = tablet.addButton({ - icon: "icons/tablet-icons/clap-i.svg", + icon: "icons/tablet-icons/clap-a.svg", text: "Destroy OBJ", - sortOrder: 1 + sortOrder: 13 }); - button.clicked.connect(createBabies); + button.clicked.connect(destroyBabies); Script.scriptEnding.connect(function () { - button.clicked.disconnect(createBabies); + button.clicked.disconnect(destroyBabies); if (tablet) { tablet.removeButton(button); } From f82e597ac7bf45dc654a1f0e3b6d1e5d85b1a7a9 Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Tue, 15 May 2018 09:34:07 -0700 Subject: [PATCH 042/380] Updating documentation for getChildrenIDs + fixing issue #1934 --- interface/src/ui/overlays/Overlays.h | 2 +- libraries/entities/src/EntityScriptingInterface.cpp | 8 -------- libraries/entities/src/EntityScriptingInterface.h | 8 ++++---- scripts/defaultScripts.js | 3 +-- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index cf1151b46a..b2728e68b2 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -482,7 +482,7 @@ public slots: /**jsdoc * Check if there is an overlay of a given ID. - * @function Overlays.isAddedOverly + * @function Overlays.isAddedOverlay * @param {Uuid} overlayID - The ID to check. * @returns {boolean} true if an overlay with the given ID exists, false otherwise. */ diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 65bacfec5a..2558cb4ed7 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1659,12 +1659,6 @@ QVector EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) { if (!_entityTree) { return result; } - - //EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID); - //if (!entity) { - // qCDebug(entities) << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID; - // return result; - //} _entityTree->withReadLock([&] { QSharedPointer parentFinder = DependencyManager::get(); if (!parentFinder) { @@ -1679,8 +1673,6 @@ QVector EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) { if (!parent) { return; } - //_entityTree->withReadLock([&] { - //entity->forEachChild([&](SpatiallyNestablePointer child) { parent->forEachChild([&](SpatiallyNestablePointer child) { result.push_back(child->getID()); }); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 7e47d9e2d4..46a994e183 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -1216,12 +1216,12 @@ public slots: /**jsdoc - * Get the IDs of entities, overlays, and avatars that are directly parented to an entity. To get all descendants of an - * entity, recurse on the IDs returned by the function. + * Get the IDs of entities, overlays, and avatars that are directly parented to an entity, overlay, or avatar model. To get all descendants of an + * entity; overlay; or avatar, recurse on the IDs returned by the function. * @function Entities.getChildrenIDs - * @param {Uuid} parentID - The ID of the entity to get the children IDs of. + * @param {Uuid} parentID - The ID of the entity, overlay, or avatar to get the children IDs of. * @returns {Uuid[]} An array of entity, overlay, and avatar IDs that are parented directly to the parentID - * entity. Does not include children's children, etc. The array is empty if no children can be found or + * entity, overlay, or avatar. Does not include children's children, etc. The array is empty if no children can be found or * parentID cannot be found. * @example Report the children of an entity. * function createEntity(description, position, parent) { diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 12e9a4fd58..71755e3abb 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -30,8 +30,7 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/dialTone.js", "system/firstPersonHMD.js", "system/tablet-ui/tabletUI.js", - "system/emote.js", - "system/createobject.js" + "system/emote.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ "system/controllers/controllerScripts.js" From 839d4a3bdaa961a0614b80bd67c665f68dc95839 Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Tue, 15 May 2018 09:36:32 -0700 Subject: [PATCH 043/380] removing test script --- scripts/system/createobject.js | 95 ---------------------------------- 1 file changed, 95 deletions(-) delete mode 100644 scripts/system/createobject.js diff --git a/scripts/system/createobject.js b/scripts/system/createobject.js deleted file mode 100644 index 887313130c..0000000000 --- a/scripts/system/createobject.js +++ /dev/null @@ -1,95 +0,0 @@ -(function(){ - var button; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - - function createEntity(description, position, parent) { - var entity = Entities.addEntity({ - type: "Sphere", - position: position, - dimensions: Vec3.HALF, - dynamic: true, - collisionless: true, - parentID: parent, - lifetime: 300 // Delete after 5 minutes. - }); - //print(description + ": " + entity); - return entity; - } - - function createBabies() { - var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 2, z: -5})); - //var root = createEntity("Root", position, Uuid.NULL); - var avatarChildren = []; - var overlayChildren = []; - var entityChildren = []; - var avatar = MyAvatar.sessionUUID; - if (avatar === Uuid.NULL) { - avatar = MyAvatar.SELF_ID; - } - var textToWrite = "Avatar UUID: " + avatar + "\n\n"; - // make five children. - for(var ctr = 0; ctr < 5; ctr++) { - var entity = createEntity("AvatarChild" + ctr, Vec3.sum(position, { x: ctr, y: -1, z: ctr }), avatar); - avatarChildren.push(entity); - textToWrite += "AvatarChild" + ctr + " UUID: " + entity + "\n"; - } - var overlay = Overlays.addOverlay("cube", { - position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })), - rotation: MyAvatar.orientation, - dimensions: { x: 0.3, y: 0.3, z: 0.3 }, - solid: true - }); - textToWrite += "\nOverlay UUID: " + overlay + "\n\n"; - for(var ctr = 0; ctr < 5; ctr++) { - var entity = createEntity("OverlayChild" + ctr, Vec3.sum(position, { x: ctr, y: -1, z: ctr }), overlay); - overlayChildren.push(entity); - textToWrite += "OverlayChild" + ctr + " UUID: " + entity + "\n"; - } - var rootEntity = Entities.addEntity({ - type: "Sphere", - position: position, - dimensions: Vec3.HALF, - dynamic: true, - collisionless: true, - lifetime: 300 // Delete after 5 minutes. - }); - textToWrite += "\nEntity UUID: " + rootEntity + "\n\n"; - for(var ctr = 0; ctr < 5; ctr++) { - var entity = createEntity("EntityChild" + ctr, Vec3.sum(position, { x: ctr, y: -1, z: ctr }), rootEntity); - entityChildren.push(entity); - textToWrite += "EntityChild" + ctr + " UUID: " + entity + "\n"; - } - console.log(textToWrite); - } - - button = tablet.addButton({ - icon: "icons/tablet-icons/clap-i.svg", - text: "Create OBJ", - sortOrder: 12 - }); - - button.clicked.connect(createBabies); - - Script.scriptEnding.connect(function () { - button.clicked.disconnect(createBabies); - if (tablet) { - tablet.removeButton(button); - } - }); - -/* var entityID = Entities.addEntity({*/ - //type: "Box", - //position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })), - //dimensions: { x: 0.5, y: 0.5, z: 0.5 }, - //dynamic: true, - //collisionless: false, - //userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }", - //lifetime: 300 // Delete after 5 minutes. - //}); - - /*var actionID = Entities.addAction("slider", entityID, {*/ - //axis: { x: 0, y: 1, z: 0 }, - //linearLow: 0, - //linearHigh: 0.6 - /*});*/ -}()); From 9269bd261965dee53c1f489fcdd0ec1267bd9beb Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Tue, 15 May 2018 09:37:42 -0700 Subject: [PATCH 044/380] removing dummy script --- scripts/system/deleteobject.js | 40 ---------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 scripts/system/deleteobject.js diff --git a/scripts/system/deleteobject.js b/scripts/system/deleteobject.js deleted file mode 100644 index ff65762497..0000000000 --- a/scripts/system/deleteobject.js +++ /dev/null @@ -1,40 +0,0 @@ -(function(){ - var button; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - - function destroyBabies() { - // TODO: destroy babies - } - - - button = tablet.addButton({ - icon: "icons/tablet-icons/clap-a.svg", - text: "Destroy OBJ", - sortOrder: 13 - }); - - button.clicked.connect(destroyBabies); - - Script.scriptEnding.connect(function () { - button.clicked.disconnect(destroyBabies); - if (tablet) { - tablet.removeButton(button); - } - }); - -/* var entityID = Entities.addEntity({*/ - //type: "Box", - //position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })), - //dimensions: { x: 0.5, y: 0.5, z: 0.5 }, - //dynamic: true, - //collisionless: false, - //userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }", - //lifetime: 300 // Delete after 5 minutes. - //}); - - /*var actionID = Entities.addAction("slider", entityID, {*/ - //axis: { x: 0, y: 1, z: 0 }, - //linearLow: 0, - //linearHigh: 0.6 - /*});*/ -}()); From ccab2dd641b0a27b9ad29aa889af97e2154fa6ac Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 15 May 2018 11:48:33 -0700 Subject: [PATCH 045/380] Starting the work --- .../qml/hifi/commerce/wallet/WalletHome.qml | 109 ++-------- .../qml/hifi/models/PSFListModel.qml | 188 ++++++++++++++++++ 2 files changed, 207 insertions(+), 90 deletions(-) create mode 100644 interface/resources/qml/hifi/models/PSFListModel.qml diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 7a14ee060f..afc205fd51 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -18,27 +18,24 @@ import QtQuick.Controls 2.2 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls +import "../../../models" as HifiModels Item { HifiConstants { id: hifi; } id: root; - property bool initialHistoryReceived: false; - property bool historyRequestPending: true; - property bool noMoreHistoryData: false; + property bool initialResultReceived: false; property int pendingCount: 0; - property int currentHistoryPage: 1; - property var pagesAlreadyAdded: new Array(); onVisibleChanged: { if (visible) { transactionHistoryModel.clear(); Commerce.balance(); - initialHistoryReceived = false; - root.currentHistoryPage = 1; - root.noMoreHistoryData = false; - root.historyRequestPending = true; - Commerce.history(root.currentHistoryPage); + transactionHistoryModel.initialResultReceived = false; + transactionHistoryModel.nextPageToRetrieve = 1; + transactionHistoryModel.noMoreDataToRetrieve = false; + transactionHistoryModel.requestPending = true; + Commerce.history(transactionHistoryModel.nextPageToRetrieve); Commerce.getAvailableUpdates(); } else { refreshTimer.stop(); @@ -53,84 +50,16 @@ Item { } onHistoryResult : { - root.initialHistoryReceived = true; - root.historyRequestPending = false; + + transactionHistoryModel.processResult(result.status, result.data.history); - if (result.status === 'success') { - var currentPage = parseInt(result.current_page); - - if (result.data.history.length === 0) { - root.noMoreHistoryData = true; - console.log("No more data to retrieve from Commerce.history() endpoint.") - } else if (root.currentHistoryPage === 1) { - var sameItemCount = 0; - tempTransactionHistoryModel.clear(); - - tempTransactionHistoryModel.append(result.data.history); - - for (var i = 0; i < tempTransactionHistoryModel.count; i++) { - if (!transactionHistoryModel.get(i)) { - sameItemCount = -1; - break; - } else if (tempTransactionHistoryModel.get(i).transaction_type === transactionHistoryModel.get(i).transaction_type && - tempTransactionHistoryModel.get(i).text === transactionHistoryModel.get(i).text) { - sameItemCount++; - } - } - - if (sameItemCount !== tempTransactionHistoryModel.count) { - transactionHistoryModel.clear(); - for (var i = 0; i < tempTransactionHistoryModel.count; i++) { - transactionHistoryModel.append(tempTransactionHistoryModel.get(i)); - } - calculatePendingAndInvalidated(); - } - } else { - if (root.pagesAlreadyAdded.indexOf(currentPage) !== -1) { - console.log("Page " + currentPage + " of history has already been added to the list."); - } else { - // First, add the history result to a temporary model - tempTransactionHistoryModel.clear(); - tempTransactionHistoryModel.append(result.data.history); - - // Make a note that we've already added this page to the model... - root.pagesAlreadyAdded.push(currentPage); - - var insertionIndex = 0; - // If there's nothing in the model right now, we don't need to modify insertionIndex. - if (transactionHistoryModel.count !== 0) { - var currentIteratorPage; - // Search through the whole transactionHistoryModel and look for the insertion point. - // The insertion point is found when the result page from the server is less than - // the page that the current item came from, OR when we've reached the end of the whole model. - for (var i = 0; i < transactionHistoryModel.count; i++) { - currentIteratorPage = transactionHistoryModel.get(i).resultIsFromPage; - - if (currentPage < currentIteratorPage) { - insertionIndex = i; - break; - } else if (i === transactionHistoryModel.count - 1) { - insertionIndex = i + 1; - break; - } - } - } - - // Go through the results we just got back from the server, setting the "resultIsFromPage" - // property of those results and adding them to the main model. - for (var i = 0; i < tempTransactionHistoryModel.count; i++) { - tempTransactionHistoryModel.setProperty(i, "resultIsFromPage", currentPage); - transactionHistoryModel.insert(i + insertionIndex, tempTransactionHistoryModel.get(i)) - } - - calculatePendingAndInvalidated(); - } - } + if (!transactionHistoryModel.noMoreDataToRetrieve) { + calculatePendingAndInvalidated(); } // Only auto-refresh if the user hasn't scrolled // and there is more data to grab - if (transactionHistory.atYBeginning && !root.noMoreHistoryData) { + if (transactionHistory.atYBeginning && !transactionHistoryModel.noMoreDataToRetrieve) { refreshTimer.start(); } } @@ -235,7 +164,7 @@ Item { onTriggered: { if (transactionHistory.atYBeginning) { console.log("Refreshing 1st Page of Recent Activity..."); - root.historyRequestPending = true; + transactionHistoryModel.requestPending = true; Commerce.balance(); Commerce.history(1); } @@ -302,7 +231,7 @@ Item { ListModel { id: tempTransactionHistoryModel; } - ListModel { + HifiModels.PSFListModel { id: transactionHistoryModel; } Item { @@ -313,7 +242,7 @@ Item { anchors.right: parent.right; Item { - visible: transactionHistoryModel.count === 0 && root.initialHistoryReceived; + visible: transactionHistoryModel.count === 0 && transactionHistoryModel.initialResultReceived; anchors.centerIn: parent; width: parent.width - 12; height: parent.height; @@ -462,11 +391,11 @@ Item { onAtYEndChanged: { if (transactionHistory.atYEnd) { console.log("User scrolled to the bottom of 'Recent Activity'."); - if (!root.historyRequestPending && !root.noMoreHistoryData) { + if (!transactionHistoryModel.requestPending && !transactionHistoryModel.noMoreDataToRetrieve) { // Grab next page of results and append to model - root.historyRequestPending = true; - Commerce.history(++root.currentHistoryPage); - console.log("Fetching Page " + root.currentHistoryPage + " of Recent Activity..."); + transactionHistoryModel.requestPending = true; + Commerce.history(++transactionHistoryModel.nextPageToRetrieve); + console.log("Fetching Page " + transactionHistoryModel.nextPageToRetrieve + " of Recent Activity..."); } } } diff --git a/interface/resources/qml/hifi/models/PSFListModel.qml b/interface/resources/qml/hifi/models/PSFListModel.qml new file mode 100644 index 0000000000..cbc28b208d --- /dev/null +++ b/interface/resources/qml/hifi/models/PSFListModel.qml @@ -0,0 +1,188 @@ +// +// PSFListModel.qml +// qml/hifi/commerce/common +// +// PSFListModel +// "PSF" stands for: +// - Paged +// - Sortable +// - Filterable +// +// Created by Zach Fox on 2018-05-15 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7 + +ListModel { + id: root; + property string sortColumnName: ""; + property bool isSortingDescending: true; + property bool valuesAreNumerical: false; + + property bool initialResultReceived: false; + property bool requestPending: false; + property bool noMoreDataToRetrieve: false; + property int nextPageToRetrieve: 1; + property var pagesAlreadyAdded: new Array(); + + ListModel { + id: tempModel; + } + + function processResult(status, retrievedResult) { + root.initialResultReceived = true; + root.requestPending = false; + + if (status === 'success') { + var currentPage = parseInt(result.current_page); + + if (retrievedResult.length === 0) { + root.noMoreDataToRetrieve = true; + console.log("No more data to retrieve from backend endpoint.") + } else if (root.nextPageToRetrieve === 1) { + var sameItemCount = 0; + + tempModel.clear(); + tempModel.append(retrievedResult); + + for (var i = 0; i < tempModel.count; i++) { + if (!root.get(i)) { + sameItemCount = -1; + break; + } + // Gotta think of another way to determine if the data we just got is the same + // as the data that we already have in the model. + /* else if (tempModel.get(i).transaction_type === root.get(i).transaction_type && + tempModel.get(i).text === root.get(i).text) { + sameItemCount++; + }*/ + } + + if (sameItemCount !== tempModel.count) { + root.clear(); + for (var i = 0; i < tempModel.count; i++) { + root.append(tempModel.get(i)); + } + } + } else { + if (root.pagesAlreadyAdded.indexOf(currentPage) !== -1) { + console.log("Page " + currentPage + " of paginated data has already been added to the list."); + } else { + // First, add the result to a temporary model + tempModel.clear(); + tempModel.append(retrievedResult); + + // Make a note that we've already added this page to the model... + root.pagesAlreadyAdded.push(currentPage); + + var insertionIndex = 0; + // If there's nothing in the model right now, we don't need to modify insertionIndex. + if (root.count !== 0) { + var currentIteratorPage; + // Search through the whole model and look for the insertion point. + // The insertion point is found when the result page from the server is less than + // the page that the current item came from, OR when we've reached the end of the whole model. + for (var i = 0; i < root.count; i++) { + currentIteratorPage = root.get(i).resultIsFromPage; + + if (currentPage < currentIteratorPage) { + insertionIndex = i; + break; + } else if (i === root.count - 1) { + insertionIndex = i + 1; + break; + } + } + } + + // Go through the results we just got back from the server, setting the "resultIsFromPage" + // property of those results and adding them to the main model. + // NOTE that this wouldn't be necessary if we did this step on the server. + for (var i = 0; i < tempModel.count; i++) { + tempModel.setProperty(i, "resultIsFromPage", currentPage); + root.insert(i + insertionIndex, tempModel.get(i)) + } + } + } + } + } + + function swap(a, b) { + if (a < b) { + move(a, b, 1); + move(b - 1, a, 1); + } else if (a > b) { + move(b, a, 1); + move(a - 1, b, 1); + } + } + + function partition(begin, end, pivot) { + if (valuesAreNumerical) { + var piv = get(pivot)[sortColumnName]; + swap(pivot, end - 1); + var store = begin; + var i; + + for (i = begin; i < end - 1; ++i) { + var currentElement = get(i)[sortColumnName]; + if (isSortingDescending) { + if (currentElement > piv) { + swap(store, i); + ++store; + } + } else { + if (currentElement < piv) { + swap(store, i); + ++store; + } + } + } + swap(end - 1, store); + + return store; + } else { + var piv = get(pivot)[sortColumnName].toLowerCase(); + swap(pivot, end - 1); + var store = begin; + var i; + + for (i = begin; i < end - 1; ++i) { + var currentElement = get(i)[sortColumnName].toLowerCase(); + if (isSortingDescending) { + if (currentElement > piv) { + swap(store, i); + ++store; + } + } else { + if (currentElement < piv) { + swap(store, i); + ++store; + } + } + } + swap(end - 1, store); + + return store; + } + } + + function qsort(begin, end) { + if (end - 1 > begin) { + var pivot = begin + Math.floor(Math.random() * (end - begin)); + + pivot = partition(begin, end, pivot); + + qsort(begin, pivot); + qsort(pivot + 1, end); + } + } + + function quickSort() { + qsort(0, count) + } +} \ No newline at end of file From 8b4298514e58530d9c5236cef450ad03431a7d0a Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 15 May 2018 21:39:17 +0200 Subject: [PATCH 046/380] send out one last blendshape update when setting MyAvatar.hasScriptedBlendshapes to false --- interface/src/avatar/MyAvatar.cpp | 13 +++++++++++++ interface/src/avatar/MyAvatar.h | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6c6f6d4d41..e4d255f4ee 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2081,6 +2081,19 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { return !defaultMode || !firstPerson || !insideHead; } +void MyAvatar::setHasScriptedBlendshapes(bool hasScriptedBlendshapes) { + if (hasScriptedBlendshapes == _hasScriptedBlendShapes) { + return; + } + if (!hasScriptedBlendshapes) { + // send a forced avatarData update to make sure the script can send neutal blendshapes on unload + // without having to wait for the update loop, make sure _hasScriptedBlendShapes is still true + // before sending the update, or else it won't send the neutal blendshapes to the receiving clients + sendAvatarDataPacket(true); + } + _hasScriptedBlendShapes = hasScriptedBlendshapes; +} + void MyAvatar::updateOrientation(float deltaTime) { // Smoothly rotate body with arrow keys diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 76966b5ab3..46cdd7b8ae 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1345,7 +1345,7 @@ private: virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override; void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; setEnableMeshVisible(shouldRender); } bool getShouldRenderLocally() const { return _shouldRender; } - void setHasScriptedBlendshapes(bool hasScriptedBlendshapes) { _hasScriptedBlendShapes = hasScriptedBlendshapes; } + void setHasScriptedBlendshapes(bool hasScriptedBlendshapes); bool getHasScriptedBlendshapes() const override { return _hasScriptedBlendShapes; } void setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement) { _hasAudioEnabledFaceMovement = hasAudioEnabledFaceMovement; } bool getHasAudioEnabledFaceMovement() const override { return _hasAudioEnabledFaceMovement; } @@ -1457,7 +1457,7 @@ private: bool _hmdRollControlEnabled { true }; float _hmdRollControlDeadZone { ROLL_CONTROL_DEAD_ZONE_DEFAULT }; float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT }; - bool _hasScriptedBlendShapes { false }; + std::atomic _hasScriptedBlendShapes { false }; bool _hasAudioEnabledFaceMovement { true }; // working copy -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access From 6b268191c82bcdcfa1f17b589ba8143b2cacc970 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 14 May 2018 15:29:36 -0700 Subject: [PATCH 047/380] local compression, patched etc2comp --- android/build.gradle | 6 +-- cmake/externals/etc2comp/CMakeLists.txt | 6 ++- libraries/gpu/src/gpu/Texture_ktx.cpp | 2 +- libraries/image/src/image/Image.cpp | 71 ++++++++++++------------- 4 files changed, 42 insertions(+), 43 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index e041142282..71d48e28d4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -146,9 +146,9 @@ def packages = [ includeLibs: ['libplugins_libhifiCodec.so'] ], etc2comp: [ - file: 'etc2comp-armv8-libcpp.tgz', - versionId: '1WfqJYWLOP0g22eikYjBzn62gza7MKE6', - checksum: '0b4c2e6de728546845f0e471dfdeb604' + file: 'etc2comp-patched-armv8-libcpp.tgz', + versionId: 'bHhGECRAQR1vkpshBcK6ByNc1BQIM8gU', + checksum: '14b02795d774457a33bbc60e00a786bc' ] ] diff --git a/cmake/externals/etc2comp/CMakeLists.txt b/cmake/externals/etc2comp/CMakeLists.txt index 9cee0652bc..1de4932380 100644 --- a/cmake/externals/etc2comp/CMakeLists.txt +++ b/cmake/externals/etc2comp/CMakeLists.txt @@ -5,10 +5,12 @@ if (ANDROID) endif () include(ExternalProject) +# We use a patched version of etc2comp that properly generates all the necessary mips +# See https://github.com/google/etc2comp/pull/29 ExternalProject_Add( ${EXTERNAL_NAME} - URL https://hifi-public.s3.amazonaws.com/dependencies/etc2comp-master.zip - URL_MD5 d0969e14af6b10b3306f880c8e2b1184 + URL https://hifi-public.s3.amazonaws.com/dependencies/etc2comp-patched.zip + URL_MD5 6fe3629de8ff99bc99f8c14558d841a3 CMAKE_ARGS ${ANDROID_CMAKE_ARGS} BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build INSTALL_COMMAND "" diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 129c125411..839cb915e2 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -352,7 +352,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { if (!Texture::evalKTXFormat(mipFormat, texelFormat, header)) { return nullptr; } - + // Set Dimensions uint32_t numFaces = 1; switch (texture.getType()) { diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 55cafe9571..2fc22b4eac 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -31,14 +31,14 @@ using namespace gpu; #define CPU_MIPMAPS 1 #include -#ifdef Q_OS_ANDROID +#ifdef USE_GLES #include #include #endif static const glm::uvec2 SPARSE_PAGE_SIZE(128); #ifdef Q_OS_ANDROID -static const glm::uvec2 MAX_TEXTURE_SIZE(1024); +static const glm::uvec2 MAX_TEXTURE_SIZE(2048); #else static const glm::uvec2 MAX_TEXTURE_SIZE(4096); #endif @@ -46,7 +46,6 @@ bool DEV_DECIMATE_TEXTURES = false; std::atomic DECIMATED_TEXTURE_COUNT{ 0 }; std::atomic RECTIFIED_TEXTURE_COUNT{ 0 }; -// TODO: pick compressed android hdr format static const auto HDR_FORMAT = gpu::Element::COLOR_R11G11B10; static std::atomic compressColorTextures { false }; @@ -563,10 +562,10 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic(localCopy.constBits()); auto mipFormat = texture->getStoredMipFormat(); -#ifndef Q_OS_ANDROID +#ifndef USE_GLES + const void* data = static_cast(localCopy.constBits()); nvtt::TextureType textureType = nvtt::TextureType_2D; nvtt::InputFormat inputFormat = nvtt::InputFormat_BGRA_8UB; nvtt::WrapMode wrapMode = nvtt::WrapMode_Mirror; @@ -681,43 +680,41 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic floatData; floatData.resize(width * height); @@ -725,27 +722,28 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic= 0) { - texture->assignStoredMipFace(i, face, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); - } else { - texture->assignStoredMip(i, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); + if (mipMaps[i].paucEncodingBits.get()) { + if (face >= 0) { + texture->assignStoredMipFace(i, face, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); + } else { + texture->assignStoredMip(i, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); + } } } @@ -755,8 +753,6 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic& abortProcessing = false, int face = -1) { #if CPU_MIPMAPS PROFILE_RANGE(resource_parse, "generateMips"); @@ -828,14 +824,15 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_SRGB; } } else { -#ifdef Q_OS_ANDROID +#ifdef USE_GLES // GLES does not support GL_BGRA formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA; + formatMip = formatGPU; #else - formatGPU = gpu::Element::COLOR_SBGRA_32; + formatGPU = gpu::Element::COLOR_SRGBA_32; + formatMip = gpu::Element::COLOR_SBGRA_32; #endif } - formatMip = formatGPU; if (isStrict) { theTexture = gpu::Texture::createStrict(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); @@ -954,7 +951,7 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr if (isNormalTexturesCompressionEnabled()) { formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_XY; } else { -#ifdef Q_OS_ANDROID +#ifdef USE_GLES formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_XY; #else formatGPU = gpu::Element::VEC2NU8_XY; @@ -994,7 +991,7 @@ gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& sr if (isGrayscaleTexturesCompressionEnabled()) { formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_RED; } else { -#ifdef Q_OS_ANDROID +#ifdef USE_GLES formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED; #else formatGPU = gpu::Element::COLOR_R_8; From 2b30c1389e79b9b82ba34b0af453e3be370a42ad Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 15 May 2018 14:30:08 -0700 Subject: [PATCH 048/380] Try reducing concurrent downloads for Android --- interface/src/Application.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 61ed5acdd2..69da4fa062 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -333,6 +333,7 @@ static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains #endif static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; +static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS_LOWEND = 4; // For processing on QThreadPool, we target a number of threads after reserving some // based on how many are being consumed by the application and the display plugin. However, @@ -1314,7 +1315,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo bool success; int concurrentDownloads = concurrentDownloadsStr.toInt(&success); if (!success) { +#if !defined(Q_OS_ANDROID) concurrentDownloads = MAX_CONCURRENT_RESOURCE_DOWNLOADS; +#else + concurrentDownloads = MAX_CONCURRENT_RESOURCE_DOWNLOADS_LOWEND; +#endif } ResourceCache::setRequestLimit(concurrentDownloads); From 92e9a8e064058644efd50f25bb03692c5c003597 Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Tue, 15 May 2018 16:32:01 -0700 Subject: [PATCH 049/380] fixing typo in documentation. --- libraries/entities/src/EntityScriptingInterface.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 46a994e183..eefb254c2a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -1216,8 +1216,7 @@ public slots: /**jsdoc - * Get the IDs of entities, overlays, and avatars that are directly parented to an entity, overlay, or avatar model. To get all descendants of an - * entity; overlay; or avatar, recurse on the IDs returned by the function. + * Get the IDs of entities, overlays, and avatars that are directly parented to an entity, overlay, or avatar model. Recurse on the IDs returned by the function to get all descendants of an entity, overlay, or avatar. * @function Entities.getChildrenIDs * @param {Uuid} parentID - The ID of the entity, overlay, or avatar to get the children IDs of. * @returns {Uuid[]} An array of entity, overlay, and avatar IDs that are parented directly to the parentID From f4d24a3d0e9a19cb87fc760677fb49ef80b2b56a Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 15 May 2018 16:40:21 -0700 Subject: [PATCH 050/380] Quiet MacOS warning --- interface/src/Application.cpp | 1746 ++++++++++++++++----------------- 1 file changed, 827 insertions(+), 919 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 69da4fa062..7cf26d377d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -237,7 +237,7 @@ // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. extern "C" { - _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; +_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; } #endif @@ -246,7 +246,8 @@ extern "C" { #include "AndroidHelper.h" #endif -enum ApplicationEvent { +enum ApplicationEvent +{ // Execute a lambda function Lambda = QEvent::User + 1, // Trigger the next render @@ -272,11 +273,13 @@ public: connect(qApp, &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); // Transfer to a new thread - moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) { - hifi::qt::addBlockingForbiddenThread("Render", renderThread); - _renderContext->moveToThreadWithContext(renderThread); - qApp->_lastTimeRendered.start(); - }, std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority); + moveToNewNamedThread(this, "RenderThread", + [this](QThread* renderThread) { + hifi::qt::addBlockingForbiddenThread("Render", renderThread); + _renderContext->moveToThreadWithContext(renderThread); + qApp->_lastTimeRendered.start(); + }, + std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority); } private: @@ -306,10 +309,9 @@ private: return Parent::event(event); } - OffscreenGLCanvas* _renderContext { nullptr }; + OffscreenGLCanvas* _renderContext{ nullptr }; }; - Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse") using namespace std; @@ -332,8 +334,11 @@ static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" }; static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD); #endif +#if !defined(Q_OS_ANDROID) static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; +#else static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS_LOWEND = 4; +#endif // For processing on QThreadPool, we target a number of threads after reserving some // based on how many are being consumed by the application and the display plugin. However, @@ -368,38 +373,37 @@ static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SI static const uint32_t INVALID_FRAME = UINT32_MAX; -static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation +static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); Setting::Handle maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com"; -static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds +static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop"; static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin"; static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system"; -const std::vector> Application::_acceptedExtensions { - { SVO_EXTENSION, &Application::importSVOFromURL }, - { SVO_JSON_EXTENSION, &Application::importSVOFromURL }, - { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }, - { JSON_EXTENSION, &Application::importJSONFromURL }, - { JS_EXTENSION, &Application::askToLoadScript }, - { FST_EXTENSION, &Application::askToSetAvatarUrl }, - { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, - { CONTENT_ZIP_EXTENSION, &Application::askToReplaceDomainContent }, - { ZIP_EXTENSION, &Application::importFromZIP }, - { JPG_EXTENSION, &Application::importImage }, - { PNG_EXTENSION, &Application::importImage } -}; +const std::vector> + Application::_acceptedExtensions{ { SVO_EXTENSION, &Application::importSVOFromURL }, + { SVO_JSON_EXTENSION, &Application::importSVOFromURL }, + { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }, + { JSON_EXTENSION, &Application::importJSONFromURL }, + { JS_EXTENSION, &Application::askToLoadScript }, + { FST_EXTENSION, &Application::askToSetAvatarUrl }, + { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, + { CONTENT_ZIP_EXTENSION, &Application::askToReplaceDomainContent }, + { ZIP_EXTENSION, &Application::importFromZIP }, + { JPG_EXTENSION, &Application::importImage }, + { PNG_EXTENSION, &Application::importImage } }; class DeadlockWatchdogThread : public QThread { public: static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1; - static const unsigned long MAX_HEARTBEAT_AGE_USECS = 120 * USECS_PER_SECOND; // 2 mins with no checkin probably a deadlock - 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 + static const unsigned long MAX_HEARTBEAT_AGE_USECS = 120 * USECS_PER_SECOND; // 2 mins with no checkin probably a deadlock + 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() { @@ -407,9 +411,7 @@ public: // Give the heartbeat an initial value _heartbeat = usecTimestampNow(); _paused = false; - connect(qApp, &QCoreApplication::aboutToQuit, [this] { - _quit = true; - }); + connect(qApp, &QCoreApplication::aboutToQuit, [this] { _quit = true; }); } static void updateHeartbeat() { @@ -429,9 +431,7 @@ public: lambda(); resume(); } - static void pause() { - _paused = true; - } + static void pause() { _paused = true; } static void resume() { // Update the heartbeat BEFORE resuming the checks @@ -446,55 +446,49 @@ public: if (_paused) { continue; } - uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us + uint64_t lastHeartbeat = + _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us uint64_t now = usecTimestampNow(); auto lastHeartbeatAge = (now > lastHeartbeat) ? now - lastHeartbeat : 0; auto elapsedMovingAverage = _movingAverage.getAverage(); if (elapsedMovingAverage > _maxElapsedAverage) { - qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" - << "lastHeartbeatAge:" << lastHeartbeatAge - << "elapsedMovingAverage:" << elapsedMovingAverage - << "maxElapsed:" << _maxElapsed - << "PREVIOUS maxElapsedAverage:" << _maxElapsedAverage + qCDebug(interfaceapp_deadlock) + << "DEADLOCK WATCHDOG WARNING:" + << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage + << "maxElapsed:" << _maxElapsed << "PREVIOUS maxElapsedAverage:" << _maxElapsedAverage << "NEW maxElapsedAverage:" << elapsedMovingAverage << "** NEW MAX ELAPSED AVERAGE **" << "samples:" << _movingAverage.getSamples(); _maxElapsedAverage = elapsedMovingAverage; } if (lastHeartbeatAge > _maxElapsed) { - qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" - << "lastHeartbeatAge:" << lastHeartbeatAge - << "elapsedMovingAverage:" << elapsedMovingAverage - << "PREVIOUS maxElapsed:" << _maxElapsed - << "NEW maxElapsed:" << lastHeartbeatAge << "** NEW MAX ELAPSED **" - << "maxElapsedAverage:" << _maxElapsedAverage - << "samples:" << _movingAverage.getSamples(); + qCDebug(interfaceapp_deadlock) + << "DEADLOCK WATCHDOG WARNING:" + << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage + << "PREVIOUS maxElapsed:" << _maxElapsed << "NEW maxElapsed:" << lastHeartbeatAge << "** NEW MAX ELAPSED **" + << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); _maxElapsed = lastHeartbeatAge; } if (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT) { qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" - << "lastHeartbeatAge:" << lastHeartbeatAge - << "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE **" - << "maxElapsed:" << _maxElapsed - << "maxElapsedAverage:" << _maxElapsedAverage - << "samples:" << _movingAverage.getSamples(); + << "lastHeartbeatAge:" << lastHeartbeatAge + << "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE **" + << "maxElapsed:" << _maxElapsed << "maxElapsedAverage:" << _maxElapsedAverage + << "samples:" << _movingAverage.getSamples(); } if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { - qCDebug(interfaceapp_deadlock) << "DEADLOCK DETECTED -- " - << "lastHeartbeatAge:" << lastHeartbeatAge - << "[ lastHeartbeat :" << lastHeartbeat - << "now:" << now << " ]" - << "elapsedMovingAverage:" << elapsedMovingAverage - << "maxElapsed:" << _maxElapsed - << "maxElapsedAverage:" << _maxElapsedAverage - << "samples:" << _movingAverage.getSamples(); + qCDebug(interfaceapp_deadlock) + << "DEADLOCK DETECTED -- " + << "lastHeartbeatAge:" << lastHeartbeatAge << "[ lastHeartbeat :" << lastHeartbeat << "now:" << now << " ]" + << "elapsedMovingAverage:" << elapsedMovingAverage << "maxElapsed:" << _maxElapsed + << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); - // Don't actually crash in debug builds, in case this apparent deadlock is simply from - // the developer actively debugging code - #ifdef NDEBUG +// Don't actually crash in debug builds, in case this apparent deadlock is simply from +// the developer actively debugging code +#ifdef NDEBUG deadlockDetectionCrash(); - #endif +#endif } } } @@ -505,7 +499,7 @@ public: static std::atomic _maxElapsedAverage; static ThreadSafeMovingAverage _movingAverage; - bool _quit { false }; + bool _quit{ false }; }; std::atomic DeadlockWatchdogThread::_paused; @@ -528,8 +522,7 @@ bool isDomainURL(QUrl url) { // url.scheme() != URL_SCHEME_HTTPS return false; } - if (url.path().endsWith(".json", Qt::CaseInsensitive) || - url.path().endsWith(".json.gz", Qt::CaseInsensitive)) { + if (url.path().endsWith(".json", Qt::CaseInsensitive) || url.path().endsWith(".json.gz", Qt::CaseInsensitive)) { return true; } return false; @@ -543,7 +536,7 @@ public: return staticInstance; } - bool nativeEventFilter(const QByteArray &eventType, void* msg, long* result) Q_DECL_OVERRIDE { + bool nativeEventFilter(const QByteArray& eventType, void* msg, long* result) Q_DECL_OVERRIDE { if (eventType == "windows_generic_MSG") { MSG* message = (MSG*)msg; @@ -571,12 +564,12 @@ public: } if (message->message == WM_DEVICECHANGE) { - const float MIN_DELTA_SECONDS = 2.0f; // de-bounce signal + const float MIN_DELTA_SECONDS = 2.0f; // de-bounce signal static float lastTriggerTime = 0.0f; const float deltaSeconds = secTimestampNow() - lastTriggerTime; lastTriggerTime = secTimestampNow(); if (deltaSeconds > MIN_DELTA_SECONDS) { - Midi::USBchanged(); // re-scan the MIDI bus + Midi::USBchanged(); // re-scan the MIDI bus } } } @@ -587,38 +580,35 @@ public: class LambdaEvent : public QEvent { std::function _fun; + public: - LambdaEvent(const std::function & fun) : - QEvent(static_cast(ApplicationEvent::Lambda)), _fun(fun) { - } - LambdaEvent(std::function && fun) : - QEvent(static_cast(ApplicationEvent::Lambda)), _fun(fun) { - } + LambdaEvent(const std::function& fun) : QEvent(static_cast(ApplicationEvent::Lambda)), _fun(fun) {} + LambdaEvent(std::function&& fun) : QEvent(static_cast(ApplicationEvent::Lambda)), _fun(fun) {} void call() const { _fun(); } }; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); + QString logMessage = LogHandler::getInstance().printMessage((LogMsgType)type, context, message); if (!logMessage.isEmpty()) { #ifdef Q_OS_ANDROID - const char * local=logMessage.toStdString().c_str(); + const char* local = logMessage.toStdString().c_str(); switch (type) { case QtDebugMsg: - __android_log_write(ANDROID_LOG_DEBUG,"Interface",local); + __android_log_write(ANDROID_LOG_DEBUG, "Interface", local); break; case QtInfoMsg: - __android_log_write(ANDROID_LOG_INFO,"Interface",local); + __android_log_write(ANDROID_LOG_INFO, "Interface", local); break; case QtWarningMsg: - __android_log_write(ANDROID_LOG_WARN,"Interface",local); + __android_log_write(ANDROID_LOG_WARN, "Interface", local); break; case QtCriticalMsg: - __android_log_write(ANDROID_LOG_ERROR,"Interface",local); + __android_log_write(ANDROID_LOG_ERROR, "Interface", local); break; case QtFatalMsg: default: - __android_log_write(ANDROID_LOG_FATAL,"Interface",local); + __android_log_write(ANDROID_LOG_FATAL, "Interface", local); abort(); } #endif @@ -626,23 +616,23 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt } } - -class ApplicationMeshProvider : public scriptable::ModelProviderFactory { +class ApplicationMeshProvider : public scriptable::ModelProviderFactory { public: virtual scriptable::ModelProviderPointer lookupModelProvider(const QUuid& uuid) override { bool success; if (auto nestable = DependencyManager::get()->find(uuid, success).lock()) { auto type = nestable->getNestableType(); #ifdef SCRIPTABLE_MESH_DEBUG - qCDebug(interfaceapp) << "ApplicationMeshProvider::lookupModelProvider" << uuid << SpatiallyNestable::nestableTypeToString(type); + qCDebug(interfaceapp) << "ApplicationMeshProvider::lookupModelProvider" << uuid + << SpatiallyNestable::nestableTypeToString(type); #endif switch (type) { - case NestableType::Entity: - return getEntityModelProvider(static_cast(uuid)); - case NestableType::Overlay: - return getOverlayModelProvider(static_cast(uuid)); - case NestableType::Avatar: - return getAvatarModelProvider(uuid); + case NestableType::Entity: + return getEntityModelProvider(static_cast(uuid)); + case NestableType::Overlay: + return getOverlayModelProvider(static_cast(uuid)); + case NestableType::Avatar: + return getAvatarModelProvider(uuid); } } return nullptr; @@ -666,7 +656,7 @@ private: scriptable::ModelProviderPointer getOverlayModelProvider(OverlayID overlayID) { scriptable::ModelProviderPointer provider; - auto &overlays = qApp->getOverlays(); + auto& overlays = qApp->getOverlays(); if (auto overlay = overlays.getOverlay(overlayID)) { if (auto base3d = std::dynamic_pointer_cast(overlay)) { provider = std::dynamic_pointer_cast(base3d); @@ -745,7 +735,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { // HRS: I could not figure out how to move these any earlier in startup, so when using this option, be sure to also supply // --allowMultipleInstances - auto reportAndQuit = [&](const char* commandSwitch, std::function report) { + auto reportAndQuit = [&](const char* commandSwitch, std::function report) { const char* reportfile = getCmdOption(argc, constArgv, commandSwitch); // Reports to the specified file, because stdout is set up to be captured for logging. if (reportfile) { @@ -753,9 +743,9 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { if (fp) { report(fp); fclose(fp); - if (!runningMarkerExisted) { // don't leave ours around + if (!runningMarkerExisted) { // don't leave ours around RunningMarker runingMarker(RUNNING_MARKER_FILENAME); - runingMarker.deleteRunningMarkerFile(); // happens in deleter, but making the side-effect explicit. + runingMarker.deleteRunningMarkerFile(); // happens in deleter, but making the side-effect explicit. } _exit(0); } @@ -765,9 +755,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { auto version = protocolVersionsSignatureBase64(); fputs(version.toLatin1().data(), fp); }); - reportAndQuit("--version", [&](FILE* fp) { - fputs(BuildInfo::VERSION.toLatin1().data(), fp); - }); + reportAndQuit("--version", [&](FILE* fp) { fputs(BuildInfo::VERSION.toLatin1().data(), fp); }); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); const int listenPort = portStr ? atoi(portStr) : INVALID_PORT; @@ -775,8 +763,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset"; bool suppressPrompt = cmdOptionExists(argc, const_cast(argv), SUPPRESS_SETTINGS_RESET); - // Ignore any previous crashes if running from command line with a test script. - bool inTestMode { false }; + // Ignore any previous crashes if running from command line with a test script. + bool inTestMode{ false }; for (int i = 0; i < argc; ++i) { QString parameter(argv[i]); if (parameter == TEST_SCRIPT_COMMAND) { @@ -785,7 +773,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { } } - bool previousSessionCrashed { false }; + bool previousSessionCrashed{ false }; if (!inTestMode) { previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt); } @@ -797,8 +785,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir); } - // FIXME fix the OSX installer to install the resources.rcc binary instead of resource files and remove - // this conditional exclusion + // FIXME fix the OSX installer to install the resources.rcc binary instead of resource files and remove + // this conditional exclusion #if !defined(Q_OS_OSX) { #if defined(Q_OS_ANDROID) @@ -910,9 +898,10 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR, - STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, - STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED } }); + controller::StateController::setStateVariables( + { { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR, STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, + STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, + STATE_NAV_FOCUSED } }); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -945,8 +934,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { std::shared_ptr _keyboardFocusHighlight{ nullptr }; OverlayID _keyboardFocusHighlightID{ UNKNOWN_OVERLAY_ID }; - -OffscreenGLCanvas* _qmlShareContext { nullptr }; +OffscreenGLCanvas* _qmlShareContext{ nullptr }; // FIXME hack access to the internal share context for the Chromium helper // Normally we'd want to use QWebEngine::initialize(), but we can't because @@ -956,8 +944,8 @@ OffscreenGLCanvas* _qmlShareContext { nullptr }; // So instead we create a new offscreen context to share with the QGLWidget, // and manually set THAT to be the shared context for the Chromium helper #if !defined(DISABLE_QML) -OffscreenGLCanvas* _chromiumShareContext { nullptr }; -Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); +OffscreenGLCanvas* _chromiumShareContext{ nullptr }; +Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext* context); #endif Setting::Handle sessionRunTime{ "sessionRunTime", 0 }; @@ -971,15 +959,10 @@ const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false; const QString DEFAULT_CURSOR_NAME = "DEFAULT"; Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runningMarkerExisted) : - QApplication(argc, argv), - _window(new MainWindow(desktop())), - _sessionRunTimer(startupTimer), - _previousSessionCrashed(setupEssentials(argc, argv, runningMarkerExisted)), - _undoStackScriptingInterface(&_undoStack), - _entitySimulation(new PhysicalEntitySimulation()), - _physicsEngine(new PhysicsEngine(Vectors::ZERO)), - _entityClipboard(new EntityTree()), - _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION), + QApplication(argc, argv), _window(new MainWindow(desktop())), _sessionRunTimer(startupTimer), + _previousSessionCrashed(setupEssentials(argc, argv, runningMarkerExisted)), _undoStackScriptingInterface(&_undoStack), + _entitySimulation(new PhysicalEntitySimulation()), _physicsEngine(new PhysicsEngine(Vectors::ZERO)), + _entityClipboard(new EntityTree()), _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION), _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES), _hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT), _desktopTabletScale("desktopTabletScale", DEFAULT_DESKTOP_TABLET_SCALE_PERCENT), @@ -988,22 +971,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _preferStylusOverLaserSetting("preferStylusOverLaser", DEFAULT_PREFER_STYLUS_OVER_LASER), _preferAvatarFingerOverStylusSetting("preferAvatarFingerOverStylus", DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS), _constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true), - _preferredCursor("preferredCursor", DEFAULT_CURSOR_NAME), - _scaleMirror(1.0f), - _mirrorYawOffset(0.0f), - _raiseMirror(0.0f), - _enableProcessOctreeThread(true), - _lastNackTime(usecTimestampNow()), - _lastSendDownstreamAudioStats(usecTimestampNow()), - _aboutToQuit(false), - _notifiedPacketVersionMismatchThisDomain(false), - _maxOctreePPS(maxOctreePacketsPerSecond.get()), - _lastFaceTrackerUpdate(0), - _snapshotSound(nullptr), - _sampleSound(nullptr) + _preferredCursor("preferredCursor", DEFAULT_CURSOR_NAME), _scaleMirror(1.0f), _mirrorYawOffset(0.0f), _raiseMirror(0.0f), + _enableProcessOctreeThread(true), _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()), + _aboutToQuit(false), _notifiedPacketVersionMismatchThisDomain(false), _maxOctreePPS(maxOctreePacketsPerSecond.get()), + _lastFaceTrackerUpdate(0), _snapshotSound(nullptr), _sampleSound(nullptr) { - auto steamClient = PluginManager::getInstance()->getSteamClientPlugin(); setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); setProperty(hifi::properties::CRASHED, _previousSessionCrashed); @@ -1018,7 +991,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // This is done so as not break previous command line scripts if (testScriptPath.left(URL_SCHEME_HTTP.length()) == URL_SCHEME_HTTP || testScriptPath.left(URL_SCHEME_FTP.length()) == URL_SCHEME_FTP) { - setProperty(hifi::properties::TEST, QUrl::fromUserInput(testScriptPath)); } else if (QFileInfo(testScriptPath).exists()) { setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath)); @@ -1043,7 +1015,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // make sure the debug draw singleton is initialized on the main thread. DebugDraw::getInstance().removeMarker(""); - PluginContainer* pluginContainer = dynamic_cast(this); // set the container for any plugins that care + PluginContainer* pluginContainer = dynamic_cast(this); // set the container for any plugins that care PluginManager::getInstance()->setContainer(pluginContainer); QThreadPool::globalInstance()->setMaxThreadCount(MIN_PROCESSING_THREAD_POOL_SIZE); @@ -1076,7 +1048,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-SemiBold.ttf"); _window->setWindowTitle("High Fidelity Interface"); - Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us + Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us auto nodeList = DependencyManager::get(); nodeList->startThread(); @@ -1134,15 +1106,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo domainCheckInTimer->deleteLater(); }); - auto audioIO = DependencyManager::get(); - audioIO->setPositionGetter([]{ + audioIO->setPositionGetter([] { auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO; }); - audioIO->setOrientationGetter([]{ + audioIO->setOrientationGetter([] { auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; @@ -1153,10 +1124,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo audioIO->handleRecordedAudioInput(frame->data); }); - connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio){ + connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio) { static auto recorder = DependencyManager::get(); if (recorder->isRecording()) { - static const recording::FrameType AUDIO_FRAME_TYPE = recording::Frame::registerFrameType(AudioConstants::getAudioFrameName()); + static const recording::FrameType AUDIO_FRAME_TYPE = + recording::Frame::registerFrameType(AudioConstants::getAudioFrameName()); recorder->recordFrame(AUDIO_FRAME_TYPE, audio); } }); @@ -1164,7 +1136,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto audioScriptingInterface = DependencyManager::set(); connect(audioIO.data(), &AudioClient::mutedByMixer, audioScriptingInterface.data(), &AudioScriptingInterface::mutedByMixer); - connect(audioIO.data(), &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), &AudioScriptingInterface::receivedFirstPacket); + connect(audioIO.data(), &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), + &AudioScriptingInterface::receivedFirstPacket); connect(audioIO.data(), &AudioClient::disconnected, audioScriptingInterface.data(), &AudioScriptingInterface::disconnected); connect(audioIO.data(), &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) { auto audioClient = DependencyManager::get(); @@ -1177,8 +1150,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo audioScriptingInterface->environmentMuted(); } }); - connect(this, &Application::activeDisplayPluginChanged, - reinterpret_cast(audioScriptingInterface.data()), &scripting::Audio::onContextChanged); + connect(this, &Application::activeDisplayPluginChanged, reinterpret_cast(audioScriptingInterface.data()), + &scripting::Audio::onContextChanged); // Make sure we don't time out during slow operations at startup updateHeartbeat(); @@ -1189,9 +1162,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo const DomainHandler& domainHandler = nodeList->getDomainHandler(); connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl))); - connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){ - setCrashAnnotation("domain", domainURL.toString().toStdString()); - }); + connect(&domainHandler, &DomainHandler::domainURLChanged, + [](QUrl domainURL) { setCrashAnnotation("domain", domainURL.toString().toStdString()); }); connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain())); connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); @@ -1205,20 +1177,21 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // We could clear ATP assets only when changing domains, but it's possible that the domain you are connected // to has gone down and switched to a new content set, so when you reconnect the cached ATP assets will no longer be valid. - connect(&domainHandler, &DomainHandler::disconnectedFromDomain, DependencyManager::get().data(), &ScriptCache::clearATPScriptsFromCache); + connect(&domainHandler, &DomainHandler::disconnectedFromDomain, DependencyManager::get().data(), + &ScriptCache::clearATPScriptsFromCache); // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * MSECS_PER_SECOND; auto discoverabilityManager = DependencyManager::get(); connect(&locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); - connect(&locationUpdateTimer, &QTimer::timeout, - DependencyManager::get().data(), &AddressManager::storeCurrentAddress); + connect(&locationUpdateTimer, &QTimer::timeout, DependencyManager::get().data(), + &AddressManager::storeCurrentAddress); locationUpdateTimer.start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS); // if we get a domain change, immediately attempt update location in metaverse server - connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, - discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); + connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, discoverabilityManager.data(), + &DiscoverabilityManager::updateLocation); // send a location update immediately discoverabilityManager->updateLocation(); @@ -1231,15 +1204,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); // you might think we could just do this in NodeList but we only want this connection for Interface - connect(&nodeList->getDomainHandler(), SIGNAL(limitOfSilentDomainCheckInsReached()), - nodeList.data(), SLOT(reset())); + connect(&nodeList->getDomainHandler(), SIGNAL(limitOfSilentDomainCheckInsReached()), nodeList.data(), SLOT(reset())); auto dialogsManager = DependencyManager::get(); connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog); connect(accountManager.data(), &AccountManager::usernameChanged, this, &Application::updateWindowTitle); - connect(accountManager.data(), &AccountManager::usernameChanged, [](QString username){ - setCrashAnnotation("username", username.toStdString()); - }); + connect(accountManager.data(), &AccountManager::usernameChanged, + [](QString username) { setCrashAnnotation("username", username.toStdString()); }); // set the account manager's root URL and trigger a login request if we don't have the access token accountManager->setIsAgent(true); @@ -1248,14 +1219,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto addressManager = DependencyManager::get(); // use our MyAvatar position and quat for address manager path - addressManager->setPositionGetter([this]{ return getMyAvatar()->getWorldPosition(); }); - addressManager->setOrientationGetter([this]{ return getMyAvatar()->getWorldOrientation(); }); + addressManager->setPositionGetter([this] { return getMyAvatar()->getWorldPosition(); }); + addressManager->setOrientationGetter([this] { return getMyAvatar()->getWorldOrientation(); }); connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount); - connect(this, &Application::activeDisplayPluginChanged, this, [](){ + connect(this, &Application::activeDisplayPluginChanged, this, []() { qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode()); auto displayPlugin = qApp->getActiveDisplayPlugin(); setCrashAnnotation("display_plugin", displayPlugin->getName().toStdString()); @@ -1264,39 +1235,42 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode); // Save avatar location immediately after a teleport. - connect(myAvatar.get(), &MyAvatar::positionGoneTo, - DependencyManager::get().data(), &AddressManager::storeCurrentAddress); + connect(myAvatar.get(), &MyAvatar::positionGoneTo, DependencyManager::get().data(), + &AddressManager::storeCurrentAddress); - connect(myAvatar.get(), &MyAvatar::skeletonModelURLChanged, [](){ + connect(myAvatar.get(), &MyAvatar::skeletonModelURLChanged, []() { QUrl avatarURL = qApp->getMyAvatar()->getSkeletonModelURL(); setCrashAnnotation("avatar", avatarURL.toString().toStdString()); }); - // Inititalize sample before registering _sampleSound = DependencyManager::get()->getSound(PathUtils::resourcesUrl("sounds/sample.wav")); auto scriptEngines = DependencyManager::get().data(); - scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){ - registerScriptEngineWithApplicationServices(engine); - }); + scriptEngines->registerScriptInitializer( + [this](ScriptEnginePointer engine) { registerScriptEngineWithApplicationServices(engine); }); - connect(scriptEngines, &ScriptEngines::scriptCountChanged, scriptEngines, [this] { - auto scriptEngines = DependencyManager::get(); - if (scriptEngines->getRunningScripts().isEmpty()) { - getMyAvatar()->clearScriptableSettings(); - } - }, Qt::QueuedConnection); + connect(scriptEngines, &ScriptEngines::scriptCountChanged, scriptEngines, + [this] { + auto scriptEngines = DependencyManager::get(); + if (scriptEngines->getRunningScripts().isEmpty()) { + getMyAvatar()->clearScriptableSettings(); + } + }, + Qt::QueuedConnection); - connect(scriptEngines, &ScriptEngines::scriptsReloading, scriptEngines, [this] { - getEntities()->reloadEntityScripts(); - loadAvatarScripts(getMyAvatar()->getScriptUrls()); - }, Qt::QueuedConnection); + connect(scriptEngines, &ScriptEngines::scriptsReloading, scriptEngines, + [this] { + getEntities()->reloadEntityScripts(); + loadAvatarScripts(getMyAvatar()->getScriptUrls()); + }, + Qt::QueuedConnection); - connect(scriptEngines, &ScriptEngines::scriptLoadError, - scriptEngines, [](const QString& filename, const QString& error){ - OffscreenUi::asyncWarning(nullptr, "Error Loading Script", filename + " failed to load."); - }, Qt::QueuedConnection); + connect(scriptEngines, &ScriptEngines::scriptLoadError, scriptEngines, + [](const QString& filename, const QString& error) { + OffscreenUi::asyncWarning(nullptr, "Error Loading Script", filename + " failed to load."); + }, + Qt::QueuedConnection); #ifdef _WIN32 WSADATA WsaData; @@ -1305,11 +1279,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // tell the NodeList instance who to tell the domain server we care about nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer - << NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer << NodeType::EntityScriptServer); + << NodeType::EntityServer << NodeType::AssetServer + << NodeType::MessagesMixer << NodeType::EntityScriptServer); // connect to the packet sent signal of the _entityEditSender connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent); - connect(&_entityEditSender, &EntityEditPacketSender::addingEntityWithCertificate, this, &Application::addingEntityWithCertificate); + connect(&_entityEditSender, &EntityEditPacketSender::addingEntityWithCertificate, this, + &Application::addingEntityWithCertificate); QString concurrentDownloadsStr = getCmdOption(argc, constArgv, "--concurrent-downloads"); bool success; @@ -1362,11 +1338,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo initializeGL(); qCDebug(interfaceapp, "Initialized GL"); - // Initialize the display plugin architecture + // Initialize the display plugin architecture initializeDisplayPlugins(); qCDebug(interfaceapp, "Initialized Display"); - // Create the rendering engine. This can be slow on some machines due to lots of + // Create the rendering engine. This can be slow on some machines due to lots of // GPU pipeline creation. initializeRenderEngine(); qCDebug(interfaceapp, "Initialized Render Engine."); @@ -1393,7 +1369,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo constexpr auto INSTALLER_INI_NAME = "installer.ini"; auto iniPath = QDir(applicationDirPath()).filePath(INSTALLER_INI_NAME); - QFile installerFile { iniPath }; + QFile installerFile{ iniPath }; std::unordered_map installerKeyValues; if (installerFile.open(QIODevice::ReadOnly)) { while (!installerFile.atEnd()) { @@ -1410,7 +1386,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // In practice we shouldn't run across installs that don't have a known installer type. // Client or Client+Server installs should always have the installer.ini next to their // respective interface.exe, and Steam installs will be detected as such. If a user were - // to delete the installer.ini, though, and as an example, we won't know the context of the + // to delete the installer.ini, though, and as an example, we won't know the context of the // original install. constexpr auto INSTALLER_KEY_TYPE = "type"; constexpr auto INSTALLER_KEY_CAMPAIGN = "campaign"; @@ -1434,7 +1410,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qDebug() << "Detected installer campaign:" << installerCampaign; // add firstRun flag from settings to launch event - Setting::Handle firstRun { Settings::firstRun, true }; + Setting::Handle firstRun{ Settings::firstRun, true }; // once the settings have been loaded, check if we need to flip the default for UserActivityLogger auto& userActivityLogger = UserActivityLogger::getInstance(); @@ -1453,28 +1429,26 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo static const QString TESTER = "HIFI_TESTER"; auto gpuIdent = GPUIdent::getInstance(); auto glContextData = getGLContextData(); - QJsonObject properties = { - { "version", applicationVersion() }, - { "tester", QProcessEnvironment::systemEnvironment().contains(TESTER) }, - { "installer_campaign", installerCampaign }, - { "installer_type", installerType }, - { "previousSessionCrashed", _previousSessionCrashed }, - { "previousSessionRuntime", sessionRunTime.get() }, - { "cpu_architecture", QSysInfo::currentCpuArchitecture() }, - { "kernel_type", QSysInfo::kernelType() }, - { "kernel_version", QSysInfo::kernelVersion() }, - { "os_type", QSysInfo::productType() }, - { "os_version", QSysInfo::productVersion() }, - { "gpu_name", gpuIdent->getName() }, - { "gpu_driver", gpuIdent->getDriver() }, - { "gpu_memory", static_cast(gpuIdent->getMemory()) }, - { "gl_version_int", glVersionToInteger(glContextData.value("version").toString()) }, - { "gl_version", glContextData["version"] }, - { "gl_vender", glContextData["vendor"] }, - { "gl_sl_version", glContextData["sl_version"] }, - { "gl_renderer", glContextData["renderer"] }, - { "ideal_thread_count", QThread::idealThreadCount() } - }; + QJsonObject properties = { { "version", applicationVersion() }, + { "tester", QProcessEnvironment::systemEnvironment().contains(TESTER) }, + { "installer_campaign", installerCampaign }, + { "installer_type", installerType }, + { "previousSessionCrashed", _previousSessionCrashed }, + { "previousSessionRuntime", sessionRunTime.get() }, + { "cpu_architecture", QSysInfo::currentCpuArchitecture() }, + { "kernel_type", QSysInfo::kernelType() }, + { "kernel_version", QSysInfo::kernelVersion() }, + { "os_type", QSysInfo::productType() }, + { "os_version", QSysInfo::productVersion() }, + { "gpu_name", gpuIdent->getName() }, + { "gpu_driver", gpuIdent->getDriver() }, + { "gpu_memory", static_cast(gpuIdent->getMemory()) }, + { "gl_version_int", glVersionToInteger(glContextData.value("version").toString()) }, + { "gl_version", glContextData["version"] }, + { "gl_vender", glContextData["vendor"] }, + { "gl_sl_version", glContextData["sl_version"] }, + { "gl_renderer", glContextData["renderer"] }, + { "ideal_thread_count", QThread::idealThreadCount() } }; auto macVersion = QSysInfo::macVersion(); if (macVersion != QSysInfo::MV_None) { properties["os_osx_version"] = QSysInfo::macVersion(); @@ -1512,10 +1486,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // For now we're going to set the PPS for outbound packets to be super high, this is // probably not the right long term solution. But for now, we're going to do this to // allow you to move an entity around in your hand - _entityEditSender.setPacketsPerSecond(3000); // super high!! + _entityEditSender.setPacketsPerSecond(3000); // super high!! // Overlays need to exist before we set the ContextOverlayInterface dependency - _overlays.init(); // do this before scripts load + _overlays.init(); // do this before scripts load DependencyManager::set(); // Make sure we don't time out during slow operations at startup @@ -1525,14 +1499,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // hook up bandwidth estimator QSharedPointer bandwidthRecorder = DependencyManager::get(); - connect(nodeList.data(), &LimitedNodeList::dataSent, - bandwidthRecorder.data(), &BandwidthRecorder::updateOutboundData); - connect(nodeList.data(), &LimitedNodeList::dataReceived, - bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData); + connect(nodeList.data(), &LimitedNodeList::dataSent, bandwidthRecorder.data(), &BandwidthRecorder::updateOutboundData); + connect(nodeList.data(), &LimitedNodeList::dataReceived, bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData); // FIXME -- I'm a little concerned about this. - connect(myAvatar->getSkeletonModel().get(), &SkeletonModel::skeletonLoaded, - this, &Application::checkSkeleton, Qt::QueuedConnection); + connect(myAvatar->getSkeletonModel().get(), &SkeletonModel::skeletonLoaded, this, &Application::checkSkeleton, + Qt::QueuedConnection); // Setup the userInputMapper with the actions auto userInputMapper = DependencyManager::get(); @@ -1613,7 +1585,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (action == controller::toInt(controller::Action::RETICLE_CLICK)) { auto reticlePos = getApplicationCompositor().getReticlePosition(); - QPoint localPos(reticlePos.x, reticlePos.y); // both hmd and desktop already handle this in our coordinates. + QPoint localPos(reticlePos.x, reticlePos.y); // both hmd and desktop already handle this in our coordinates. if (state) { QMouseEvent mousePress(QEvent::MouseButtonPress, localPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); sendEvent(_glWidget, &mousePress); @@ -1623,7 +1595,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo sendEvent(_glWidget, &mouseRelease); _reticleClickPressed = false; } - return; // nothing else to do + return; // nothing else to do } if (state) { @@ -1648,9 +1620,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _applicationStateDevice = userInputMapper->getStateDevice(); - _applicationStateDevice->setInputVariant(STATE_IN_HMD, []() -> float { - return qApp->isHMDMode() ? 1 : 0; - }); + _applicationStateDevice->setInputVariant(STATE_IN_HMD, []() -> float { return qApp->isHMDMode() ? 1 : 0; }); _applicationStateDevice->setInputVariant(STATE_CAMERA_FULL_SCREEN_MIRROR, []() -> float { return qApp->getCamera().getMode() == CAMERA_MODE_MIRROR ? 1 : 0; }); @@ -1666,9 +1636,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _applicationStateDevice->setInputVariant(STATE_CAMERA_INDEPENDENT, []() -> float { return qApp->getCamera().getMode() == CAMERA_MODE_INDEPENDENT ? 1 : 0; }); - _applicationStateDevice->setInputVariant(STATE_SNAP_TURN, []() -> float { - return qApp->getMyAvatar()->getSnapTurn() ? 1 : 0; - }); + _applicationStateDevice->setInputVariant(STATE_SNAP_TURN, + []() -> float { return qApp->getMyAvatar()->getSnapTurn() ? 1 : 0; }); _applicationStateDevice->setInputVariant(STATE_ADVANCED_MOVEMENT_CONTROLS, []() -> float { return qApp->getMyAvatar()->useAdvancedMovementControls() ? 1 : 0; }); @@ -1726,25 +1695,27 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo updateHeartbeat(); QTimer* settingsTimer = new QTimer(); - moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{ - connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer]{ - // Disconnect the signal from the save settings - QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); - // Stop the settings timer - settingsTimer->stop(); - // Delete it (this will trigger the thread destruction - settingsTimer->deleteLater(); - // Mark the settings thread as finished, so we know we can safely save in the main application - // shutdown code - _settingsGuard.trigger(); - }); + moveToNewNamedThread(settingsTimer, "Settings Thread", + [this, settingsTimer] { + connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer] { + // Disconnect the signal from the save settings + QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); + // Stop the settings timer + settingsTimer->stop(); + // Delete it (this will trigger the thread destruction + settingsTimer->deleteLater(); + // Mark the settings thread as finished, so we know we can safely save in the main application + // shutdown code + _settingsGuard.trigger(); + }); - int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now - settingsTimer->setSingleShot(false); - settingsTimer->setInterval(SAVE_SETTINGS_INTERVAL); // 10s, Qt::CoarseTimer acceptable - QObject::connect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); - settingsTimer->start(); - }, QThread::LowestPriority); + int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now + settingsTimer->setSingleShot(false); + settingsTimer->setInterval(SAVE_SETTINGS_INTERVAL); // 10s, Qt::CoarseTimer acceptable + QObject::connect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); + settingsTimer->start(); + }, + QThread::LowestPriority); if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) { getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN); // So that camera doesn't auto-switch to third person. @@ -1759,9 +1730,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // set the local loopback interface for local sounds AudioInjector::setLocalAudioInterface(audioIO.data()); audioScriptingInterface->setLocalAudioInterface(audioIO.data()); - connect(audioIO.data(), &AudioClient::noiseGateOpened, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateOpened); - connect(audioIO.data(), &AudioClient::noiseGateClosed, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateClosed); - connect(audioIO.data(), &AudioClient::inputReceived, audioScriptingInterface.data(), &AudioScriptingInterface::inputReceived); + connect(audioIO.data(), &AudioClient::noiseGateOpened, audioScriptingInterface.data(), + &AudioScriptingInterface::noiseGateOpened); + connect(audioIO.data(), &AudioClient::noiseGateClosed, audioScriptingInterface.data(), + &AudioScriptingInterface::noiseGateClosed); + connect(audioIO.data(), &AudioClient::inputReceived, audioScriptingInterface.data(), + &AudioScriptingInterface::inputReceived); this->installEventFilter(this); @@ -1785,12 +1759,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto applicationUpdater = DependencyManager::get(); - AutoUpdater::InstallerType type = installerType == INSTALLER_TYPE_CLIENT_ONLY - ? AutoUpdater::InstallerType::CLIENT_ONLY : AutoUpdater::InstallerType::FULL; + AutoUpdater::InstallerType type = installerType == INSTALLER_TYPE_CLIENT_ONLY ? AutoUpdater::InstallerType::CLIENT_ONLY + : AutoUpdater::InstallerType::FULL; applicationUpdater->setInstallerType(type); applicationUpdater->setInstallerCampaign(installerCampaign); - connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog); + connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), + &DialogsManager::showUpdateDialog); applicationUpdater->checkForUpdate(); } @@ -1806,15 +1781,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto entityScriptingInterface = DependencyManager::get(); connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, [this](const EntityItemID& entityItemID, const PointerEvent& event) { - if (event.shouldFocus()) { - if (getEntities()->wantsKeyboardFocus(entityItemID)) { - setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); - setKeyboardFocusEntity(entityItemID); - } else { - setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); - } - } - }); + if (event.shouldFocus()) { + if (getEntities()->wantsKeyboardFocus(entityItemID)) { + setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); + setKeyboardFocusEntity(entityItemID); + } else { + setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); + } + } + }); connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, [=](const EntityItemID& entityItemID) { if (entityItemID == _keyboardFocusedEntity.get()) { @@ -1830,72 +1805,78 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); - EntityTree::setAddMaterialToEntityOperator([&](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - // try to find the renderable - auto renderable = getEntities()->renderableForEntityId(entityID); - if (renderable) { - renderable->addMaterial(material, parentMaterialName); - } + EntityTree::setAddMaterialToEntityOperator( + [&](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + // try to find the renderable + auto renderable = getEntities()->renderableForEntityId(entityID); + if (renderable) { + renderable->addMaterial(material, parentMaterialName); + } - // even if we don't find it, try to find the entity - auto entity = getEntities()->getEntity(entityID); - if (entity) { - entity->addMaterial(material, parentMaterialName); - return true; - } - return false; - }); - EntityTree::setRemoveMaterialFromEntityOperator([&](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - // try to find the renderable - auto renderable = getEntities()->renderableForEntityId(entityID); - if (renderable) { - renderable->removeMaterial(material, parentMaterialName); - } + // even if we don't find it, try to find the entity + auto entity = getEntities()->getEntity(entityID); + if (entity) { + entity->addMaterial(material, parentMaterialName); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromEntityOperator( + [&](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + // try to find the renderable + auto renderable = getEntities()->renderableForEntityId(entityID); + if (renderable) { + renderable->removeMaterial(material, parentMaterialName); + } - // even if we don't find it, try to find the entity - auto entity = getEntities()->getEntity(entityID); - if (entity) { - entity->removeMaterial(material, parentMaterialName); - return true; - } - return false; - }); + // even if we don't find it, try to find the entity + auto entity = getEntities()->getEntity(entityID); + if (entity) { + entity->removeMaterial(material, parentMaterialName); + return true; + } + return false; + }); - EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - auto avatarManager = DependencyManager::get(); - auto avatar = avatarManager->getAvatarBySessionID(avatarID); - if (avatar) { - avatar->addMaterial(material, parentMaterialName); - return true; - } - return false; - }); - EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - auto avatarManager = DependencyManager::get(); - auto avatar = avatarManager->getAvatarBySessionID(avatarID); - if (avatar) { - avatar->removeMaterial(material, parentMaterialName); - return true; - } - return false; - }); + EntityTree::setAddMaterialToAvatarOperator( + [](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + auto avatarManager = DependencyManager::get(); + auto avatar = avatarManager->getAvatarBySessionID(avatarID); + if (avatar) { + avatar->addMaterial(material, parentMaterialName); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromAvatarOperator( + [](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + auto avatarManager = DependencyManager::get(); + auto avatar = avatarManager->getAvatarBySessionID(avatarID); + if (avatar) { + avatar->removeMaterial(material, parentMaterialName); + return true; + } + return false; + }); - EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - auto overlay = _overlays.getOverlay(overlayID); - if (overlay) { - overlay->addMaterial(material, parentMaterialName); - return true; - } - return false; - }); - EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - auto overlay = _overlays.getOverlay(overlayID); - if (overlay) { - overlay->removeMaterial(material, parentMaterialName); - return true; - } - return false; - }); + EntityTree::setAddMaterialToOverlayOperator( + [&](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + auto overlay = _overlays.getOverlay(overlayID); + if (overlay) { + overlay->addMaterial(material, parentMaterialName); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromOverlayOperator( + [&](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + auto overlay = _overlays.getOverlay(overlayID); + if (overlay) { + overlay->removeMaterial(material, parentMaterialName); + return true; + } + return false; + }); // Keyboard focus handling for Web overlays. auto overlays = &(qApp->getOverlays()); @@ -1938,8 +1919,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // content location and build info - useful for filtering stats auto addressManager = DependencyManager::get(); - auto currentDomain = addressManager->currentShareableAddress(true).toString(); // domain only - auto currentPath = addressManager->currentPath(true); // with orientation + auto currentDomain = addressManager->currentShareableAddress(true).toString(); // domain only + auto currentPath = addressManager->currentPath(true); // with orientation properties["current_domain"] = currentDomain; properties["current_path"] = currentPath; properties["build_version"] = BuildInfo::VERSION; @@ -2005,24 +1986,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo startedRequests["atp"] = statTracker->getStat(STAT_ATP_REQUEST_STARTED).toInt(); startedRequests["http"] = statTracker->getStat(STAT_HTTP_REQUEST_STARTED).toInt(); startedRequests["file"] = statTracker->getStat(STAT_FILE_REQUEST_STARTED).toInt(); - startedRequests["total"] = startedRequests["atp"].toInt() + startedRequests["http"].toInt() - + startedRequests["file"].toInt(); + startedRequests["total"] = + startedRequests["atp"].toInt() + startedRequests["http"].toInt() + startedRequests["file"].toInt(); properties["started_requests"] = startedRequests; QJsonObject successfulRequests; successfulRequests["atp"] = statTracker->getStat(STAT_ATP_REQUEST_SUCCESS).toInt(); successfulRequests["http"] = statTracker->getStat(STAT_HTTP_REQUEST_SUCCESS).toInt(); successfulRequests["file"] = statTracker->getStat(STAT_FILE_REQUEST_SUCCESS).toInt(); - successfulRequests["total"] = successfulRequests["atp"].toInt() + successfulRequests["http"].toInt() - + successfulRequests["file"].toInt(); + successfulRequests["total"] = + successfulRequests["atp"].toInt() + successfulRequests["http"].toInt() + successfulRequests["file"].toInt(); properties["successful_requests"] = successfulRequests; QJsonObject failedRequests; failedRequests["atp"] = statTracker->getStat(STAT_ATP_REQUEST_FAILED).toInt(); failedRequests["http"] = statTracker->getStat(STAT_HTTP_REQUEST_FAILED).toInt(); failedRequests["file"] = statTracker->getStat(STAT_FILE_REQUEST_FAILED).toInt(); - failedRequests["total"] = failedRequests["atp"].toInt() + failedRequests["http"].toInt() - + failedRequests["file"].toInt(); + failedRequests["total"] = + failedRequests["atp"].toInt() + failedRequests["http"].toInt() + failedRequests["file"].toInt(); properties["failed_requests"] = failedRequests; QJsonObject cacheRequests; @@ -2067,21 +2048,18 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo totalServerOctreeElements += i->second.getTotalElements(); } - properties["local_octree_elements"] = (qint64) OctreeElement::getInternalNodeCount(); - properties["server_octree_elements"] = (qint64) totalServerOctreeElements; + properties["local_octree_elements"] = (qint64)OctreeElement::getInternalNodeCount(); + properties["server_octree_elements"] = (qint64)totalServerOctreeElements; properties["active_display_plugin"] = getActiveDisplayPlugin()->getName(); properties["using_hmd"] = isHMDMode(); _autoSwitchDisplayModeSupportedHMDPlugin = nullptr; - foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { - if (displayPlugin->isHmd() && - displayPlugin->getSupportsAutoSwitch()) { + foreach (DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { + if (displayPlugin->isHmd() && displayPlugin->getSupportsAutoSwitch()) { _autoSwitchDisplayModeSupportedHMDPlugin = displayPlugin; - _autoSwitchDisplayModeSupportedHMDPluginName = - _autoSwitchDisplayModeSupportedHMDPlugin->getName(); - _previousHMDWornStatus = - _autoSwitchDisplayModeSupportedHMDPlugin->isDisplayVisible(); + _autoSwitchDisplayModeSupportedHMDPluginName = _autoSwitchDisplayModeSupportedHMDPlugin->getName(); + _previousHMDWornStatus = _autoSwitchDisplayModeSupportedHMDPlugin->isDisplayVisible(); break; } } @@ -2089,7 +2067,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (_autoSwitchDisplayModeSupportedHMDPlugin) { if (getActiveDisplayPlugin() != _autoSwitchDisplayModeSupportedHMDPlugin && !_autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { - startHMDStandBySession(); + startHMDStandBySession(); } // Poll periodically to check whether the user has worn HMD or not. Switch Display mode accordingly. // If the user wears HMD then switch to VR mode. If the user removes HMD then switch to Desktop mode. @@ -2115,8 +2093,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // controller::Pose considers two poses to be different if either are invalid. In our case, we actually // want to consider the pose to be unchanged if it was invalid and still is invalid, so we check that first. properties["hand_pose_changed"] = - ((leftHandPose.valid || lastLeftHandPose.valid) && (leftHandPose != lastLeftHandPose)) - || ((rightHandPose.valid || lastRightHandPose.valid) && (rightHandPose != lastRightHandPose)); + ((leftHandPose.valid || lastLeftHandPose.valid) && (leftHandPose != lastLeftHandPose)) || + ((rightHandPose.valid || lastRightHandPose.valid) && (rightHandPose != lastRightHandPose)); lastLeftHandPose = leftHandPose; lastRightHandPose = rightHandPose; @@ -2127,11 +2105,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Periodically check for count of nearby avatars static int lastCountOfNearbyAvatars = -1; QTimer* checkNearbyAvatarsTimer = new QTimer(this); - checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); // 10 seconds, Qt::CoarseTimer ok + checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); // 10 seconds, Qt::CoarseTimer ok connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, []() { auto avatarManager = DependencyManager::get(); int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getWorldPosition(), - NEARBY_AVATAR_RADIUS_METERS) - 1; + NEARBY_AVATAR_RADIUS_METERS) - + 1; if (nearbyAvatars != lastCountOfNearbyAvatars) { lastCountOfNearbyAvatars = nearbyAvatars; UserActivityLogger::getInstance().logAction("nearby_avatars", { { "count", nearbyAvatars } }); @@ -2140,9 +2119,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo checkNearbyAvatarsTimer->start(); // Track user activity event when we receive a mute packet - auto onMutedByMixer = []() { - UserActivityLogger::getInstance().logAction("received_mute_packet"); - }; + auto onMutedByMixer = []() { UserActivityLogger::getInstance().logAction("received_mute_packet"); }; connect(DependencyManager::get().data(), &AudioClient::mutedByMixer, this, onMutedByMixer); // Track when the address bar is opened @@ -2175,37 +2152,33 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (testProperty.isValid()) { auto scriptEngines = DependencyManager::get(); const auto testScript = property(hifi::properties::TEST).toUrl(); - + // Set last parameter to exit interface when the test script finishes, if so requested scriptEngines->loadScript(testScript, false, false, false, false, quitWhenFinished); // This is done so we don't get a "connection time-out" message when we haven't passed in a URL. if (arguments().contains("--url")) { auto reply = SandboxUtils::getStatus(); - connect(reply, &QNetworkReply::finished, this, [=] { - handleSandboxStatus(reply); - }); + connect(reply, &QNetworkReply::finished, this, [=] { handleSandboxStatus(reply); }); } } else { PROFILE_RANGE(render, "GetSandboxStatus"); auto reply = SandboxUtils::getStatus(); - connect(reply, &QNetworkReply::finished, this, [=] { - handleSandboxStatus(reply); - }); + connect(reply, &QNetworkReply::finished, this, [=] { handleSandboxStatus(reply); }); } // Monitor model assets (e.g., from Clara.io) added to the world that may need resizing. static const int ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS = 1000; - _addAssetToWorldResizeTimer.setInterval(ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS); // 1s, Qt::CoarseTimer acceptable + _addAssetToWorldResizeTimer.setInterval(ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS); // 1s, Qt::CoarseTimer acceptable connect(&_addAssetToWorldResizeTimer, &QTimer::timeout, this, &Application::addAssetToWorldCheckModelSize); // Auto-update and close adding asset to world info message box. static const int ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS = 5000; - _addAssetToWorldInfoTimer.setInterval(ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS); // 5s, Qt::CoarseTimer acceptable + _addAssetToWorldInfoTimer.setInterval(ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS); // 5s, Qt::CoarseTimer acceptable _addAssetToWorldInfoTimer.setSingleShot(true); connect(&_addAssetToWorldInfoTimer, &QTimer::timeout, this, &Application::addAssetToWorldInfoTimeout); static const int ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS = 8000; - _addAssetToWorldErrorTimer.setInterval(ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS); // 8s, Qt::CoarseTimer acceptable + _addAssetToWorldErrorTimer.setInterval(ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS); // 8s, Qt::CoarseTimer acceptable _addAssetToWorldErrorTimer.setSingleShot(true); connect(&_addAssetToWorldErrorTimer, &QTimer::timeout, this, &Application::addAssetToWorldErrorTimeout); @@ -2216,7 +2189,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged); - DependencyManager::get()->setShouldPickHUDOperator([&]() { return DependencyManager::get()->isHMDMode(); }); + DependencyManager::get()->setShouldPickHUDOperator( + [&]() { return DependencyManager::get()->isHMDMode(); }); DependencyManager::get()->setCalculatePos2DFromHUDOperator([&](const glm::vec3& intersection) { const glm::vec2 MARGIN(25.0f); glm::vec2 maxPos = _controllerScriptingInterface->getViewportDimensions() - MARGIN; @@ -2225,8 +2199,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo }); // Setup the mouse ray pick and related operators - DependencyManager::get()->setMouseRayPickID(DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared( - PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true))); + DependencyManager::get()->setMouseRayPickID( + DependencyManager::get() + ->addPick(PickQuery::Ray, + std::make_shared(PickFilter(PickScriptingInterface::PICK_ENTITIES() | + PickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), + 0.0f, true))); DependencyManager::get()->setMouseRayPickResultOperator([&](unsigned int rayPickID) { RayToEntityIntersectionResult entityResult; entityResult.intersects = false; @@ -2246,9 +2224,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get()->setSetPrecisionPickingOperator([&](unsigned int rayPickID, bool value) { DependencyManager::get()->setPrecisionPicking(rayPickID, value); }); - EntityTreeRenderer::setRenderDebugHullsOperator([] { - return Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls); - }); + EntityTreeRenderer::setRenderDebugHullsOperator( + [] { return Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls); }); // Preload Tablet sounds DependencyManager::get()->preloadSounds(); @@ -2307,10 +2284,10 @@ QString Application::getUserAgent() { return userAgent; } - QString userAgent = "Mozilla/5.0 (HighFidelityInterface/" + BuildInfo::VERSION + "; " - + QSysInfo::productType() + " " + QSysInfo::productVersion() + ")"; + QString userAgent = "Mozilla/5.0 (HighFidelityInterface/" + BuildInfo::VERSION + "; " + QSysInfo::productType() + " " + + QSysInfo::productVersion() + ")"; - auto formatPluginName = [](QString name) -> QString { return name.trimmed().replace(" ", "-"); }; + auto formatPluginName = [](QString name) -> QString { return name.trimmed().replace(" ", "-"); }; // For each plugin, add to userAgent auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); @@ -2319,7 +2296,7 @@ QString Application::getUserAgent() { userAgent += " " + formatPluginName(dp->getName()); } } - auto inputPlugins= PluginManager::getInstance()->getInputPlugins(); + auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); for (auto& ip : inputPlugins) { if (ip->isActive()) { userAgent += " " + formatPluginName(ip->getName()); @@ -2347,7 +2324,7 @@ void Application::checkChangeCursor() { QMutexLocker locker(&_changeCursorLock); if (_cursorNeedsChanging) { #ifdef Q_OS_MAC - auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget + 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 // window menu, which is a pain, so only hide it for the GL surface @@ -2379,19 +2356,18 @@ void Application::updateHeartbeat() const { void Application::onAboutToQuit() { emit beforeAboutToQuit(); - foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { + foreach (auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { if (inputPlugin->isActive()) { inputPlugin->deactivate(); } } - // The active display plugin needs to be loaded before the menu system is active, + // The active display plugin needs to be loaded before the menu system is active, // so its persisted explicitly here Setting::Handle{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME }.set(getActiveDisplayPlugin()->getName()); getActiveDisplayPlugin()->deactivate(); - if (_autoSwitchDisplayModeSupportedHMDPlugin - && _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { + if (_autoSwitchDisplayModeSupportedHMDPlugin && _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { _autoSwitchDisplayModeSupportedHMDPlugin->endSession(); } // use the CloseEventSender via a QThread to send an event that says the user asked for the app to close @@ -2417,7 +2393,7 @@ void Application::cleanupBeforeQuit() { tracer->serialize(outputFile); } - // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash. + // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash. #ifdef HAVE_DDE DependencyManager::get()->setEnabled(false); #endif @@ -2446,12 +2422,12 @@ void Application::cleanupBeforeQuit() { // tell the packet receiver we're shutting down, so it can drop packets nodeList->getPacketReceiver().setShouldDropPackets(true); - getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts + getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts // Clear any queued processing (I/O, FBX/OBJ/Texture parsing) QThreadPool::globalInstance()->clear(); - DependencyManager::get()->shutdownScripting(); // stop all currently running global scripts + DependencyManager::get()->shutdownScripting(); // stop all currently running global scripts DependencyManager::destroy(); _displayPlugin.reset(); @@ -2462,8 +2438,8 @@ void Application::cleanupBeforeQuit() { // The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual // removal of the items. // See https://highfidelity.fogbugz.com/f/cases/5328 - _main3DScene->enqueueFrame(); // flush all the transactions - _main3DScene->processTransactionQueue(); // process and apply deletions + _main3DScene->enqueueFrame(); // flush all the transactions + _main3DScene->processTransactionQueue(); // process and apply deletions // first stop all timers directly or by invokeMethod // depending on what thread they run in @@ -2619,12 +2595,12 @@ void Application::initializeGL() { // Create the GPU backend // Requires the window context, because that's what's used in the actual rendering - // and the GPU backend will make things like the VAO which cannot be shared across + // and the GPU backend will make things like the VAO which cannot be shared across // contexts _glWidget->makeCurrent(); gpu::Context::init(); qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK, - QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram))); + QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram))); _glWidget->makeCurrent(); _gpuContext = std::make_shared(); @@ -2634,7 +2610,9 @@ void Application::initializeGL() { _offscreenContext->makeCurrent(); } -static const QString SPLASH_SKYBOX{ "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" }; +static const QString SPLASH_SKYBOX{ + "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" +}; void Application::initializeDisplayPlugins() { auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); @@ -2642,20 +2620,20 @@ void Application::initializeDisplayPlugins() { auto lastActiveDisplayPluginName = activeDisplayPluginSetting.get(); auto defaultDisplayPlugin = displayPlugins.at(0); - // Once time initialization code + // Once time initialization code DisplayPluginPointer targetDisplayPlugin; - foreach(auto displayPlugin, displayPlugins) { + foreach (auto displayPlugin, displayPlugins) { displayPlugin->setContext(_gpuContext); if (displayPlugin->getName() == lastActiveDisplayPluginName) { targetDisplayPlugin = displayPlugin; } QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, - [this](const QSize& size) { resizeGL(); }); + [this](const QSize& size) { resizeGL(); }); QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset); } // The default display plugin needs to be activated first, otherwise the display plugin thread - // may be launched by an external plugin, which is bad + // may be launched by an external plugin, which is bad setDisplayPlugin(defaultDisplayPlugin); // Now set the desired plugin if it's not the same as the default plugin @@ -2719,7 +2697,8 @@ void Application::initializeRenderEngine() { #ifndef Q_OS_ANDROID _renderEngine->addJob("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED); #endif - _renderEngine->addJob("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0); + _renderEngine->addJob("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, + render::ItemKey::TAG_BITS_0); _renderEngine->load(); _renderEngine->registerScene(_main3DScene); @@ -2732,7 +2711,7 @@ extern void setupPreferences(); static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, bool active); void Application::initializeUi() { - // Build a shared canvas / context for the Chromium processes +// Build a shared canvas / context for the Chromium processes #if !defined(DISABLE_QML) // Chromium rendering uses some GL functions that prevent nSight from capturing // frames, so we only create the shared context if nsight is NOT active. @@ -2771,32 +2750,32 @@ void Application::initializeUi() { LoginDialog::registerType(); Tooltip::registerType(); UpdateDialog::registerType(); - QmlContextCallback callback = [](QQmlContext* context) { - context->setContextProperty("Commerce", new QmlCommerce()); - }; - OffscreenQmlSurface::addWhitelistContextHandler({ - QUrl{ "hifi/commerce/checkout/Checkout.qml" }, - QUrl{ "hifi/commerce/common/CommerceLightbox.qml" }, - QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, - QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" }, - QUrl{ "hifi/commerce/common/SortableListModel.qml" }, - QUrl{ "hifi/commerce/common/sendAsset/SendAsset.qml" }, - QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, - QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" }, - QUrl{ "hifi/commerce/purchases/Purchases.qml" }, - QUrl{ "hifi/commerce/wallet/Help.qml" }, - QUrl{ "hifi/commerce/wallet/NeedsLogIn.qml" }, - QUrl{ "hifi/commerce/wallet/PassphraseChange.qml" }, - QUrl{ "hifi/commerce/wallet/PassphraseModal.qml" }, - QUrl{ "hifi/commerce/wallet/PassphraseSelection.qml" }, - QUrl{ "hifi/commerce/wallet/Security.qml" }, - QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" }, - QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" }, - QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" }, - QUrl{ "hifi/commerce/wallet/Wallet.qml" }, - QUrl{ "hifi/commerce/wallet/WalletHome.qml" }, - QUrl{ "hifi/commerce/wallet/WalletSetup.qml" }, - }, callback); + QmlContextCallback callback = [](QQmlContext* context) { context->setContextProperty("Commerce", new QmlCommerce()); }; + OffscreenQmlSurface::addWhitelistContextHandler( + { + QUrl{ "hifi/commerce/checkout/Checkout.qml" }, + QUrl{ "hifi/commerce/common/CommerceLightbox.qml" }, + QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, + QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" }, + QUrl{ "hifi/commerce/common/SortableListModel.qml" }, + QUrl{ "hifi/commerce/common/sendAsset/SendAsset.qml" }, + QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, + QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" }, + QUrl{ "hifi/commerce/purchases/Purchases.qml" }, + QUrl{ "hifi/commerce/wallet/Help.qml" }, + QUrl{ "hifi/commerce/wallet/NeedsLogIn.qml" }, + QUrl{ "hifi/commerce/wallet/PassphraseChange.qml" }, + QUrl{ "hifi/commerce/wallet/PassphraseModal.qml" }, + QUrl{ "hifi/commerce/wallet/PassphraseSelection.qml" }, + QUrl{ "hifi/commerce/wallet/Security.qml" }, + QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" }, + QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" }, + QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" }, + QUrl{ "hifi/commerce/wallet/Wallet.qml" }, + QUrl{ "hifi/commerce/wallet/WalletHome.qml" }, + QUrl{ "hifi/commerce/wallet/WalletSetup.qml" }, + }, + callback); qmlRegisterType("Hifi", 1, 0, "ResourceImageItem"); qmlRegisterType("Hifi", 1, 0, "Preference"); qmlRegisterType("HifiWeb", 1, 0, "WebBrowserSuggestionsEngine"); @@ -2807,17 +2786,14 @@ void Application::initializeUi() { } auto offscreenUi = DependencyManager::get(); - connect(offscreenUi.data(), &hifi::qml::OffscreenSurface::rootContextCreated, - this, &Application::onDesktopRootContextCreated); - connect(offscreenUi.data(), &hifi::qml::OffscreenSurface::rootItemCreated, - this, &Application::onDesktopRootItemCreated); + connect(offscreenUi.data(), &hifi::qml::OffscreenSurface::rootContextCreated, this, + &Application::onDesktopRootContextCreated); + connect(offscreenUi.data(), &hifi::qml::OffscreenSurface::rootItemCreated, this, &Application::onDesktopRootItemCreated); offscreenUi->setProxyWindow(_window->windowHandle()); // OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to // support the window management and scripting proxies for VR use - DeadlockWatchdogThread::withPause([&] { - offscreenUi->createDesktop(PathUtils::qmlUrl("hifi/Desktop.qml")); - }); + DeadlockWatchdogThread::withPause([&] { offscreenUi->createDesktop(PathUtils::qmlUrl("hifi/Desktop.qml")); }); // FIXME either expose so that dialogs can set this themselves or // do better detection in the offscreen UI of what has focus offscreenUi->setNavigationFocused(false); @@ -2836,7 +2812,7 @@ void Application::initializeUi() { return result.toPoint(); }); offscreenUi->resume(); - connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r){ + connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r) { resizeGL(); if (_touchscreenVirtualPadDevice) { _touchscreenVirtualPadDevice->resize(); @@ -2845,7 +2821,7 @@ void Application::initializeUi() { // This will set up the input plugins UI _activeInputPlugins.clear(); - foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { + foreach (auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { if (KeyboardMouseDevice::NAME == inputPlugin->getName()) { _keyboardMouseDevice = std::dynamic_pointer_cast(inputPlugin); } @@ -2860,9 +2836,8 @@ void Application::initializeUi() { auto compositorHelper = DependencyManager::get(); connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, this, [=] { if (isHMDMode()) { - showCursor(compositorHelper->getAllowMouseCapture() ? - Cursor::Manager::lookupIcon(_preferredCursor.get()) : - Cursor::Icon::SYSTEM); + showCursor(compositorHelper->getAllowMouseCapture() ? Cursor::Manager::lookupIcon(_preferredCursor.get()) + : Cursor::Icon::SYSTEM); } }); @@ -2878,10 +2853,12 @@ void Application::initializeUi() { auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); // first sort the plugins into groupings: standard, advanced, developer std::stable_sort(displayPlugins.begin(), displayPlugins.end(), - [](const DisplayPluginPointer& a, const DisplayPluginPointer& b)->bool { return a->getGrouping() < b->getGrouping(); }); + [](const DisplayPluginPointer& a, const DisplayPluginPointer& b) -> bool { + return a->getGrouping() < b->getGrouping(); + }); // concatenate the groupings into a single list in the order: standard, advanced, developer - for(const auto& displayPlugin : displayPlugins) { + for (const auto& displayPlugin : displayPlugins) { addDisplayPluginToMenu(displayPlugin, _displayPlugin == displayPlugin); } @@ -2897,7 +2874,6 @@ void Application::initializeUi() { } } - void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { auto engine = surfaceContext->engine(); // in Qt 5.10.0 there is already an "Audio" object in the QML context @@ -2930,7 +2906,8 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("AvatarList", DependencyManager::get().data()); surfaceContext->setContextProperty("Users", DependencyManager::get().data()); - surfaceContext->setContextProperty("UserActivityLogger", DependencyManager::get().data()); + surfaceContext->setContextProperty("UserActivityLogger", + DependencyManager::get().data()); surfaceContext->setContextProperty("Camera", &_myCamera); @@ -2953,8 +2930,10 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("SoundCache", DependencyManager::get().data()); surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get().data()); - surfaceContext->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED - surfaceContext->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED + surfaceContext->setContextProperty("Account", + AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED + surfaceContext->setContextProperty("GlobalServices", + AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED surfaceContext->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance()); surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface); @@ -3007,20 +2986,17 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { // Using the latter will cause the camera to wobble with idle animations, // or with changes from the face tracker if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { - _thirdPersonHMDCameraBoomValid= false; + _thirdPersonHMDCameraBoomValid = false; if (isHMDMode()) { mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); _myCamera.setPosition(extractTranslation(camMat)); _myCamera.setOrientation(glmExtractRotation(camMat)); - } - else { + } else { _myCamera.setPosition(myAvatar->getDefaultEyePosition()); _myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation()); } - } - else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { if (isHMDMode()) { - if (!_thirdPersonHMDCameraBoomValid) { const glm::vec3 CAMERA_OFFSET = glm::vec3(0.0f, 0.0f, 0.7f); _thirdPersonHMDCameraBoom = cancelOutRollAndPitch(myAvatar->getHMDSensorOrientation()) * CAMERA_OFFSET; @@ -3029,32 +3005,29 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { glm::mat4 thirdPersonCameraSensorToWorldMatrix = myAvatar->getSensorToWorldMatrix(); - const glm::vec3 cameraPos = myAvatar->getHMDSensorPosition() + _thirdPersonHMDCameraBoom * myAvatar->getBoomLength(); + const glm::vec3 cameraPos = + myAvatar->getHMDSensorPosition() + _thirdPersonHMDCameraBoom * myAvatar->getBoomLength(); glm::mat4 sensorCameraMat = createMatFromQuatAndPos(myAvatar->getHMDSensorOrientation(), cameraPos); glm::mat4 worldCameraMat = thirdPersonCameraSensorToWorldMatrix * sensorCameraMat; _myCamera.setOrientation(glm::normalize(glmExtractRotation(worldCameraMat))); _myCamera.setPosition(extractTranslation(worldCameraMat)); - } - else { + } else { _thirdPersonHMDCameraBoomValid = false; _myCamera.setOrientation(myAvatar->getHead()->getOrientation()); if (isOptionChecked(MenuOption::CenterPlayerInView)) { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + _myCamera.getOrientation() * boomOffset); - } - else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + myAvatar->getWorldOrientation() * boomOffset); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + _myCamera.getOrientation() * boomOffset); + } else { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + myAvatar->getWorldOrientation() * boomOffset); } } - } - else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - _thirdPersonHMDCameraBoomValid= false; + } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + _thirdPersonHMDCameraBoomValid = false; if (isHMDMode()) { - auto mirrorBodyOrientation = myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _mirrorYawOffset, 0.0f)); + auto mirrorBodyOrientation = + myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _mirrorYawOffset, 0.0f)); glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); // Mirror HMD yaw and roll @@ -3071,26 +3044,24 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { // Mirror HMD lateral offsets hmdOffset.x = -hmdOffset.x; - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) - + mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror - + mirrorBodyOrientation * hmdOffset); - } - else { + _myCamera.setPosition( + myAvatar->getDefaultEyePosition() + glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) + + mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + + mirrorBodyOrientation * hmdOffset); + } else { auto userInputMapper = DependencyManager::get(); const float YAW_SPEED = TWO_PI / 5.0f; float deltaYaw = userInputMapper->getActionState(controller::Action::YAW) * YAW_SPEED * deltaTime; _mirrorYawOffset += deltaYaw; _myCamera.setOrientation(myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _mirrorYawOffset, 0.0f))); - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) - + (myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, _mirrorYawOffset, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * myAvatar->getBoomLength() * _scaleMirror); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) + + (myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, _mirrorYawOffset, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * myAvatar->getBoomLength() * _scaleMirror); } renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; - } - else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) { - _thirdPersonHMDCameraBoomValid= false; + } else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) { + _thirdPersonHMDCameraBoomValid = false; EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer(); if (cameraEntity != nullptr) { if (isHMDMode()) { @@ -3098,8 +3069,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { _myCamera.setOrientation(cameraEntity->getWorldOrientation() * hmdRotation); glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); _myCamera.setPosition(cameraEntity->getWorldPosition() + (hmdRotation * hmdOffset)); - } - else { + } else { _myCamera.setOrientation(cameraEntity->getWorldOrientation()); _myCamera.setPosition(cameraEntity->getWorldPosition()); } @@ -3119,7 +3089,6 @@ void Application::runTests() { } void Application::faceTrackerMuteToggled() { - QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteFaceTracking); Q_CHECK_PTR(muteAction); bool isMuted = getSelectedFaceTracker()->isMuted(); @@ -3225,8 +3194,8 @@ void Application::resizeGL() { // FIXME the aspect ratio for stereo displays is incorrect based on this. float aspectRatio = displayPlugin->getRecommendedAspectRatio(); - _myCamera.setProjection(glm::perspective(glm::radians(_fieldOfView.get()), aspectRatio, - DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); + _myCamera.setProjection( + glm::perspective(glm::radians(_fieldOfView.get()), aspectRatio, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); // Possible change in aspect ratio { QMutexLocker viewLocker(&_viewMutex); @@ -3241,14 +3210,12 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { bool sandboxIsRunning = SandboxUtils::readStatus(reply->readAll()); - enum HandControllerType { + enum HandControllerType + { Vive, Oculus }; - static const std::map MIN_CONTENT_VERSION = { - { Vive, 1 }, - { Oculus, 27 } - }; + static const std::map MIN_CONTENT_VERSION = { { Vive, 1 }, { Oculus, 27 } }; // Get sandbox content set version auto acDirPath = PathUtils::getAppDataPath() + "../../" + BuildInfo::MODIFIED_ORGANIZATION + "/assignment-client/"; @@ -3258,7 +3225,7 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { QFile contentVersionFile(contentVersionPath); if (contentVersionFile.open(QIODevice::ReadOnly | QIODevice::Text)) { QString line = contentVersionFile.readAll(); - contentVersion = line.toInt(); // returns 0 if conversion fails + contentVersion = line.toInt(); // returns 0 if conversion fails } // Get controller availability @@ -3274,7 +3241,8 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { Setting::Handle firstRun{ Settings::firstRun, true }; - qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers; + qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers + << ", Using HMD: " << isUsingHMDAndHandControllers; // when --url in command line, teleport to location const QString HIFI_URL_COMMAND_LINE_KEY = "--url"; @@ -3292,7 +3260,8 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { // If this is a first run we short-circuit the address passed in if (firstRun.get()) { #if defined(Q_OS_ANDROID) - qCDebug(interfaceapp) << "First run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("default location") : addressLookupString); + qCDebug(interfaceapp) << "First run... going to" + << qPrintable(addressLookupString.isEmpty() ? QString("default location") : addressLookupString); DependencyManager::get()->loadSettings(addressLookupString); #else DependencyManager::get()->goToEntry(); @@ -3301,27 +3270,27 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { firstRun.set(false); } else { - qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); + qCDebug(interfaceapp) << "Not first run... going to" + << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); DependencyManager::get()->loadSettings(addressLookupString); sentTo = SENT_TO_PREVIOUS_LOCATION; } - UserActivityLogger::getInstance().logAction("startup_sent_to", { - { "sent_to", sentTo }, - { "sandbox_is_running", sandboxIsRunning }, - { "has_hmd", hasHMD }, - { "has_hand_controllers", hasHandControllers }, - { "is_using_hmd", isUsingHMD }, - { "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers }, - { "content_version", contentVersion } - }); + UserActivityLogger::getInstance().logAction("startup_sent_to", + { { "sent_to", sentTo }, + { "sandbox_is_running", sandboxIsRunning }, + { "has_hmd", hasHMD }, + { "has_hand_controllers", hasHandControllers }, + { "is_using_hmd", isUsingHMD }, + { "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers }, + { "content_version", contentVersion } }); _connectionMonitor.init(); } bool Application::importJSONFromURL(const QString& urlString) { // we only load files that terminate in just .json (not .svo.json and not .ava.json) - QUrl jsonURL { urlString }; + QUrl jsonURL{ urlString }; emit svoImportRequested(urlString); return true; @@ -3395,7 +3364,6 @@ void Application::loadServerlessDomain(QUrl domainURL) { std::map namedPaths = tmpTree->getNamedPaths(); nodeList->getDomainHandler().connectedToServerless(namedPaths); - _fullSceneReceivedCounter++; } @@ -3427,19 +3395,18 @@ bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) { if (!_keyboardFocusedEntity.get().isInvalidID()) { switch (event->type()) { case QEvent::KeyPress: - case QEvent::KeyRelease: - { - auto eventHandler = getEntities()->getEventHandler(_keyboardFocusedEntity.get()); - if (eventHandler) { - event->setAccepted(false); - QCoreApplication::sendEvent(eventHandler, event); - if (event->isAccepted()) { - _lastAcceptedKeyPress = usecTimestampNow(); - return true; - } + case QEvent::KeyRelease: { + auto eventHandler = getEntities()->getEventHandler(_keyboardFocusedEntity.get()); + if (eventHandler) { + event->setAccepted(false); + QCoreApplication::sendEvent(eventHandler, event); + if (event->isAccepted()) { + _lastAcceptedKeyPress = usecTimestampNow(); + return true; } - break; } + break; + } default: break; } @@ -3449,18 +3416,17 @@ bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) { switch (event->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: { - // Only Web overlays can have focus. - auto overlay = std::dynamic_pointer_cast(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); - if (overlay && overlay->getEventHandler()) { - event->setAccepted(false); - QCoreApplication::sendEvent(overlay->getEventHandler(), event); - if (event->isAccepted()) { - _lastAcceptedKeyPress = usecTimestampNow(); - return true; - } + // Only Web overlays can have focus. + auto overlay = std::dynamic_pointer_cast(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); + if (overlay && overlay->getEventHandler()) { + event->setAccepted(false); + QCoreApplication::sendEvent(overlay->getEventHandler(), event); + if (event->isAccepted()) { + _lastAcceptedKeyPress = usecTimestampNow(); + return true; } } - break; + } break; default: break; @@ -3497,10 +3463,9 @@ static void dumpEventQueue(QThread* thread) { qDebug() << " " << type; } } -#endif // DEBUG_EVENT_QUEUE +#endif // DEBUG_EVENT_QUEUE bool Application::event(QEvent* event) { - if (!Menu::getInstance()) { return false; } @@ -3528,7 +3493,7 @@ bool Application::event(QEvent* event) { dumpEventQueue(QThread::currentThread()); } } -#endif // DEBUG_EVENT_QUEUE +#endif // DEBUG_EVENT_QUEUE _pendingIdleEvent.store(false); @@ -3589,7 +3554,6 @@ bool Application::event(QEvent* event) { } bool Application::eventFilter(QObject* object, QEvent* event) { - if (event->type() == QEvent::Leave) { getApplicationCompositor().handleLeaveEvent(); } @@ -3616,7 +3580,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _altPressed = event->key() == Qt::Key_Alt; _keysPressed.insert(event->key()); - _controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts + _controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isKeyCaptured(event)) { @@ -3753,7 +3717,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } else { showCursor(Cursor::Icon::DEFAULT); } - } else if (!event->isAutoRepeat()){ + } else if (!event->isAutoRepeat()) { resetSensors(true); } break; @@ -3873,7 +3837,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { openAndroidActivity("Home"); } #endif - _controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts + _controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isKeyCaptured(event)) { @@ -3887,7 +3851,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { void Application::focusOutEvent(QFocusEvent* event) { auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); - foreach(auto inputPlugin, inputPlugins) { + foreach (auto inputPlugin, inputPlugins) { if (inputPlugin->isActive()) { inputPlugin->pluginFocusOutEvent(); } @@ -3920,7 +3884,7 @@ void Application::maybeToggleMenuVisible(QMouseEvent* event) const { if (event->pos().y() <= MENU_TOGGLE_AREA) { menuBar->setVisible(true); } - } else { + } else { if (event->pos().y() > MENU_TOGGLE_AREA) { menuBar->setVisible(false); } @@ -3944,7 +3908,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { // compositor reticle // handleRealMouseMoveEvent() will return true, if we shouldn't process the event further if (!compositor.fakeEventActive() && compositor.handleRealMouseMoveEvent()) { - return; // bail + return; // bail } auto offscreenUi = DependencyManager::get(); @@ -3960,10 +3924,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { buttons |= Qt::LeftButton; } - QMouseEvent mappedEvent(event->type(), - transformedPos, - event->screenPos(), button, - buttons, event->modifiers()); + QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), button, buttons, event->modifiers()); if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() || getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_OVERLAY_ID) { @@ -3971,7 +3932,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { getEntities()->mouseMoveEvent(&mappedEvent); } - _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts + _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { @@ -3996,10 +3957,8 @@ void Application::mousePressEvent(QMouseEvent* event) { auto eventPosition = getApplicationCompositor().getMouseEventPosition(event); QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition); - QMouseEvent mappedEvent(event->type(), - transformedPos, - event->screenPos(), event->button(), - event->buttons(), event->modifiers()); + QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), + event->modifiers()); if (!_aboutToQuit) { getOverlays().mousePressEvent(&mappedEvent); @@ -4008,7 +3967,7 @@ void Application::mousePressEvent(QMouseEvent* event) { } } - _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts + _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { @@ -4026,10 +3985,8 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { auto offscreenUi = DependencyManager::get(); auto eventPosition = getApplicationCompositor().getMouseEventPosition(event); QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition); - QMouseEvent mappedEvent(event->type(), - transformedPos, - event->screenPos(), event->button(), - event->buttons(), event->modifiers()); + QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), + event->modifiers()); if (!_aboutToQuit) { getOverlays().mouseDoublePressEvent(&mappedEvent); @@ -4038,7 +3995,6 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { } } - // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; @@ -4048,21 +4004,18 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { } void Application::mouseReleaseEvent(QMouseEvent* event) { - auto offscreenUi = DependencyManager::get(); auto eventPosition = getApplicationCompositor().getMouseEventPosition(event); QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition); - QMouseEvent mappedEvent(event->type(), - transformedPos, - event->screenPos(), event->button(), - event->buttons(), event->modifiers()); + QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), + event->modifiers()); if (!_aboutToQuit) { getOverlays().mouseReleaseEvent(&mappedEvent); getEntities()->mouseReleaseEvent(&mappedEvent); } - _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts + _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { @@ -4081,7 +4034,7 @@ void Application::touchUpdateEvent(QTouchEvent* event) { if (event->type() == QEvent::TouchUpdate) { TouchEvent thisEvent(*event, _lastTouchEvent); - _controllerScriptingInterface->emitTouchUpdateEvent(thisEvent); // send events to any registered scripts + _controllerScriptingInterface->emitTouchUpdateEvent(thisEvent); // send events to any registered scripts _lastTouchEvent = thisEvent; } @@ -4103,10 +4056,10 @@ void Application::touchUpdateEvent(QTouchEvent* event) { void Application::touchBeginEvent(QTouchEvent* event) { _altPressed = false; - TouchEvent thisEvent(*event); // on touch begin, we don't compare to last event - _controllerScriptingInterface->emitTouchBeginEvent(thisEvent); // send events to any registered scripts + TouchEvent thisEvent(*event); // on touch begin, we don't compare to last event + _controllerScriptingInterface->emitTouchBeginEvent(thisEvent); // send events to any registered scripts - _lastTouchEvent = thisEvent; // and we reset our last event to this event before we call our update + _lastTouchEvent = thisEvent; // and we reset our last event to this event before we call our update touchUpdateEvent(event); // if one of our scripts have asked to capture this event, then stop processing it @@ -4123,13 +4076,12 @@ void Application::touchBeginEvent(QTouchEvent* event) { if (_touchscreenVirtualPadDevice && _touchscreenVirtualPadDevice->isActive()) { _touchscreenVirtualPadDevice->touchBeginEvent(event); } - } void Application::touchEndEvent(QTouchEvent* event) { _altPressed = false; TouchEvent thisEvent(*event, _lastTouchEvent); - _controllerScriptingInterface->emitTouchEndEvent(thisEvent); // send events to any registered scripts + _controllerScriptingInterface->emitTouchEndEvent(thisEvent); // send events to any registered scripts _lastTouchEvent = thisEvent; // if one of our scripts have asked to capture this event, then stop processing it @@ -4160,7 +4112,7 @@ void Application::touchGestureEvent(QGestureEvent* event) { void Application::wheelEvent(QWheelEvent* event) const { _altPressed = false; - _controllerScriptingInterface->emitWheelEvent(event); // send events to any registered scripts + _controllerScriptingInterface->emitWheelEvent(event); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isWheelCaptured()) { @@ -4172,7 +4124,7 @@ void Application::wheelEvent(QWheelEvent* event) const { } } -void Application::dropEvent(QDropEvent *event) { +void Application::dropEvent(QDropEvent* event) { const QMimeData* mimeData = event->mimeData(); for (auto& url : mimeData->urls()) { QString urlString = url.toString(); @@ -4198,20 +4150,19 @@ bool Application::acceptSnapshot(const QString& urlString) { DependencyManager::get()->handleLookupString(snapshotData->getURL().toString()); } } else { - OffscreenUi::asyncWarning("", "No location details were found in the file\n" + - snapshotPath + "\nTry dragging in an authentic Hifi snapshot."); + OffscreenUi::asyncWarning("", "No location details were found in the file\n" + snapshotPath + + "\nTry dragging in an authentic Hifi snapshot."); } return true; } -static uint32_t _renderedFrameIndex { INVALID_FRAME }; +static uint32_t _renderedFrameIndex{ INVALID_FRAME }; bool Application::shouldPaint() const { if (_aboutToQuit) { return false; } - auto displayPlugin = getActiveDisplayPlugin(); #ifdef DEBUG_PAINT_DELAY @@ -4222,9 +4173,8 @@ bool Application::shouldPaint() const { static const int PAINT_DELAY_THROTTLE = 1000; if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) { - qCDebug(interfaceapp).nospace() << - "Paint delay (" << paintDelaySamples << " samples): " << - (float)paintDelaySamples / paintDelayUsecs << "us"; + qCDebug(interfaceapp).nospace() << "Paint delay (" << paintDelaySamples + << " samples): " << (float)paintDelaySamples / paintDelayUsecs << "us"; } #endif @@ -4246,41 +4196,39 @@ bool Application::shouldPaint() const { #pragma comment(lib, "ntdll.lib") extern "C" { - enum SYSTEM_INFORMATION_CLASS { - SystemBasicInformation = 0, - SystemProcessorPerformanceInformation = 8, - }; +enum SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation = 0, + SystemProcessorPerformanceInformation = 8, +}; - struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { - LARGE_INTEGER IdleTime; - LARGE_INTEGER KernelTime; - LARGE_INTEGER UserTime; - LARGE_INTEGER DpcTime; - LARGE_INTEGER InterruptTime; - ULONG InterruptCount; - }; +struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +}; - struct SYSTEM_BASIC_INFORMATION { - ULONG Reserved; - ULONG TimerResolution; - ULONG PageSize; - ULONG NumberOfPhysicalPages; - ULONG LowestPhysicalPageNumber; - ULONG HighestPhysicalPageNumber; - ULONG AllocationGranularity; - ULONG_PTR MinimumUserModeAddress; - ULONG_PTR MaximumUserModeAddress; - ULONG_PTR ActiveProcessorsAffinityMask; - CCHAR NumberOfProcessors; - }; - - NTSYSCALLAPI NTSTATUS NTAPI NtQuerySystemInformation( - _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, - _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, - _In_ ULONG SystemInformationLength, - _Out_opt_ PULONG ReturnLength - ); +struct SYSTEM_BASIC_INFORMATION { + ULONG Reserved; + ULONG TimerResolution; + ULONG PageSize; + ULONG NumberOfPhysicalPages; + ULONG LowestPhysicalPageNumber; + ULONG HighestPhysicalPageNumber; + ULONG AllocationGranularity; + ULONG_PTR MinimumUserModeAddress; + ULONG_PTR MaximumUserModeAddress; + ULONG_PTR ActiveProcessorsAffinityMask; + CCHAR NumberOfProcessors; +}; +NTSYSCALLAPI NTSTATUS NTAPI NtQuerySystemInformation(_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, + _Out_opt_ PULONG ReturnLength); } template NTSTATUS NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, T& t) { @@ -4292,7 +4240,6 @@ NTSTATUS NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClas return NtQuerySystemInformation(SystemInformationClass, t.data(), (ULONG)(sizeof(T) * t.size()), nullptr); } - template void updateValueAndDelta(std::pair& pair, T newValue) { auto& value = pair.first; @@ -4304,11 +4251,11 @@ void updateValueAndDelta(std::pair& pair, T newValue) { struct MyCpuInfo { using ValueAndDelta = std::pair; std::string name; - ValueAndDelta kernel { 0, 0 }; - ValueAndDelta user { 0, 0 }; - ValueAndDelta idle { 0, 0 }; - float kernelUsage { 0.0f }; - float userUsage { 0.0f }; + ValueAndDelta kernel{ 0, 0 }; + ValueAndDelta user{ 0, 0 }; + ValueAndDelta idle{ 0, 0 }; + float kernelUsage{ 0.0f }; + float userUsage{ 0.0f }; void update(const SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION& cpuInfo) { updateValueAndDelta(kernel, cpuInfo.KernelTime.QuadPart); @@ -4326,13 +4273,13 @@ struct MyCpuInfo { void updateCpuInformation() { static std::once_flag once; - static SYSTEM_BASIC_INFORMATION systemInfo {}; + static SYSTEM_BASIC_INFORMATION systemInfo{}; static SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuTotals; static std::vector cpuInfos; static std::vector myCpuInfos; static MyCpuInfo myCpuTotals; std::call_once(once, [&] { - NtQuerySystemInformation( SystemBasicInformation, systemInfo); + NtQuerySystemInformation(SystemBasicInformation, systemInfo); cpuInfos.resize(systemInfo.NumberOfProcessors); myCpuInfos.resize(systemInfo.NumberOfProcessors); for (size_t i = 0; i < systemInfo.NumberOfProcessors; ++i) { @@ -4357,20 +4304,14 @@ void updateCpuInformation() { // Update friendly structure auto& myCpuInfo = myCpuInfos[i]; myCpuInfo.update(cpuInfo); - PROFILE_COUNTER(app, myCpuInfo.name.c_str(), { - { "kernel", myCpuInfo.kernelUsage }, - { "user", myCpuInfo.userUsage } - }); + PROFILE_COUNTER(app, myCpuInfo.name.c_str(), { { "kernel", myCpuInfo.kernelUsage }, { "user", myCpuInfo.userUsage } }); } myCpuTotals.update(cpuTotals); - PROFILE_COUNTER(app, myCpuTotals.name.c_str(), { - { "kernel", myCpuTotals.kernelUsage }, - { "user", myCpuTotals.userUsage } - }); + PROFILE_COUNTER(app, myCpuTotals.name.c_str(), + { { "kernel", myCpuTotals.kernelUsage }, { "user", myCpuTotals.userUsage } }); } - static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU; static int numProcessors; static HANDLE self; @@ -4491,8 +4432,10 @@ void Application::idle() { PROFILE_COUNTER_IF_CHANGED(app, "renderLoopRate", float, _renderLoopCounter.rate()); PROFILE_COUNTER_IF_CHANGED(app, "currentDownloads", int, ResourceCache::getLoadingRequests().length()); PROFILE_COUNTER_IF_CHANGED(app, "pendingDownloads", int, ResourceCache::getPendingRequestCount()); - PROFILE_COUNTER_IF_CHANGED(app, "currentProcessing", int, DependencyManager::get()->getStat("Processing").toInt()); - PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, DependencyManager::get()->getStat("PendingProcessing").toInt()); + PROFILE_COUNTER_IF_CHANGED(app, "currentProcessing", int, + DependencyManager::get()->getStat("Processing").toInt()); + PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, + DependencyManager::get()->getStat("PendingProcessing").toInt()); auto renderConfig = _renderEngine->getConfiguration(); PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_gpuContext->getFrameTimerGPUAverage()); auto opaqueRangeTimer = renderConfig->getConfig("OpaqueRangeTimer"); @@ -4501,13 +4444,12 @@ void Application::idle() { auto renderDeferred = renderConfig->getConfig("RenderDeferred"); auto toneAndPostRangeTimer = renderConfig->getConfig("ToneAndPostRangeTimer"); - PROFILE_COUNTER(render_detail, "gpuTimes", { - { "OpaqueRangeTimer", opaqueRangeTimer ? opaqueRangeTimer->property("gpuRunTime") : 0 }, - { "LinearDepth", linearDepth ? linearDepth->property("gpuRunTime") : 0 }, - { "SurfaceGeometry", surfaceGeometry ? surfaceGeometry->property("gpuRunTime") : 0 }, - { "RenderDeferred", renderDeferred ? renderDeferred->property("gpuRunTime") : 0 }, - { "ToneAndPostRangeTimer", toneAndPostRangeTimer ? toneAndPostRangeTimer->property("gpuRunTime") : 0 } - }); + PROFILE_COUNTER(render_detail, "gpuTimes", + { { "OpaqueRangeTimer", opaqueRangeTimer ? opaqueRangeTimer->property("gpuRunTime") : 0 }, + { "LinearDepth", linearDepth ? linearDepth->property("gpuRunTime") : 0 }, + { "SurfaceGeometry", surfaceGeometry ? surfaceGeometry->property("gpuRunTime") : 0 }, + { "RenderDeferred", renderDeferred ? renderDeferred->property("gpuRunTime") : 0 }, + { "ToneAndPostRangeTimer", toneAndPostRangeTimer ? toneAndPostRangeTimer->property("gpuRunTime") : 0 } }); PROFILE_RANGE(app, __FUNCTION__); @@ -4547,11 +4489,10 @@ void Application::idle() { update(glm::clamp(secondsSinceLastUpdate, 0.0f, BIGGEST_DELTA_TIME_SECS)); } - // Update focus highlight for entity or overlay. { if (!_keyboardFocusedEntity.get().isInvalidID() || _keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) { - const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus + const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress; if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) { setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); @@ -4582,7 +4523,7 @@ void Application::idle() { PerformanceWarning warn(showWarnings, "Application::idle()... pluginIdle()"); getActiveDisplayPlugin()->idle(); auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); - foreach(auto inputPlugin, inputPlugins) { + foreach (auto inputPlugin, inputPlugins) { if (inputPlugin->isActive()) { inputPlugin->idle(); } @@ -4691,7 +4632,7 @@ bool Application::exportEntities(const QString& filename, glm::vec3 root(TREE_SCALE, TREE_SCALE, TREE_SCALE); bool success = true; entityTree->withReadLock([&] { - for (auto entityID : entityIDs) { // Gather entities and properties. + for (auto entityID : entityIDs) { // Gather entities and properties. auto entityItem = entityTree->findEntityByEntityItemID(entityID); if (!entityItem) { qCWarning(interfaceapp) << "Skipping export of" << entityID << "that is not in scene."; @@ -4701,8 +4642,7 @@ bool Application::exportEntities(const QString& filename, if (!givenOffset) { EntityItemID parentID = entityItem->getParentID(); bool parentIsAvatar = (parentID == AVATAR_SELF_ID || parentID == myAvatarID); - if (!parentIsAvatar && (parentID.isInvalidID() || - !entityIDs.contains(parentID) || + if (!parentIsAvatar && (parentID.isInvalidID() || !entityIDs.contains(parentID) || !entityTree->findEntityByEntityItemID(parentID))) { // If parent wasn't selected, we want absolute position, which isn't in properties. auto position = entityItem->getWorldPosition(); @@ -4733,7 +4673,7 @@ bool Application::exportEntities(const QString& filename, properties.setPosition(properties.getPosition() - root); } else if (!entities.contains(parentID)) { entityDatum->globalizeProperties(properties, "Parent %3 of %2 %1 is not selected for export.", -root); - } // else valid parent -- don't offset + } // else valid parent -- don't offset } exportTree->addEntity(entityDatum->getEntityItemID(), properties); } @@ -4757,16 +4697,13 @@ bool Application::exportEntities(const QString& filename, float x, float y, floa auto entityTree = getEntities()->getTree(); entityTree->withReadLock([&] { entityTree->findEntities(boundingCube, entities); - foreach(EntityItemPointer entity, entities) { - ids << entity->getEntityItemID(); - } + foreach (EntityItemPointer entity, entities) { ids << entity->getEntityItemID(); } }); return exportEntities(filename, ids, ¢er); } void Application::loadSettings() { - - sessionRunTime.set(0); // Just clean living. We're about to saveSettings, which will update value. + sessionRunTime.set(0); // Just clean living. We're about to saveSettings, which will update value. DependencyManager::get()->loadSettings(); DependencyManager::get()->loadSettings(); @@ -4790,7 +4727,7 @@ void Application::loadSettings() { } } - Setting::Handle firstRun { Settings::firstRun, true }; + Setting::Handle firstRun{ Settings::firstRun, true }; bool isFirstPerson = false; if (firstRun.get()) { // If this is our first run, and no preferred devices were set, default to @@ -4886,7 +4823,6 @@ void Application::init() { } } - qCDebug(interfaceapp) << "Loaded settings"; // fire off an immediate domain-server check in now that settings are loaded @@ -4921,23 +4857,27 @@ void Application::init() { auto entityScriptingInterface = DependencyManager::get(); // connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts - connect(_entitySimulation.get(), &PhysicalEntitySimulation::entityCollisionWithEntity, - getEntities().data(), &EntityTreeRenderer::entityCollisionWithEntity); + connect(_entitySimulation.get(), &PhysicalEntitySimulation::entityCollisionWithEntity, getEntities().data(), + &EntityTreeRenderer::entityCollisionWithEntity); // connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing // of events related clicking, hovering over, and entering entities getEntities()->connectSignalsToSlots(entityScriptingInterface.data()); // Make sure any new sounds are loaded as soon as know about them. - connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) { - getEntities()->setCollisionSound(id, DependencyManager::get()->getSound(newURL)); - }, Qt::QueuedConnection); - connect(getMyAvatar().get(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) { - if (auto avatar = getMyAvatar()) { - auto sound = DependencyManager::get()->getSound(newURL); - avatar->setCollisionSound(sound); - } - }, Qt::QueuedConnection); + connect(tree.get(), &EntityTree::newCollisionSoundURL, this, + [this](QUrl newURL, EntityItemID id) { + getEntities()->setCollisionSound(id, DependencyManager::get()->getSound(newURL)); + }, + Qt::QueuedConnection); + connect(getMyAvatar().get(), &MyAvatar::newCollisionSoundURL, this, + [this](QUrl newURL) { + if (auto avatar = getMyAvatar()) { + auto sound = DependencyManager::get()->getSound(newURL); + avatar->setCollisionSound(sound); + } + }, + Qt::QueuedConnection); } void Application::loadAvatarScripts(const QVector& urls) { @@ -5014,8 +4954,8 @@ void Application::updateMyAvatarLookAtPosition() { glm::quat hmdRotation = glm::quat_cast(headPose); lookAtSpot = _myCamera.getPosition() + myAvatar->getWorldOrientation() * (hmdRotation * lookAtPosition); } else { - lookAtSpot = myAvatar->getHead()->getEyePosition() - + (myAvatar->getHead()->getFinalOrientationInWorldFrame() * lookAtPosition); + lookAtSpot = myAvatar->getHead()->getEyePosition() + + (myAvatar->getHead()->getFinalOrientationInWorldFrame() * lookAtPosition); } } else { AvatarSharedPointer lookingAt = myAvatar->getLookAtTargetAvatar().lock(); @@ -5029,14 +4969,14 @@ void Application::updateMyAvatarLookAtPosition() { const float MAXIMUM_FACE_ANGLE = 65.0f * RADIANS_PER_DEGREE; glm::vec3 lookingAtFaceOrientation = lookingAtHead->getFinalOrientationInWorldFrame() * IDENTITY_FORWARD; - glm::vec3 fromLookingAtToMe = glm::normalize(myAvatar->getHead()->getEyePosition() - - lookingAtHead->getEyePosition()); + glm::vec3 fromLookingAtToMe = + glm::normalize(myAvatar->getHead()->getEyePosition() - lookingAtHead->getEyePosition()); float faceAngle = glm::angle(lookingAtFaceOrientation, fromLookingAtToMe); if (faceAngle < MAXIMUM_FACE_ANGLE) { // Randomly look back and forth between look targets - eyeContactTarget target = Menu::getInstance()->isOptionChecked(MenuOption::FixGaze) ? - LEFT_EYE : myAvatar->getEyeContactTarget(); + eyeContactTarget target = + Menu::getInstance()->isOptionChecked(MenuOption::FixGaze) ? LEFT_EYE : myAvatar->getEyeContactTarget(); switch (target) { case LEFT_EYE: lookAtSpot = lookingAtHead->getLeftEyePosition(); @@ -5059,7 +4999,7 @@ void Application::updateMyAvatarLookAtPosition() { lookAtSpot = transformPoint(headPose.getMatrix(), glm::vec3(0.0f, 0.0f, TREE_SCALE)); } else { lookAtSpot = myAvatar->getHead()->getEyePosition() + - (myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE)); + (myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE)); } } @@ -5073,9 +5013,9 @@ void Application::updateMyAvatarLookAtPosition() { if (isLookingAtSomeone) { deflection *= GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT; } - lookAtSpot = origin + _myCamera.getOrientation() * glm::quat(glm::radians(glm::vec3( - eyePitch * deflection, eyeYaw * deflection, 0.0f))) * - glm::inverse(_myCamera.getOrientation()) * (lookAtSpot - origin); + lookAtSpot = origin + _myCamera.getOrientation() * + glm::quat(glm::radians(glm::vec3(eyePitch * deflection, eyeYaw * deflection, 0.0f))) * + glm::inverse(_myCamera.getOrientation()) * (lookAtSpot - origin); } } @@ -5111,17 +5051,14 @@ void Application::centerUI() { void Application::cycleCamera() { auto menu = Menu::getInstance(); if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { - menu->setIsOptionChecked(MenuOption::FullscreenMirror, false); menu->setIsOptionChecked(MenuOption::FirstPerson, true); } else if (menu->isOptionChecked(MenuOption::FirstPerson)) { - menu->setIsOptionChecked(MenuOption::FirstPerson, false); menu->setIsOptionChecked(MenuOption::ThirdPerson, true); } else if (menu->isOptionChecked(MenuOption::ThirdPerson)) { - menu->setIsOptionChecked(MenuOption::ThirdPerson, false); menu->setIsOptionChecked(MenuOption::FullscreenMirror, true); @@ -5129,7 +5066,7 @@ void Application::cycleCamera() { // do nothing if in independent or camera entity modes return; } - cameraMenuChanged(); // handle the menu change + cameraMenuChanged(); // handle the menu change } void Application::cameraModeChanged() { @@ -5155,14 +5092,13 @@ void Application::cameraModeChanged() { cameraMenuChanged(); } - void Application::cameraMenuChanged() { auto menu = Menu::getInstance(); if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { if (!isHMDMode() && _myCamera.getMode() != CAMERA_MODE_MIRROR) { _mirrorYawOffset = 0.0f; _myCamera.setMode(CAMERA_MODE_MIRROR); - getMyAvatar()->reset(false, false, false); // to reset any active MyAvatar::FollowHelpers + getMyAvatar()->reset(false, false, false); // to reset any active MyAvatar::FollowHelpers getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT); } } else if (menu->isOptionChecked(MenuOption::FirstPerson)) { @@ -5198,7 +5134,6 @@ void Application::resetPhysicsReadyInformation() { _physicsEnabled = false; } - void Application::reloadResourceCaches() { resetPhysicsReadyInformation(); @@ -5269,7 +5204,6 @@ void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) { auto entityScriptingInterface = DependencyManager::get(); auto properties = entityScriptingInterface->getEntityProperties(entityItemID); if (!properties.getLocked() && properties.getVisible()) { - auto entities = getEntities(); auto entityId = _keyboardFocusedEntity.get(); if (entities->wantsKeyboardFocus(entityId)) { @@ -5281,7 +5215,7 @@ void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) { _lastAcceptedKeyPress = usecTimestampNow(); setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(), - entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR); + entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR); } } } @@ -5317,7 +5251,8 @@ void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) { if (overlay->getProperty("showKeyboardFocusHighlight").toBool()) { auto size = overlay->getSize() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR; const float OVERLAY_DEPTH = 0.0105f; - setKeyboardFocusHighlight(overlay->getWorldPosition(), overlay->getWorldOrientation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH)); + setKeyboardFocusHighlight(overlay->getWorldPosition(), overlay->getWorldOrientation(), + glm::vec3(size.x, size.y, OVERLAY_DEPTH)); } else if (_keyboardFocusHighlight) { _keyboardFocusHighlight->setVisible(false); } @@ -5370,8 +5305,8 @@ void Application::updateSecondaryCameraViewFrustum() { // get mirror camera position by reflecting main camera position's z coordinate in mirror space glm::vec3 mainCameraPositionWorld = getCamera().getPosition(); glm::vec3 mainCameraPositionMirror = vec3(mirrorFromWorld * vec4(mainCameraPositionWorld, 1.0f)); - glm::vec3 mirrorCameraPositionMirror = vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, - -mainCameraPositionMirror.z); + glm::vec3 mirrorCameraPositionMirror = + vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, -mainCameraPositionMirror.z); glm::vec3 mirrorCameraPositionWorld = vec3(worldFromMirror * vec4(mirrorCameraPositionMirror, 1.0f)); // set frustum position to be mirrored camera and set orientation to mirror's adjusted rotation @@ -5383,7 +5318,8 @@ void Application::updateSecondaryCameraViewFrustum() { float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; - glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, camera->farClipPlaneDistance); + glm::mat4 frustum = + glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, camera->farClipPlaneDistance); secondaryViewFrustum.setProjection(frustum); } else { if (!camera->attachedEntityId.isNull()) { @@ -5397,10 +5333,8 @@ void Application::updateSecondaryCameraViewFrustum() { } float aspectRatio = (float)camera->textureWidth / (float)camera->textureHeight; - secondaryViewFrustum.setProjection(camera->vFoV, - aspectRatio, - camera->nearClipPlaneDistance, - camera->farClipPlaneDistance); + secondaryViewFrustum.setProjection(camera->vFoV, aspectRatio, camera->nearClipPlaneDistance, + camera->farClipPlaneDistance); } // Without calculating the bound planes, the secondary camera will use the same culling frustum as the main camera, // which is not what we want here. @@ -5425,7 +5359,8 @@ void Application::update(float deltaTime) { quint64 now = usecTimestampNow(); const int PHYSICS_CHECK_TIMEOUT = 2 * USECS_PER_SECOND; - if (now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT || _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) { + if (now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT || + _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) { // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway _lastPhysicsCheckTime = now; _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter; @@ -5464,8 +5399,8 @@ void Application::update(float deltaTime) { Menu* menu = Menu::getInstance(); auto audioClient = DependencyManager::get(); if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !audioClient->isMuted()) { - if (_lastFaceTrackerUpdate > 0 - && ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) { + if (_lastFaceTrackerUpdate > 0 && + ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) { audioClient->setMuted(true); _lastFaceTrackerUpdate = 0; } @@ -5479,21 +5414,20 @@ void Application::update(float deltaTime) { auto userInputMapper = DependencyManager::get(); - controller::InputCalibrationData calibrationData = { - myAvatar->getSensorToWorldMatrix(), - createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition()), - myAvatar->getHMDSensorMatrix(), - myAvatar->getCenterEyeCalibrationMat(), - myAvatar->getHeadCalibrationMat(), - myAvatar->getSpine2CalibrationMat(), - myAvatar->getHipsCalibrationMat(), - myAvatar->getLeftFootCalibrationMat(), - myAvatar->getRightFootCalibrationMat(), - myAvatar->getRightArmCalibrationMat(), - myAvatar->getLeftArmCalibrationMat(), - myAvatar->getRightHandCalibrationMat(), - myAvatar->getLeftHandCalibrationMat() - }; + controller::InputCalibrationData calibrationData = + { myAvatar->getSensorToWorldMatrix(), + createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition()), + myAvatar->getHMDSensorMatrix(), + myAvatar->getCenterEyeCalibrationMat(), + myAvatar->getHeadCalibrationMat(), + myAvatar->getSpine2CalibrationMat(), + myAvatar->getHipsCalibrationMat(), + myAvatar->getLeftFootCalibrationMat(), + myAvatar->getRightFootCalibrationMat(), + myAvatar->getRightArmCalibrationMat(), + myAvatar->getLeftArmCalibrationMat(), + myAvatar->getRightHandCalibrationMat(), + myAvatar->getLeftHandCalibrationMat() }; InputPluginPointer keyboardMousePlugin; for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) { @@ -5516,80 +5450,80 @@ void Application::update(float deltaTime) { myAvatar->clearDriveKeys(); if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) { if (!_controllerScriptingInterface->areActionsCaptured() && _myCamera.getMode() != CAMERA_MODE_MIRROR) { - myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z)); + myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, + -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z)); myAvatar->setDriveKey(MyAvatar::TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y)); myAvatar->setDriveKey(MyAvatar::TRANSLATE_X, userInputMapper->getActionState(controller::Action::TRANSLATE_X)); if (deltaTime > FLT_EPSILON) { myAvatar->setDriveKey(MyAvatar::PITCH, -1.0f * userInputMapper->getActionState(controller::Action::PITCH)); myAvatar->setDriveKey(MyAvatar::YAW, -1.0f * userInputMapper->getActionState(controller::Action::YAW)); - myAvatar->setDriveKey(MyAvatar::STEP_YAW, -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW)); + myAvatar->setDriveKey(MyAvatar::STEP_YAW, + -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW)); } } myAvatar->setDriveKey(MyAvatar::ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z)); } myAvatar->setSprintMode((bool)userInputMapper->getActionState(controller::Action::SPRINT)); - static const std::vector avatarControllerActions = { - controller::Action::LEFT_HAND, - controller::Action::RIGHT_HAND, - controller::Action::LEFT_FOOT, - controller::Action::RIGHT_FOOT, - controller::Action::HIPS, - controller::Action::SPINE2, - controller::Action::HEAD, - controller::Action::LEFT_HAND_THUMB1, - controller::Action::LEFT_HAND_THUMB2, - controller::Action::LEFT_HAND_THUMB3, - controller::Action::LEFT_HAND_THUMB4, - controller::Action::LEFT_HAND_INDEX1, - controller::Action::LEFT_HAND_INDEX2, - controller::Action::LEFT_HAND_INDEX3, - controller::Action::LEFT_HAND_INDEX4, - controller::Action::LEFT_HAND_MIDDLE1, - controller::Action::LEFT_HAND_MIDDLE2, - controller::Action::LEFT_HAND_MIDDLE3, - controller::Action::LEFT_HAND_MIDDLE4, - controller::Action::LEFT_HAND_RING1, - controller::Action::LEFT_HAND_RING2, - controller::Action::LEFT_HAND_RING3, - controller::Action::LEFT_HAND_RING4, - controller::Action::LEFT_HAND_PINKY1, - controller::Action::LEFT_HAND_PINKY2, - controller::Action::LEFT_HAND_PINKY3, - controller::Action::LEFT_HAND_PINKY4, - controller::Action::RIGHT_HAND_THUMB1, - controller::Action::RIGHT_HAND_THUMB2, - controller::Action::RIGHT_HAND_THUMB3, - controller::Action::RIGHT_HAND_THUMB4, - controller::Action::RIGHT_HAND_INDEX1, - controller::Action::RIGHT_HAND_INDEX2, - controller::Action::RIGHT_HAND_INDEX3, - controller::Action::RIGHT_HAND_INDEX4, - controller::Action::RIGHT_HAND_MIDDLE1, - controller::Action::RIGHT_HAND_MIDDLE2, - controller::Action::RIGHT_HAND_MIDDLE3, - controller::Action::RIGHT_HAND_MIDDLE4, - controller::Action::RIGHT_HAND_RING1, - controller::Action::RIGHT_HAND_RING2, - controller::Action::RIGHT_HAND_RING3, - controller::Action::RIGHT_HAND_RING4, - controller::Action::RIGHT_HAND_PINKY1, - controller::Action::RIGHT_HAND_PINKY2, - controller::Action::RIGHT_HAND_PINKY3, - controller::Action::RIGHT_HAND_PINKY4, - controller::Action::LEFT_ARM, - controller::Action::RIGHT_ARM, - controller::Action::LEFT_SHOULDER, - controller::Action::RIGHT_SHOULDER, - controller::Action::LEFT_FORE_ARM, - controller::Action::RIGHT_FORE_ARM, - controller::Action::LEFT_LEG, - controller::Action::RIGHT_LEG, - controller::Action::LEFT_UP_LEG, - controller::Action::RIGHT_UP_LEG, - controller::Action::LEFT_TOE_BASE, - controller::Action::RIGHT_TOE_BASE - }; + static const std::vector avatarControllerActions = { controller::Action::LEFT_HAND, + controller::Action::RIGHT_HAND, + controller::Action::LEFT_FOOT, + controller::Action::RIGHT_FOOT, + controller::Action::HIPS, + controller::Action::SPINE2, + controller::Action::HEAD, + controller::Action::LEFT_HAND_THUMB1, + controller::Action::LEFT_HAND_THUMB2, + controller::Action::LEFT_HAND_THUMB3, + controller::Action::LEFT_HAND_THUMB4, + controller::Action::LEFT_HAND_INDEX1, + controller::Action::LEFT_HAND_INDEX2, + controller::Action::LEFT_HAND_INDEX3, + controller::Action::LEFT_HAND_INDEX4, + controller::Action::LEFT_HAND_MIDDLE1, + controller::Action::LEFT_HAND_MIDDLE2, + controller::Action::LEFT_HAND_MIDDLE3, + controller::Action::LEFT_HAND_MIDDLE4, + controller::Action::LEFT_HAND_RING1, + controller::Action::LEFT_HAND_RING2, + controller::Action::LEFT_HAND_RING3, + controller::Action::LEFT_HAND_RING4, + controller::Action::LEFT_HAND_PINKY1, + controller::Action::LEFT_HAND_PINKY2, + controller::Action::LEFT_HAND_PINKY3, + controller::Action::LEFT_HAND_PINKY4, + controller::Action::RIGHT_HAND_THUMB1, + controller::Action::RIGHT_HAND_THUMB2, + controller::Action::RIGHT_HAND_THUMB3, + controller::Action::RIGHT_HAND_THUMB4, + controller::Action::RIGHT_HAND_INDEX1, + controller::Action::RIGHT_HAND_INDEX2, + controller::Action::RIGHT_HAND_INDEX3, + controller::Action::RIGHT_HAND_INDEX4, + controller::Action::RIGHT_HAND_MIDDLE1, + controller::Action::RIGHT_HAND_MIDDLE2, + controller::Action::RIGHT_HAND_MIDDLE3, + controller::Action::RIGHT_HAND_MIDDLE4, + controller::Action::RIGHT_HAND_RING1, + controller::Action::RIGHT_HAND_RING2, + controller::Action::RIGHT_HAND_RING3, + controller::Action::RIGHT_HAND_RING4, + controller::Action::RIGHT_HAND_PINKY1, + controller::Action::RIGHT_HAND_PINKY2, + controller::Action::RIGHT_HAND_PINKY3, + controller::Action::RIGHT_HAND_PINKY4, + controller::Action::LEFT_ARM, + controller::Action::RIGHT_ARM, + controller::Action::LEFT_SHOULDER, + controller::Action::RIGHT_SHOULDER, + controller::Action::LEFT_FORE_ARM, + controller::Action::RIGHT_FORE_ARM, + controller::Action::LEFT_LEG, + controller::Action::RIGHT_LEG, + controller::Action::LEFT_UP_LEG, + controller::Action::RIGHT_UP_LEG, + controller::Action::LEFT_TOE_BASE, + controller::Action::RIGHT_TOE_BASE }; // copy controller poses from userInputMapper to myAvatar. glm::mat4 myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition()); @@ -5601,8 +5535,8 @@ void Application::update(float deltaTime) { } } - updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... - updateDialogs(deltaTime); // update various stats dialogs if present + updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... + updateDialogs(deltaTime); // update various stats dialogs if present QSharedPointer avatarManager = DependencyManager::get(); @@ -5641,16 +5575,12 @@ void Application::update(float deltaTime) { _physicsEngine->changeObjects(motionStates); myAvatar->prepareForPhysicsSimulation(); - _physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) { - dynamic->prepareForPhysicsSimulation(); - }); + _physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) { dynamic->prepareForPhysicsSimulation(); }); } { PROFILE_RANGE(simulation_physics, "StepPhysics"); PerformanceTimer perfTimer("stepPhysics"); - getEntities()->getTree()->withWriteLock([&] { - _physicsEngine->stepSimulation(); - }); + getEntities()->getTree()->withWriteLock([&] { _physicsEngine->stepSimulation(); }); } { if (_physicsEngine->hasOutgoingChanges()) { @@ -5690,8 +5620,8 @@ void Application::update(float deltaTime) { } if (PerformanceTimer::isActive() && - Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) && - Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsTiming)) { + Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) && + Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsTiming)) { _physicsEngine->harvestPerformanceStats(); } // NOTE: the PhysicsEngine stats are written to stdout NOT to Qt log framework @@ -5701,7 +5631,7 @@ void Application::update(float deltaTime) { if (!_aboutToQuit) { // NOTE: the getEntities()->update() call below will wait for lock // and will provide non-physical entity motion - getEntities()->update(true); // update the models... + getEntities()->update(true); // update the models... } } } @@ -5791,9 +5721,8 @@ void Application::update(float deltaTime) { viewIsDifferentEnough = true; } - // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it - static const std::chrono::seconds MIN_PERIOD_BETWEEN_QUERIES { 3 }; + static const std::chrono::seconds MIN_PERIOD_BETWEEN_QUERIES{ 3 }; auto now = SteadyClock::now(); if (now > _queryExpiry || viewIsDifferentEnough) { if (DependencyManager::get()->shouldRenderEntities()) { @@ -5822,7 +5751,8 @@ void Application::update(float deltaTime) { if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS) { _lastSendDownstreamAudioStats = now; - QMetaObject::invokeMethod(DependencyManager::get().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection); + QMetaObject::invokeMethod(DependencyManager::get().data(), "sendDownstreamAudioStatsPacket", + Qt::QueuedConnection); } } @@ -5841,7 +5771,6 @@ void Application::update(float deltaTime) { _postUpdateLambdas.clear(); } - updateRenderArgs(deltaTime); // HACK @@ -5850,7 +5779,6 @@ void Application::update(float deltaTime) { // Then we can move this logic into the Avatar::simulate call. myAvatar->preDisplaySide(&_appRenderArgs._renderArgs); - { PerformanceTimer perfTimer("limitless"); AnimDebugDraw::getInstance().update(); @@ -5861,7 +5789,7 @@ void Application::update(float deltaTime) { DependencyManager::get()->update(); } - { // Game loop is done, mark the end of the frame for the scene transactions and the render loop to take over + { // Game loop is done, mark the end of the frame for the scene transactions and the render loop to take over PerformanceTimer perfTimer("enqueueFrame"); getMain3DScene()->enqueueFrame(); } @@ -5890,16 +5818,15 @@ void Application::updateRenderArgs(float deltaTime) { { QMutexLocker viewLocker(&_viewMutex); // adjust near clip plane to account for sensor scaling. - auto adjustedProjection = glm::perspective(glm::radians(_fieldOfView.get()), - getActiveDisplayPlugin()->getRecommendedAspectRatio(), - DEFAULT_NEAR_CLIP * sensorToWorldScale, - DEFAULT_FAR_CLIP); + auto adjustedProjection = + glm::perspective(glm::radians(_fieldOfView.get()), getActiveDisplayPlugin()->getRecommendedAspectRatio(), + DEFAULT_NEAR_CLIP * sensorToWorldScale, DEFAULT_FAR_CLIP); _viewFrustum.setProjection(adjustedProjection); _viewFrustum.calculate(); } - appRenderArgs._renderArgs = RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(), - lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, - RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); + appRenderArgs._renderArgs = + RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(), lodManager->getBoundaryLevelAdjust(), + RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); appRenderArgs._renderArgs._scene = getMain3DScene(); { @@ -6003,18 +5930,15 @@ void Application::queryAvatars() { DependencyManager::get()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); } - int Application::sendNackPackets() { - // iterates through all nodes in NodeList auto nodeList = DependencyManager::get(); int packetsSent = 0; - nodeList->eachNode([&](const SharedNodePointer& node){ + nodeList->eachNode([&](const SharedNodePointer& node) { if (node->getActiveSocket() && node->getType() == NodeType::EntityServer) { - auto nackPacketList = NLPacketList::create(PacketType::OctreeDataNack); QUuid nodeUUID = node->getUUID(); @@ -6032,13 +5956,14 @@ int Application::sendNackPackets() { return; } // get sequence number stats of node, prune its missing set, and make a copy of the missing set - SequenceNumberStats& sequenceNumberStats = _octreeServerSceneStats[nodeUUID].getIncomingOctreeSequenceNumberStats(); + SequenceNumberStats& sequenceNumberStats = + _octreeServerSceneStats[nodeUUID].getIncomingOctreeSequenceNumberStats(); sequenceNumberStats.pruneMissingSet(); missingSequenceNumbers = sequenceNumberStats.getMissingSet(); }); // construct nack packet(s) for this node - foreach(const OCTREE_PACKET_SEQUENCE& missingNumber, missingSequenceNumbers) { + foreach (const OCTREE_PACKET_SEQUENCE& missingNumber, missingSequenceNumbers) { nackPacketList->writePrimitive(missingNumber); } @@ -6055,9 +5980,8 @@ int Application::sendNackPackets() { } void Application::queryOctree(NodeType_t serverType, PacketType packetType) { - if (!_settingsLoaded) { - return; // bail early if settings are not loaded + return; // bail early if settings are not loaded } _octreeQuery.setConicalViews(_conicalViews); @@ -6084,12 +6008,13 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) { } } - bool Application::isHMDMode() const { return getActiveDisplayPlugin()->isHmd(); } -float Application::getTargetRenderFrameRate() const { return getActiveDisplayPlugin()->getTargetFrameRate(); } +float Application::getTargetRenderFrameRate() const { + return getActiveDisplayPlugin()->getTargetFrameRate(); +} QRect Application::getDesirableApplicationGeometry() const { QRect applicationGeometry = getWindow()->geometry(); @@ -6115,7 +6040,7 @@ QRect Application::getDesirableApplicationGeometry() const { } PickRay Application::computePickRay(float x, float y) const { - vec2 pickPoint { x, y }; + vec2 pickPoint{ x, y }; PickRay result; if (isHMDMode()) { getApplicationCompositor().computeHmdPickRay(pickPoint, result.origin, result.direction); @@ -6155,7 +6080,6 @@ void Application::resetSensors(bool andReload) { } void Application::updateWindowTitle() const { - auto nodeList = DependencyManager::get(); auto accountManager = DependencyManager::get(); @@ -6176,8 +6100,8 @@ void Application::updateWindowTitle() const { } } - QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) - + currentPlaceName + connectionStatus + loginStatus + buildVersion; + QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) + currentPlaceName + connectionStatus + + loginStatus + buildVersion; #ifndef WIN32 // crashes with vs2013/win32 @@ -6187,11 +6111,10 @@ void Application::updateWindowTitle() const { // updateTitleWindow gets called whenever there's a change regarding the domain, so rather // than placing this within domainURLChanged, it's placed here to cover the other potential cases. - DependencyManager::get< MessagesClient >()->sendLocalMessage("Toolbar-DomainChanged", ""); + DependencyManager::get()->sendLocalMessage("Toolbar-DomainChanged", ""); } void Application::clearDomainOctreeDetails() { - // if we're about to quit, we really don't need to do any of these things... if (_aboutToQuit) { return; @@ -6201,9 +6124,7 @@ void Application::clearDomainOctreeDetails() { resetPhysicsReadyInformation(); - _octreeServerSceneStats.withWriteLock([&] { - _octreeServerSceneStats.clear(); - }); + _octreeServerSceneStats.withWriteLock([&] { _octreeServerSceneStats.clear(); }); // reset the model renderer getEntities()->clear(); @@ -6221,7 +6142,7 @@ void Application::clearDomainOctreeDetails() { } void Application::clearDomainAvatars() { - getMyAvatar()->setAvatarEntityDataChanged(true); // to recreate worn entities + getMyAvatar()->setAvatarEntityDataChanged(true); // to recreate worn entities DependencyManager::get()->clearOtherAvatars(); } @@ -6235,7 +6156,6 @@ void Application::domainURLChanged(QUrl domainURL) { updateWindowTitle(); } - void Application::resettingDomain() { _notifiedPacketVersionMismatchThisDomain = false; @@ -6361,7 +6281,7 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { QVector entities; AABox avatarBox(getMyAvatar()->getWorldPosition() - glm::vec3(PHYSICS_READY_RANGE), glm::vec3(2 * PHYSICS_READY_RANGE)); // create two functions that use avatarBox (entityScan and elementScan), the second calls the first - std::function entityScan = [=](EntityItemPointer& entity) { + std::function entityScan = [=](EntityItemPointer& entity) { if (entity->shouldBePhysical()) { bool success = false; AABox entityBox = entity->getAABox(success); @@ -6370,7 +6290,8 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { } return false; }; - std::function elementScan = [&](const OctreeElementPointer& element, void* unused) { + std::function elementScan = [&](const OctreeElementPointer& element, + void* unused) { if (element->getAACube().touches(avatarBox)) { EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->getEntities(entityScan, entities); @@ -6440,7 +6361,6 @@ void Application::addingEntityWithCertificate(const QString& certificateID, cons } void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) { - scriptEngine->setEmitScriptUpdatesFunction([this]() { SharedNodePointer entityServerNode = DependencyManager::get()->soloNodeOfType(NodeType::EntityServer); return !entityServerNode || isPhysicsEnabled(); @@ -6485,13 +6405,13 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Desktop", DependencyManager::get().data()); qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); - qScriptRegisterMetaType(scriptEngine.data(), - wrapperToScriptValue, wrapperFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, + wrapperFromScriptValue); scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get().data()); qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); - qScriptRegisterMetaType(scriptEngine.data(), - wrapperToScriptValue, wrapperFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, + wrapperFromScriptValue); scriptEngine->registerGlobalObject("Tablet", DependencyManager::get().data()); // FIXME remove these deprecated names for the tablet scripting interface scriptEngine->registerGlobalObject("tabletInterface", DependencyManager::get().data()); @@ -6501,7 +6421,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Window", DependencyManager::get().data()); scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, - LocationScriptingInterface::locationSetter, "Window"); + LocationScriptingInterface::locationSetter, "Window"); // register `location` on the global object. scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter); @@ -6535,8 +6455,10 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface); - scriptEngine->registerGlobalObject("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED - scriptEngine->registerGlobalObject("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED + scriptEngine->registerGlobalObject("Account", + AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED + scriptEngine->registerGlobalObject("GlobalServices", + AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED scriptEngine->registerGlobalObject("AccountServices", AccountServicesScriptingInterface::getInstance()); qScriptRegisterMetaType(scriptEngine.data(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue); @@ -6563,10 +6485,12 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Reticle", getApplicationCompositor().getReticleInterface()); - scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("UserActivityLogger", + DependencyManager::get().data()); scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", + DependencyManager::get().data()); scriptEngine->registerGlobalObject("GooglePoly", DependencyManager::get().data()); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { @@ -6594,17 +6518,16 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe DependencyManager::get()->registerMetaTypes(scriptEngine.data()); // connect this script engines printedMessage signal to the global ScriptEngines these various messages - connect(scriptEngine.data(), &ScriptEngine::printedMessage, - DependencyManager::get().data(), &ScriptEngines::onPrintedMessage); - connect(scriptEngine.data(), &ScriptEngine::errorMessage, - DependencyManager::get().data(), &ScriptEngines::onErrorMessage); - connect(scriptEngine.data(), &ScriptEngine::warningMessage, - DependencyManager::get().data(), &ScriptEngines::onWarningMessage); - connect(scriptEngine.data(), &ScriptEngine::infoMessage, - DependencyManager::get().data(), &ScriptEngines::onInfoMessage); - connect(scriptEngine.data(), &ScriptEngine::clearDebugWindow, - DependencyManager::get().data(), &ScriptEngines::onClearDebugWindow); - + connect(scriptEngine.data(), &ScriptEngine::printedMessage, DependencyManager::get().data(), + &ScriptEngines::onPrintedMessage); + connect(scriptEngine.data(), &ScriptEngine::errorMessage, DependencyManager::get().data(), + &ScriptEngines::onErrorMessage); + connect(scriptEngine.data(), &ScriptEngine::warningMessage, DependencyManager::get().data(), + &ScriptEngines::onWarningMessage); + connect(scriptEngine.data(), &ScriptEngine::infoMessage, DependencyManager::get().data(), + &ScriptEngines::onInfoMessage); + connect(scriptEngine.data(), &ScriptEngine::clearDebugWindow, DependencyManager::get().data(), + &ScriptEngines::onClearDebugWindow); } bool Application::canAcceptURL(const QString& urlString) const { @@ -6628,8 +6551,8 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) { if (url.scheme() == URL_SCHEME_HIFI) { // this is a hifi URL - have the AddressManager handle it - QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString", - Qt::AutoConnection, Q_ARG(const QString&, urlString)); + QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString", Qt::AutoConnection, + Q_ARG(const QString&, urlString)); return true; } @@ -6666,13 +6589,13 @@ bool Application::askToSetAvatarUrl(const QString& url) { QString modelName = fstMapping["name"].toString(); QString modelLicense = fstMapping["license"].toString(); - bool agreeToLicense = true; // assume true + bool agreeToLicense = true; // assume true //create set avatar callback - auto setAvatar = [=] (QString url, QString modelName) { - ModalDialogListener* dlg = OffscreenUi::asyncQuestion("Set Avatar", - "Would you like to use '" + modelName + "' for your avatar?", - QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); - QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) { + auto setAvatar = [=](QString url, QString modelName) { + ModalDialogListener* dlg = + OffscreenUi::asyncQuestion("Set Avatar", "Would you like to use '" + modelName + "' for your avatar?", + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + QObject::connect(dlg, &ModalDialogListener::response, this, [=](QVariant answer) { QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr); bool ok = (QMessageBox::Ok == static_cast(answer.toInt())); @@ -6690,22 +6613,22 @@ bool Application::askToSetAvatarUrl(const QString& url) { const int MAX_CHARACTERS_PER_LINE = 90; modelLicense = simpleWordWrap(modelLicense, MAX_CHARACTERS_PER_LINE); - ModalDialogListener* dlg = OffscreenUi::asyncQuestion("Avatar Usage License", - modelLicense + "\nDo you agree to these terms?", - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - QObject::connect(dlg, &ModalDialogListener::response, this, [=, &agreeToLicense] (QVariant answer) { + ModalDialogListener* dlg = + OffscreenUi::asyncQuestion("Avatar Usage License", modelLicense + "\nDo you agree to these terms?", + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + QObject::connect(dlg, &ModalDialogListener::response, this, [=, &agreeToLicense](QVariant answer) { QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr); agreeToLicense = (static_cast(answer.toInt()) == QMessageBox::Yes); if (agreeToLicense) { switch (modelType) { case FSTReader::HEAD_AND_BODY_MODEL: { - setAvatar(url, modelName); - break; - } - default: - OffscreenUi::asyncWarning("", modelName + "Does not support a head and body as required."); - break; + setAvatar(url, modelName); + break; + } + default: + OffscreenUi::asyncWarning("", modelName + "Does not support a head and body as required."); + break; } } else { qCDebug(interfaceapp) << "Declined to agree to avatar license: " << url; @@ -6720,11 +6643,10 @@ bool Application::askToSetAvatarUrl(const QString& url) { return true; } - bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { QString shortName = scriptFilenameOrURL; - QUrl scriptURL { scriptFilenameOrURL }; + QUrl scriptURL{ scriptFilenameOrURL }; if (scriptURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) { int startIndex = shortName.lastIndexOf('/') + 1; @@ -6733,10 +6655,10 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { } QString message = "Would you like to run this script:\n" + shortName; - ModalDialogListener* dlg = OffscreenUi::asyncQuestion(getWindow(), "Run Script", message, - QMessageBox::Yes | QMessageBox::No); + ModalDialogListener* dlg = + OffscreenUi::asyncQuestion(getWindow(), "Run Script", message, QMessageBox::Yes | QMessageBox::No); - QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) { + QObject::connect(dlg, &ModalDialogListener::response, this, [=](QVariant answer) { const QString& fileName = scriptFilenameOrURL; if (static_cast(answer.toInt()) == QMessageBox::Yes) { qCDebug(interfaceapp) << "Chose to run the script: " << fileName; @@ -6773,7 +6695,6 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) { QJsonParseError jsonError; auto doc = QJsonDocument::fromJson(contents, &jsonError); if (jsonError.error == QJsonParseError::NoError) { - auto jsonObject = doc.object(); // retrieve optional name field from JSON @@ -6785,10 +6706,10 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) { auto avatarAttachmentConfirmationTitle = tr("Avatar Attachment Confirmation"); auto avatarAttachmentConfirmationMessage = tr("Would you like to wear '%1' on your avatar?").arg(name); - ModalDialogListener* dlg = OffscreenUi::asyncQuestion(avatarAttachmentConfirmationTitle, - avatarAttachmentConfirmationMessage, - QMessageBox::Ok | QMessageBox::Cancel); - QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) { + ModalDialogListener* dlg = + OffscreenUi::asyncQuestion(avatarAttachmentConfirmationTitle, avatarAttachmentConfirmationMessage, + QMessageBox::Ok | QMessageBox::Cancel); + QObject::connect(dlg, &ModalDialogListener::response, this, [=](QVariant answer) { QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr); if (static_cast(answer.toInt()) == QMessageBox::Yes) { // add attachment to avatar @@ -6839,18 +6760,23 @@ bool Application::askToReplaceDomainContent(const QString& url) { QString methodDetails; const int MAX_CHARACTERS_PER_LINE = 90; if (DependencyManager::get()->getThisNodeCanReplaceContent()) { - QUrl originURL { url }; + QUrl originURL{ url }; if (originURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) { // Create a confirmation dialog when this call is made - static const QString infoText = simpleWordWrap("Your domain's content will be replaced with a new content set. " - "If you want to save what you have now, create a backup before proceeding. For more information about backing up " - "and restoring content, visit the documentation page at: ", MAX_CHARACTERS_PER_LINE) + + static const QString infoText = + simpleWordWrap( + "Your domain's content will be replaced with a new content set. " + "If you want to save what you have now, create a backup before proceeding. For more information about " + "backing up " + "and restoring content, visit the documentation page at: ", + MAX_CHARACTERS_PER_LINE) + "\nhttps://docs.highfidelity.com/create-and-explore/start-working-in-your-sandbox/restoring-sandbox-content"; - ModalDialogListener* dig = OffscreenUi::asyncQuestion("Are you sure you want to replace this domain's content set?", - infoText, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + ModalDialogListener* dig = + OffscreenUi::asyncQuestion("Are you sure you want to replace this domain's content set?", infoText, + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - QObject::connect(dig, &ModalDialogListener::response, this, [=] (QVariant answer) { + QObject::connect(dig, &ModalDialogListener::response, this, [=](QVariant answer) { QString details; if (static_cast(answer.toInt()) == QMessageBox::Yes) { // Given confirmation, send request to domain server to replace content @@ -6859,33 +6785,26 @@ bool Application::askToReplaceDomainContent(const QString& url) { } else { details = "UserDeclinedToReplaceContent"; } - QJsonObject messageProperties = { - { "status", details }, - { "content_set_url", url } - }; + QJsonObject messageProperties = { { "status", details }, { "content_set_url", url } }; UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); QObject::disconnect(dig, &ModalDialogListener::response, this, nullptr); }); } else { methodDetails = "ContentSetDidNotOriginateFromMarketplace"; - QJsonObject messageProperties = { - { "status", methodDetails }, - { "content_set_url", url } - }; + QJsonObject messageProperties = { { "status", methodDetails }, { "content_set_url", url } }; UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); } } else { - methodDetails = "UserDoesNotHavePermissionToReplaceContent"; - static const QString warningMessage = simpleWordWrap("The domain owner must enable 'Replace Content' " - "permissions for you in this domain's server settings before you can continue.", MAX_CHARACTERS_PER_LINE); - OffscreenUi::asyncWarning("You do not have permissions to replace domain content", warningMessage, - QMessageBox::Ok, QMessageBox::Ok); + methodDetails = "UserDoesNotHavePermissionToReplaceContent"; + static const QString warningMessage = simpleWordWrap( + "The domain owner must enable 'Replace Content' " + "permissions for you in this domain's server settings before you can continue.", + MAX_CHARACTERS_PER_LINE); + OffscreenUi::asyncWarning("You do not have permissions to replace domain content", warningMessage, QMessageBox::Ok, + QMessageBox::Ok); - QJsonObject messageProperties = { - { "status", methodDetails }, - { "content_set_url", url } - }; - UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); + QJsonObject messageProperties = { { "status", methodDetails }, { "content_set_url", url } }; + UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); } return true; } @@ -6926,9 +6845,9 @@ void Application::showAssetServerWidget(QString filePath) { if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { return; } - static const QUrl url { "hifi/AssetServer.qml" }; + static const QUrl url{ "hifi/AssetServer.qml" }; - auto startUpload = [=](QQmlContext* context, QObject* newObject){ + auto startUpload = [=](QQmlContext* context, QObject* newObject) { if (!filePath.isEmpty()) { emit uploadRequest(filePath); } @@ -6964,7 +6883,6 @@ void Application::addAssetToWorldFromURL(QString url) { } else { filename.remove(".zip"); } - } if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { @@ -7035,7 +6953,6 @@ void Application::addAssetToWorldFromURLRequestFinished() { request->deleteLater(); } - QString filenameFromPath(QString filePath) { return filePath.right(filePath.length() - filePath.lastIndexOf("/") - 1); } @@ -7080,8 +6997,8 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin if (result == GetMappingRequest::NotFound) { addAssetToWorldUpload(filePath, mapping, isZip, isBlocks); } else if (result != GetMappingRequest::NoError) { - QString errorInfo = "Could not map asset name: " - + mapping.left(mapping.length() - QString::number(copy).length() - 1); + QString errorInfo = + "Could not map asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else if (copy < MAX_COPY_COUNT - 1) { @@ -7092,8 +7009,8 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin mapping = mapping.insert(mapping.lastIndexOf("."), "-" + QString::number(copy)); addAssetToWorldWithNewMapping(filePath, mapping, copy, isZip, isBlocks); } else { - QString errorInfo = "Too many copies of asset name: " - + mapping.left(mapping.length() - QString::number(copy).length() - 1); + QString errorInfo = + "Too many copies of asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } @@ -7140,7 +7057,7 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q // to prevent files that aren't models or texture files from being loaded into world automatically if ((filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION)) || ((filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION)) && - ((!isBlocks) && (!isZip)))) { + ((!isBlocks) && (!isZip)))) { addAssetToWorldAddEntity(filePath, mapping); } else { qCDebug(interfaceapp) << "Zipped contents are not supported entity files"; @@ -7158,9 +7075,7 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { properties.setType(EntityTypes::Model); properties.setName(mapping.right(mapping.length() - 1)); if (filePath.toLower().endsWith(PNG_EXTENSION) || filePath.toLower().endsWith(JPG_EXTENSION)) { - QJsonObject textures { - {"tex.picture", QString("atp:" + mapping) } - }; + QJsonObject textures{ { "tex.picture", QString("atp:" + mapping) } }; properties.setModelURL("https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"); properties.setTextures(QJsonDocument(textures).toJson(QJsonDocument::Compact)); properties.setShapeType(SHAPE_TYPE_BOX); @@ -7169,8 +7084,9 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND); } properties.setCollisionless(true); // Temporarily set so that doesn't collide with avatar. - properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions. - glm::vec3 positionOffset = getMyAvatar()->getWorldOrientation() * (getMyAvatar()->getSensorToWorldScale() * glm::vec3(0.0f, 0.0f, -2.0f)); + properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions. + glm::vec3 positionOffset = + getMyAvatar()->getWorldOrientation() * (getMyAvatar()->getSensorToWorldScale() * glm::vec3(0.0f, 0.0f, -2.0f)); properties.setPosition(getMyAvatar()->getWorldPosition() + positionOffset); properties.setRotation(getMyAvatar()->getWorldOrientation()); properties.setGravity(glm::vec3(0.0f, 0.0f, 0.0f)); @@ -7217,12 +7133,11 @@ void Application::addAssetToWorldCheckModelSize() { const glm::vec3 DEFAULT_DIMENSIONS = glm::vec3(0.1f, 0.1f, 0.1f); if (dimensions != DEFAULT_DIMENSIONS) { - // Scale model so that its maximum is exactly specific size. const float MAXIMUM_DIMENSION = getMyAvatar()->getSensorToWorldScale(); auto previousDimensions = dimensions; - auto scale = std::min(MAXIMUM_DIMENSION / dimensions.x, std::min(MAXIMUM_DIMENSION / dimensions.y, - MAXIMUM_DIMENSION / dimensions.z)); + auto scale = std::min(MAXIMUM_DIMENSION / dimensions.x, + std::min(MAXIMUM_DIMENSION / dimensions.y, MAXIMUM_DIMENSION / dimensions.z)); dimensions *= scale; qInfo(interfaceapp) << "Model" << name << "auto-resized from" << previousDimensions << " to " << dimensions; doResize = true; @@ -7268,7 +7183,6 @@ void Application::addAssetToWorldCheckModelSize() { } } - void Application::addAssetToWorldInfo(QString modelName, QString infoText) { // Displays the most recent info message, subject to being overridden by error messages. @@ -7293,8 +7207,9 @@ void Application::addAssetToWorldInfo(QString modelName, QString infoText) { if (!_addAssetToWorldErrorTimer.isActive()) { if (!_addAssetToWorldMessageBox) { - _addAssetToWorldMessageBox = DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, - "Downloading Model", "", QMessageBox::NoButton, QMessageBox::NoButton); + _addAssetToWorldMessageBox = + DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, "Downloading Model", "", + QMessageBox::NoButton, QMessageBox::NoButton); connect(_addAssetToWorldMessageBox, SIGNAL(destroyed()), this, SLOT(onAssetToWorldMessageBoxClosed())); } @@ -7376,8 +7291,9 @@ void Application::addAssetToWorldError(QString modelName, QString errorText) { addAssetToWorldInfoClear(modelName); if (!_addAssetToWorldMessageBox) { - _addAssetToWorldMessageBox = DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, - "Downloading Model", "", QMessageBox::NoButton, QMessageBox::NoButton); + _addAssetToWorldMessageBox = + DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, "Downloading Model", "", + QMessageBox::NoButton, QMessageBox::NoButton); connect(_addAssetToWorldMessageBox, SIGNAL(destroyed()), this, SLOT(onAssetToWorldMessageBoxClosed())); } @@ -7409,7 +7325,6 @@ void Application::addAssetToWorldErrorTimeout() { } } - void Application::addAssetToWorldMessageClose() { // Clear messages, e.g., if Interface is being closed or domain changes. @@ -7447,7 +7362,6 @@ void Application::onAssetToWorldMessageBoxClosed() { } } - void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip, bool isBlocks) { if (autoAdd) { if (!unzipFile.isEmpty()) { @@ -7482,10 +7396,9 @@ void Application::openUrl(const QUrl& url) const { void Application::loadDialog() { auto scriptEngines = DependencyManager::get(); - ModalDialogListener* dlg = OffscreenUi::getOpenFileNameAsync(_glWidget, tr("Open Script"), - getPreviousScriptLocation(), + ModalDialogListener* dlg = OffscreenUi::getOpenFileNameAsync(_glWidget, tr("Open Script"), getPreviousScriptLocation(), tr("JavaScript Files (*.js)")); - connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) { + connect(dlg, &ModalDialogListener::response, this, [=](QVariant answer) { disconnect(dlg, &ModalDialogListener::response, this, nullptr); const QString& response = answer.toString(); if (!response.isEmpty() && QFile(response).exists()) { @@ -7506,7 +7419,7 @@ void Application::setPreviousScriptLocation(const QString& location) { void Application::loadScriptURLDialog() const { ModalDialogListener* dlg = OffscreenUi::getTextAsync(OffscreenUi::ICON_NONE, "Open and Run Script", "Script URL"); - connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) { + connect(dlg, &ModalDialogListener::response, this, [=](QVariant response) { disconnect(dlg, &ModalDialogListener::response, this, nullptr); const QString& newScript = response.toString(); if (QUrl(newScript).scheme() == "atp") { @@ -7532,7 +7445,6 @@ void Application::loadLODToolsDialog() { } } - void Application::loadEntityStatisticsDialog() { auto tabletScriptingInterface = DependencyManager::get(); auto tablet = dynamic_cast(tabletScriptingInterface->getTablet(SYSTEM_TABLET)); @@ -7556,7 +7468,7 @@ void Application::loadDomainConnectionDialog() { } void Application::toggleLogDialog() { - if (! _logDialog) { + if (!_logDialog) { _logDialog = new LogDialog(nullptr, getLogger()); } @@ -7568,7 +7480,7 @@ void Application::toggleLogDialog() { } void Application::toggleEntityScriptServerLogDialog() { - if (! _entityScriptServerLogDialog) { + if (!_entityScriptServerLogDialog) { _entityScriptServerLogDialog = new EntityScriptServerLogDialog(nullptr); } @@ -7585,10 +7497,12 @@ void Application::loadAddAvatarBookmarkDialog() const { } void Application::loadAvatarBrowser() const { - auto tablet = dynamic_cast(DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); + auto tablet = dynamic_cast( + DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); // construct the url to the marketplace item QString url = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace?category=avatars"; - QString MARKETPLACES_INJECT_SCRIPT_PATH = "file:///" + qApp->applicationDirPath() + "/scripts/system/html/js/marketplacesInject.js"; + QString MARKETPLACES_INJECT_SCRIPT_PATH = + "file:///" + qApp->applicationDirPath() + "/scripts/system/html/js/marketplacesInject.js"; tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_PATH); DependencyManager::get()->openTablet(); } @@ -7690,7 +7604,8 @@ void Application::windowMinimizedChanged(bool minimized) { static std::once_flag once; std::call_once(once, [&] { connect(&_minimizedWindowTimer, &QTimer::timeout, this, [] { - QCoreApplication::postEvent(QCoreApplication::instance(), new QEvent(static_cast(Idle)), Qt::HighEventPriority); + QCoreApplication::postEvent(QCoreApplication::instance(), new QEvent(static_cast(Idle)), + Qt::HighEventPriority); }); }); @@ -7719,7 +7634,7 @@ void Application::sendLambdaEvent(const std::function& f) { } else { LambdaEvent event(f); QCoreApplication::sendEvent(this, &event); - } + } } void Application::initPlugins(const QStringList& arguments) { @@ -7741,7 +7656,7 @@ void Application::initPlugins(const QStringList& arguments) { if (parser.isSet(disableDisplays)) { auto disabledDisplays = parser.value(disableDisplays).split(',', QString::SkipEmptyParts); - qInfo() << "Disabling following display plugins:" << disabledDisplays; + qInfo() << "Disabling following display plugins:" << disabledDisplays; PluginManager::getInstance()->disableDisplays(disabledDisplays); } @@ -7867,7 +7782,7 @@ static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, bo auto menu = Menu::getInstance(); QString name = displayPlugin->getName(); auto grouping = displayPlugin->getGrouping(); - QString groupingMenu { "" }; + QString groupingMenu{ "" }; Q_ASSERT(!menu->menuItemExists(MenuOption::OutputMenu, name)); // assign the meny grouping based on plugin grouping @@ -7889,10 +7804,8 @@ static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, bo displayPluginGroup->setExclusive(true); } auto parent = menu->getMenu(MenuOption::OutputMenu); - auto action = menu->addActionToQMenuAndActionHash(parent, - name, 0, qApp, - SLOT(updateDisplayMode()), - QAction::NoRole, Menu::UNSPECIFIED_POSITION, groupingMenu); + auto action = menu->addActionToQMenuAndActionHash(parent, name, 0, qApp, SLOT(updateDisplayMode()), QAction::NoRole, + Menu::UNSPECIFIED_POSITION, groupingMenu); action->setCheckable(true); action->setChecked(active); @@ -7915,7 +7828,7 @@ void Application::updateDisplayMode() { DisplayPluginPointer newDisplayPlugin = displayPlugins.at(0); auto menu = getPrimaryMenu(); if (menu) { - foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { + foreach (DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { QString name = displayPlugin->getName(); QAction* action = menu->getActionForOption(name); // Menu might have been removed if the display plugin lost @@ -7942,7 +7855,7 @@ void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) { } // FIXME don't have the application directly set the state of the UI, - // instead emit a signal that the display plugin is changing and let + // instead emit a signal that the display plugin is changing and let // the desktop lock itself. Reduces coupling between the UI and display // plugins auto offscreenUi = DependencyManager::get(); @@ -8005,11 +7918,10 @@ void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) { qCDebug(interfaceapp) << "Entering into" << (isHmd ? "HMD" : "Desktop") << "Mode"; // Only log/emit after a successful change - UserActivityLogger::getInstance().logAction("changed_display_mode", { - { "previous_display_mode", _displayPlugin ? _displayPlugin->getName() : "" }, - { "display_mode", newDisplayPlugin ? newDisplayPlugin->getName() : "" }, - { "hmd", isHmd } - }); + UserActivityLogger::getInstance().logAction("changed_display_mode", + { { "previous_display_mode", _displayPlugin ? _displayPlugin->getName() : "" }, + { "display_mode", newDisplayPlugin ? newDisplayPlugin->getName() : "" }, + { "hmd", isHmd } }); emit activeDisplayPluginChanged(); // reset the avatar, to set head and hand palms back to a reasonable default pose. @@ -8175,7 +8087,6 @@ CompositorHelper& Application::getApplicationCompositor() const { return *DependencyManager::get(); } - // virtual functions required for PluginContainer ui::Menu* Application::getPrimaryMenu() { auto appMenu = _window->menuBar(); @@ -8265,19 +8176,16 @@ void Application::openAndroidActivity(const QString& activityName) { #if defined(Q_OS_ANDROID) void Application::enterBackground() { - QMetaObject::invokeMethod(DependencyManager::get().data(), - "stop", Qt::BlockingQueuedConnection); + QMetaObject::invokeMethod(DependencyManager::get().data(), "stop", Qt::BlockingQueuedConnection); //GC: commenting it out until we fix it //getActiveDisplayPlugin()->deactivate(); } void Application::enterForeground() { - QMetaObject::invokeMethod(DependencyManager::get().data(), - "start", Qt::BlockingQueuedConnection); + QMetaObject::invokeMethod(DependencyManager::get().data(), "start", Qt::BlockingQueuedConnection); //GC: commenting it out until we fix it /*if (!getActiveDisplayPlugin() || !getActiveDisplayPlugin()->activate()) { qWarning() << "Could not re-activate display plugin"; }*/ - } #endif From f74e21902995af02fc39885eb2386868d38136ef Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 15 May 2018 17:24:14 -0700 Subject: [PATCH 051/380] rename properties, add clone avatar entity, remove worldEntityProps arg, fix clone ID cleanup on delete --- libraries/entities/src/EntityItem.cpp | 94 +++++++++++++------ libraries/entities/src/EntityItem.h | 28 +++--- .../entities/src/EntityItemProperties.cpp | 90 +++++++++++------- libraries/entities/src/EntityItemProperties.h | 8 +- .../src/EntityItemPropertiesDefaults.h | 8 +- libraries/entities/src/EntityPropertyFlags.h | 8 +- .../entities/src/EntityScriptingInterface.cpp | 3 +- libraries/entities/src/EntityTree.cpp | 38 +++++--- libraries/entities/src/EntityTree.h | 2 +- .../controllerModules/equipEntity.js | 3 +- .../controllerModules/nearActionGrabEntity.js | 3 +- .../controllerModules/nearParentGrabEntity.js | 3 +- scripts/system/html/js/entityProperties.js | 14 +-- scripts/system/libraries/cloneEntityUtils.js | 4 +- 14 files changed, 192 insertions(+), 114 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9d7e536f25..1e95e999b1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -125,9 +125,11 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_LAST_EDITED_BY; requestedProperties += PROP_CLONEABLE; - requestedProperties += PROP_CLONEABLE_LIFETIME; - requestedProperties += PROP_CLONEABLE_LIMIT; - requestedProperties += PROP_CLONEABLE_DYNAMIC; + requestedProperties += PROP_CLONE_LIFETIME; + requestedProperties += PROP_CLONE_LIMIT; + requestedProperties += PROP_CLONE_DYNAMIC; + requestedProperties += PROP_CLONE_AVATAR_ENTITY; + requestedProperties += PROP_CLONE_ORIGIN_ID; return requestedProperties; } @@ -294,9 +296,11 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, getLastEditedBy()); APPEND_ENTITY_PROPERTY(PROP_CLONEABLE, getCloneable()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIFETIME, getCloneableLifetime()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIMIT, getCloneableLimit()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_DYNAMIC, getCloneableDynamic()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_LIFETIME, getCloneLifetime()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_LIMIT, getCloneLimit()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, getCloneDynamic()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, getCloneAvatarEntity()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, getCloneOriginID()); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -859,9 +863,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, QUuid, setLastEditedBy); READ_ENTITY_PROPERTY(PROP_CLONEABLE, bool, setCloneable); - READ_ENTITY_PROPERTY(PROP_CLONEABLE_LIFETIME, float, setCloneableLifetime); - READ_ENTITY_PROPERTY(PROP_CLONEABLE_LIMIT, float, setCloneableLimit); - READ_ENTITY_PROPERTY(PROP_CLONEABLE_DYNAMIC, bool, setCloneableDynamic); + READ_ENTITY_PROPERTY(PROP_CLONE_LIFETIME, float, setCloneLifetime); + READ_ENTITY_PROPERTY(PROP_CLONE_LIMIT, float, setCloneLimit); + READ_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, bool, setCloneDynamic); + READ_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, bool, setCloneAvatarEntity); + READ_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, QUuid, setCloneOriginID); bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, somethingChanged); @@ -1291,9 +1297,11 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(lastEditedBy, getLastEditedBy); COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneable, getCloneable); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneableLifetime, getCloneableLifetime); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneableLimit, getCloneableLimit); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneableDynamic, getCloneableDynamic); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneLifetime, getCloneLifetime); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneLimit, getCloneLimit); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneDynamic, getCloneDynamic); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneAvatarEntity, getCloneAvatarEntity); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneOriginID, getCloneOriginID); properties._defaultSettings = false; @@ -1403,9 +1411,11 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(lastEditedBy, setLastEditedBy); SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneable, setCloneable); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneableLifetime, setCloneableLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneableLimit, setCloneableLimit); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneableDynamic, setCloneableDynamic); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneLifetime, setCloneLifetime); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneLimit, setCloneLimit); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneDynamic, setCloneDynamic); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneAvatarEntity, setCloneAvatarEntity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneOriginID, setCloneOriginID); if (updateQueryAACube()) { somethingChanged = true; @@ -3015,45 +3025,73 @@ void EntityItem::setCloneable(bool value) { }); } -float EntityItem::getCloneableLifetime() const { +float EntityItem::getCloneLifetime() const { float result; withReadLock([&] { - result = _cloneableLifetime; + result = _cloneLifetime; }); return result; } -void EntityItem::setCloneableLifetime(float value) { +void EntityItem::setCloneLifetime(float value) { withWriteLock([&] { - _cloneableLifetime = value; + _cloneLifetime = value; }); } -float EntityItem::getCloneableLimit() const { +float EntityItem::getCloneLimit() const { float result; withReadLock([&] { - result = _cloneableLimit; + result = _cloneLimit; }); return result; } -void EntityItem::setCloneableLimit(float value) { +void EntityItem::setCloneLimit(float value) { withWriteLock([&] { - _cloneableLimit = value; + _cloneLimit = value; }); } -bool EntityItem::getCloneableDynamic() const { +bool EntityItem::getCloneDynamic() const { bool result; withReadLock([&] { - result = _cloneableDynamic; + result = _cloneDynamic; }); return result; } -void EntityItem::setCloneableDynamic(const bool value) { +void EntityItem::setCloneDynamic(const bool value) { withWriteLock([&] { - _cloneableDynamic = value; + _cloneDynamic = value; + }); +} + +bool EntityItem::getCloneAvatarEntity() const { + bool result; + withReadLock([&] { + result = _cloneAvatarEntity; + }); + return result; +} + +void EntityItem::setCloneAvatarEntity(const bool value) { + withWriteLock([&] { + _cloneAvatarEntity = value; + }); +} + +const QUuid EntityItem::getCloneOriginID() const { + QUuid result; + withReadLock([&] { + result = _cloneOriginID; + }); + return result; +} + +void EntityItem::setCloneOriginID(const QUuid& value) { + withWriteLock([&] { + _cloneOriginID = value; }); } @@ -3072,4 +3110,4 @@ bool EntityItem::removeCloneID(const QUuid& cloneID) { return true; } return false; -} \ No newline at end of file +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 95cc5f96e1..f314cd1418 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -343,12 +343,16 @@ public: bool getCloneable() const; void setCloneable(bool value); - float getCloneableLifetime() const; - void setCloneableLifetime(float value); - float getCloneableLimit() const; - void setCloneableLimit(float value); - bool getCloneableDynamic() const; - void setCloneableDynamic(const bool value); + float getCloneLifetime() const; + void setCloneLifetime(float value); + float getCloneLimit() const; + void setCloneLimit(float value); + bool getCloneDynamic() const; + void setCloneDynamic(const bool value); + bool getCloneAvatarEntity() const; + void setCloneAvatarEntity(const bool value); + const QUuid getCloneOriginID() const; + void setCloneOriginID(const QUuid& value); // TODO: get rid of users of getRadius()... float getRadius() const; @@ -506,8 +510,6 @@ public: bool addCloneID(const QUuid& cloneID); bool removeCloneID(const QUuid& cloneID); const QList& getCloneIDs() const { return _cloneIDs; } - void setCloneParent(const QUuid& cloneParentID) { _cloneParentID = cloneParentID; } - const QUuid& getCloneParent() const { return _cloneParentID; } signals: void requestRenderUpdate(); @@ -664,12 +666,12 @@ protected: bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera bool _cloneable; - float _cloneableLifetime; - float _cloneableLimit; - bool _cloneableDynamic; - + float _cloneLifetime; + float _cloneLimit; + bool _cloneDynamic; + bool _cloneAvatarEntity; + QUuid _cloneOriginID; QList _cloneIDs; - QUuid _cloneParentID; private: std::unordered_map _materials; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 7c799a64e1..11ef5a4a84 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -437,9 +437,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RELAY_PARENT_JOINTS, relayParentJoints); CHECK_PROPERTY_CHANGE(PROP_CLONEABLE, cloneable); - CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_LIFETIME, cloneableLifetime); - CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_LIMIT, cloneableLimit); - CHECK_PROPERTY_CHANGE(PROP_CLONEABLE_DYNAMIC, cloneableDynamic); + CHECK_PROPERTY_CHANGE(PROP_CLONE_LIFETIME, cloneLifetime); + CHECK_PROPERTY_CHANGE(PROP_CLONE_LIMIT, cloneLimit); + CHECK_PROPERTY_CHANGE(PROP_CLONE_DYNAMIC, cloneDynamic); + CHECK_PROPERTY_CHANGE(PROP_CLONE_AVATAR_ENTITY, cloneAvatarEntity); + CHECK_PROPERTY_CHANGE(PROP_CLONE_ORIGIN_ID, cloneOriginID); changedProperties += _animation.getChangedProperties(); changedProperties += _keyLight.getChangedProperties(); @@ -1436,9 +1438,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); // Gettable but not settable COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE, cloneable); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_LIFETIME, cloneableLifetime); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_LIMIT, cloneableLimit); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE_DYNAMIC, cloneableDynamic); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_LIFETIME, cloneLifetime); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_LIMIT, cloneLimit); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_DYNAMIC, cloneDynamic); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_AVATAR_ENTITY, cloneAvatarEntity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_ORIGIN_ID, cloneOriginID); // Rendering info if (!skipDefaults && !strictSemantics) { @@ -1653,9 +1657,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(dpi, uint16_t, setDPI); COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneable, bool, setCloneable); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableLifetime, float, setCloneableLifetime); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableLimit, float, setCloneableLimit); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneableDynamic, bool, setCloneableDynamic); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneLifetime, float, setCloneLifetime); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneLimit, float, setCloneLimit); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneDynamic, bool, setCloneDynamic); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneAvatarEntity, bool, setCloneAvatarEntity); + COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneOriginID, QUuid, setCloneOriginID); _lastEdited = usecTimestampNow(); } @@ -2033,9 +2039,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_DPI, DPI, dpi, uint16_t); ADD_PROPERTY_TO_MAP(PROP_CLONEABLE, Cloneable, cloneable, bool); - ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_LIFETIME, CloneableLifetime, cloneableLifetime, float); - ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_LIMIT, CloneableLimit, cloneableLimit, float); - ADD_PROPERTY_TO_MAP(PROP_CLONEABLE_DYNAMIC, CloneableDynamic, cloneableDynamic, bool); + ADD_PROPERTY_TO_MAP(PROP_CLONE_LIFETIME, CloneLifetime, cloneLifetime, float); + ADD_PROPERTY_TO_MAP(PROP_CLONE_LIMIT, CloneLimit, cloneLimit, float); + ADD_PROPERTY_TO_MAP(PROP_CLONE_DYNAMIC, CloneDynamic, cloneDynamic, bool); + ADD_PROPERTY_TO_MAP(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool); + ADD_PROPERTY_TO_MAP(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid); // FIXME - these are not yet handled //ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64); @@ -2353,9 +2361,11 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, properties.getStaticCertificateVersion()); APPEND_ENTITY_PROPERTY(PROP_CLONEABLE, properties.getCloneable()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIFETIME, properties.getCloneableLifetime()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_LIMIT, properties.getCloneableLimit()); - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE_DYNAMIC, properties.getCloneableDynamic()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_LIFETIME, properties.getCloneLifetime()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_LIMIT, properties.getCloneLimit()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, properties.getCloneDynamic()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, properties.getCloneAvatarEntity()); + APPEND_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, properties.getCloneOriginID()); } if (propertyCount > 0) { @@ -2727,9 +2737,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STATIC_CERTIFICATE_VERSION, quint32, setStaticCertificateVersion); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE, bool, setCloneable); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_LIFETIME, float, setCloneableLifetime); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_LIMIT, float, setCloneableLimit); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE_DYNAMIC, bool, setCloneableDynamic); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_LIFETIME, float, setCloneLifetime); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_LIMIT, float, setCloneLimit); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_DYNAMIC, bool, setCloneDynamic); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_AVATAR_ENTITY, bool, setCloneAvatarEntity); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_ORIGIN_ID, QUuid, setCloneOriginID); return valid; } @@ -2815,7 +2827,7 @@ bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityID char* copyAt = buffer.data(); int outputLength = 0; - if (buffer.size() < (int)(sizeof(NUM_BYTES_RFC4122_UUID) * 2)) { + if (buffer.size() < (int)(NUM_BYTES_RFC4122_UUID * 2)) { qCDebug(entities) << "ERROR - encodeCloneEntityMessage() called with buffer that is too small!"; return false; } @@ -3021,9 +3033,11 @@ void EntityItemProperties::markAllChanged() { _relayParentJointsChanged = true; _cloneableChanged = true; - _cloneableLifetimeChanged = true; - _cloneableLimitChanged = true; - _cloneableDynamicChanged = true; + _cloneLifetimeChanged = true; + _cloneLimitChanged = true; + _cloneDynamicChanged = true; + _cloneAvatarEntityChanged = true; + _cloneOriginIDChanged = true; } // The minimum bounding box for the entity. @@ -3459,14 +3473,20 @@ QList EntityItemProperties::listChangedProperties() { if (cloneableChanged()) { out += "cloneable"; } - if (cloneableLifetimeChanged()) { - out += "cloneableLifetime"; + if (cloneLifetimeChanged()) { + out += "cloneLifetime"; } - if (cloneableLimitChanged()) { - out += "cloneableLimit"; + if (cloneLimitChanged()) { + out += "cloneLimit"; } - if (cloneableDynamicChanged()) { - out += "cloneableDynamic"; + if (cloneDynamicChanged()) { + out += "cloneDynamic"; + } + if (cloneAvatarEntityChanged()) { + out += "cloneAvatarEntity"; + } + if (cloneOriginIDChanged()) { + out += "cloneOriginID"; } @@ -3637,10 +3657,12 @@ bool EntityItemProperties::verifyStaticCertificateProperties() { void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityIDToClone) { setName(getName() + "-clone-" + entityIDToClone.toString()); setLocked(false); - setLifetime(getCloneableLifetime()); - setDynamic(getCloneableDynamic()); + setLifetime(getCloneLifetime()); + setDynamic(getCloneDynamic()); + setClientOnly(getCloneAvatarEntity()); setCloneable(ENTITY_ITEM_CLONEABLE); - setCloneableLifetime(ENTITY_ITEM_CLONEABLE_LIFETIME); - setCloneableLimit(ENTITY_ITEM_CLONEABLE_LIMIT); - setCloneableDynamic(ENTITY_ITEM_CLONEABLE_DYNAMIC); -} \ No newline at end of file + setCloneLifetime(ENTITY_ITEM_CLONE_LIFETIME); + setCloneLimit(ENTITY_ITEM_CLONE_LIMIT); + setCloneDynamic(ENTITY_ITEM_CLONE_DYNAMIC); + setCloneAvatarEntity(ENTITY_ITEM_CLONE_AVATAR_ENTITY); +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 12d4bdf919..a34058c010 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -273,9 +273,11 @@ public: DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS); DEFINE_PROPERTY(PROP_CLONEABLE, Cloneable, cloneable, bool, ENTITY_ITEM_CLONEABLE); - DEFINE_PROPERTY(PROP_CLONEABLE_LIFETIME, CloneableLifetime, cloneableLifetime, float, ENTITY_ITEM_CLONEABLE_LIFETIME); - DEFINE_PROPERTY(PROP_CLONEABLE_LIMIT, CloneableLimit, cloneableLimit, float, ENTITY_ITEM_CLONEABLE_LIMIT); - DEFINE_PROPERTY(PROP_CLONEABLE_DYNAMIC, CloneableDynamic, cloneableDynamic, bool, ENTITY_ITEM_CLONEABLE_DYNAMIC); + DEFINE_PROPERTY(PROP_CLONE_LIFETIME, CloneLifetime, cloneLifetime, float, ENTITY_ITEM_CLONE_LIFETIME); + DEFINE_PROPERTY(PROP_CLONE_LIMIT, CloneLimit, cloneLimit, float, ENTITY_ITEM_CLONE_LIMIT); + DEFINE_PROPERTY(PROP_CLONE_DYNAMIC, CloneDynamic, cloneDynamic, bool, ENTITY_ITEM_CLONE_DYNAMIC); + DEFINE_PROPERTY(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool, ENTITY_ITEM_CLONE_AVATAR_ENTITY); + DEFINE_PROPERTY(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid, ENTITY_ITEM_CLONE_ORIGIN_ID); static QString getComponentModeString(uint32_t mode); static QString getComponentModeAsString(uint32_t mode); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 6e46453bda..1a31bddebe 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -98,8 +98,10 @@ const QUuid ENTITY_ITEM_DEFAULT_LAST_EDITED_BY = QUuid(); const bool ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS = false; const bool ENTITY_ITEM_CLONEABLE = false; -const float ENTITY_ITEM_CLONEABLE_LIFETIME = 300.0f; -const int ENTITY_ITEM_CLONEABLE_LIMIT = 0; -const bool ENTITY_ITEM_CLONEABLE_DYNAMIC = false; +const float ENTITY_ITEM_CLONE_LIFETIME = 300.0f; +const int ENTITY_ITEM_CLONE_LIMIT = 0; +const bool ENTITY_ITEM_CLONE_DYNAMIC = false; +const bool ENTITY_ITEM_CLONE_AVATAR_ENTITY = false; +const QUuid ENTITY_ITEM_CLONE_ORIGIN_ID = QUuid(); #endif // hifi_EntityItemPropertiesDefaults_h diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index f698739e01..85ab28afdc 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -243,9 +243,11 @@ enum EntityPropertyList { PROP_MATERIAL_DATA, PROP_CLONEABLE, - PROP_CLONEABLE_LIFETIME, - PROP_CLONEABLE_LIMIT, - PROP_CLONEABLE_DYNAMIC, + PROP_CLONE_LIFETIME, + PROP_CLONE_LIMIT, + PROP_CLONE_DYNAMIC, + PROP_CLONE_AVATAR_ENTITY, + PROP_CLONE_ORIGIN_ID, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 71e7d1c7c0..f47a353ae8 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -333,7 +333,8 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); properties.convertToCloneProperties(entityIDToClone); - if (addLocalEntityCopy(properties, newEntityID)) { + bool success = addLocalEntityCopy(properties, newEntityID); + if (success) { getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); return newEntityID; } else { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bcea89232e..647edaccc0 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -593,7 +593,7 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign return; } - removeCloneIDFromCloneParent(entityID); + cleanupCloneIDs(entityID); unhookChildAvatar(entityID); emit deletingEntity(entityID); emit deletingEntityPointer(existingEntity.get()); @@ -627,14 +627,23 @@ void EntityTree::unhookChildAvatar(const EntityItemID entityID) { }); } -void EntityTree::removeCloneIDFromCloneParent(const EntityItemID& entityID) { +void EntityTree::cleanupCloneIDs(const EntityItemID& entityID) { EntityItemPointer entity = findEntityByEntityItemID(entityID); if (entity) { - const QUuid& cloneParentID = entity->getCloneParent(); - if (!cloneParentID.isNull()) { - EntityItemPointer cloneParent = findEntityByID(cloneParentID); - if (cloneParent) { - cloneParent->removeCloneID(entityID); + // remove clone ID from it's clone origin's clone ID list if clone origin exists + const QUuid cloneOriginID = entity->getCloneOriginID(); + if (!cloneOriginID.isNull()) { + EntityItemPointer cloneOrigin = findEntityByID(cloneOriginID); + if (cloneOrigin) { + cloneOrigin->removeCloneID(entityID); + } + } + // clear the clone origin ID on any clones that this entity had + const QList& cloneIDs = entity->getCloneIDs(); + foreach(const QUuid& cloneChildID, cloneIDs) { + EntityItemPointer cloneChild = findEntityByEntityItemID(cloneChildID); + if (cloneChild) { + cloneChild->setCloneOriginID(QUuid()); } } } @@ -668,7 +677,7 @@ void EntityTree::deleteEntities(QSet entityIDs, bool force, bool i } // tell our delete operator about this entityID - removeCloneIDFromCloneParent(entityID); + cleanupCloneIDs(entityID); unhookChildAvatar(entityID); theOperator.addEntityIDToDeleteList(entityID); emit deletingEntity(entityID); @@ -1601,7 +1610,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c bool failedAdd = !allowed; bool isCertified = !properties.getCertificateID().isEmpty(); bool isCloneable = properties.getCloneable(); - int cloneLimit = properties.getCloneableLimit(); + int cloneLimit = properties.getCloneLimit(); if (!allowed) { qCDebug(entities) << "Filtered entity add. ID:" << entityItemID; } else if (!isClone && !isCertified && !senderNode->getCanRez() && !senderNode->getCanRezTmp()) { @@ -1646,14 +1655,15 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } } + if (newEntity && isClone) { + entityToClone->addCloneID(newEntity->getEntityItemID()); + newEntity->setCloneOriginID(entityIDToClone); + } + if (newEntity) { newEntity->markAsChangedOnServer(); notifyNewlyCreatedEntity(*newEntity, senderNode); - if (isClone) { - entityToClone->addCloneID(newEntity->getEntityItemID()); - newEntity->setCloneParent(entityIDToClone); - } - + startLogging = usecTimestampNow(); if (wantEditLogging()) { qCDebug(entities) << "User [" << senderNode->getUUID() << "] added entity. ID:" diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 0d7cc54df7..aa6e382112 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -117,7 +117,7 @@ public: // check if the avatar is a child of this entity, If so set the avatar parentID to null void unhookChildAvatar(const EntityItemID entityID); - void removeCloneIDFromCloneParent(const EntityItemID& entityID); + void cleanupCloneIDs(const EntityItemID& entityID); void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = true); void deleteEntities(QSet entityIDs, bool force = false, bool ignoreWarnings = true); diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 1fce772ec8..b6cad6841d 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -413,8 +413,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.cloneHotspot = function(props, controllerData) { if (entityIsCloneable(props)) { - var worldEntityProps = controllerData.nearbyEntityProperties[this.hand]; - var cloneID = cloneEntity(props, worldEntityProps); + var cloneID = cloneEntity(props); return cloneID; } diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js index a4e439fe2f..5e06ed762d 100644 --- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js @@ -235,8 +235,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); // switch to grabbing var targetCloneable = entityIsCloneable(targetProps); if (targetCloneable) { - var worldEntityProps = controllerData.nearbyEntityProperties[this.hand]; - var cloneID = cloneEntity(targetProps, worldEntityProps); + var cloneID = cloneEntity(targetProps); var cloneProps = Entities.getEntityProperties(cloneID); this.targetEntityID = cloneID; this.startNearGrabAction(controllerData, cloneProps); diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index d454d20a02..cda0a683c7 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -342,8 +342,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var targetCloneable = entityIsCloneable(targetProps); if (targetCloneable) { - var worldEntityProps = controllerData.nearbyEntityProperties[this.hand]; - var cloneID = cloneEntity(targetProps, worldEntityProps); + var cloneID = cloneEntity(targetProps); var cloneProps = Entities.getEntityProperties(cloneID); this.grabbing = true; this.targetEntityID = cloneID; diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index c81e51d674..10e7b4b60e 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1041,10 +1041,11 @@ function loaded() { elIgnoreIK.checked = true; elCloneable.checked = properties.cloneable; - elCloneableDynamic.checked = properties.cloneableDynamic; + elCloneableDynamic.checked = properties.cloneDynamic; + elCloneableAvatarEntity.checked = properties.cloneAvatarEntity; elCloneableGroup.style.display = elCloneable.checked ? "block": "none"; - elCloneableLimit.value = properties.cloneableLimit; - elCloneableLifetime.value = properties.cloneableLifetime; + elCloneableLimit.value = properties.cloneLimit; + elCloneableLifetime.value = properties.cloneLifetime; var grabbablesSet = false; var parsedUserData = {}; @@ -1441,9 +1442,10 @@ function loaded() { }); elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); - elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneableDynamic')); - elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLifetime')); - elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneableLimit')); + elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneDynamic')); + elCloneableAvatarEntity.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneAvatarEntity')); + elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLifetime')); + elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLimit')); elWantsTrigger.addEventListener('change', function() { userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); diff --git a/scripts/system/libraries/cloneEntityUtils.js b/scripts/system/libraries/cloneEntityUtils.js index 358bc4a75f..5381d39116 100644 --- a/scripts/system/libraries/cloneEntityUtils.js +++ b/scripts/system/libraries/cloneEntityUtils.js @@ -41,12 +41,12 @@ entityIsCloneable = function(props) { propsAreCloneDynamic = function(props) { var cloneable = entityIsCloneable(props); if (cloneable) { - return props.cloneableDynamic; + return props.cloneDynamic; } return false; }; -cloneEntity = function(props, worldEntityProps) { +cloneEntity = function(props) { var entityToClone = props.id; var certificateID = Entities.getEntityProperties(entityToClone, ['certificateID']).certificateID; // ensure entity is cloneable and does not have a certificate ID, whereas cloneable limits From 1e2d2819d512056db75701321e0674ec2c031a41 Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 15 May 2018 17:36:39 -0700 Subject: [PATCH 052/380] tweaks --- libraries/entities/src/EntityItemProperties.cpp | 3 --- libraries/entities/src/EntityTree.cpp | 2 +- scripts/system/html/js/entityProperties.js | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 11ef5a4a84..5a2f3a8fc5 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -2823,7 +2823,6 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt } bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID, QByteArray& buffer) { - char* copyAt = buffer.data(); int outputLength = 0; @@ -2846,7 +2845,6 @@ bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityID } bool EntityItemProperties::decodeCloneEntityMessage(const QByteArray& buffer, int& processedBytes, EntityItemID& entityIDToClone, EntityItemID& newEntityID) { - const unsigned char* packetData = (const unsigned char*)buffer.constData(); const unsigned char* dataAt = packetData; size_t packetLength = buffer.size(); @@ -3489,7 +3487,6 @@ QList EntityItemProperties::listChangedProperties() { out += "cloneOriginID"; } - getAnimation().listChangedProperties(out); getKeyLight().listChangedProperties(out); getAmbientLight().listChangedProperties(out); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 647edaccc0..b2daed4e72 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1429,7 +1429,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c case PacketType::EntityClone: isClone = true; // fall through to next case case PacketType::EntityAdd: - isAdd = true; // fall through to next case + isAdd = true; // fall through to next case // FALLTHRU case PacketType::EntityPhysics: case PacketType::EntityEdit: { diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index e016a21731..4271aa9b09 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1042,7 +1042,7 @@ function loaded() { elCloneable.checked = properties.cloneable; elCloneableDynamic.checked = properties.cloneDynamic; - elCloneableAvatarEntity.checked = properties.cloneAvatarEntity; + elCloneableAvatarEntity.checked = properties.cloneAvatarEntity; elCloneableGroup.style.display = elCloneable.checked ? "block": "none"; elCloneableLimit.value = properties.cloneLimit; elCloneableLifetime.value = properties.cloneLifetime; @@ -1443,7 +1443,7 @@ function loaded() { elCloneable.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneable')); elCloneableDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneDynamic')); - elCloneableAvatarEntity.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneAvatarEntity')); + elCloneableAvatarEntity.addEventListener('change', createEmitCheckedPropertyUpdateFunction('cloneAvatarEntity')); elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLifetime')); elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLimit')); From b43cb5b86f86760bba2c0733d87e4647c2817950 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 16 May 2018 09:36:55 -0700 Subject: [PATCH 053/380] Take out VS's auto reformatting --- interface/src/Application.cpp | 1743 +++++++++++++++++---------------- 1 file changed, 919 insertions(+), 824 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7cf26d377d..9b9914e261 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -237,7 +237,7 @@ // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. extern "C" { -_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; + _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; } #endif @@ -246,8 +246,7 @@ _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; #include "AndroidHelper.h" #endif -enum ApplicationEvent -{ +enum ApplicationEvent { // Execute a lambda function Lambda = QEvent::User + 1, // Trigger the next render @@ -273,13 +272,11 @@ public: connect(qApp, &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); // Transfer to a new thread - moveToNewNamedThread(this, "RenderThread", - [this](QThread* renderThread) { - hifi::qt::addBlockingForbiddenThread("Render", renderThread); - _renderContext->moveToThreadWithContext(renderThread); - qApp->_lastTimeRendered.start(); - }, - std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority); + moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) { + hifi::qt::addBlockingForbiddenThread("Render", renderThread); + _renderContext->moveToThreadWithContext(renderThread); + qApp->_lastTimeRendered.start(); + }, std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority); } private: @@ -309,9 +306,10 @@ private: return Parent::event(event); } - OffscreenGLCanvas* _renderContext{ nullptr }; + OffscreenGLCanvas* _renderContext { nullptr }; }; + Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse") using namespace std; @@ -373,37 +371,38 @@ static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SI static const uint32_t INVALID_FRAME = UINT32_MAX; -static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation +static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); Setting::Handle maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com"; -static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds +static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop"; static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin"; static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system"; -const std::vector> - Application::_acceptedExtensions{ { SVO_EXTENSION, &Application::importSVOFromURL }, - { SVO_JSON_EXTENSION, &Application::importSVOFromURL }, - { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }, - { JSON_EXTENSION, &Application::importJSONFromURL }, - { JS_EXTENSION, &Application::askToLoadScript }, - { FST_EXTENSION, &Application::askToSetAvatarUrl }, - { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, - { CONTENT_ZIP_EXTENSION, &Application::askToReplaceDomainContent }, - { ZIP_EXTENSION, &Application::importFromZIP }, - { JPG_EXTENSION, &Application::importImage }, - { PNG_EXTENSION, &Application::importImage } }; +const std::vector> Application::_acceptedExtensions { + { SVO_EXTENSION, &Application::importSVOFromURL }, + { SVO_JSON_EXTENSION, &Application::importSVOFromURL }, + { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }, + { JSON_EXTENSION, &Application::importJSONFromURL }, + { JS_EXTENSION, &Application::askToLoadScript }, + { FST_EXTENSION, &Application::askToSetAvatarUrl }, + { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, + { CONTENT_ZIP_EXTENSION, &Application::askToReplaceDomainContent }, + { ZIP_EXTENSION, &Application::importFromZIP }, + { JPG_EXTENSION, &Application::importImage }, + { PNG_EXTENSION, &Application::importImage } +}; class DeadlockWatchdogThread : public QThread { public: static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1; - static const unsigned long MAX_HEARTBEAT_AGE_USECS = 120 * USECS_PER_SECOND; // 2 mins with no checkin probably a deadlock - 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 + static const unsigned long MAX_HEARTBEAT_AGE_USECS = 120 * USECS_PER_SECOND; // 2 mins with no checkin probably a deadlock + 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() { @@ -411,7 +410,9 @@ public: // Give the heartbeat an initial value _heartbeat = usecTimestampNow(); _paused = false; - connect(qApp, &QCoreApplication::aboutToQuit, [this] { _quit = true; }); + connect(qApp, &QCoreApplication::aboutToQuit, [this] { + _quit = true; + }); } static void updateHeartbeat() { @@ -431,7 +432,9 @@ public: lambda(); resume(); } - static void pause() { _paused = true; } + static void pause() { + _paused = true; + } static void resume() { // Update the heartbeat BEFORE resuming the checks @@ -446,49 +449,55 @@ public: if (_paused) { continue; } - uint64_t lastHeartbeat = - _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us + uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us uint64_t now = usecTimestampNow(); auto lastHeartbeatAge = (now > lastHeartbeat) ? now - lastHeartbeat : 0; auto elapsedMovingAverage = _movingAverage.getAverage(); if (elapsedMovingAverage > _maxElapsedAverage) { - qCDebug(interfaceapp_deadlock) - << "DEADLOCK WATCHDOG WARNING:" - << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage - << "maxElapsed:" << _maxElapsed << "PREVIOUS maxElapsedAverage:" << _maxElapsedAverage + qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" + << "lastHeartbeatAge:" << lastHeartbeatAge + << "elapsedMovingAverage:" << elapsedMovingAverage + << "maxElapsed:" << _maxElapsed + << "PREVIOUS maxElapsedAverage:" << _maxElapsedAverage << "NEW maxElapsedAverage:" << elapsedMovingAverage << "** NEW MAX ELAPSED AVERAGE **" << "samples:" << _movingAverage.getSamples(); _maxElapsedAverage = elapsedMovingAverage; } if (lastHeartbeatAge > _maxElapsed) { - qCDebug(interfaceapp_deadlock) - << "DEADLOCK WATCHDOG WARNING:" - << "lastHeartbeatAge:" << lastHeartbeatAge << "elapsedMovingAverage:" << elapsedMovingAverage - << "PREVIOUS maxElapsed:" << _maxElapsed << "NEW maxElapsed:" << lastHeartbeatAge << "** NEW MAX ELAPSED **" - << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); + qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" + << "lastHeartbeatAge:" << lastHeartbeatAge + << "elapsedMovingAverage:" << elapsedMovingAverage + << "PREVIOUS maxElapsed:" << _maxElapsed + << "NEW maxElapsed:" << lastHeartbeatAge << "** NEW MAX ELAPSED **" + << "maxElapsedAverage:" << _maxElapsedAverage + << "samples:" << _movingAverage.getSamples(); _maxElapsed = lastHeartbeatAge; } if (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT) { qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:" - << "lastHeartbeatAge:" << lastHeartbeatAge - << "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE **" - << "maxElapsed:" << _maxElapsed << "maxElapsedAverage:" << _maxElapsedAverage - << "samples:" << _movingAverage.getSamples(); + << "lastHeartbeatAge:" << lastHeartbeatAge + << "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE **" + << "maxElapsed:" << _maxElapsed + << "maxElapsedAverage:" << _maxElapsedAverage + << "samples:" << _movingAverage.getSamples(); } if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { - qCDebug(interfaceapp_deadlock) - << "DEADLOCK DETECTED -- " - << "lastHeartbeatAge:" << lastHeartbeatAge << "[ lastHeartbeat :" << lastHeartbeat << "now:" << now << " ]" - << "elapsedMovingAverage:" << elapsedMovingAverage << "maxElapsed:" << _maxElapsed - << "maxElapsedAverage:" << _maxElapsedAverage << "samples:" << _movingAverage.getSamples(); + qCDebug(interfaceapp_deadlock) << "DEADLOCK DETECTED -- " + << "lastHeartbeatAge:" << lastHeartbeatAge + << "[ lastHeartbeat :" << lastHeartbeat + << "now:" << now << " ]" + << "elapsedMovingAverage:" << elapsedMovingAverage + << "maxElapsed:" << _maxElapsed + << "maxElapsedAverage:" << _maxElapsedAverage + << "samples:" << _movingAverage.getSamples(); -// Don't actually crash in debug builds, in case this apparent deadlock is simply from -// the developer actively debugging code -#ifdef NDEBUG + // Don't actually crash in debug builds, in case this apparent deadlock is simply from + // the developer actively debugging code + #ifdef NDEBUG deadlockDetectionCrash(); -#endif + #endif } } } @@ -499,7 +508,7 @@ public: static std::atomic _maxElapsedAverage; static ThreadSafeMovingAverage _movingAverage; - bool _quit{ false }; + bool _quit { false }; }; std::atomic DeadlockWatchdogThread::_paused; @@ -522,7 +531,8 @@ bool isDomainURL(QUrl url) { // url.scheme() != URL_SCHEME_HTTPS return false; } - if (url.path().endsWith(".json", Qt::CaseInsensitive) || url.path().endsWith(".json.gz", Qt::CaseInsensitive)) { + if (url.path().endsWith(".json", Qt::CaseInsensitive) || + url.path().endsWith(".json.gz", Qt::CaseInsensitive)) { return true; } return false; @@ -536,7 +546,7 @@ public: return staticInstance; } - bool nativeEventFilter(const QByteArray& eventType, void* msg, long* result) Q_DECL_OVERRIDE { + bool nativeEventFilter(const QByteArray &eventType, void* msg, long* result) Q_DECL_OVERRIDE { if (eventType == "windows_generic_MSG") { MSG* message = (MSG*)msg; @@ -564,12 +574,12 @@ public: } if (message->message == WM_DEVICECHANGE) { - const float MIN_DELTA_SECONDS = 2.0f; // de-bounce signal + const float MIN_DELTA_SECONDS = 2.0f; // de-bounce signal static float lastTriggerTime = 0.0f; const float deltaSeconds = secTimestampNow() - lastTriggerTime; lastTriggerTime = secTimestampNow(); if (deltaSeconds > MIN_DELTA_SECONDS) { - Midi::USBchanged(); // re-scan the MIDI bus + Midi::USBchanged(); // re-scan the MIDI bus } } } @@ -580,35 +590,38 @@ public: class LambdaEvent : public QEvent { std::function _fun; - public: - LambdaEvent(const std::function& fun) : QEvent(static_cast(ApplicationEvent::Lambda)), _fun(fun) {} - LambdaEvent(std::function&& fun) : QEvent(static_cast(ApplicationEvent::Lambda)), _fun(fun) {} + LambdaEvent(const std::function & fun) : + QEvent(static_cast(ApplicationEvent::Lambda)), _fun(fun) { + } + LambdaEvent(std::function && fun) : + QEvent(static_cast(ApplicationEvent::Lambda)), _fun(fun) { + } void call() const { _fun(); } }; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - QString logMessage = LogHandler::getInstance().printMessage((LogMsgType)type, context, message); + QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); if (!logMessage.isEmpty()) { #ifdef Q_OS_ANDROID - const char* local = logMessage.toStdString().c_str(); + const char * local=logMessage.toStdString().c_str(); switch (type) { case QtDebugMsg: - __android_log_write(ANDROID_LOG_DEBUG, "Interface", local); + __android_log_write(ANDROID_LOG_DEBUG,"Interface",local); break; case QtInfoMsg: - __android_log_write(ANDROID_LOG_INFO, "Interface", local); + __android_log_write(ANDROID_LOG_INFO,"Interface",local); break; case QtWarningMsg: - __android_log_write(ANDROID_LOG_WARN, "Interface", local); + __android_log_write(ANDROID_LOG_WARN,"Interface",local); break; case QtCriticalMsg: - __android_log_write(ANDROID_LOG_ERROR, "Interface", local); + __android_log_write(ANDROID_LOG_ERROR,"Interface",local); break; case QtFatalMsg: default: - __android_log_write(ANDROID_LOG_FATAL, "Interface", local); + __android_log_write(ANDROID_LOG_FATAL,"Interface",local); abort(); } #endif @@ -616,23 +629,23 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt } } -class ApplicationMeshProvider : public scriptable::ModelProviderFactory { + +class ApplicationMeshProvider : public scriptable::ModelProviderFactory { public: virtual scriptable::ModelProviderPointer lookupModelProvider(const QUuid& uuid) override { bool success; if (auto nestable = DependencyManager::get()->find(uuid, success).lock()) { auto type = nestable->getNestableType(); #ifdef SCRIPTABLE_MESH_DEBUG - qCDebug(interfaceapp) << "ApplicationMeshProvider::lookupModelProvider" << uuid - << SpatiallyNestable::nestableTypeToString(type); + qCDebug(interfaceapp) << "ApplicationMeshProvider::lookupModelProvider" << uuid << SpatiallyNestable::nestableTypeToString(type); #endif switch (type) { - case NestableType::Entity: - return getEntityModelProvider(static_cast(uuid)); - case NestableType::Overlay: - return getOverlayModelProvider(static_cast(uuid)); - case NestableType::Avatar: - return getAvatarModelProvider(uuid); + case NestableType::Entity: + return getEntityModelProvider(static_cast(uuid)); + case NestableType::Overlay: + return getOverlayModelProvider(static_cast(uuid)); + case NestableType::Avatar: + return getAvatarModelProvider(uuid); } } return nullptr; @@ -656,7 +669,7 @@ private: scriptable::ModelProviderPointer getOverlayModelProvider(OverlayID overlayID) { scriptable::ModelProviderPointer provider; - auto& overlays = qApp->getOverlays(); + auto &overlays = qApp->getOverlays(); if (auto overlay = overlays.getOverlay(overlayID)) { if (auto base3d = std::dynamic_pointer_cast(overlay)) { provider = std::dynamic_pointer_cast(base3d); @@ -735,7 +748,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { // HRS: I could not figure out how to move these any earlier in startup, so when using this option, be sure to also supply // --allowMultipleInstances - auto reportAndQuit = [&](const char* commandSwitch, std::function report) { + auto reportAndQuit = [&](const char* commandSwitch, std::function report) { const char* reportfile = getCmdOption(argc, constArgv, commandSwitch); // Reports to the specified file, because stdout is set up to be captured for logging. if (reportfile) { @@ -743,9 +756,9 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { if (fp) { report(fp); fclose(fp); - if (!runningMarkerExisted) { // don't leave ours around + if (!runningMarkerExisted) { // don't leave ours around RunningMarker runingMarker(RUNNING_MARKER_FILENAME); - runingMarker.deleteRunningMarkerFile(); // happens in deleter, but making the side-effect explicit. + runingMarker.deleteRunningMarkerFile(); // happens in deleter, but making the side-effect explicit. } _exit(0); } @@ -755,7 +768,9 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { auto version = protocolVersionsSignatureBase64(); fputs(version.toLatin1().data(), fp); }); - reportAndQuit("--version", [&](FILE* fp) { fputs(BuildInfo::VERSION.toLatin1().data(), fp); }); + reportAndQuit("--version", [&](FILE* fp) { + fputs(BuildInfo::VERSION.toLatin1().data(), fp); + }); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); const int listenPort = portStr ? atoi(portStr) : INVALID_PORT; @@ -763,8 +778,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset"; bool suppressPrompt = cmdOptionExists(argc, const_cast(argv), SUPPRESS_SETTINGS_RESET); - // Ignore any previous crashes if running from command line with a test script. - bool inTestMode{ false }; + // Ignore any previous crashes if running from command line with a test script. + bool inTestMode { false }; for (int i = 0; i < argc; ++i) { QString parameter(argv[i]); if (parameter == TEST_SCRIPT_COMMAND) { @@ -773,7 +788,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { } } - bool previousSessionCrashed{ false }; + bool previousSessionCrashed { false }; if (!inTestMode) { previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt); } @@ -785,8 +800,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir); } - // FIXME fix the OSX installer to install the resources.rcc binary instead of resource files and remove - // this conditional exclusion + // FIXME fix the OSX installer to install the resources.rcc binary instead of resource files and remove + // this conditional exclusion #if !defined(Q_OS_OSX) { #if defined(Q_OS_ANDROID) @@ -898,10 +913,9 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - controller::StateController::setStateVariables( - { { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR, STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, - STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, - STATE_NAV_FOCUSED } }); + controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR, + STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, + STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED } }); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -934,7 +948,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { std::shared_ptr _keyboardFocusHighlight{ nullptr }; OverlayID _keyboardFocusHighlightID{ UNKNOWN_OVERLAY_ID }; -OffscreenGLCanvas* _qmlShareContext{ nullptr }; + +OffscreenGLCanvas* _qmlShareContext { nullptr }; // FIXME hack access to the internal share context for the Chromium helper // Normally we'd want to use QWebEngine::initialize(), but we can't because @@ -944,8 +959,8 @@ OffscreenGLCanvas* _qmlShareContext{ nullptr }; // So instead we create a new offscreen context to share with the QGLWidget, // and manually set THAT to be the shared context for the Chromium helper #if !defined(DISABLE_QML) -OffscreenGLCanvas* _chromiumShareContext{ nullptr }; -Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext* context); +OffscreenGLCanvas* _chromiumShareContext { nullptr }; +Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); #endif Setting::Handle sessionRunTime{ "sessionRunTime", 0 }; @@ -959,10 +974,15 @@ const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false; const QString DEFAULT_CURSOR_NAME = "DEFAULT"; Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runningMarkerExisted) : - QApplication(argc, argv), _window(new MainWindow(desktop())), _sessionRunTimer(startupTimer), - _previousSessionCrashed(setupEssentials(argc, argv, runningMarkerExisted)), _undoStackScriptingInterface(&_undoStack), - _entitySimulation(new PhysicalEntitySimulation()), _physicsEngine(new PhysicsEngine(Vectors::ZERO)), - _entityClipboard(new EntityTree()), _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION), + QApplication(argc, argv), + _window(new MainWindow(desktop())), + _sessionRunTimer(startupTimer), + _previousSessionCrashed(setupEssentials(argc, argv, runningMarkerExisted)), + _undoStackScriptingInterface(&_undoStack), + _entitySimulation(new PhysicalEntitySimulation()), + _physicsEngine(new PhysicsEngine(Vectors::ZERO)), + _entityClipboard(new EntityTree()), + _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION), _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES), _hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT), _desktopTabletScale("desktopTabletScale", DEFAULT_DESKTOP_TABLET_SCALE_PERCENT), @@ -971,12 +991,22 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _preferStylusOverLaserSetting("preferStylusOverLaser", DEFAULT_PREFER_STYLUS_OVER_LASER), _preferAvatarFingerOverStylusSetting("preferAvatarFingerOverStylus", DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS), _constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true), - _preferredCursor("preferredCursor", DEFAULT_CURSOR_NAME), _scaleMirror(1.0f), _mirrorYawOffset(0.0f), _raiseMirror(0.0f), - _enableProcessOctreeThread(true), _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()), - _aboutToQuit(false), _notifiedPacketVersionMismatchThisDomain(false), _maxOctreePPS(maxOctreePacketsPerSecond.get()), - _lastFaceTrackerUpdate(0), _snapshotSound(nullptr), _sampleSound(nullptr) + _preferredCursor("preferredCursor", DEFAULT_CURSOR_NAME), + _scaleMirror(1.0f), + _mirrorYawOffset(0.0f), + _raiseMirror(0.0f), + _enableProcessOctreeThread(true), + _lastNackTime(usecTimestampNow()), + _lastSendDownstreamAudioStats(usecTimestampNow()), + _aboutToQuit(false), + _notifiedPacketVersionMismatchThisDomain(false), + _maxOctreePPS(maxOctreePacketsPerSecond.get()), + _lastFaceTrackerUpdate(0), + _snapshotSound(nullptr), + _sampleSound(nullptr) { + auto steamClient = PluginManager::getInstance()->getSteamClientPlugin(); setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); setProperty(hifi::properties::CRASHED, _previousSessionCrashed); @@ -991,6 +1021,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // This is done so as not break previous command line scripts if (testScriptPath.left(URL_SCHEME_HTTP.length()) == URL_SCHEME_HTTP || testScriptPath.left(URL_SCHEME_FTP.length()) == URL_SCHEME_FTP) { + setProperty(hifi::properties::TEST, QUrl::fromUserInput(testScriptPath)); } else if (QFileInfo(testScriptPath).exists()) { setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath)); @@ -1015,7 +1046,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // make sure the debug draw singleton is initialized on the main thread. DebugDraw::getInstance().removeMarker(""); - PluginContainer* pluginContainer = dynamic_cast(this); // set the container for any plugins that care + PluginContainer* pluginContainer = dynamic_cast(this); // set the container for any plugins that care PluginManager::getInstance()->setContainer(pluginContainer); QThreadPool::globalInstance()->setMaxThreadCount(MIN_PROCESSING_THREAD_POOL_SIZE); @@ -1048,7 +1079,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-SemiBold.ttf"); _window->setWindowTitle("High Fidelity Interface"); - Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us + Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us auto nodeList = DependencyManager::get(); nodeList->startThread(); @@ -1106,14 +1137,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo domainCheckInTimer->deleteLater(); }); + auto audioIO = DependencyManager::get(); - audioIO->setPositionGetter([] { + audioIO->setPositionGetter([]{ auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO; }); - audioIO->setOrientationGetter([] { + audioIO->setOrientationGetter([]{ auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; @@ -1124,11 +1156,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo audioIO->handleRecordedAudioInput(frame->data); }); - connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio) { + connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio){ static auto recorder = DependencyManager::get(); if (recorder->isRecording()) { - static const recording::FrameType AUDIO_FRAME_TYPE = - recording::Frame::registerFrameType(AudioConstants::getAudioFrameName()); + static const recording::FrameType AUDIO_FRAME_TYPE = recording::Frame::registerFrameType(AudioConstants::getAudioFrameName()); recorder->recordFrame(AUDIO_FRAME_TYPE, audio); } }); @@ -1136,8 +1167,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto audioScriptingInterface = DependencyManager::set(); connect(audioIO.data(), &AudioClient::mutedByMixer, audioScriptingInterface.data(), &AudioScriptingInterface::mutedByMixer); - connect(audioIO.data(), &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), - &AudioScriptingInterface::receivedFirstPacket); + connect(audioIO.data(), &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), &AudioScriptingInterface::receivedFirstPacket); connect(audioIO.data(), &AudioClient::disconnected, audioScriptingInterface.data(), &AudioScriptingInterface::disconnected); connect(audioIO.data(), &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) { auto audioClient = DependencyManager::get(); @@ -1150,8 +1180,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo audioScriptingInterface->environmentMuted(); } }); - connect(this, &Application::activeDisplayPluginChanged, reinterpret_cast(audioScriptingInterface.data()), - &scripting::Audio::onContextChanged); + connect(this, &Application::activeDisplayPluginChanged, + reinterpret_cast(audioScriptingInterface.data()), &scripting::Audio::onContextChanged); // Make sure we don't time out during slow operations at startup updateHeartbeat(); @@ -1162,8 +1192,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo const DomainHandler& domainHandler = nodeList->getDomainHandler(); connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl))); - connect(&domainHandler, &DomainHandler::domainURLChanged, - [](QUrl domainURL) { setCrashAnnotation("domain", domainURL.toString().toStdString()); }); + connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){ + setCrashAnnotation("domain", domainURL.toString().toStdString()); + }); connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain())); connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); @@ -1177,21 +1208,20 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // We could clear ATP assets only when changing domains, but it's possible that the domain you are connected // to has gone down and switched to a new content set, so when you reconnect the cached ATP assets will no longer be valid. - connect(&domainHandler, &DomainHandler::disconnectedFromDomain, DependencyManager::get().data(), - &ScriptCache::clearATPScriptsFromCache); + connect(&domainHandler, &DomainHandler::disconnectedFromDomain, DependencyManager::get().data(), &ScriptCache::clearATPScriptsFromCache); // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * MSECS_PER_SECOND; auto discoverabilityManager = DependencyManager::get(); connect(&locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); - connect(&locationUpdateTimer, &QTimer::timeout, DependencyManager::get().data(), - &AddressManager::storeCurrentAddress); + connect(&locationUpdateTimer, &QTimer::timeout, + DependencyManager::get().data(), &AddressManager::storeCurrentAddress); locationUpdateTimer.start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS); // if we get a domain change, immediately attempt update location in metaverse server - connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, discoverabilityManager.data(), - &DiscoverabilityManager::updateLocation); + connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, + discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); // send a location update immediately discoverabilityManager->updateLocation(); @@ -1204,13 +1234,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); // you might think we could just do this in NodeList but we only want this connection for Interface - connect(&nodeList->getDomainHandler(), SIGNAL(limitOfSilentDomainCheckInsReached()), nodeList.data(), SLOT(reset())); + connect(&nodeList->getDomainHandler(), SIGNAL(limitOfSilentDomainCheckInsReached()), + nodeList.data(), SLOT(reset())); auto dialogsManager = DependencyManager::get(); connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog); connect(accountManager.data(), &AccountManager::usernameChanged, this, &Application::updateWindowTitle); - connect(accountManager.data(), &AccountManager::usernameChanged, - [](QString username) { setCrashAnnotation("username", username.toStdString()); }); + connect(accountManager.data(), &AccountManager::usernameChanged, [](QString username){ + setCrashAnnotation("username", username.toStdString()); + }); // set the account manager's root URL and trigger a login request if we don't have the access token accountManager->setIsAgent(true); @@ -1219,14 +1251,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto addressManager = DependencyManager::get(); // use our MyAvatar position and quat for address manager path - addressManager->setPositionGetter([this] { return getMyAvatar()->getWorldPosition(); }); - addressManager->setOrientationGetter([this] { return getMyAvatar()->getWorldOrientation(); }); + addressManager->setPositionGetter([this]{ return getMyAvatar()->getWorldPosition(); }); + addressManager->setOrientationGetter([this]{ return getMyAvatar()->getWorldOrientation(); }); connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount); - connect(this, &Application::activeDisplayPluginChanged, this, []() { + connect(this, &Application::activeDisplayPluginChanged, this, [](){ qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode()); auto displayPlugin = qApp->getActiveDisplayPlugin(); setCrashAnnotation("display_plugin", displayPlugin->getName().toStdString()); @@ -1235,42 +1267,39 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode); // Save avatar location immediately after a teleport. - connect(myAvatar.get(), &MyAvatar::positionGoneTo, DependencyManager::get().data(), - &AddressManager::storeCurrentAddress); + connect(myAvatar.get(), &MyAvatar::positionGoneTo, + DependencyManager::get().data(), &AddressManager::storeCurrentAddress); - connect(myAvatar.get(), &MyAvatar::skeletonModelURLChanged, []() { + connect(myAvatar.get(), &MyAvatar::skeletonModelURLChanged, [](){ QUrl avatarURL = qApp->getMyAvatar()->getSkeletonModelURL(); setCrashAnnotation("avatar", avatarURL.toString().toStdString()); }); + // Inititalize sample before registering _sampleSound = DependencyManager::get()->getSound(PathUtils::resourcesUrl("sounds/sample.wav")); auto scriptEngines = DependencyManager::get().data(); - scriptEngines->registerScriptInitializer( - [this](ScriptEnginePointer engine) { registerScriptEngineWithApplicationServices(engine); }); + scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){ + registerScriptEngineWithApplicationServices(engine); + }); - connect(scriptEngines, &ScriptEngines::scriptCountChanged, scriptEngines, - [this] { - auto scriptEngines = DependencyManager::get(); - if (scriptEngines->getRunningScripts().isEmpty()) { - getMyAvatar()->clearScriptableSettings(); - } - }, - Qt::QueuedConnection); + connect(scriptEngines, &ScriptEngines::scriptCountChanged, scriptEngines, [this] { + auto scriptEngines = DependencyManager::get(); + if (scriptEngines->getRunningScripts().isEmpty()) { + getMyAvatar()->clearScriptableSettings(); + } + }, Qt::QueuedConnection); - connect(scriptEngines, &ScriptEngines::scriptsReloading, scriptEngines, - [this] { - getEntities()->reloadEntityScripts(); - loadAvatarScripts(getMyAvatar()->getScriptUrls()); - }, - Qt::QueuedConnection); + connect(scriptEngines, &ScriptEngines::scriptsReloading, scriptEngines, [this] { + getEntities()->reloadEntityScripts(); + loadAvatarScripts(getMyAvatar()->getScriptUrls()); + }, Qt::QueuedConnection); - connect(scriptEngines, &ScriptEngines::scriptLoadError, scriptEngines, - [](const QString& filename, const QString& error) { - OffscreenUi::asyncWarning(nullptr, "Error Loading Script", filename + " failed to load."); - }, - Qt::QueuedConnection); + connect(scriptEngines, &ScriptEngines::scriptLoadError, + scriptEngines, [](const QString& filename, const QString& error){ + OffscreenUi::asyncWarning(nullptr, "Error Loading Script", filename + " failed to load."); + }, Qt::QueuedConnection); #ifdef _WIN32 WSADATA WsaData; @@ -1279,13 +1308,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // tell the NodeList instance who to tell the domain server we care about nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer - << NodeType::EntityServer << NodeType::AssetServer - << NodeType::MessagesMixer << NodeType::EntityScriptServer); + << NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer << NodeType::EntityScriptServer); // connect to the packet sent signal of the _entityEditSender connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent); - connect(&_entityEditSender, &EntityEditPacketSender::addingEntityWithCertificate, this, - &Application::addingEntityWithCertificate); + connect(&_entityEditSender, &EntityEditPacketSender::addingEntityWithCertificate, this, &Application::addingEntityWithCertificate); QString concurrentDownloadsStr = getCmdOption(argc, constArgv, "--concurrent-downloads"); bool success; @@ -1338,11 +1365,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo initializeGL(); qCDebug(interfaceapp, "Initialized GL"); - // Initialize the display plugin architecture + // Initialize the display plugin architecture initializeDisplayPlugins(); qCDebug(interfaceapp, "Initialized Display"); - // Create the rendering engine. This can be slow on some machines due to lots of + // Create the rendering engine. This can be slow on some machines due to lots of // GPU pipeline creation. initializeRenderEngine(); qCDebug(interfaceapp, "Initialized Render Engine."); @@ -1369,7 +1396,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo constexpr auto INSTALLER_INI_NAME = "installer.ini"; auto iniPath = QDir(applicationDirPath()).filePath(INSTALLER_INI_NAME); - QFile installerFile{ iniPath }; + QFile installerFile { iniPath }; std::unordered_map installerKeyValues; if (installerFile.open(QIODevice::ReadOnly)) { while (!installerFile.atEnd()) { @@ -1386,7 +1413,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // In practice we shouldn't run across installs that don't have a known installer type. // Client or Client+Server installs should always have the installer.ini next to their // respective interface.exe, and Steam installs will be detected as such. If a user were - // to delete the installer.ini, though, and as an example, we won't know the context of the + // to delete the installer.ini, though, and as an example, we won't know the context of the // original install. constexpr auto INSTALLER_KEY_TYPE = "type"; constexpr auto INSTALLER_KEY_CAMPAIGN = "campaign"; @@ -1410,7 +1437,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qDebug() << "Detected installer campaign:" << installerCampaign; // add firstRun flag from settings to launch event - Setting::Handle firstRun{ Settings::firstRun, true }; + Setting::Handle firstRun { Settings::firstRun, true }; // once the settings have been loaded, check if we need to flip the default for UserActivityLogger auto& userActivityLogger = UserActivityLogger::getInstance(); @@ -1429,26 +1456,28 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo static const QString TESTER = "HIFI_TESTER"; auto gpuIdent = GPUIdent::getInstance(); auto glContextData = getGLContextData(); - QJsonObject properties = { { "version", applicationVersion() }, - { "tester", QProcessEnvironment::systemEnvironment().contains(TESTER) }, - { "installer_campaign", installerCampaign }, - { "installer_type", installerType }, - { "previousSessionCrashed", _previousSessionCrashed }, - { "previousSessionRuntime", sessionRunTime.get() }, - { "cpu_architecture", QSysInfo::currentCpuArchitecture() }, - { "kernel_type", QSysInfo::kernelType() }, - { "kernel_version", QSysInfo::kernelVersion() }, - { "os_type", QSysInfo::productType() }, - { "os_version", QSysInfo::productVersion() }, - { "gpu_name", gpuIdent->getName() }, - { "gpu_driver", gpuIdent->getDriver() }, - { "gpu_memory", static_cast(gpuIdent->getMemory()) }, - { "gl_version_int", glVersionToInteger(glContextData.value("version").toString()) }, - { "gl_version", glContextData["version"] }, - { "gl_vender", glContextData["vendor"] }, - { "gl_sl_version", glContextData["sl_version"] }, - { "gl_renderer", glContextData["renderer"] }, - { "ideal_thread_count", QThread::idealThreadCount() } }; + QJsonObject properties = { + { "version", applicationVersion() }, + { "tester", QProcessEnvironment::systemEnvironment().contains(TESTER) }, + { "installer_campaign", installerCampaign }, + { "installer_type", installerType }, + { "previousSessionCrashed", _previousSessionCrashed }, + { "previousSessionRuntime", sessionRunTime.get() }, + { "cpu_architecture", QSysInfo::currentCpuArchitecture() }, + { "kernel_type", QSysInfo::kernelType() }, + { "kernel_version", QSysInfo::kernelVersion() }, + { "os_type", QSysInfo::productType() }, + { "os_version", QSysInfo::productVersion() }, + { "gpu_name", gpuIdent->getName() }, + { "gpu_driver", gpuIdent->getDriver() }, + { "gpu_memory", static_cast(gpuIdent->getMemory()) }, + { "gl_version_int", glVersionToInteger(glContextData.value("version").toString()) }, + { "gl_version", glContextData["version"] }, + { "gl_vender", glContextData["vendor"] }, + { "gl_sl_version", glContextData["sl_version"] }, + { "gl_renderer", glContextData["renderer"] }, + { "ideal_thread_count", QThread::idealThreadCount() } + }; auto macVersion = QSysInfo::macVersion(); if (macVersion != QSysInfo::MV_None) { properties["os_osx_version"] = QSysInfo::macVersion(); @@ -1486,10 +1515,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // For now we're going to set the PPS for outbound packets to be super high, this is // probably not the right long term solution. But for now, we're going to do this to // allow you to move an entity around in your hand - _entityEditSender.setPacketsPerSecond(3000); // super high!! + _entityEditSender.setPacketsPerSecond(3000); // super high!! // Overlays need to exist before we set the ContextOverlayInterface dependency - _overlays.init(); // do this before scripts load + _overlays.init(); // do this before scripts load DependencyManager::set(); // Make sure we don't time out during slow operations at startup @@ -1499,12 +1528,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // hook up bandwidth estimator QSharedPointer bandwidthRecorder = DependencyManager::get(); - connect(nodeList.data(), &LimitedNodeList::dataSent, bandwidthRecorder.data(), &BandwidthRecorder::updateOutboundData); - connect(nodeList.data(), &LimitedNodeList::dataReceived, bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData); + connect(nodeList.data(), &LimitedNodeList::dataSent, + bandwidthRecorder.data(), &BandwidthRecorder::updateOutboundData); + connect(nodeList.data(), &LimitedNodeList::dataReceived, + bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData); // FIXME -- I'm a little concerned about this. - connect(myAvatar->getSkeletonModel().get(), &SkeletonModel::skeletonLoaded, this, &Application::checkSkeleton, - Qt::QueuedConnection); + connect(myAvatar->getSkeletonModel().get(), &SkeletonModel::skeletonLoaded, + this, &Application::checkSkeleton, Qt::QueuedConnection); // Setup the userInputMapper with the actions auto userInputMapper = DependencyManager::get(); @@ -1585,7 +1616,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (action == controller::toInt(controller::Action::RETICLE_CLICK)) { auto reticlePos = getApplicationCompositor().getReticlePosition(); - QPoint localPos(reticlePos.x, reticlePos.y); // both hmd and desktop already handle this in our coordinates. + QPoint localPos(reticlePos.x, reticlePos.y); // both hmd and desktop already handle this in our coordinates. if (state) { QMouseEvent mousePress(QEvent::MouseButtonPress, localPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); sendEvent(_glWidget, &mousePress); @@ -1595,7 +1626,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo sendEvent(_glWidget, &mouseRelease); _reticleClickPressed = false; } - return; // nothing else to do + return; // nothing else to do } if (state) { @@ -1620,7 +1651,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _applicationStateDevice = userInputMapper->getStateDevice(); - _applicationStateDevice->setInputVariant(STATE_IN_HMD, []() -> float { return qApp->isHMDMode() ? 1 : 0; }); + _applicationStateDevice->setInputVariant(STATE_IN_HMD, []() -> float { + return qApp->isHMDMode() ? 1 : 0; + }); _applicationStateDevice->setInputVariant(STATE_CAMERA_FULL_SCREEN_MIRROR, []() -> float { return qApp->getCamera().getMode() == CAMERA_MODE_MIRROR ? 1 : 0; }); @@ -1636,8 +1669,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _applicationStateDevice->setInputVariant(STATE_CAMERA_INDEPENDENT, []() -> float { return qApp->getCamera().getMode() == CAMERA_MODE_INDEPENDENT ? 1 : 0; }); - _applicationStateDevice->setInputVariant(STATE_SNAP_TURN, - []() -> float { return qApp->getMyAvatar()->getSnapTurn() ? 1 : 0; }); + _applicationStateDevice->setInputVariant(STATE_SNAP_TURN, []() -> float { + return qApp->getMyAvatar()->getSnapTurn() ? 1 : 0; + }); _applicationStateDevice->setInputVariant(STATE_ADVANCED_MOVEMENT_CONTROLS, []() -> float { return qApp->getMyAvatar()->useAdvancedMovementControls() ? 1 : 0; }); @@ -1695,27 +1729,25 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo updateHeartbeat(); QTimer* settingsTimer = new QTimer(); - moveToNewNamedThread(settingsTimer, "Settings Thread", - [this, settingsTimer] { - connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer] { - // Disconnect the signal from the save settings - QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); - // Stop the settings timer - settingsTimer->stop(); - // Delete it (this will trigger the thread destruction - settingsTimer->deleteLater(); - // Mark the settings thread as finished, so we know we can safely save in the main application - // shutdown code - _settingsGuard.trigger(); - }); + moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{ + connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer]{ + // Disconnect the signal from the save settings + QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); + // Stop the settings timer + settingsTimer->stop(); + // Delete it (this will trigger the thread destruction + settingsTimer->deleteLater(); + // Mark the settings thread as finished, so we know we can safely save in the main application + // shutdown code + _settingsGuard.trigger(); + }); - int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now - settingsTimer->setSingleShot(false); - settingsTimer->setInterval(SAVE_SETTINGS_INTERVAL); // 10s, Qt::CoarseTimer acceptable - QObject::connect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); - settingsTimer->start(); - }, - QThread::LowestPriority); + int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now + settingsTimer->setSingleShot(false); + settingsTimer->setInterval(SAVE_SETTINGS_INTERVAL); // 10s, Qt::CoarseTimer acceptable + QObject::connect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); + settingsTimer->start(); + }, QThread::LowestPriority); if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) { getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN); // So that camera doesn't auto-switch to third person. @@ -1730,12 +1762,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // set the local loopback interface for local sounds AudioInjector::setLocalAudioInterface(audioIO.data()); audioScriptingInterface->setLocalAudioInterface(audioIO.data()); - connect(audioIO.data(), &AudioClient::noiseGateOpened, audioScriptingInterface.data(), - &AudioScriptingInterface::noiseGateOpened); - connect(audioIO.data(), &AudioClient::noiseGateClosed, audioScriptingInterface.data(), - &AudioScriptingInterface::noiseGateClosed); - connect(audioIO.data(), &AudioClient::inputReceived, audioScriptingInterface.data(), - &AudioScriptingInterface::inputReceived); + connect(audioIO.data(), &AudioClient::noiseGateOpened, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateOpened); + connect(audioIO.data(), &AudioClient::noiseGateClosed, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateClosed); + connect(audioIO.data(), &AudioClient::inputReceived, audioScriptingInterface.data(), &AudioScriptingInterface::inputReceived); this->installEventFilter(this); @@ -1759,13 +1788,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto applicationUpdater = DependencyManager::get(); - AutoUpdater::InstallerType type = installerType == INSTALLER_TYPE_CLIENT_ONLY ? AutoUpdater::InstallerType::CLIENT_ONLY - : AutoUpdater::InstallerType::FULL; + AutoUpdater::InstallerType type = installerType == INSTALLER_TYPE_CLIENT_ONLY + ? AutoUpdater::InstallerType::CLIENT_ONLY : AutoUpdater::InstallerType::FULL; applicationUpdater->setInstallerType(type); applicationUpdater->setInstallerCampaign(installerCampaign); - connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), - &DialogsManager::showUpdateDialog); + connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog); applicationUpdater->checkForUpdate(); } @@ -1781,15 +1809,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto entityScriptingInterface = DependencyManager::get(); connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, [this](const EntityItemID& entityItemID, const PointerEvent& event) { - if (event.shouldFocus()) { - if (getEntities()->wantsKeyboardFocus(entityItemID)) { - setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); - setKeyboardFocusEntity(entityItemID); - } else { - setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); - } - } - }); + if (event.shouldFocus()) { + if (getEntities()->wantsKeyboardFocus(entityItemID)) { + setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); + setKeyboardFocusEntity(entityItemID); + } else { + setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); + } + } + }); connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, [=](const EntityItemID& entityItemID) { if (entityItemID == _keyboardFocusedEntity.get()) { @@ -1805,78 +1833,72 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); - EntityTree::setAddMaterialToEntityOperator( - [&](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - // try to find the renderable - auto renderable = getEntities()->renderableForEntityId(entityID); - if (renderable) { - renderable->addMaterial(material, parentMaterialName); - } + EntityTree::setAddMaterialToEntityOperator([&](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + // try to find the renderable + auto renderable = getEntities()->renderableForEntityId(entityID); + if (renderable) { + renderable->addMaterial(material, parentMaterialName); + } - // even if we don't find it, try to find the entity - auto entity = getEntities()->getEntity(entityID); - if (entity) { - entity->addMaterial(material, parentMaterialName); - return true; - } - return false; - }); - EntityTree::setRemoveMaterialFromEntityOperator( - [&](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - // try to find the renderable - auto renderable = getEntities()->renderableForEntityId(entityID); - if (renderable) { - renderable->removeMaterial(material, parentMaterialName); - } + // even if we don't find it, try to find the entity + auto entity = getEntities()->getEntity(entityID); + if (entity) { + entity->addMaterial(material, parentMaterialName); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromEntityOperator([&](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + // try to find the renderable + auto renderable = getEntities()->renderableForEntityId(entityID); + if (renderable) { + renderable->removeMaterial(material, parentMaterialName); + } - // even if we don't find it, try to find the entity - auto entity = getEntities()->getEntity(entityID); - if (entity) { - entity->removeMaterial(material, parentMaterialName); - return true; - } - return false; - }); + // even if we don't find it, try to find the entity + auto entity = getEntities()->getEntity(entityID); + if (entity) { + entity->removeMaterial(material, parentMaterialName); + return true; + } + return false; + }); - EntityTree::setAddMaterialToAvatarOperator( - [](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - auto avatarManager = DependencyManager::get(); - auto avatar = avatarManager->getAvatarBySessionID(avatarID); - if (avatar) { - avatar->addMaterial(material, parentMaterialName); - return true; - } - return false; - }); - EntityTree::setRemoveMaterialFromAvatarOperator( - [](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - auto avatarManager = DependencyManager::get(); - auto avatar = avatarManager->getAvatarBySessionID(avatarID); - if (avatar) { - avatar->removeMaterial(material, parentMaterialName); - return true; - } - return false; - }); + EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + auto avatarManager = DependencyManager::get(); + auto avatar = avatarManager->getAvatarBySessionID(avatarID); + if (avatar) { + avatar->addMaterial(material, parentMaterialName); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + auto avatarManager = DependencyManager::get(); + auto avatar = avatarManager->getAvatarBySessionID(avatarID); + if (avatar) { + avatar->removeMaterial(material, parentMaterialName); + return true; + } + return false; + }); - EntityTree::setAddMaterialToOverlayOperator( - [&](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - auto overlay = _overlays.getOverlay(overlayID); - if (overlay) { - overlay->addMaterial(material, parentMaterialName); - return true; - } - return false; - }); - EntityTree::setRemoveMaterialFromOverlayOperator( - [&](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - auto overlay = _overlays.getOverlay(overlayID); - if (overlay) { - overlay->removeMaterial(material, parentMaterialName); - return true; - } - return false; - }); + EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + auto overlay = _overlays.getOverlay(overlayID); + if (overlay) { + overlay->addMaterial(material, parentMaterialName); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + auto overlay = _overlays.getOverlay(overlayID); + if (overlay) { + overlay->removeMaterial(material, parentMaterialName); + return true; + } + return false; + }); // Keyboard focus handling for Web overlays. auto overlays = &(qApp->getOverlays()); @@ -1919,8 +1941,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // content location and build info - useful for filtering stats auto addressManager = DependencyManager::get(); - auto currentDomain = addressManager->currentShareableAddress(true).toString(); // domain only - auto currentPath = addressManager->currentPath(true); // with orientation + auto currentDomain = addressManager->currentShareableAddress(true).toString(); // domain only + auto currentPath = addressManager->currentPath(true); // with orientation properties["current_domain"] = currentDomain; properties["current_path"] = currentPath; properties["build_version"] = BuildInfo::VERSION; @@ -1986,24 +2008,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo startedRequests["atp"] = statTracker->getStat(STAT_ATP_REQUEST_STARTED).toInt(); startedRequests["http"] = statTracker->getStat(STAT_HTTP_REQUEST_STARTED).toInt(); startedRequests["file"] = statTracker->getStat(STAT_FILE_REQUEST_STARTED).toInt(); - startedRequests["total"] = - startedRequests["atp"].toInt() + startedRequests["http"].toInt() + startedRequests["file"].toInt(); + startedRequests["total"] = startedRequests["atp"].toInt() + startedRequests["http"].toInt() + + startedRequests["file"].toInt(); properties["started_requests"] = startedRequests; QJsonObject successfulRequests; successfulRequests["atp"] = statTracker->getStat(STAT_ATP_REQUEST_SUCCESS).toInt(); successfulRequests["http"] = statTracker->getStat(STAT_HTTP_REQUEST_SUCCESS).toInt(); successfulRequests["file"] = statTracker->getStat(STAT_FILE_REQUEST_SUCCESS).toInt(); - successfulRequests["total"] = - successfulRequests["atp"].toInt() + successfulRequests["http"].toInt() + successfulRequests["file"].toInt(); + successfulRequests["total"] = successfulRequests["atp"].toInt() + successfulRequests["http"].toInt() + + successfulRequests["file"].toInt(); properties["successful_requests"] = successfulRequests; QJsonObject failedRequests; failedRequests["atp"] = statTracker->getStat(STAT_ATP_REQUEST_FAILED).toInt(); failedRequests["http"] = statTracker->getStat(STAT_HTTP_REQUEST_FAILED).toInt(); failedRequests["file"] = statTracker->getStat(STAT_FILE_REQUEST_FAILED).toInt(); - failedRequests["total"] = - failedRequests["atp"].toInt() + failedRequests["http"].toInt() + failedRequests["file"].toInt(); + failedRequests["total"] = failedRequests["atp"].toInt() + failedRequests["http"].toInt() + + failedRequests["file"].toInt(); properties["failed_requests"] = failedRequests; QJsonObject cacheRequests; @@ -2048,18 +2070,21 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo totalServerOctreeElements += i->second.getTotalElements(); } - properties["local_octree_elements"] = (qint64)OctreeElement::getInternalNodeCount(); - properties["server_octree_elements"] = (qint64)totalServerOctreeElements; + properties["local_octree_elements"] = (qint64) OctreeElement::getInternalNodeCount(); + properties["server_octree_elements"] = (qint64) totalServerOctreeElements; properties["active_display_plugin"] = getActiveDisplayPlugin()->getName(); properties["using_hmd"] = isHMDMode(); _autoSwitchDisplayModeSupportedHMDPlugin = nullptr; - foreach (DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { - if (displayPlugin->isHmd() && displayPlugin->getSupportsAutoSwitch()) { + foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { + if (displayPlugin->isHmd() && + displayPlugin->getSupportsAutoSwitch()) { _autoSwitchDisplayModeSupportedHMDPlugin = displayPlugin; - _autoSwitchDisplayModeSupportedHMDPluginName = _autoSwitchDisplayModeSupportedHMDPlugin->getName(); - _previousHMDWornStatus = _autoSwitchDisplayModeSupportedHMDPlugin->isDisplayVisible(); + _autoSwitchDisplayModeSupportedHMDPluginName = + _autoSwitchDisplayModeSupportedHMDPlugin->getName(); + _previousHMDWornStatus = + _autoSwitchDisplayModeSupportedHMDPlugin->isDisplayVisible(); break; } } @@ -2067,7 +2092,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (_autoSwitchDisplayModeSupportedHMDPlugin) { if (getActiveDisplayPlugin() != _autoSwitchDisplayModeSupportedHMDPlugin && !_autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { - startHMDStandBySession(); + startHMDStandBySession(); } // Poll periodically to check whether the user has worn HMD or not. Switch Display mode accordingly. // If the user wears HMD then switch to VR mode. If the user removes HMD then switch to Desktop mode. @@ -2093,8 +2118,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // controller::Pose considers two poses to be different if either are invalid. In our case, we actually // want to consider the pose to be unchanged if it was invalid and still is invalid, so we check that first. properties["hand_pose_changed"] = - ((leftHandPose.valid || lastLeftHandPose.valid) && (leftHandPose != lastLeftHandPose)) || - ((rightHandPose.valid || lastRightHandPose.valid) && (rightHandPose != lastRightHandPose)); + ((leftHandPose.valid || lastLeftHandPose.valid) && (leftHandPose != lastLeftHandPose)) + || ((rightHandPose.valid || lastRightHandPose.valid) && (rightHandPose != lastRightHandPose)); lastLeftHandPose = leftHandPose; lastRightHandPose = rightHandPose; @@ -2105,12 +2130,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Periodically check for count of nearby avatars static int lastCountOfNearbyAvatars = -1; QTimer* checkNearbyAvatarsTimer = new QTimer(this); - checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); // 10 seconds, Qt::CoarseTimer ok + checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); // 10 seconds, Qt::CoarseTimer ok connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, []() { auto avatarManager = DependencyManager::get(); int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getWorldPosition(), - NEARBY_AVATAR_RADIUS_METERS) - - 1; + NEARBY_AVATAR_RADIUS_METERS) - 1; if (nearbyAvatars != lastCountOfNearbyAvatars) { lastCountOfNearbyAvatars = nearbyAvatars; UserActivityLogger::getInstance().logAction("nearby_avatars", { { "count", nearbyAvatars } }); @@ -2119,7 +2143,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo checkNearbyAvatarsTimer->start(); // Track user activity event when we receive a mute packet - auto onMutedByMixer = []() { UserActivityLogger::getInstance().logAction("received_mute_packet"); }; + auto onMutedByMixer = []() { + UserActivityLogger::getInstance().logAction("received_mute_packet"); + }; connect(DependencyManager::get().data(), &AudioClient::mutedByMixer, this, onMutedByMixer); // Track when the address bar is opened @@ -2152,33 +2178,37 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (testProperty.isValid()) { auto scriptEngines = DependencyManager::get(); const auto testScript = property(hifi::properties::TEST).toUrl(); - + // Set last parameter to exit interface when the test script finishes, if so requested scriptEngines->loadScript(testScript, false, false, false, false, quitWhenFinished); // This is done so we don't get a "connection time-out" message when we haven't passed in a URL. if (arguments().contains("--url")) { auto reply = SandboxUtils::getStatus(); - connect(reply, &QNetworkReply::finished, this, [=] { handleSandboxStatus(reply); }); + connect(reply, &QNetworkReply::finished, this, [=] { + handleSandboxStatus(reply); + }); } } else { PROFILE_RANGE(render, "GetSandboxStatus"); auto reply = SandboxUtils::getStatus(); - connect(reply, &QNetworkReply::finished, this, [=] { handleSandboxStatus(reply); }); + connect(reply, &QNetworkReply::finished, this, [=] { + handleSandboxStatus(reply); + }); } // Monitor model assets (e.g., from Clara.io) added to the world that may need resizing. static const int ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS = 1000; - _addAssetToWorldResizeTimer.setInterval(ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS); // 1s, Qt::CoarseTimer acceptable + _addAssetToWorldResizeTimer.setInterval(ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS); // 1s, Qt::CoarseTimer acceptable connect(&_addAssetToWorldResizeTimer, &QTimer::timeout, this, &Application::addAssetToWorldCheckModelSize); // Auto-update and close adding asset to world info message box. static const int ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS = 5000; - _addAssetToWorldInfoTimer.setInterval(ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS); // 5s, Qt::CoarseTimer acceptable + _addAssetToWorldInfoTimer.setInterval(ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS); // 5s, Qt::CoarseTimer acceptable _addAssetToWorldInfoTimer.setSingleShot(true); connect(&_addAssetToWorldInfoTimer, &QTimer::timeout, this, &Application::addAssetToWorldInfoTimeout); static const int ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS = 8000; - _addAssetToWorldErrorTimer.setInterval(ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS); // 8s, Qt::CoarseTimer acceptable + _addAssetToWorldErrorTimer.setInterval(ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS); // 8s, Qt::CoarseTimer acceptable _addAssetToWorldErrorTimer.setSingleShot(true); connect(&_addAssetToWorldErrorTimer, &QTimer::timeout, this, &Application::addAssetToWorldErrorTimeout); @@ -2189,8 +2219,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged); - DependencyManager::get()->setShouldPickHUDOperator( - [&]() { return DependencyManager::get()->isHMDMode(); }); + DependencyManager::get()->setShouldPickHUDOperator([&]() { return DependencyManager::get()->isHMDMode(); }); DependencyManager::get()->setCalculatePos2DFromHUDOperator([&](const glm::vec3& intersection) { const glm::vec2 MARGIN(25.0f); glm::vec2 maxPos = _controllerScriptingInterface->getViewportDimensions() - MARGIN; @@ -2199,12 +2228,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo }); // Setup the mouse ray pick and related operators - DependencyManager::get()->setMouseRayPickID( - DependencyManager::get() - ->addPick(PickQuery::Ray, - std::make_shared(PickFilter(PickScriptingInterface::PICK_ENTITIES() | - PickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), - 0.0f, true))); + DependencyManager::get()->setMouseRayPickID(DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared( + PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true))); DependencyManager::get()->setMouseRayPickResultOperator([&](unsigned int rayPickID) { RayToEntityIntersectionResult entityResult; entityResult.intersects = false; @@ -2224,8 +2249,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get()->setSetPrecisionPickingOperator([&](unsigned int rayPickID, bool value) { DependencyManager::get()->setPrecisionPicking(rayPickID, value); }); - EntityTreeRenderer::setRenderDebugHullsOperator( - [] { return Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls); }); + EntityTreeRenderer::setRenderDebugHullsOperator([] { + return Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls); + }); // Preload Tablet sounds DependencyManager::get()->preloadSounds(); @@ -2284,10 +2310,10 @@ QString Application::getUserAgent() { return userAgent; } - QString userAgent = "Mozilla/5.0 (HighFidelityInterface/" + BuildInfo::VERSION + "; " + QSysInfo::productType() + " " + - QSysInfo::productVersion() + ")"; + QString userAgent = "Mozilla/5.0 (HighFidelityInterface/" + BuildInfo::VERSION + "; " + + QSysInfo::productType() + " " + QSysInfo::productVersion() + ")"; - auto formatPluginName = [](QString name) -> QString { return name.trimmed().replace(" ", "-"); }; + auto formatPluginName = [](QString name) -> QString { return name.trimmed().replace(" ", "-"); }; // For each plugin, add to userAgent auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); @@ -2296,7 +2322,7 @@ QString Application::getUserAgent() { userAgent += " " + formatPluginName(dp->getName()); } } - auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); + auto inputPlugins= PluginManager::getInstance()->getInputPlugins(); for (auto& ip : inputPlugins) { if (ip->isActive()) { userAgent += " " + formatPluginName(ip->getName()); @@ -2324,7 +2350,7 @@ void Application::checkChangeCursor() { QMutexLocker locker(&_changeCursorLock); if (_cursorNeedsChanging) { #ifdef Q_OS_MAC - auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget + 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 // window menu, which is a pain, so only hide it for the GL surface @@ -2356,18 +2382,19 @@ void Application::updateHeartbeat() const { void Application::onAboutToQuit() { emit beforeAboutToQuit(); - foreach (auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { + foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { if (inputPlugin->isActive()) { inputPlugin->deactivate(); } } - // The active display plugin needs to be loaded before the menu system is active, + // The active display plugin needs to be loaded before the menu system is active, // so its persisted explicitly here Setting::Handle{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME }.set(getActiveDisplayPlugin()->getName()); getActiveDisplayPlugin()->deactivate(); - if (_autoSwitchDisplayModeSupportedHMDPlugin && _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { + if (_autoSwitchDisplayModeSupportedHMDPlugin + && _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { _autoSwitchDisplayModeSupportedHMDPlugin->endSession(); } // use the CloseEventSender via a QThread to send an event that says the user asked for the app to close @@ -2393,7 +2420,7 @@ void Application::cleanupBeforeQuit() { tracer->serialize(outputFile); } - // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash. + // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash. #ifdef HAVE_DDE DependencyManager::get()->setEnabled(false); #endif @@ -2422,12 +2449,12 @@ void Application::cleanupBeforeQuit() { // tell the packet receiver we're shutting down, so it can drop packets nodeList->getPacketReceiver().setShouldDropPackets(true); - getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts + getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts // Clear any queued processing (I/O, FBX/OBJ/Texture parsing) QThreadPool::globalInstance()->clear(); - DependencyManager::get()->shutdownScripting(); // stop all currently running global scripts + DependencyManager::get()->shutdownScripting(); // stop all currently running global scripts DependencyManager::destroy(); _displayPlugin.reset(); @@ -2438,8 +2465,8 @@ void Application::cleanupBeforeQuit() { // The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual // removal of the items. // See https://highfidelity.fogbugz.com/f/cases/5328 - _main3DScene->enqueueFrame(); // flush all the transactions - _main3DScene->processTransactionQueue(); // process and apply deletions + _main3DScene->enqueueFrame(); // flush all the transactions + _main3DScene->processTransactionQueue(); // process and apply deletions // first stop all timers directly or by invokeMethod // depending on what thread they run in @@ -2595,12 +2622,12 @@ void Application::initializeGL() { // Create the GPU backend // Requires the window context, because that's what's used in the actual rendering - // and the GPU backend will make things like the VAO which cannot be shared across + // and the GPU backend will make things like the VAO which cannot be shared across // contexts _glWidget->makeCurrent(); gpu::Context::init(); qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK, - QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram))); + QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram))); _glWidget->makeCurrent(); _gpuContext = std::make_shared(); @@ -2610,9 +2637,7 @@ void Application::initializeGL() { _offscreenContext->makeCurrent(); } -static const QString SPLASH_SKYBOX{ - "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" -}; +static const QString SPLASH_SKYBOX{ "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" }; void Application::initializeDisplayPlugins() { auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); @@ -2620,20 +2645,20 @@ void Application::initializeDisplayPlugins() { auto lastActiveDisplayPluginName = activeDisplayPluginSetting.get(); auto defaultDisplayPlugin = displayPlugins.at(0); - // Once time initialization code + // Once time initialization code DisplayPluginPointer targetDisplayPlugin; - foreach (auto displayPlugin, displayPlugins) { + foreach(auto displayPlugin, displayPlugins) { displayPlugin->setContext(_gpuContext); if (displayPlugin->getName() == lastActiveDisplayPluginName) { targetDisplayPlugin = displayPlugin; } QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, - [this](const QSize& size) { resizeGL(); }); + [this](const QSize& size) { resizeGL(); }); QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset); } // The default display plugin needs to be activated first, otherwise the display plugin thread - // may be launched by an external plugin, which is bad + // may be launched by an external plugin, which is bad setDisplayPlugin(defaultDisplayPlugin); // Now set the desired plugin if it's not the same as the default plugin @@ -2697,8 +2722,7 @@ void Application::initializeRenderEngine() { #ifndef Q_OS_ANDROID _renderEngine->addJob("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED); #endif - _renderEngine->addJob("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, - render::ItemKey::TAG_BITS_0); + _renderEngine->addJob("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0); _renderEngine->load(); _renderEngine->registerScene(_main3DScene); @@ -2711,7 +2735,7 @@ extern void setupPreferences(); static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, bool active); void Application::initializeUi() { -// Build a shared canvas / context for the Chromium processes + // Build a shared canvas / context for the Chromium processes #if !defined(DISABLE_QML) // Chromium rendering uses some GL functions that prevent nSight from capturing // frames, so we only create the shared context if nsight is NOT active. @@ -2750,32 +2774,32 @@ void Application::initializeUi() { LoginDialog::registerType(); Tooltip::registerType(); UpdateDialog::registerType(); - QmlContextCallback callback = [](QQmlContext* context) { context->setContextProperty("Commerce", new QmlCommerce()); }; - OffscreenQmlSurface::addWhitelistContextHandler( - { - QUrl{ "hifi/commerce/checkout/Checkout.qml" }, - QUrl{ "hifi/commerce/common/CommerceLightbox.qml" }, - QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, - QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" }, - QUrl{ "hifi/commerce/common/SortableListModel.qml" }, - QUrl{ "hifi/commerce/common/sendAsset/SendAsset.qml" }, - QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, - QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" }, - QUrl{ "hifi/commerce/purchases/Purchases.qml" }, - QUrl{ "hifi/commerce/wallet/Help.qml" }, - QUrl{ "hifi/commerce/wallet/NeedsLogIn.qml" }, - QUrl{ "hifi/commerce/wallet/PassphraseChange.qml" }, - QUrl{ "hifi/commerce/wallet/PassphraseModal.qml" }, - QUrl{ "hifi/commerce/wallet/PassphraseSelection.qml" }, - QUrl{ "hifi/commerce/wallet/Security.qml" }, - QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" }, - QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" }, - QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" }, - QUrl{ "hifi/commerce/wallet/Wallet.qml" }, - QUrl{ "hifi/commerce/wallet/WalletHome.qml" }, - QUrl{ "hifi/commerce/wallet/WalletSetup.qml" }, - }, - callback); + QmlContextCallback callback = [](QQmlContext* context) { + context->setContextProperty("Commerce", new QmlCommerce()); + }; + OffscreenQmlSurface::addWhitelistContextHandler({ + QUrl{ "hifi/commerce/checkout/Checkout.qml" }, + QUrl{ "hifi/commerce/common/CommerceLightbox.qml" }, + QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, + QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" }, + QUrl{ "hifi/commerce/common/SortableListModel.qml" }, + QUrl{ "hifi/commerce/common/sendAsset/SendAsset.qml" }, + QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, + QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" }, + QUrl{ "hifi/commerce/purchases/Purchases.qml" }, + QUrl{ "hifi/commerce/wallet/Help.qml" }, + QUrl{ "hifi/commerce/wallet/NeedsLogIn.qml" }, + QUrl{ "hifi/commerce/wallet/PassphraseChange.qml" }, + QUrl{ "hifi/commerce/wallet/PassphraseModal.qml" }, + QUrl{ "hifi/commerce/wallet/PassphraseSelection.qml" }, + QUrl{ "hifi/commerce/wallet/Security.qml" }, + QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" }, + QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" }, + QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" }, + QUrl{ "hifi/commerce/wallet/Wallet.qml" }, + QUrl{ "hifi/commerce/wallet/WalletHome.qml" }, + QUrl{ "hifi/commerce/wallet/WalletSetup.qml" }, + }, callback); qmlRegisterType("Hifi", 1, 0, "ResourceImageItem"); qmlRegisterType("Hifi", 1, 0, "Preference"); qmlRegisterType("HifiWeb", 1, 0, "WebBrowserSuggestionsEngine"); @@ -2786,14 +2810,17 @@ void Application::initializeUi() { } auto offscreenUi = DependencyManager::get(); - connect(offscreenUi.data(), &hifi::qml::OffscreenSurface::rootContextCreated, this, - &Application::onDesktopRootContextCreated); - connect(offscreenUi.data(), &hifi::qml::OffscreenSurface::rootItemCreated, this, &Application::onDesktopRootItemCreated); + connect(offscreenUi.data(), &hifi::qml::OffscreenSurface::rootContextCreated, + this, &Application::onDesktopRootContextCreated); + connect(offscreenUi.data(), &hifi::qml::OffscreenSurface::rootItemCreated, + this, &Application::onDesktopRootItemCreated); offscreenUi->setProxyWindow(_window->windowHandle()); // OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to // support the window management and scripting proxies for VR use - DeadlockWatchdogThread::withPause([&] { offscreenUi->createDesktop(PathUtils::qmlUrl("hifi/Desktop.qml")); }); + DeadlockWatchdogThread::withPause([&] { + offscreenUi->createDesktop(PathUtils::qmlUrl("hifi/Desktop.qml")); + }); // FIXME either expose so that dialogs can set this themselves or // do better detection in the offscreen UI of what has focus offscreenUi->setNavigationFocused(false); @@ -2812,7 +2839,7 @@ void Application::initializeUi() { return result.toPoint(); }); offscreenUi->resume(); - connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r) { + connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r){ resizeGL(); if (_touchscreenVirtualPadDevice) { _touchscreenVirtualPadDevice->resize(); @@ -2821,7 +2848,7 @@ void Application::initializeUi() { // This will set up the input plugins UI _activeInputPlugins.clear(); - foreach (auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { + foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { if (KeyboardMouseDevice::NAME == inputPlugin->getName()) { _keyboardMouseDevice = std::dynamic_pointer_cast(inputPlugin); } @@ -2836,8 +2863,9 @@ void Application::initializeUi() { auto compositorHelper = DependencyManager::get(); connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, this, [=] { if (isHMDMode()) { - showCursor(compositorHelper->getAllowMouseCapture() ? Cursor::Manager::lookupIcon(_preferredCursor.get()) - : Cursor::Icon::SYSTEM); + showCursor(compositorHelper->getAllowMouseCapture() ? + Cursor::Manager::lookupIcon(_preferredCursor.get()) : + Cursor::Icon::SYSTEM); } }); @@ -2853,12 +2881,10 @@ void Application::initializeUi() { auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); // first sort the plugins into groupings: standard, advanced, developer std::stable_sort(displayPlugins.begin(), displayPlugins.end(), - [](const DisplayPluginPointer& a, const DisplayPluginPointer& b) -> bool { - return a->getGrouping() < b->getGrouping(); - }); + [](const DisplayPluginPointer& a, const DisplayPluginPointer& b)->bool { return a->getGrouping() < b->getGrouping(); }); // concatenate the groupings into a single list in the order: standard, advanced, developer - for (const auto& displayPlugin : displayPlugins) { + for(const auto& displayPlugin : displayPlugins) { addDisplayPluginToMenu(displayPlugin, _displayPlugin == displayPlugin); } @@ -2874,6 +2900,7 @@ void Application::initializeUi() { } } + void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { auto engine = surfaceContext->engine(); // in Qt 5.10.0 there is already an "Audio" object in the QML context @@ -2906,8 +2933,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("AvatarList", DependencyManager::get().data()); surfaceContext->setContextProperty("Users", DependencyManager::get().data()); - surfaceContext->setContextProperty("UserActivityLogger", - DependencyManager::get().data()); + surfaceContext->setContextProperty("UserActivityLogger", DependencyManager::get().data()); surfaceContext->setContextProperty("Camera", &_myCamera); @@ -2930,10 +2956,8 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("SoundCache", DependencyManager::get().data()); surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get().data()); - surfaceContext->setContextProperty("Account", - AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED - surfaceContext->setContextProperty("GlobalServices", - AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED + surfaceContext->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED + surfaceContext->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED surfaceContext->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance()); surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface); @@ -2986,17 +3010,20 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { // Using the latter will cause the camera to wobble with idle animations, // or with changes from the face tracker if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { - _thirdPersonHMDCameraBoomValid = false; + _thirdPersonHMDCameraBoomValid= false; if (isHMDMode()) { mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); _myCamera.setPosition(extractTranslation(camMat)); _myCamera.setOrientation(glmExtractRotation(camMat)); - } else { + } + else { _myCamera.setPosition(myAvatar->getDefaultEyePosition()); _myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation()); } - } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + } + else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { if (isHMDMode()) { + if (!_thirdPersonHMDCameraBoomValid) { const glm::vec3 CAMERA_OFFSET = glm::vec3(0.0f, 0.0f, 0.7f); _thirdPersonHMDCameraBoom = cancelOutRollAndPitch(myAvatar->getHMDSensorOrientation()) * CAMERA_OFFSET; @@ -3005,29 +3032,32 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { glm::mat4 thirdPersonCameraSensorToWorldMatrix = myAvatar->getSensorToWorldMatrix(); - const glm::vec3 cameraPos = - myAvatar->getHMDSensorPosition() + _thirdPersonHMDCameraBoom * myAvatar->getBoomLength(); + const glm::vec3 cameraPos = myAvatar->getHMDSensorPosition() + _thirdPersonHMDCameraBoom * myAvatar->getBoomLength(); glm::mat4 sensorCameraMat = createMatFromQuatAndPos(myAvatar->getHMDSensorOrientation(), cameraPos); glm::mat4 worldCameraMat = thirdPersonCameraSensorToWorldMatrix * sensorCameraMat; _myCamera.setOrientation(glm::normalize(glmExtractRotation(worldCameraMat))); _myCamera.setPosition(extractTranslation(worldCameraMat)); - } else { + } + else { _thirdPersonHMDCameraBoomValid = false; _myCamera.setOrientation(myAvatar->getHead()->getOrientation()); if (isOptionChecked(MenuOption::CenterPlayerInView)) { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() + _myCamera.getOrientation() * boomOffset); - } else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() + myAvatar->getWorldOrientation() * boomOffset); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + _myCamera.getOrientation() * boomOffset); + } + else { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + myAvatar->getWorldOrientation() * boomOffset); } } - } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - _thirdPersonHMDCameraBoomValid = false; + } + else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + _thirdPersonHMDCameraBoomValid= false; if (isHMDMode()) { - auto mirrorBodyOrientation = - myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _mirrorYawOffset, 0.0f)); + auto mirrorBodyOrientation = myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _mirrorYawOffset, 0.0f)); glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); // Mirror HMD yaw and roll @@ -3044,24 +3074,26 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { // Mirror HMD lateral offsets hmdOffset.x = -hmdOffset.x; - _myCamera.setPosition( - myAvatar->getDefaultEyePosition() + glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) + - mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + - mirrorBodyOrientation * hmdOffset); - } else { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) + + mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + + mirrorBodyOrientation * hmdOffset); + } + else { auto userInputMapper = DependencyManager::get(); const float YAW_SPEED = TWO_PI / 5.0f; float deltaYaw = userInputMapper->getActionState(controller::Action::YAW) * YAW_SPEED * deltaTime; _mirrorYawOffset += deltaYaw; _myCamera.setOrientation(myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _mirrorYawOffset, 0.0f))); - _myCamera.setPosition(myAvatar->getDefaultEyePosition() + - glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) + - (myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, _mirrorYawOffset, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * myAvatar->getBoomLength() * _scaleMirror); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) + + (myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, _mirrorYawOffset, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * myAvatar->getBoomLength() * _scaleMirror); } renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; - } else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) { - _thirdPersonHMDCameraBoomValid = false; + } + else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) { + _thirdPersonHMDCameraBoomValid= false; EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer(); if (cameraEntity != nullptr) { if (isHMDMode()) { @@ -3069,7 +3101,8 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { _myCamera.setOrientation(cameraEntity->getWorldOrientation() * hmdRotation); glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); _myCamera.setPosition(cameraEntity->getWorldPosition() + (hmdRotation * hmdOffset)); - } else { + } + else { _myCamera.setOrientation(cameraEntity->getWorldOrientation()); _myCamera.setPosition(cameraEntity->getWorldPosition()); } @@ -3089,6 +3122,7 @@ void Application::runTests() { } void Application::faceTrackerMuteToggled() { + QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteFaceTracking); Q_CHECK_PTR(muteAction); bool isMuted = getSelectedFaceTracker()->isMuted(); @@ -3194,8 +3228,8 @@ void Application::resizeGL() { // FIXME the aspect ratio for stereo displays is incorrect based on this. float aspectRatio = displayPlugin->getRecommendedAspectRatio(); - _myCamera.setProjection( - glm::perspective(glm::radians(_fieldOfView.get()), aspectRatio, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); + _myCamera.setProjection(glm::perspective(glm::radians(_fieldOfView.get()), aspectRatio, + DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); // Possible change in aspect ratio { QMutexLocker viewLocker(&_viewMutex); @@ -3210,12 +3244,14 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { bool sandboxIsRunning = SandboxUtils::readStatus(reply->readAll()); - enum HandControllerType - { + enum HandControllerType { Vive, Oculus }; - static const std::map MIN_CONTENT_VERSION = { { Vive, 1 }, { Oculus, 27 } }; + static const std::map MIN_CONTENT_VERSION = { + { Vive, 1 }, + { Oculus, 27 } + }; // Get sandbox content set version auto acDirPath = PathUtils::getAppDataPath() + "../../" + BuildInfo::MODIFIED_ORGANIZATION + "/assignment-client/"; @@ -3225,7 +3261,7 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { QFile contentVersionFile(contentVersionPath); if (contentVersionFile.open(QIODevice::ReadOnly | QIODevice::Text)) { QString line = contentVersionFile.readAll(); - contentVersion = line.toInt(); // returns 0 if conversion fails + contentVersion = line.toInt(); // returns 0 if conversion fails } // Get controller availability @@ -3241,8 +3277,7 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { Setting::Handle firstRun{ Settings::firstRun, true }; - qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers - << ", Using HMD: " << isUsingHMDAndHandControllers; + qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers; // when --url in command line, teleport to location const QString HIFI_URL_COMMAND_LINE_KEY = "--url"; @@ -3260,8 +3295,7 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { // If this is a first run we short-circuit the address passed in if (firstRun.get()) { #if defined(Q_OS_ANDROID) - qCDebug(interfaceapp) << "First run... going to" - << qPrintable(addressLookupString.isEmpty() ? QString("default location") : addressLookupString); + qCDebug(interfaceapp) << "First run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("default location") : addressLookupString); DependencyManager::get()->loadSettings(addressLookupString); #else DependencyManager::get()->goToEntry(); @@ -3270,27 +3304,27 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { firstRun.set(false); } else { - qCDebug(interfaceapp) << "Not first run... going to" - << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); + qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); DependencyManager::get()->loadSettings(addressLookupString); sentTo = SENT_TO_PREVIOUS_LOCATION; } - UserActivityLogger::getInstance().logAction("startup_sent_to", - { { "sent_to", sentTo }, - { "sandbox_is_running", sandboxIsRunning }, - { "has_hmd", hasHMD }, - { "has_hand_controllers", hasHandControllers }, - { "is_using_hmd", isUsingHMD }, - { "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers }, - { "content_version", contentVersion } }); + UserActivityLogger::getInstance().logAction("startup_sent_to", { + { "sent_to", sentTo }, + { "sandbox_is_running", sandboxIsRunning }, + { "has_hmd", hasHMD }, + { "has_hand_controllers", hasHandControllers }, + { "is_using_hmd", isUsingHMD }, + { "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers }, + { "content_version", contentVersion } + }); _connectionMonitor.init(); } bool Application::importJSONFromURL(const QString& urlString) { // we only load files that terminate in just .json (not .svo.json and not .ava.json) - QUrl jsonURL{ urlString }; + QUrl jsonURL { urlString }; emit svoImportRequested(urlString); return true; @@ -3364,6 +3398,7 @@ void Application::loadServerlessDomain(QUrl domainURL) { std::map namedPaths = tmpTree->getNamedPaths(); nodeList->getDomainHandler().connectedToServerless(namedPaths); + _fullSceneReceivedCounter++; } @@ -3395,18 +3430,19 @@ bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) { if (!_keyboardFocusedEntity.get().isInvalidID()) { switch (event->type()) { case QEvent::KeyPress: - case QEvent::KeyRelease: { - auto eventHandler = getEntities()->getEventHandler(_keyboardFocusedEntity.get()); - if (eventHandler) { - event->setAccepted(false); - QCoreApplication::sendEvent(eventHandler, event); - if (event->isAccepted()) { - _lastAcceptedKeyPress = usecTimestampNow(); - return true; + case QEvent::KeyRelease: + { + auto eventHandler = getEntities()->getEventHandler(_keyboardFocusedEntity.get()); + if (eventHandler) { + event->setAccepted(false); + QCoreApplication::sendEvent(eventHandler, event); + if (event->isAccepted()) { + _lastAcceptedKeyPress = usecTimestampNow(); + return true; + } } + break; } - break; - } default: break; } @@ -3416,17 +3452,18 @@ bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) { switch (event->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: { - // Only Web overlays can have focus. - auto overlay = std::dynamic_pointer_cast(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); - if (overlay && overlay->getEventHandler()) { - event->setAccepted(false); - QCoreApplication::sendEvent(overlay->getEventHandler(), event); - if (event->isAccepted()) { - _lastAcceptedKeyPress = usecTimestampNow(); - return true; + // Only Web overlays can have focus. + auto overlay = std::dynamic_pointer_cast(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); + if (overlay && overlay->getEventHandler()) { + event->setAccepted(false); + QCoreApplication::sendEvent(overlay->getEventHandler(), event); + if (event->isAccepted()) { + _lastAcceptedKeyPress = usecTimestampNow(); + return true; + } } } - } break; + break; default: break; @@ -3463,9 +3500,10 @@ static void dumpEventQueue(QThread* thread) { qDebug() << " " << type; } } -#endif // DEBUG_EVENT_QUEUE +#endif // DEBUG_EVENT_QUEUE bool Application::event(QEvent* event) { + if (!Menu::getInstance()) { return false; } @@ -3493,7 +3531,7 @@ bool Application::event(QEvent* event) { dumpEventQueue(QThread::currentThread()); } } -#endif // DEBUG_EVENT_QUEUE +#endif // DEBUG_EVENT_QUEUE _pendingIdleEvent.store(false); @@ -3554,6 +3592,7 @@ bool Application::event(QEvent* event) { } bool Application::eventFilter(QObject* object, QEvent* event) { + if (event->type() == QEvent::Leave) { getApplicationCompositor().handleLeaveEvent(); } @@ -3580,7 +3619,7 @@ void Application::keyPressEvent(QKeyEvent* event) { _altPressed = event->key() == Qt::Key_Alt; _keysPressed.insert(event->key()); - _controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts + _controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isKeyCaptured(event)) { @@ -3717,7 +3756,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } else { showCursor(Cursor::Icon::DEFAULT); } - } else if (!event->isAutoRepeat()) { + } else if (!event->isAutoRepeat()){ resetSensors(true); } break; @@ -3837,7 +3876,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { openAndroidActivity("Home"); } #endif - _controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts + _controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isKeyCaptured(event)) { @@ -3851,7 +3890,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { void Application::focusOutEvent(QFocusEvent* event) { auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); - foreach (auto inputPlugin, inputPlugins) { + foreach(auto inputPlugin, inputPlugins) { if (inputPlugin->isActive()) { inputPlugin->pluginFocusOutEvent(); } @@ -3884,7 +3923,7 @@ void Application::maybeToggleMenuVisible(QMouseEvent* event) const { if (event->pos().y() <= MENU_TOGGLE_AREA) { menuBar->setVisible(true); } - } else { + } else { if (event->pos().y() > MENU_TOGGLE_AREA) { menuBar->setVisible(false); } @@ -3908,7 +3947,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { // compositor reticle // handleRealMouseMoveEvent() will return true, if we shouldn't process the event further if (!compositor.fakeEventActive() && compositor.handleRealMouseMoveEvent()) { - return; // bail + return; // bail } auto offscreenUi = DependencyManager::get(); @@ -3924,7 +3963,10 @@ void Application::mouseMoveEvent(QMouseEvent* event) { buttons |= Qt::LeftButton; } - QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), button, buttons, event->modifiers()); + QMouseEvent mappedEvent(event->type(), + transformedPos, + event->screenPos(), button, + buttons, event->modifiers()); if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() || getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_OVERLAY_ID) { @@ -3932,7 +3974,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { getEntities()->mouseMoveEvent(&mappedEvent); } - _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts + _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { @@ -3957,8 +3999,10 @@ void Application::mousePressEvent(QMouseEvent* event) { auto eventPosition = getApplicationCompositor().getMouseEventPosition(event); QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition); - QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), - event->modifiers()); + QMouseEvent mappedEvent(event->type(), + transformedPos, + event->screenPos(), event->button(), + event->buttons(), event->modifiers()); if (!_aboutToQuit) { getOverlays().mousePressEvent(&mappedEvent); @@ -3967,7 +4011,7 @@ void Application::mousePressEvent(QMouseEvent* event) { } } - _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts + _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { @@ -3985,8 +4029,10 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { auto offscreenUi = DependencyManager::get(); auto eventPosition = getApplicationCompositor().getMouseEventPosition(event); QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition); - QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), - event->modifiers()); + QMouseEvent mappedEvent(event->type(), + transformedPos, + event->screenPos(), event->button(), + event->buttons(), event->modifiers()); if (!_aboutToQuit) { getOverlays().mouseDoublePressEvent(&mappedEvent); @@ -3995,6 +4041,7 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { } } + // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; @@ -4004,18 +4051,21 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { } void Application::mouseReleaseEvent(QMouseEvent* event) { + auto offscreenUi = DependencyManager::get(); auto eventPosition = getApplicationCompositor().getMouseEventPosition(event); QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition); - QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), - event->modifiers()); + QMouseEvent mappedEvent(event->type(), + transformedPos, + event->screenPos(), event->button(), + event->buttons(), event->modifiers()); if (!_aboutToQuit) { getOverlays().mouseReleaseEvent(&mappedEvent); getEntities()->mouseReleaseEvent(&mappedEvent); } - _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts + _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { @@ -4034,7 +4084,7 @@ void Application::touchUpdateEvent(QTouchEvent* event) { if (event->type() == QEvent::TouchUpdate) { TouchEvent thisEvent(*event, _lastTouchEvent); - _controllerScriptingInterface->emitTouchUpdateEvent(thisEvent); // send events to any registered scripts + _controllerScriptingInterface->emitTouchUpdateEvent(thisEvent); // send events to any registered scripts _lastTouchEvent = thisEvent; } @@ -4056,10 +4106,10 @@ void Application::touchUpdateEvent(QTouchEvent* event) { void Application::touchBeginEvent(QTouchEvent* event) { _altPressed = false; - TouchEvent thisEvent(*event); // on touch begin, we don't compare to last event - _controllerScriptingInterface->emitTouchBeginEvent(thisEvent); // send events to any registered scripts + TouchEvent thisEvent(*event); // on touch begin, we don't compare to last event + _controllerScriptingInterface->emitTouchBeginEvent(thisEvent); // send events to any registered scripts - _lastTouchEvent = thisEvent; // and we reset our last event to this event before we call our update + _lastTouchEvent = thisEvent; // and we reset our last event to this event before we call our update touchUpdateEvent(event); // if one of our scripts have asked to capture this event, then stop processing it @@ -4076,12 +4126,13 @@ void Application::touchBeginEvent(QTouchEvent* event) { if (_touchscreenVirtualPadDevice && _touchscreenVirtualPadDevice->isActive()) { _touchscreenVirtualPadDevice->touchBeginEvent(event); } + } void Application::touchEndEvent(QTouchEvent* event) { _altPressed = false; TouchEvent thisEvent(*event, _lastTouchEvent); - _controllerScriptingInterface->emitTouchEndEvent(thisEvent); // send events to any registered scripts + _controllerScriptingInterface->emitTouchEndEvent(thisEvent); // send events to any registered scripts _lastTouchEvent = thisEvent; // if one of our scripts have asked to capture this event, then stop processing it @@ -4112,7 +4163,7 @@ void Application::touchGestureEvent(QGestureEvent* event) { void Application::wheelEvent(QWheelEvent* event) const { _altPressed = false; - _controllerScriptingInterface->emitWheelEvent(event); // send events to any registered scripts + _controllerScriptingInterface->emitWheelEvent(event); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isWheelCaptured()) { @@ -4124,7 +4175,7 @@ void Application::wheelEvent(QWheelEvent* event) const { } } -void Application::dropEvent(QDropEvent* event) { +void Application::dropEvent(QDropEvent *event) { const QMimeData* mimeData = event->mimeData(); for (auto& url : mimeData->urls()) { QString urlString = url.toString(); @@ -4150,19 +4201,20 @@ bool Application::acceptSnapshot(const QString& urlString) { DependencyManager::get()->handleLookupString(snapshotData->getURL().toString()); } } else { - OffscreenUi::asyncWarning("", "No location details were found in the file\n" + snapshotPath + - "\nTry dragging in an authentic Hifi snapshot."); + OffscreenUi::asyncWarning("", "No location details were found in the file\n" + + snapshotPath + "\nTry dragging in an authentic Hifi snapshot."); } return true; } -static uint32_t _renderedFrameIndex{ INVALID_FRAME }; +static uint32_t _renderedFrameIndex { INVALID_FRAME }; bool Application::shouldPaint() const { if (_aboutToQuit) { return false; } + auto displayPlugin = getActiveDisplayPlugin(); #ifdef DEBUG_PAINT_DELAY @@ -4173,8 +4225,9 @@ bool Application::shouldPaint() const { static const int PAINT_DELAY_THROTTLE = 1000; if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) { - qCDebug(interfaceapp).nospace() << "Paint delay (" << paintDelaySamples - << " samples): " << (float)paintDelaySamples / paintDelayUsecs << "us"; + qCDebug(interfaceapp).nospace() << + "Paint delay (" << paintDelaySamples << " samples): " << + (float)paintDelaySamples / paintDelayUsecs << "us"; } #endif @@ -4196,39 +4249,41 @@ bool Application::shouldPaint() const { #pragma comment(lib, "ntdll.lib") extern "C" { -enum SYSTEM_INFORMATION_CLASS -{ - SystemBasicInformation = 0, - SystemProcessorPerformanceInformation = 8, -}; + enum SYSTEM_INFORMATION_CLASS { + SystemBasicInformation = 0, + SystemProcessorPerformanceInformation = 8, + }; -struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { - LARGE_INTEGER IdleTime; - LARGE_INTEGER KernelTime; - LARGE_INTEGER UserTime; - LARGE_INTEGER DpcTime; - LARGE_INTEGER InterruptTime; - ULONG InterruptCount; -}; + struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; + }; -struct SYSTEM_BASIC_INFORMATION { - ULONG Reserved; - ULONG TimerResolution; - ULONG PageSize; - ULONG NumberOfPhysicalPages; - ULONG LowestPhysicalPageNumber; - ULONG HighestPhysicalPageNumber; - ULONG AllocationGranularity; - ULONG_PTR MinimumUserModeAddress; - ULONG_PTR MaximumUserModeAddress; - ULONG_PTR ActiveProcessorsAffinityMask; - CCHAR NumberOfProcessors; -}; + struct SYSTEM_BASIC_INFORMATION { + ULONG Reserved; + ULONG TimerResolution; + ULONG PageSize; + ULONG NumberOfPhysicalPages; + ULONG LowestPhysicalPageNumber; + ULONG HighestPhysicalPageNumber; + ULONG AllocationGranularity; + ULONG_PTR MinimumUserModeAddress; + ULONG_PTR MaximumUserModeAddress; + ULONG_PTR ActiveProcessorsAffinityMask; + CCHAR NumberOfProcessors; + }; + + NTSYSCALLAPI NTSTATUS NTAPI NtQuerySystemInformation( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, + _Out_opt_ PULONG ReturnLength + ); -NTSYSCALLAPI NTSTATUS NTAPI NtQuerySystemInformation(_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, - _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, - _In_ ULONG SystemInformationLength, - _Out_opt_ PULONG ReturnLength); } template NTSTATUS NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, T& t) { @@ -4240,6 +4295,7 @@ NTSTATUS NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClas return NtQuerySystemInformation(SystemInformationClass, t.data(), (ULONG)(sizeof(T) * t.size()), nullptr); } + template void updateValueAndDelta(std::pair& pair, T newValue) { auto& value = pair.first; @@ -4251,11 +4307,11 @@ void updateValueAndDelta(std::pair& pair, T newValue) { struct MyCpuInfo { using ValueAndDelta = std::pair; std::string name; - ValueAndDelta kernel{ 0, 0 }; - ValueAndDelta user{ 0, 0 }; - ValueAndDelta idle{ 0, 0 }; - float kernelUsage{ 0.0f }; - float userUsage{ 0.0f }; + ValueAndDelta kernel { 0, 0 }; + ValueAndDelta user { 0, 0 }; + ValueAndDelta idle { 0, 0 }; + float kernelUsage { 0.0f }; + float userUsage { 0.0f }; void update(const SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION& cpuInfo) { updateValueAndDelta(kernel, cpuInfo.KernelTime.QuadPart); @@ -4273,13 +4329,13 @@ struct MyCpuInfo { void updateCpuInformation() { static std::once_flag once; - static SYSTEM_BASIC_INFORMATION systemInfo{}; + static SYSTEM_BASIC_INFORMATION systemInfo {}; static SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuTotals; static std::vector cpuInfos; static std::vector myCpuInfos; static MyCpuInfo myCpuTotals; std::call_once(once, [&] { - NtQuerySystemInformation(SystemBasicInformation, systemInfo); + NtQuerySystemInformation( SystemBasicInformation, systemInfo); cpuInfos.resize(systemInfo.NumberOfProcessors); myCpuInfos.resize(systemInfo.NumberOfProcessors); for (size_t i = 0; i < systemInfo.NumberOfProcessors; ++i) { @@ -4304,14 +4360,20 @@ void updateCpuInformation() { // Update friendly structure auto& myCpuInfo = myCpuInfos[i]; myCpuInfo.update(cpuInfo); - PROFILE_COUNTER(app, myCpuInfo.name.c_str(), { { "kernel", myCpuInfo.kernelUsage }, { "user", myCpuInfo.userUsage } }); + PROFILE_COUNTER(app, myCpuInfo.name.c_str(), { + { "kernel", myCpuInfo.kernelUsage }, + { "user", myCpuInfo.userUsage } + }); } myCpuTotals.update(cpuTotals); - PROFILE_COUNTER(app, myCpuTotals.name.c_str(), - { { "kernel", myCpuTotals.kernelUsage }, { "user", myCpuTotals.userUsage } }); + PROFILE_COUNTER(app, myCpuTotals.name.c_str(), { + { "kernel", myCpuTotals.kernelUsage }, + { "user", myCpuTotals.userUsage } + }); } + static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU; static int numProcessors; static HANDLE self; @@ -4432,10 +4494,8 @@ void Application::idle() { PROFILE_COUNTER_IF_CHANGED(app, "renderLoopRate", float, _renderLoopCounter.rate()); PROFILE_COUNTER_IF_CHANGED(app, "currentDownloads", int, ResourceCache::getLoadingRequests().length()); PROFILE_COUNTER_IF_CHANGED(app, "pendingDownloads", int, ResourceCache::getPendingRequestCount()); - PROFILE_COUNTER_IF_CHANGED(app, "currentProcessing", int, - DependencyManager::get()->getStat("Processing").toInt()); - PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, - DependencyManager::get()->getStat("PendingProcessing").toInt()); + PROFILE_COUNTER_IF_CHANGED(app, "currentProcessing", int, DependencyManager::get()->getStat("Processing").toInt()); + PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, DependencyManager::get()->getStat("PendingProcessing").toInt()); auto renderConfig = _renderEngine->getConfiguration(); PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_gpuContext->getFrameTimerGPUAverage()); auto opaqueRangeTimer = renderConfig->getConfig("OpaqueRangeTimer"); @@ -4444,12 +4504,13 @@ void Application::idle() { auto renderDeferred = renderConfig->getConfig("RenderDeferred"); auto toneAndPostRangeTimer = renderConfig->getConfig("ToneAndPostRangeTimer"); - PROFILE_COUNTER(render_detail, "gpuTimes", - { { "OpaqueRangeTimer", opaqueRangeTimer ? opaqueRangeTimer->property("gpuRunTime") : 0 }, - { "LinearDepth", linearDepth ? linearDepth->property("gpuRunTime") : 0 }, - { "SurfaceGeometry", surfaceGeometry ? surfaceGeometry->property("gpuRunTime") : 0 }, - { "RenderDeferred", renderDeferred ? renderDeferred->property("gpuRunTime") : 0 }, - { "ToneAndPostRangeTimer", toneAndPostRangeTimer ? toneAndPostRangeTimer->property("gpuRunTime") : 0 } }); + PROFILE_COUNTER(render_detail, "gpuTimes", { + { "OpaqueRangeTimer", opaqueRangeTimer ? opaqueRangeTimer->property("gpuRunTime") : 0 }, + { "LinearDepth", linearDepth ? linearDepth->property("gpuRunTime") : 0 }, + { "SurfaceGeometry", surfaceGeometry ? surfaceGeometry->property("gpuRunTime") : 0 }, + { "RenderDeferred", renderDeferred ? renderDeferred->property("gpuRunTime") : 0 }, + { "ToneAndPostRangeTimer", toneAndPostRangeTimer ? toneAndPostRangeTimer->property("gpuRunTime") : 0 } + }); PROFILE_RANGE(app, __FUNCTION__); @@ -4489,10 +4550,11 @@ void Application::idle() { update(glm::clamp(secondsSinceLastUpdate, 0.0f, BIGGEST_DELTA_TIME_SECS)); } + // Update focus highlight for entity or overlay. { if (!_keyboardFocusedEntity.get().isInvalidID() || _keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) { - const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus + const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress; if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) { setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); @@ -4523,7 +4585,7 @@ void Application::idle() { PerformanceWarning warn(showWarnings, "Application::idle()... pluginIdle()"); getActiveDisplayPlugin()->idle(); auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); - foreach (auto inputPlugin, inputPlugins) { + foreach(auto inputPlugin, inputPlugins) { if (inputPlugin->isActive()) { inputPlugin->idle(); } @@ -4632,7 +4694,7 @@ bool Application::exportEntities(const QString& filename, glm::vec3 root(TREE_SCALE, TREE_SCALE, TREE_SCALE); bool success = true; entityTree->withReadLock([&] { - for (auto entityID : entityIDs) { // Gather entities and properties. + for (auto entityID : entityIDs) { // Gather entities and properties. auto entityItem = entityTree->findEntityByEntityItemID(entityID); if (!entityItem) { qCWarning(interfaceapp) << "Skipping export of" << entityID << "that is not in scene."; @@ -4642,7 +4704,8 @@ bool Application::exportEntities(const QString& filename, if (!givenOffset) { EntityItemID parentID = entityItem->getParentID(); bool parentIsAvatar = (parentID == AVATAR_SELF_ID || parentID == myAvatarID); - if (!parentIsAvatar && (parentID.isInvalidID() || !entityIDs.contains(parentID) || + if (!parentIsAvatar && (parentID.isInvalidID() || + !entityIDs.contains(parentID) || !entityTree->findEntityByEntityItemID(parentID))) { // If parent wasn't selected, we want absolute position, which isn't in properties. auto position = entityItem->getWorldPosition(); @@ -4673,7 +4736,7 @@ bool Application::exportEntities(const QString& filename, properties.setPosition(properties.getPosition() - root); } else if (!entities.contains(parentID)) { entityDatum->globalizeProperties(properties, "Parent %3 of %2 %1 is not selected for export.", -root); - } // else valid parent -- don't offset + } // else valid parent -- don't offset } exportTree->addEntity(entityDatum->getEntityItemID(), properties); } @@ -4697,13 +4760,16 @@ bool Application::exportEntities(const QString& filename, float x, float y, floa auto entityTree = getEntities()->getTree(); entityTree->withReadLock([&] { entityTree->findEntities(boundingCube, entities); - foreach (EntityItemPointer entity, entities) { ids << entity->getEntityItemID(); } + foreach(EntityItemPointer entity, entities) { + ids << entity->getEntityItemID(); + } }); return exportEntities(filename, ids, ¢er); } void Application::loadSettings() { - sessionRunTime.set(0); // Just clean living. We're about to saveSettings, which will update value. + + sessionRunTime.set(0); // Just clean living. We're about to saveSettings, which will update value. DependencyManager::get()->loadSettings(); DependencyManager::get()->loadSettings(); @@ -4727,7 +4793,7 @@ void Application::loadSettings() { } } - Setting::Handle firstRun{ Settings::firstRun, true }; + Setting::Handle firstRun { Settings::firstRun, true }; bool isFirstPerson = false; if (firstRun.get()) { // If this is our first run, and no preferred devices were set, default to @@ -4823,6 +4889,7 @@ void Application::init() { } } + qCDebug(interfaceapp) << "Loaded settings"; // fire off an immediate domain-server check in now that settings are loaded @@ -4857,27 +4924,23 @@ void Application::init() { auto entityScriptingInterface = DependencyManager::get(); // connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts - connect(_entitySimulation.get(), &PhysicalEntitySimulation::entityCollisionWithEntity, getEntities().data(), - &EntityTreeRenderer::entityCollisionWithEntity); + connect(_entitySimulation.get(), &PhysicalEntitySimulation::entityCollisionWithEntity, + getEntities().data(), &EntityTreeRenderer::entityCollisionWithEntity); // connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing // of events related clicking, hovering over, and entering entities getEntities()->connectSignalsToSlots(entityScriptingInterface.data()); // Make sure any new sounds are loaded as soon as know about them. - connect(tree.get(), &EntityTree::newCollisionSoundURL, this, - [this](QUrl newURL, EntityItemID id) { - getEntities()->setCollisionSound(id, DependencyManager::get()->getSound(newURL)); - }, - Qt::QueuedConnection); - connect(getMyAvatar().get(), &MyAvatar::newCollisionSoundURL, this, - [this](QUrl newURL) { - if (auto avatar = getMyAvatar()) { - auto sound = DependencyManager::get()->getSound(newURL); - avatar->setCollisionSound(sound); - } - }, - Qt::QueuedConnection); + connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) { + getEntities()->setCollisionSound(id, DependencyManager::get()->getSound(newURL)); + }, Qt::QueuedConnection); + connect(getMyAvatar().get(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) { + if (auto avatar = getMyAvatar()) { + auto sound = DependencyManager::get()->getSound(newURL); + avatar->setCollisionSound(sound); + } + }, Qt::QueuedConnection); } void Application::loadAvatarScripts(const QVector& urls) { @@ -4954,8 +5017,8 @@ void Application::updateMyAvatarLookAtPosition() { glm::quat hmdRotation = glm::quat_cast(headPose); lookAtSpot = _myCamera.getPosition() + myAvatar->getWorldOrientation() * (hmdRotation * lookAtPosition); } else { - lookAtSpot = myAvatar->getHead()->getEyePosition() + - (myAvatar->getHead()->getFinalOrientationInWorldFrame() * lookAtPosition); + lookAtSpot = myAvatar->getHead()->getEyePosition() + + (myAvatar->getHead()->getFinalOrientationInWorldFrame() * lookAtPosition); } } else { AvatarSharedPointer lookingAt = myAvatar->getLookAtTargetAvatar().lock(); @@ -4969,14 +5032,14 @@ void Application::updateMyAvatarLookAtPosition() { const float MAXIMUM_FACE_ANGLE = 65.0f * RADIANS_PER_DEGREE; glm::vec3 lookingAtFaceOrientation = lookingAtHead->getFinalOrientationInWorldFrame() * IDENTITY_FORWARD; - glm::vec3 fromLookingAtToMe = - glm::normalize(myAvatar->getHead()->getEyePosition() - lookingAtHead->getEyePosition()); + glm::vec3 fromLookingAtToMe = glm::normalize(myAvatar->getHead()->getEyePosition() + - lookingAtHead->getEyePosition()); float faceAngle = glm::angle(lookingAtFaceOrientation, fromLookingAtToMe); if (faceAngle < MAXIMUM_FACE_ANGLE) { // Randomly look back and forth between look targets - eyeContactTarget target = - Menu::getInstance()->isOptionChecked(MenuOption::FixGaze) ? LEFT_EYE : myAvatar->getEyeContactTarget(); + eyeContactTarget target = Menu::getInstance()->isOptionChecked(MenuOption::FixGaze) ? + LEFT_EYE : myAvatar->getEyeContactTarget(); switch (target) { case LEFT_EYE: lookAtSpot = lookingAtHead->getLeftEyePosition(); @@ -4999,7 +5062,7 @@ void Application::updateMyAvatarLookAtPosition() { lookAtSpot = transformPoint(headPose.getMatrix(), glm::vec3(0.0f, 0.0f, TREE_SCALE)); } else { lookAtSpot = myAvatar->getHead()->getEyePosition() + - (myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE)); + (myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE)); } } @@ -5013,9 +5076,9 @@ void Application::updateMyAvatarLookAtPosition() { if (isLookingAtSomeone) { deflection *= GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT; } - lookAtSpot = origin + _myCamera.getOrientation() * - glm::quat(glm::radians(glm::vec3(eyePitch * deflection, eyeYaw * deflection, 0.0f))) * - glm::inverse(_myCamera.getOrientation()) * (lookAtSpot - origin); + lookAtSpot = origin + _myCamera.getOrientation() * glm::quat(glm::radians(glm::vec3( + eyePitch * deflection, eyeYaw * deflection, 0.0f))) * + glm::inverse(_myCamera.getOrientation()) * (lookAtSpot - origin); } } @@ -5051,14 +5114,17 @@ void Application::centerUI() { void Application::cycleCamera() { auto menu = Menu::getInstance(); if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { + menu->setIsOptionChecked(MenuOption::FullscreenMirror, false); menu->setIsOptionChecked(MenuOption::FirstPerson, true); } else if (menu->isOptionChecked(MenuOption::FirstPerson)) { + menu->setIsOptionChecked(MenuOption::FirstPerson, false); menu->setIsOptionChecked(MenuOption::ThirdPerson, true); } else if (menu->isOptionChecked(MenuOption::ThirdPerson)) { + menu->setIsOptionChecked(MenuOption::ThirdPerson, false); menu->setIsOptionChecked(MenuOption::FullscreenMirror, true); @@ -5066,7 +5132,7 @@ void Application::cycleCamera() { // do nothing if in independent or camera entity modes return; } - cameraMenuChanged(); // handle the menu change + cameraMenuChanged(); // handle the menu change } void Application::cameraModeChanged() { @@ -5092,13 +5158,14 @@ void Application::cameraModeChanged() { cameraMenuChanged(); } + void Application::cameraMenuChanged() { auto menu = Menu::getInstance(); if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { if (!isHMDMode() && _myCamera.getMode() != CAMERA_MODE_MIRROR) { _mirrorYawOffset = 0.0f; _myCamera.setMode(CAMERA_MODE_MIRROR); - getMyAvatar()->reset(false, false, false); // to reset any active MyAvatar::FollowHelpers + getMyAvatar()->reset(false, false, false); // to reset any active MyAvatar::FollowHelpers getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT); } } else if (menu->isOptionChecked(MenuOption::FirstPerson)) { @@ -5134,6 +5201,7 @@ void Application::resetPhysicsReadyInformation() { _physicsEnabled = false; } + void Application::reloadResourceCaches() { resetPhysicsReadyInformation(); @@ -5204,6 +5272,7 @@ void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) { auto entityScriptingInterface = DependencyManager::get(); auto properties = entityScriptingInterface->getEntityProperties(entityItemID); if (!properties.getLocked() && properties.getVisible()) { + auto entities = getEntities(); auto entityId = _keyboardFocusedEntity.get(); if (entities->wantsKeyboardFocus(entityId)) { @@ -5215,7 +5284,7 @@ void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) { _lastAcceptedKeyPress = usecTimestampNow(); setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(), - entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR); + entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR); } } } @@ -5251,8 +5320,7 @@ void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) { if (overlay->getProperty("showKeyboardFocusHighlight").toBool()) { auto size = overlay->getSize() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR; const float OVERLAY_DEPTH = 0.0105f; - setKeyboardFocusHighlight(overlay->getWorldPosition(), overlay->getWorldOrientation(), - glm::vec3(size.x, size.y, OVERLAY_DEPTH)); + setKeyboardFocusHighlight(overlay->getWorldPosition(), overlay->getWorldOrientation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH)); } else if (_keyboardFocusHighlight) { _keyboardFocusHighlight->setVisible(false); } @@ -5305,8 +5373,8 @@ void Application::updateSecondaryCameraViewFrustum() { // get mirror camera position by reflecting main camera position's z coordinate in mirror space glm::vec3 mainCameraPositionWorld = getCamera().getPosition(); glm::vec3 mainCameraPositionMirror = vec3(mirrorFromWorld * vec4(mainCameraPositionWorld, 1.0f)); - glm::vec3 mirrorCameraPositionMirror = - vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, -mainCameraPositionMirror.z); + glm::vec3 mirrorCameraPositionMirror = vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, + -mainCameraPositionMirror.z); glm::vec3 mirrorCameraPositionWorld = vec3(worldFromMirror * vec4(mirrorCameraPositionMirror, 1.0f)); // set frustum position to be mirrored camera and set orientation to mirror's adjusted rotation @@ -5318,8 +5386,7 @@ void Application::updateSecondaryCameraViewFrustum() { float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; - glm::mat4 frustum = - glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, camera->farClipPlaneDistance); + glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, camera->farClipPlaneDistance); secondaryViewFrustum.setProjection(frustum); } else { if (!camera->attachedEntityId.isNull()) { @@ -5333,8 +5400,10 @@ void Application::updateSecondaryCameraViewFrustum() { } float aspectRatio = (float)camera->textureWidth / (float)camera->textureHeight; - secondaryViewFrustum.setProjection(camera->vFoV, aspectRatio, camera->nearClipPlaneDistance, - camera->farClipPlaneDistance); + secondaryViewFrustum.setProjection(camera->vFoV, + aspectRatio, + camera->nearClipPlaneDistance, + camera->farClipPlaneDistance); } // Without calculating the bound planes, the secondary camera will use the same culling frustum as the main camera, // which is not what we want here. @@ -5359,8 +5428,7 @@ void Application::update(float deltaTime) { quint64 now = usecTimestampNow(); const int PHYSICS_CHECK_TIMEOUT = 2 * USECS_PER_SECOND; - if (now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT || - _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) { + if (now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT || _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) { // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway _lastPhysicsCheckTime = now; _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter; @@ -5399,8 +5467,8 @@ void Application::update(float deltaTime) { Menu* menu = Menu::getInstance(); auto audioClient = DependencyManager::get(); if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !audioClient->isMuted()) { - if (_lastFaceTrackerUpdate > 0 && - ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) { + if (_lastFaceTrackerUpdate > 0 + && ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) { audioClient->setMuted(true); _lastFaceTrackerUpdate = 0; } @@ -5414,20 +5482,21 @@ void Application::update(float deltaTime) { auto userInputMapper = DependencyManager::get(); - controller::InputCalibrationData calibrationData = - { myAvatar->getSensorToWorldMatrix(), - createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition()), - myAvatar->getHMDSensorMatrix(), - myAvatar->getCenterEyeCalibrationMat(), - myAvatar->getHeadCalibrationMat(), - myAvatar->getSpine2CalibrationMat(), - myAvatar->getHipsCalibrationMat(), - myAvatar->getLeftFootCalibrationMat(), - myAvatar->getRightFootCalibrationMat(), - myAvatar->getRightArmCalibrationMat(), - myAvatar->getLeftArmCalibrationMat(), - myAvatar->getRightHandCalibrationMat(), - myAvatar->getLeftHandCalibrationMat() }; + controller::InputCalibrationData calibrationData = { + myAvatar->getSensorToWorldMatrix(), + createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition()), + myAvatar->getHMDSensorMatrix(), + myAvatar->getCenterEyeCalibrationMat(), + myAvatar->getHeadCalibrationMat(), + myAvatar->getSpine2CalibrationMat(), + myAvatar->getHipsCalibrationMat(), + myAvatar->getLeftFootCalibrationMat(), + myAvatar->getRightFootCalibrationMat(), + myAvatar->getRightArmCalibrationMat(), + myAvatar->getLeftArmCalibrationMat(), + myAvatar->getRightHandCalibrationMat(), + myAvatar->getLeftHandCalibrationMat() + }; InputPluginPointer keyboardMousePlugin; for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) { @@ -5450,80 +5519,80 @@ void Application::update(float deltaTime) { myAvatar->clearDriveKeys(); if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) { if (!_controllerScriptingInterface->areActionsCaptured() && _myCamera.getMode() != CAMERA_MODE_MIRROR) { - myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, - -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z)); + myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z)); myAvatar->setDriveKey(MyAvatar::TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y)); myAvatar->setDriveKey(MyAvatar::TRANSLATE_X, userInputMapper->getActionState(controller::Action::TRANSLATE_X)); if (deltaTime > FLT_EPSILON) { myAvatar->setDriveKey(MyAvatar::PITCH, -1.0f * userInputMapper->getActionState(controller::Action::PITCH)); myAvatar->setDriveKey(MyAvatar::YAW, -1.0f * userInputMapper->getActionState(controller::Action::YAW)); - myAvatar->setDriveKey(MyAvatar::STEP_YAW, - -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW)); + myAvatar->setDriveKey(MyAvatar::STEP_YAW, -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW)); } } myAvatar->setDriveKey(MyAvatar::ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z)); } myAvatar->setSprintMode((bool)userInputMapper->getActionState(controller::Action::SPRINT)); - static const std::vector avatarControllerActions = { controller::Action::LEFT_HAND, - controller::Action::RIGHT_HAND, - controller::Action::LEFT_FOOT, - controller::Action::RIGHT_FOOT, - controller::Action::HIPS, - controller::Action::SPINE2, - controller::Action::HEAD, - controller::Action::LEFT_HAND_THUMB1, - controller::Action::LEFT_HAND_THUMB2, - controller::Action::LEFT_HAND_THUMB3, - controller::Action::LEFT_HAND_THUMB4, - controller::Action::LEFT_HAND_INDEX1, - controller::Action::LEFT_HAND_INDEX2, - controller::Action::LEFT_HAND_INDEX3, - controller::Action::LEFT_HAND_INDEX4, - controller::Action::LEFT_HAND_MIDDLE1, - controller::Action::LEFT_HAND_MIDDLE2, - controller::Action::LEFT_HAND_MIDDLE3, - controller::Action::LEFT_HAND_MIDDLE4, - controller::Action::LEFT_HAND_RING1, - controller::Action::LEFT_HAND_RING2, - controller::Action::LEFT_HAND_RING3, - controller::Action::LEFT_HAND_RING4, - controller::Action::LEFT_HAND_PINKY1, - controller::Action::LEFT_HAND_PINKY2, - controller::Action::LEFT_HAND_PINKY3, - controller::Action::LEFT_HAND_PINKY4, - controller::Action::RIGHT_HAND_THUMB1, - controller::Action::RIGHT_HAND_THUMB2, - controller::Action::RIGHT_HAND_THUMB3, - controller::Action::RIGHT_HAND_THUMB4, - controller::Action::RIGHT_HAND_INDEX1, - controller::Action::RIGHT_HAND_INDEX2, - controller::Action::RIGHT_HAND_INDEX3, - controller::Action::RIGHT_HAND_INDEX4, - controller::Action::RIGHT_HAND_MIDDLE1, - controller::Action::RIGHT_HAND_MIDDLE2, - controller::Action::RIGHT_HAND_MIDDLE3, - controller::Action::RIGHT_HAND_MIDDLE4, - controller::Action::RIGHT_HAND_RING1, - controller::Action::RIGHT_HAND_RING2, - controller::Action::RIGHT_HAND_RING3, - controller::Action::RIGHT_HAND_RING4, - controller::Action::RIGHT_HAND_PINKY1, - controller::Action::RIGHT_HAND_PINKY2, - controller::Action::RIGHT_HAND_PINKY3, - controller::Action::RIGHT_HAND_PINKY4, - controller::Action::LEFT_ARM, - controller::Action::RIGHT_ARM, - controller::Action::LEFT_SHOULDER, - controller::Action::RIGHT_SHOULDER, - controller::Action::LEFT_FORE_ARM, - controller::Action::RIGHT_FORE_ARM, - controller::Action::LEFT_LEG, - controller::Action::RIGHT_LEG, - controller::Action::LEFT_UP_LEG, - controller::Action::RIGHT_UP_LEG, - controller::Action::LEFT_TOE_BASE, - controller::Action::RIGHT_TOE_BASE }; + static const std::vector avatarControllerActions = { + controller::Action::LEFT_HAND, + controller::Action::RIGHT_HAND, + controller::Action::LEFT_FOOT, + controller::Action::RIGHT_FOOT, + controller::Action::HIPS, + controller::Action::SPINE2, + controller::Action::HEAD, + controller::Action::LEFT_HAND_THUMB1, + controller::Action::LEFT_HAND_THUMB2, + controller::Action::LEFT_HAND_THUMB3, + controller::Action::LEFT_HAND_THUMB4, + controller::Action::LEFT_HAND_INDEX1, + controller::Action::LEFT_HAND_INDEX2, + controller::Action::LEFT_HAND_INDEX3, + controller::Action::LEFT_HAND_INDEX4, + controller::Action::LEFT_HAND_MIDDLE1, + controller::Action::LEFT_HAND_MIDDLE2, + controller::Action::LEFT_HAND_MIDDLE3, + controller::Action::LEFT_HAND_MIDDLE4, + controller::Action::LEFT_HAND_RING1, + controller::Action::LEFT_HAND_RING2, + controller::Action::LEFT_HAND_RING3, + controller::Action::LEFT_HAND_RING4, + controller::Action::LEFT_HAND_PINKY1, + controller::Action::LEFT_HAND_PINKY2, + controller::Action::LEFT_HAND_PINKY3, + controller::Action::LEFT_HAND_PINKY4, + controller::Action::RIGHT_HAND_THUMB1, + controller::Action::RIGHT_HAND_THUMB2, + controller::Action::RIGHT_HAND_THUMB3, + controller::Action::RIGHT_HAND_THUMB4, + controller::Action::RIGHT_HAND_INDEX1, + controller::Action::RIGHT_HAND_INDEX2, + controller::Action::RIGHT_HAND_INDEX3, + controller::Action::RIGHT_HAND_INDEX4, + controller::Action::RIGHT_HAND_MIDDLE1, + controller::Action::RIGHT_HAND_MIDDLE2, + controller::Action::RIGHT_HAND_MIDDLE3, + controller::Action::RIGHT_HAND_MIDDLE4, + controller::Action::RIGHT_HAND_RING1, + controller::Action::RIGHT_HAND_RING2, + controller::Action::RIGHT_HAND_RING3, + controller::Action::RIGHT_HAND_RING4, + controller::Action::RIGHT_HAND_PINKY1, + controller::Action::RIGHT_HAND_PINKY2, + controller::Action::RIGHT_HAND_PINKY3, + controller::Action::RIGHT_HAND_PINKY4, + controller::Action::LEFT_ARM, + controller::Action::RIGHT_ARM, + controller::Action::LEFT_SHOULDER, + controller::Action::RIGHT_SHOULDER, + controller::Action::LEFT_FORE_ARM, + controller::Action::RIGHT_FORE_ARM, + controller::Action::LEFT_LEG, + controller::Action::RIGHT_LEG, + controller::Action::LEFT_UP_LEG, + controller::Action::RIGHT_UP_LEG, + controller::Action::LEFT_TOE_BASE, + controller::Action::RIGHT_TOE_BASE + }; // copy controller poses from userInputMapper to myAvatar. glm::mat4 myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition()); @@ -5535,8 +5604,8 @@ void Application::update(float deltaTime) { } } - updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... - updateDialogs(deltaTime); // update various stats dialogs if present + updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... + updateDialogs(deltaTime); // update various stats dialogs if present QSharedPointer avatarManager = DependencyManager::get(); @@ -5575,12 +5644,16 @@ void Application::update(float deltaTime) { _physicsEngine->changeObjects(motionStates); myAvatar->prepareForPhysicsSimulation(); - _physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) { dynamic->prepareForPhysicsSimulation(); }); + _physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) { + dynamic->prepareForPhysicsSimulation(); + }); } { PROFILE_RANGE(simulation_physics, "StepPhysics"); PerformanceTimer perfTimer("stepPhysics"); - getEntities()->getTree()->withWriteLock([&] { _physicsEngine->stepSimulation(); }); + getEntities()->getTree()->withWriteLock([&] { + _physicsEngine->stepSimulation(); + }); } { if (_physicsEngine->hasOutgoingChanges()) { @@ -5620,8 +5693,8 @@ void Application::update(float deltaTime) { } if (PerformanceTimer::isActive() && - Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) && - Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsTiming)) { + Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) && + Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsTiming)) { _physicsEngine->harvestPerformanceStats(); } // NOTE: the PhysicsEngine stats are written to stdout NOT to Qt log framework @@ -5631,7 +5704,7 @@ void Application::update(float deltaTime) { if (!_aboutToQuit) { // NOTE: the getEntities()->update() call below will wait for lock // and will provide non-physical entity motion - getEntities()->update(true); // update the models... + getEntities()->update(true); // update the models... } } } @@ -5721,8 +5794,9 @@ void Application::update(float deltaTime) { viewIsDifferentEnough = true; } + // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it - static const std::chrono::seconds MIN_PERIOD_BETWEEN_QUERIES{ 3 }; + static const std::chrono::seconds MIN_PERIOD_BETWEEN_QUERIES { 3 }; auto now = SteadyClock::now(); if (now > _queryExpiry || viewIsDifferentEnough) { if (DependencyManager::get()->shouldRenderEntities()) { @@ -5751,8 +5825,7 @@ void Application::update(float deltaTime) { if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS) { _lastSendDownstreamAudioStats = now; - QMetaObject::invokeMethod(DependencyManager::get().data(), "sendDownstreamAudioStatsPacket", - Qt::QueuedConnection); + QMetaObject::invokeMethod(DependencyManager::get().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection); } } @@ -5771,6 +5844,7 @@ void Application::update(float deltaTime) { _postUpdateLambdas.clear(); } + updateRenderArgs(deltaTime); // HACK @@ -5779,6 +5853,7 @@ void Application::update(float deltaTime) { // Then we can move this logic into the Avatar::simulate call. myAvatar->preDisplaySide(&_appRenderArgs._renderArgs); + { PerformanceTimer perfTimer("limitless"); AnimDebugDraw::getInstance().update(); @@ -5789,7 +5864,7 @@ void Application::update(float deltaTime) { DependencyManager::get()->update(); } - { // Game loop is done, mark the end of the frame for the scene transactions and the render loop to take over + { // Game loop is done, mark the end of the frame for the scene transactions and the render loop to take over PerformanceTimer perfTimer("enqueueFrame"); getMain3DScene()->enqueueFrame(); } @@ -5818,15 +5893,16 @@ void Application::updateRenderArgs(float deltaTime) { { QMutexLocker viewLocker(&_viewMutex); // adjust near clip plane to account for sensor scaling. - auto adjustedProjection = - glm::perspective(glm::radians(_fieldOfView.get()), getActiveDisplayPlugin()->getRecommendedAspectRatio(), - DEFAULT_NEAR_CLIP * sensorToWorldScale, DEFAULT_FAR_CLIP); + auto adjustedProjection = glm::perspective(glm::radians(_fieldOfView.get()), + getActiveDisplayPlugin()->getRecommendedAspectRatio(), + DEFAULT_NEAR_CLIP * sensorToWorldScale, + DEFAULT_FAR_CLIP); _viewFrustum.setProjection(adjustedProjection); _viewFrustum.calculate(); } - appRenderArgs._renderArgs = - RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(), lodManager->getBoundaryLevelAdjust(), - RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); + appRenderArgs._renderArgs = RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(), + lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, + RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); appRenderArgs._renderArgs._scene = getMain3DScene(); { @@ -5930,15 +6006,18 @@ void Application::queryAvatars() { DependencyManager::get()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); } + int Application::sendNackPackets() { + // iterates through all nodes in NodeList auto nodeList = DependencyManager::get(); int packetsSent = 0; - nodeList->eachNode([&](const SharedNodePointer& node) { + nodeList->eachNode([&](const SharedNodePointer& node){ if (node->getActiveSocket() && node->getType() == NodeType::EntityServer) { + auto nackPacketList = NLPacketList::create(PacketType::OctreeDataNack); QUuid nodeUUID = node->getUUID(); @@ -5956,14 +6035,13 @@ int Application::sendNackPackets() { return; } // get sequence number stats of node, prune its missing set, and make a copy of the missing set - SequenceNumberStats& sequenceNumberStats = - _octreeServerSceneStats[nodeUUID].getIncomingOctreeSequenceNumberStats(); + SequenceNumberStats& sequenceNumberStats = _octreeServerSceneStats[nodeUUID].getIncomingOctreeSequenceNumberStats(); sequenceNumberStats.pruneMissingSet(); missingSequenceNumbers = sequenceNumberStats.getMissingSet(); }); // construct nack packet(s) for this node - foreach (const OCTREE_PACKET_SEQUENCE& missingNumber, missingSequenceNumbers) { + foreach(const OCTREE_PACKET_SEQUENCE& missingNumber, missingSequenceNumbers) { nackPacketList->writePrimitive(missingNumber); } @@ -5980,8 +6058,9 @@ int Application::sendNackPackets() { } void Application::queryOctree(NodeType_t serverType, PacketType packetType) { + if (!_settingsLoaded) { - return; // bail early if settings are not loaded + return; // bail early if settings are not loaded } _octreeQuery.setConicalViews(_conicalViews); @@ -6008,13 +6087,12 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) { } } + bool Application::isHMDMode() const { return getActiveDisplayPlugin()->isHmd(); } -float Application::getTargetRenderFrameRate() const { - return getActiveDisplayPlugin()->getTargetFrameRate(); -} +float Application::getTargetRenderFrameRate() const { return getActiveDisplayPlugin()->getTargetFrameRate(); } QRect Application::getDesirableApplicationGeometry() const { QRect applicationGeometry = getWindow()->geometry(); @@ -6040,7 +6118,7 @@ QRect Application::getDesirableApplicationGeometry() const { } PickRay Application::computePickRay(float x, float y) const { - vec2 pickPoint{ x, y }; + vec2 pickPoint { x, y }; PickRay result; if (isHMDMode()) { getApplicationCompositor().computeHmdPickRay(pickPoint, result.origin, result.direction); @@ -6080,6 +6158,7 @@ void Application::resetSensors(bool andReload) { } void Application::updateWindowTitle() const { + auto nodeList = DependencyManager::get(); auto accountManager = DependencyManager::get(); @@ -6100,8 +6179,8 @@ void Application::updateWindowTitle() const { } } - QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) + currentPlaceName + connectionStatus + - loginStatus + buildVersion; + QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) + + currentPlaceName + connectionStatus + loginStatus + buildVersion; #ifndef WIN32 // crashes with vs2013/win32 @@ -6111,10 +6190,11 @@ void Application::updateWindowTitle() const { // updateTitleWindow gets called whenever there's a change regarding the domain, so rather // than placing this within domainURLChanged, it's placed here to cover the other potential cases. - DependencyManager::get()->sendLocalMessage("Toolbar-DomainChanged", ""); + DependencyManager::get< MessagesClient >()->sendLocalMessage("Toolbar-DomainChanged", ""); } void Application::clearDomainOctreeDetails() { + // if we're about to quit, we really don't need to do any of these things... if (_aboutToQuit) { return; @@ -6124,7 +6204,9 @@ void Application::clearDomainOctreeDetails() { resetPhysicsReadyInformation(); - _octreeServerSceneStats.withWriteLock([&] { _octreeServerSceneStats.clear(); }); + _octreeServerSceneStats.withWriteLock([&] { + _octreeServerSceneStats.clear(); + }); // reset the model renderer getEntities()->clear(); @@ -6142,7 +6224,7 @@ void Application::clearDomainOctreeDetails() { } void Application::clearDomainAvatars() { - getMyAvatar()->setAvatarEntityDataChanged(true); // to recreate worn entities + getMyAvatar()->setAvatarEntityDataChanged(true); // to recreate worn entities DependencyManager::get()->clearOtherAvatars(); } @@ -6156,6 +6238,7 @@ void Application::domainURLChanged(QUrl domainURL) { updateWindowTitle(); } + void Application::resettingDomain() { _notifiedPacketVersionMismatchThisDomain = false; @@ -6281,7 +6364,7 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { QVector entities; AABox avatarBox(getMyAvatar()->getWorldPosition() - glm::vec3(PHYSICS_READY_RANGE), glm::vec3(2 * PHYSICS_READY_RANGE)); // create two functions that use avatarBox (entityScan and elementScan), the second calls the first - std::function entityScan = [=](EntityItemPointer& entity) { + std::function entityScan = [=](EntityItemPointer& entity) { if (entity->shouldBePhysical()) { bool success = false; AABox entityBox = entity->getAABox(success); @@ -6290,8 +6373,7 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { } return false; }; - std::function elementScan = [&](const OctreeElementPointer& element, - void* unused) { + std::function elementScan = [&](const OctreeElementPointer& element, void* unused) { if (element->getAACube().touches(avatarBox)) { EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->getEntities(entityScan, entities); @@ -6361,6 +6443,7 @@ void Application::addingEntityWithCertificate(const QString& certificateID, cons } void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) { + scriptEngine->setEmitScriptUpdatesFunction([this]() { SharedNodePointer entityServerNode = DependencyManager::get()->soloNodeOfType(NodeType::EntityServer); return !entityServerNode || isPhysicsEnabled(); @@ -6405,13 +6488,13 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Desktop", DependencyManager::get().data()); qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); - qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, - wrapperFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), + wrapperToScriptValue, wrapperFromScriptValue); scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get().data()); qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, wrapperFromScriptValue); - qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue, - wrapperFromScriptValue); + qScriptRegisterMetaType(scriptEngine.data(), + wrapperToScriptValue, wrapperFromScriptValue); scriptEngine->registerGlobalObject("Tablet", DependencyManager::get().data()); // FIXME remove these deprecated names for the tablet scripting interface scriptEngine->registerGlobalObject("tabletInterface", DependencyManager::get().data()); @@ -6421,7 +6504,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Window", DependencyManager::get().data()); scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, - LocationScriptingInterface::locationSetter, "Window"); + LocationScriptingInterface::locationSetter, "Window"); // register `location` on the global object. scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter); @@ -6455,10 +6538,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface); - scriptEngine->registerGlobalObject("Account", - AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED - scriptEngine->registerGlobalObject("GlobalServices", - AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED + scriptEngine->registerGlobalObject("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED + scriptEngine->registerGlobalObject("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED scriptEngine->registerGlobalObject("AccountServices", AccountServicesScriptingInterface::getInstance()); qScriptRegisterMetaType(scriptEngine.data(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue); @@ -6485,12 +6566,10 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Reticle", getApplicationCompositor().getReticleInterface()); - scriptEngine->registerGlobalObject("UserActivityLogger", - DependencyManager::get().data()); + scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", - DependencyManager::get().data()); + scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get().data()); scriptEngine->registerGlobalObject("GooglePoly", DependencyManager::get().data()); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { @@ -6518,16 +6597,17 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe DependencyManager::get()->registerMetaTypes(scriptEngine.data()); // connect this script engines printedMessage signal to the global ScriptEngines these various messages - connect(scriptEngine.data(), &ScriptEngine::printedMessage, DependencyManager::get().data(), - &ScriptEngines::onPrintedMessage); - connect(scriptEngine.data(), &ScriptEngine::errorMessage, DependencyManager::get().data(), - &ScriptEngines::onErrorMessage); - connect(scriptEngine.data(), &ScriptEngine::warningMessage, DependencyManager::get().data(), - &ScriptEngines::onWarningMessage); - connect(scriptEngine.data(), &ScriptEngine::infoMessage, DependencyManager::get().data(), - &ScriptEngines::onInfoMessage); - connect(scriptEngine.data(), &ScriptEngine::clearDebugWindow, DependencyManager::get().data(), - &ScriptEngines::onClearDebugWindow); + connect(scriptEngine.data(), &ScriptEngine::printedMessage, + DependencyManager::get().data(), &ScriptEngines::onPrintedMessage); + connect(scriptEngine.data(), &ScriptEngine::errorMessage, + DependencyManager::get().data(), &ScriptEngines::onErrorMessage); + connect(scriptEngine.data(), &ScriptEngine::warningMessage, + DependencyManager::get().data(), &ScriptEngines::onWarningMessage); + connect(scriptEngine.data(), &ScriptEngine::infoMessage, + DependencyManager::get().data(), &ScriptEngines::onInfoMessage); + connect(scriptEngine.data(), &ScriptEngine::clearDebugWindow, + DependencyManager::get().data(), &ScriptEngines::onClearDebugWindow); + } bool Application::canAcceptURL(const QString& urlString) const { @@ -6551,8 +6631,8 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) { if (url.scheme() == URL_SCHEME_HIFI) { // this is a hifi URL - have the AddressManager handle it - QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString", Qt::AutoConnection, - Q_ARG(const QString&, urlString)); + QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString", + Qt::AutoConnection, Q_ARG(const QString&, urlString)); return true; } @@ -6589,13 +6669,13 @@ bool Application::askToSetAvatarUrl(const QString& url) { QString modelName = fstMapping["name"].toString(); QString modelLicense = fstMapping["license"].toString(); - bool agreeToLicense = true; // assume true + bool agreeToLicense = true; // assume true //create set avatar callback - auto setAvatar = [=](QString url, QString modelName) { - ModalDialogListener* dlg = - OffscreenUi::asyncQuestion("Set Avatar", "Would you like to use '" + modelName + "' for your avatar?", - QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); - QObject::connect(dlg, &ModalDialogListener::response, this, [=](QVariant answer) { + auto setAvatar = [=] (QString url, QString modelName) { + ModalDialogListener* dlg = OffscreenUi::asyncQuestion("Set Avatar", + "Would you like to use '" + modelName + "' for your avatar?", + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) { QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr); bool ok = (QMessageBox::Ok == static_cast(answer.toInt())); @@ -6613,22 +6693,22 @@ bool Application::askToSetAvatarUrl(const QString& url) { const int MAX_CHARACTERS_PER_LINE = 90; modelLicense = simpleWordWrap(modelLicense, MAX_CHARACTERS_PER_LINE); - ModalDialogListener* dlg = - OffscreenUi::asyncQuestion("Avatar Usage License", modelLicense + "\nDo you agree to these terms?", - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - QObject::connect(dlg, &ModalDialogListener::response, this, [=, &agreeToLicense](QVariant answer) { + ModalDialogListener* dlg = OffscreenUi::asyncQuestion("Avatar Usage License", + modelLicense + "\nDo you agree to these terms?", + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + QObject::connect(dlg, &ModalDialogListener::response, this, [=, &agreeToLicense] (QVariant answer) { QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr); agreeToLicense = (static_cast(answer.toInt()) == QMessageBox::Yes); if (agreeToLicense) { switch (modelType) { case FSTReader::HEAD_AND_BODY_MODEL: { - setAvatar(url, modelName); - break; - } - default: - OffscreenUi::asyncWarning("", modelName + "Does not support a head and body as required."); - break; + setAvatar(url, modelName); + break; + } + default: + OffscreenUi::asyncWarning("", modelName + "Does not support a head and body as required."); + break; } } else { qCDebug(interfaceapp) << "Declined to agree to avatar license: " << url; @@ -6643,10 +6723,11 @@ bool Application::askToSetAvatarUrl(const QString& url) { return true; } + bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { QString shortName = scriptFilenameOrURL; - QUrl scriptURL{ scriptFilenameOrURL }; + QUrl scriptURL { scriptFilenameOrURL }; if (scriptURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) { int startIndex = shortName.lastIndexOf('/') + 1; @@ -6655,10 +6736,10 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { } QString message = "Would you like to run this script:\n" + shortName; - ModalDialogListener* dlg = - OffscreenUi::asyncQuestion(getWindow(), "Run Script", message, QMessageBox::Yes | QMessageBox::No); + ModalDialogListener* dlg = OffscreenUi::asyncQuestion(getWindow(), "Run Script", message, + QMessageBox::Yes | QMessageBox::No); - QObject::connect(dlg, &ModalDialogListener::response, this, [=](QVariant answer) { + QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) { const QString& fileName = scriptFilenameOrURL; if (static_cast(answer.toInt()) == QMessageBox::Yes) { qCDebug(interfaceapp) << "Chose to run the script: " << fileName; @@ -6695,6 +6776,7 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) { QJsonParseError jsonError; auto doc = QJsonDocument::fromJson(contents, &jsonError); if (jsonError.error == QJsonParseError::NoError) { + auto jsonObject = doc.object(); // retrieve optional name field from JSON @@ -6706,10 +6788,10 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) { auto avatarAttachmentConfirmationTitle = tr("Avatar Attachment Confirmation"); auto avatarAttachmentConfirmationMessage = tr("Would you like to wear '%1' on your avatar?").arg(name); - ModalDialogListener* dlg = - OffscreenUi::asyncQuestion(avatarAttachmentConfirmationTitle, avatarAttachmentConfirmationMessage, - QMessageBox::Ok | QMessageBox::Cancel); - QObject::connect(dlg, &ModalDialogListener::response, this, [=](QVariant answer) { + ModalDialogListener* dlg = OffscreenUi::asyncQuestion(avatarAttachmentConfirmationTitle, + avatarAttachmentConfirmationMessage, + QMessageBox::Ok | QMessageBox::Cancel); + QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) { QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr); if (static_cast(answer.toInt()) == QMessageBox::Yes) { // add attachment to avatar @@ -6760,23 +6842,18 @@ bool Application::askToReplaceDomainContent(const QString& url) { QString methodDetails; const int MAX_CHARACTERS_PER_LINE = 90; if (DependencyManager::get()->getThisNodeCanReplaceContent()) { - QUrl originURL{ url }; + QUrl originURL { url }; if (originURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) { // Create a confirmation dialog when this call is made - static const QString infoText = - simpleWordWrap( - "Your domain's content will be replaced with a new content set. " - "If you want to save what you have now, create a backup before proceeding. For more information about " - "backing up " - "and restoring content, visit the documentation page at: ", - MAX_CHARACTERS_PER_LINE) + + static const QString infoText = simpleWordWrap("Your domain's content will be replaced with a new content set. " + "If you want to save what you have now, create a backup before proceeding. For more information about backing up " + "and restoring content, visit the documentation page at: ", MAX_CHARACTERS_PER_LINE) + "\nhttps://docs.highfidelity.com/create-and-explore/start-working-in-your-sandbox/restoring-sandbox-content"; - ModalDialogListener* dig = - OffscreenUi::asyncQuestion("Are you sure you want to replace this domain's content set?", infoText, - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + ModalDialogListener* dig = OffscreenUi::asyncQuestion("Are you sure you want to replace this domain's content set?", + infoText, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - QObject::connect(dig, &ModalDialogListener::response, this, [=](QVariant answer) { + QObject::connect(dig, &ModalDialogListener::response, this, [=] (QVariant answer) { QString details; if (static_cast(answer.toInt()) == QMessageBox::Yes) { // Given confirmation, send request to domain server to replace content @@ -6785,26 +6862,33 @@ bool Application::askToReplaceDomainContent(const QString& url) { } else { details = "UserDeclinedToReplaceContent"; } - QJsonObject messageProperties = { { "status", details }, { "content_set_url", url } }; + QJsonObject messageProperties = { + { "status", details }, + { "content_set_url", url } + }; UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); QObject::disconnect(dig, &ModalDialogListener::response, this, nullptr); }); } else { methodDetails = "ContentSetDidNotOriginateFromMarketplace"; - QJsonObject messageProperties = { { "status", methodDetails }, { "content_set_url", url } }; + QJsonObject messageProperties = { + { "status", methodDetails }, + { "content_set_url", url } + }; UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); } } else { - methodDetails = "UserDoesNotHavePermissionToReplaceContent"; - static const QString warningMessage = simpleWordWrap( - "The domain owner must enable 'Replace Content' " - "permissions for you in this domain's server settings before you can continue.", - MAX_CHARACTERS_PER_LINE); - OffscreenUi::asyncWarning("You do not have permissions to replace domain content", warningMessage, QMessageBox::Ok, - QMessageBox::Ok); + methodDetails = "UserDoesNotHavePermissionToReplaceContent"; + static const QString warningMessage = simpleWordWrap("The domain owner must enable 'Replace Content' " + "permissions for you in this domain's server settings before you can continue.", MAX_CHARACTERS_PER_LINE); + OffscreenUi::asyncWarning("You do not have permissions to replace domain content", warningMessage, + QMessageBox::Ok, QMessageBox::Ok); - QJsonObject messageProperties = { { "status", methodDetails }, { "content_set_url", url } }; - UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); + QJsonObject messageProperties = { + { "status", methodDetails }, + { "content_set_url", url } + }; + UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); } return true; } @@ -6845,9 +6929,9 @@ void Application::showAssetServerWidget(QString filePath) { if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { return; } - static const QUrl url{ "hifi/AssetServer.qml" }; + static const QUrl url { "hifi/AssetServer.qml" }; - auto startUpload = [=](QQmlContext* context, QObject* newObject) { + auto startUpload = [=](QQmlContext* context, QObject* newObject){ if (!filePath.isEmpty()) { emit uploadRequest(filePath); } @@ -6883,6 +6967,7 @@ void Application::addAssetToWorldFromURL(QString url) { } else { filename.remove(".zip"); } + } if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { @@ -6953,6 +7038,7 @@ void Application::addAssetToWorldFromURLRequestFinished() { request->deleteLater(); } + QString filenameFromPath(QString filePath) { return filePath.right(filePath.length() - filePath.lastIndexOf("/") - 1); } @@ -6997,8 +7083,8 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin if (result == GetMappingRequest::NotFound) { addAssetToWorldUpload(filePath, mapping, isZip, isBlocks); } else if (result != GetMappingRequest::NoError) { - QString errorInfo = - "Could not map asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); + QString errorInfo = "Could not map asset name: " + + mapping.left(mapping.length() - QString::number(copy).length() - 1); qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else if (copy < MAX_COPY_COUNT - 1) { @@ -7009,8 +7095,8 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin mapping = mapping.insert(mapping.lastIndexOf("."), "-" + QString::number(copy)); addAssetToWorldWithNewMapping(filePath, mapping, copy, isZip, isBlocks); } else { - QString errorInfo = - "Too many copies of asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); + QString errorInfo = "Too many copies of asset name: " + + mapping.left(mapping.length() - QString::number(copy).length() - 1); qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } @@ -7057,7 +7143,7 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q // to prevent files that aren't models or texture files from being loaded into world automatically if ((filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION)) || ((filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION)) && - ((!isBlocks) && (!isZip)))) { + ((!isBlocks) && (!isZip)))) { addAssetToWorldAddEntity(filePath, mapping); } else { qCDebug(interfaceapp) << "Zipped contents are not supported entity files"; @@ -7075,7 +7161,9 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { properties.setType(EntityTypes::Model); properties.setName(mapping.right(mapping.length() - 1)); if (filePath.toLower().endsWith(PNG_EXTENSION) || filePath.toLower().endsWith(JPG_EXTENSION)) { - QJsonObject textures{ { "tex.picture", QString("atp:" + mapping) } }; + QJsonObject textures { + {"tex.picture", QString("atp:" + mapping) } + }; properties.setModelURL("https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"); properties.setTextures(QJsonDocument(textures).toJson(QJsonDocument::Compact)); properties.setShapeType(SHAPE_TYPE_BOX); @@ -7084,9 +7172,8 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND); } properties.setCollisionless(true); // Temporarily set so that doesn't collide with avatar. - properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions. - glm::vec3 positionOffset = - getMyAvatar()->getWorldOrientation() * (getMyAvatar()->getSensorToWorldScale() * glm::vec3(0.0f, 0.0f, -2.0f)); + properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions. + glm::vec3 positionOffset = getMyAvatar()->getWorldOrientation() * (getMyAvatar()->getSensorToWorldScale() * glm::vec3(0.0f, 0.0f, -2.0f)); properties.setPosition(getMyAvatar()->getWorldPosition() + positionOffset); properties.setRotation(getMyAvatar()->getWorldOrientation()); properties.setGravity(glm::vec3(0.0f, 0.0f, 0.0f)); @@ -7133,11 +7220,12 @@ void Application::addAssetToWorldCheckModelSize() { const glm::vec3 DEFAULT_DIMENSIONS = glm::vec3(0.1f, 0.1f, 0.1f); if (dimensions != DEFAULT_DIMENSIONS) { + // Scale model so that its maximum is exactly specific size. const float MAXIMUM_DIMENSION = getMyAvatar()->getSensorToWorldScale(); auto previousDimensions = dimensions; - auto scale = std::min(MAXIMUM_DIMENSION / dimensions.x, - std::min(MAXIMUM_DIMENSION / dimensions.y, MAXIMUM_DIMENSION / dimensions.z)); + auto scale = std::min(MAXIMUM_DIMENSION / dimensions.x, std::min(MAXIMUM_DIMENSION / dimensions.y, + MAXIMUM_DIMENSION / dimensions.z)); dimensions *= scale; qInfo(interfaceapp) << "Model" << name << "auto-resized from" << previousDimensions << " to " << dimensions; doResize = true; @@ -7183,6 +7271,7 @@ void Application::addAssetToWorldCheckModelSize() { } } + void Application::addAssetToWorldInfo(QString modelName, QString infoText) { // Displays the most recent info message, subject to being overridden by error messages. @@ -7207,9 +7296,8 @@ void Application::addAssetToWorldInfo(QString modelName, QString infoText) { if (!_addAssetToWorldErrorTimer.isActive()) { if (!_addAssetToWorldMessageBox) { - _addAssetToWorldMessageBox = - DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, "Downloading Model", "", - QMessageBox::NoButton, QMessageBox::NoButton); + _addAssetToWorldMessageBox = DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, + "Downloading Model", "", QMessageBox::NoButton, QMessageBox::NoButton); connect(_addAssetToWorldMessageBox, SIGNAL(destroyed()), this, SLOT(onAssetToWorldMessageBoxClosed())); } @@ -7291,9 +7379,8 @@ void Application::addAssetToWorldError(QString modelName, QString errorText) { addAssetToWorldInfoClear(modelName); if (!_addAssetToWorldMessageBox) { - _addAssetToWorldMessageBox = - DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, "Downloading Model", "", - QMessageBox::NoButton, QMessageBox::NoButton); + _addAssetToWorldMessageBox = DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, + "Downloading Model", "", QMessageBox::NoButton, QMessageBox::NoButton); connect(_addAssetToWorldMessageBox, SIGNAL(destroyed()), this, SLOT(onAssetToWorldMessageBoxClosed())); } @@ -7325,6 +7412,7 @@ void Application::addAssetToWorldErrorTimeout() { } } + void Application::addAssetToWorldMessageClose() { // Clear messages, e.g., if Interface is being closed or domain changes. @@ -7362,6 +7450,7 @@ void Application::onAssetToWorldMessageBoxClosed() { } } + void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip, bool isBlocks) { if (autoAdd) { if (!unzipFile.isEmpty()) { @@ -7396,9 +7485,10 @@ void Application::openUrl(const QUrl& url) const { void Application::loadDialog() { auto scriptEngines = DependencyManager::get(); - ModalDialogListener* dlg = OffscreenUi::getOpenFileNameAsync(_glWidget, tr("Open Script"), getPreviousScriptLocation(), + ModalDialogListener* dlg = OffscreenUi::getOpenFileNameAsync(_glWidget, tr("Open Script"), + getPreviousScriptLocation(), tr("JavaScript Files (*.js)")); - connect(dlg, &ModalDialogListener::response, this, [=](QVariant answer) { + connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) { disconnect(dlg, &ModalDialogListener::response, this, nullptr); const QString& response = answer.toString(); if (!response.isEmpty() && QFile(response).exists()) { @@ -7419,7 +7509,7 @@ void Application::setPreviousScriptLocation(const QString& location) { void Application::loadScriptURLDialog() const { ModalDialogListener* dlg = OffscreenUi::getTextAsync(OffscreenUi::ICON_NONE, "Open and Run Script", "Script URL"); - connect(dlg, &ModalDialogListener::response, this, [=](QVariant response) { + connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) { disconnect(dlg, &ModalDialogListener::response, this, nullptr); const QString& newScript = response.toString(); if (QUrl(newScript).scheme() == "atp") { @@ -7445,6 +7535,7 @@ void Application::loadLODToolsDialog() { } } + void Application::loadEntityStatisticsDialog() { auto tabletScriptingInterface = DependencyManager::get(); auto tablet = dynamic_cast(tabletScriptingInterface->getTablet(SYSTEM_TABLET)); @@ -7468,7 +7559,7 @@ void Application::loadDomainConnectionDialog() { } void Application::toggleLogDialog() { - if (!_logDialog) { + if (! _logDialog) { _logDialog = new LogDialog(nullptr, getLogger()); } @@ -7480,7 +7571,7 @@ void Application::toggleLogDialog() { } void Application::toggleEntityScriptServerLogDialog() { - if (!_entityScriptServerLogDialog) { + if (! _entityScriptServerLogDialog) { _entityScriptServerLogDialog = new EntityScriptServerLogDialog(nullptr); } @@ -7497,12 +7588,10 @@ void Application::loadAddAvatarBookmarkDialog() const { } void Application::loadAvatarBrowser() const { - auto tablet = dynamic_cast( - DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); + auto tablet = dynamic_cast(DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); // construct the url to the marketplace item QString url = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace?category=avatars"; - QString MARKETPLACES_INJECT_SCRIPT_PATH = - "file:///" + qApp->applicationDirPath() + "/scripts/system/html/js/marketplacesInject.js"; + QString MARKETPLACES_INJECT_SCRIPT_PATH = "file:///" + qApp->applicationDirPath() + "/scripts/system/html/js/marketplacesInject.js"; tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_PATH); DependencyManager::get()->openTablet(); } @@ -7604,8 +7693,7 @@ void Application::windowMinimizedChanged(bool minimized) { static std::once_flag once; std::call_once(once, [&] { connect(&_minimizedWindowTimer, &QTimer::timeout, this, [] { - QCoreApplication::postEvent(QCoreApplication::instance(), new QEvent(static_cast(Idle)), - Qt::HighEventPriority); + QCoreApplication::postEvent(QCoreApplication::instance(), new QEvent(static_cast(Idle)), Qt::HighEventPriority); }); }); @@ -7634,7 +7722,7 @@ void Application::sendLambdaEvent(const std::function& f) { } else { LambdaEvent event(f); QCoreApplication::sendEvent(this, &event); - } + } } void Application::initPlugins(const QStringList& arguments) { @@ -7656,7 +7744,7 @@ void Application::initPlugins(const QStringList& arguments) { if (parser.isSet(disableDisplays)) { auto disabledDisplays = parser.value(disableDisplays).split(',', QString::SkipEmptyParts); - qInfo() << "Disabling following display plugins:" << disabledDisplays; + qInfo() << "Disabling following display plugins:" << disabledDisplays; PluginManager::getInstance()->disableDisplays(disabledDisplays); } @@ -7782,7 +7870,7 @@ static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, bo auto menu = Menu::getInstance(); QString name = displayPlugin->getName(); auto grouping = displayPlugin->getGrouping(); - QString groupingMenu{ "" }; + QString groupingMenu { "" }; Q_ASSERT(!menu->menuItemExists(MenuOption::OutputMenu, name)); // assign the meny grouping based on plugin grouping @@ -7804,8 +7892,10 @@ static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, bo displayPluginGroup->setExclusive(true); } auto parent = menu->getMenu(MenuOption::OutputMenu); - auto action = menu->addActionToQMenuAndActionHash(parent, name, 0, qApp, SLOT(updateDisplayMode()), QAction::NoRole, - Menu::UNSPECIFIED_POSITION, groupingMenu); + auto action = menu->addActionToQMenuAndActionHash(parent, + name, 0, qApp, + SLOT(updateDisplayMode()), + QAction::NoRole, Menu::UNSPECIFIED_POSITION, groupingMenu); action->setCheckable(true); action->setChecked(active); @@ -7828,7 +7918,7 @@ void Application::updateDisplayMode() { DisplayPluginPointer newDisplayPlugin = displayPlugins.at(0); auto menu = getPrimaryMenu(); if (menu) { - foreach (DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { + foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { QString name = displayPlugin->getName(); QAction* action = menu->getActionForOption(name); // Menu might have been removed if the display plugin lost @@ -7855,7 +7945,7 @@ void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) { } // FIXME don't have the application directly set the state of the UI, - // instead emit a signal that the display plugin is changing and let + // instead emit a signal that the display plugin is changing and let // the desktop lock itself. Reduces coupling between the UI and display // plugins auto offscreenUi = DependencyManager::get(); @@ -7918,10 +8008,11 @@ void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) { qCDebug(interfaceapp) << "Entering into" << (isHmd ? "HMD" : "Desktop") << "Mode"; // Only log/emit after a successful change - UserActivityLogger::getInstance().logAction("changed_display_mode", - { { "previous_display_mode", _displayPlugin ? _displayPlugin->getName() : "" }, - { "display_mode", newDisplayPlugin ? newDisplayPlugin->getName() : "" }, - { "hmd", isHmd } }); + UserActivityLogger::getInstance().logAction("changed_display_mode", { + { "previous_display_mode", _displayPlugin ? _displayPlugin->getName() : "" }, + { "display_mode", newDisplayPlugin ? newDisplayPlugin->getName() : "" }, + { "hmd", isHmd } + }); emit activeDisplayPluginChanged(); // reset the avatar, to set head and hand palms back to a reasonable default pose. @@ -8087,6 +8178,7 @@ CompositorHelper& Application::getApplicationCompositor() const { return *DependencyManager::get(); } + // virtual functions required for PluginContainer ui::Menu* Application::getPrimaryMenu() { auto appMenu = _window->menuBar(); @@ -8176,16 +8268,19 @@ void Application::openAndroidActivity(const QString& activityName) { #if defined(Q_OS_ANDROID) void Application::enterBackground() { - QMetaObject::invokeMethod(DependencyManager::get().data(), "stop", Qt::BlockingQueuedConnection); + QMetaObject::invokeMethod(DependencyManager::get().data(), + "stop", Qt::BlockingQueuedConnection); //GC: commenting it out until we fix it //getActiveDisplayPlugin()->deactivate(); } void Application::enterForeground() { - QMetaObject::invokeMethod(DependencyManager::get().data(), "start", Qt::BlockingQueuedConnection); + QMetaObject::invokeMethod(DependencyManager::get().data(), + "start", Qt::BlockingQueuedConnection); //GC: commenting it out until we fix it /*if (!getActiveDisplayPlugin() || !getActiveDisplayPlugin()->activate()) { qWarning() << "Could not re-activate display plugin"; }*/ + } #endif From 6c946d7ac5e7f9da7640ef21258f7d60e944609c Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 16 May 2018 11:36:57 -0700 Subject: [PATCH 054/380] prevent continuous clone calls --- .../controllerModules/nearParentGrabEntity.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index 0ebd4efb2f..5f310e471f 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -35,6 +35,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); this.lastUnexpectedChildrenCheckTime = 0; this.robbed = false; this.highlightedEntity = null; + this.cloneAllowed = true; this.parameters = makeDispatcherModuleParameters( 500, @@ -272,6 +273,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { this.checkForUnexpectedChildren(controllerData); this.robbed = false; + this.cloneAllowed = true; return makeRunningValues(false, [], []); } @@ -335,12 +337,14 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var targetCloneable = entityIsCloneable(targetProps); if (targetCloneable) { - var cloneID = cloneEntity(targetProps); - var cloneProps = Entities.getEntityProperties(cloneID); - this.grabbing = true; - this.targetEntityID = cloneID; - this.startNearParentingGrabEntity(controllerData, cloneProps); - + if (this.cloneAllowed) { + var cloneID = cloneEntity(targetProps); + var cloneProps = Entities.getEntityProperties(cloneID); + this.grabbing = true; + this.targetEntityID = cloneID; + this.startNearParentingGrabEntity(controllerData, cloneProps); + this.cloneAllowed = false; + } } else if (targetProps) { this.grabbing = true; this.startNearParentingGrabEntity(controllerData, targetProps); From 06fa4efe055240e900c109bd1b5a9ba705b327b7 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 16 May 2018 11:39:53 -0700 Subject: [PATCH 055/380] add comment --- .../controllers/controllerModules/nearParentGrabEntity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index 5f310e471f..4ab45b33f7 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -343,7 +343,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); this.grabbing = true; this.targetEntityID = cloneID; this.startNearParentingGrabEntity(controllerData, cloneProps); - this.cloneAllowed = false; + this.cloneAllowed = false; // prevent another clone call until inputs released } } else if (targetProps) { this.grabbing = true; From 154d70866f5261075c83323a322e34d912a52e2d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 16 May 2018 12:17:17 -0700 Subject: [PATCH 056/380] It's working --- .../qml/hifi/commerce/wallet/WalletHome.qml | 52 +++---- .../qml/hifi/models/PSFListModel.qml | 147 +++++++++++++++--- interface/src/commerce/Ledger.cpp | 4 +- interface/src/commerce/Ledger.h | 2 +- interface/src/commerce/QmlCommerce.cpp | 4 +- interface/src/commerce/QmlCommerce.h | 2 +- 6 files changed, 158 insertions(+), 53 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index afc205fd51..ac3afd3cf2 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -18,7 +18,7 @@ import QtQuick.Controls 2.2 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls -import "../../../models" as HifiModels +import "../../models" as HifiModels Item { HifiConstants { id: hifi; } @@ -32,10 +32,10 @@ Item { transactionHistoryModel.clear(); Commerce.balance(); transactionHistoryModel.initialResultReceived = false; - transactionHistoryModel.nextPageToRetrieve = 1; + transactionHistoryModel.currentPageToRetrieve = 1; transactionHistoryModel.noMoreDataToRetrieve = false; transactionHistoryModel.requestPending = true; - Commerce.history(transactionHistoryModel.nextPageToRetrieve); + transactionHistoryModel.getPage(); Commerce.getAvailableUpdates(); } else { refreshTimer.stop(); @@ -50,18 +50,7 @@ Item { } onHistoryResult : { - - transactionHistoryModel.processResult(result.status, result.data.history); - - if (!transactionHistoryModel.noMoreDataToRetrieve) { - calculatePendingAndInvalidated(); - } - - // Only auto-refresh if the user hasn't scrolled - // and there is more data to grab - if (transactionHistory.atYBeginning && !transactionHistoryModel.noMoreDataToRetrieve) { - refreshTimer.start(); - } + transactionHistoryModel.pageRetrieved(result); } onAvailableUpdatesResult: { @@ -166,7 +155,8 @@ Item { console.log("Refreshing 1st Page of Recent Activity..."); transactionHistoryModel.requestPending = true; Commerce.balance(); - Commerce.history(1); + transactionHistoryModel.currentPageToRetrieve = 1; + transactionHistoryModel.getPage(); } } } @@ -228,11 +218,26 @@ Item { } } - ListModel { - id: tempTransactionHistoryModel; - } HifiModels.PSFListModel { id: transactionHistoryModel; + + itemsPerPage: 100; + getPage: function() { + Commerce.history(transactionHistoryModel.currentPageToRetrieve, transactionHistoryModel.itemsPerPage); + } + pageRetrieved: function(result) { + transactionHistoryModel.processResult(result.status, result.data.history); + + if (!transactionHistoryModel.noMoreDataToRetrieve) { + calculatePendingAndInvalidated(); + } + + // Only auto-refresh if the user hasn't scrolled + // and there is more data to grab + if (transactionHistory.atYBeginning && !transactionHistoryModel.noMoreDataToRetrieve) { + refreshTimer.start(); + } + } } Item { anchors.top: recentActivityText.bottom; @@ -311,7 +316,7 @@ Item { height: parent.height; visible: transactionHistoryModel.count !== 0; clip: true; - model: transactionHistoryModel; + model: transactionHistoryModel.model; delegate: Item { width: parent.width; height: (model.transaction_type === "pendingCount" && root.pendingCount !== 0) ? 40 : ((model.status === "confirmed" || model.status === "invalidated") ? transactionText.height + 30 : 0); @@ -391,12 +396,7 @@ Item { onAtYEndChanged: { if (transactionHistory.atYEnd) { console.log("User scrolled to the bottom of 'Recent Activity'."); - if (!transactionHistoryModel.requestPending && !transactionHistoryModel.noMoreDataToRetrieve) { - // Grab next page of results and append to model - transactionHistoryModel.requestPending = true; - Commerce.history(++transactionHistoryModel.nextPageToRetrieve); - console.log("Fetching Page " + transactionHistoryModel.nextPageToRetrieve + " of Recent Activity..."); - } + transactionHistoryModel.getNextPage(); } } } diff --git a/interface/resources/qml/hifi/models/PSFListModel.qml b/interface/resources/qml/hifi/models/PSFListModel.qml index cbc28b208d..ee639a4f71 100644 --- a/interface/resources/qml/hifi/models/PSFListModel.qml +++ b/interface/resources/qml/hifi/models/PSFListModel.qml @@ -17,58 +17,156 @@ import QtQuick 2.7 -ListModel { +Item { id: root; - property string sortColumnName: ""; - property bool isSortingDescending: true; - property bool valuesAreNumerical: false; + + // Used when printing debug statements + property string listModelName: ""; + + // Holds the value of the page that'll be retrieved the next time `getPage()` is called + property int currentPageToRetrieve: 1; + + // If defined, the endpoint that `getPage()` will hit (as long as there isn't a custom `getPage()` + // that does something fancy) + property string endpoint; + // If defined, the sort key used when calling the above endpoint. + // (as long as there isn't a custom `getPage()` that does something fancy) + property string sortKey; + // If defined, the search filter used when calling the above endpoint. + // (as long as there isn't a custom `getPage()` that does something fancy) + property string searchFilter; + // If defined, the tags filter used when calling the above endpoint. + // (as long as there isn't a custom `getPage()` that does something fancy) + property string tagsFilter; + // The number of items that'll be retrieved per page when calling `getPage()` + // (as long as there isn't a custom `getPage()` that does something fancy) + property int itemsPerPage: 100; + + // This function, by default, will retrieve data from the above-defined `endpoint` with the + // sort and filter data as set above. It can be custom-defined by this item's Parent. + property var getPage: function() { + // Put code here that calls the `endpoint` with the proper `sortKey`, `searchFilter`, and `tagsFilter`. + // Whatever code goes here should define the below `pageRetrieved()` as + // the callback for after the page is asynchronously retrieved. + + // The parent of this Item can also define custom `getPage()` and `pageRetrieved()` functions. + // See `WalletHome.qml` as an example of a file that does this. `WalletHome.qml` must use that method because + // it hits an endpoint that must be authenticated via the Wallet. + console.log("default getPage()"); + } + // This function, by default, will handle the data retrieved using `getPage()` above. + // It can be custom-defined by this item's Parent. + property var pageRetrieved: function() { + console.log("default pageRetrieved()"); + } + + // This function, by default, will get the _next_ page of data according to `getPage()` if there + // isn't a pending request and if there's more data to retrieve. + // It can be custom-defined by this item's Parent. + property var getNextPage: function() { + if (!root.requestPending && !root.noMoreDataToRetrieve) { + root.requestPending = true; + root.currentPageToRetrieve++; + root.getPage(); + console.log("Fetching Page " + root.currentPageToRetrieve + " of " + root.listModelName + "..."); + } + } + + // Resets both internal `ListModel`s and resets the page to retrieve to "1". + function resetModel() { + pagesAlreadyAdded = new Array(); + tempModel.clear(); + finalModel.clear(); + root.currentPageToRetrieve = 1; + } + + onEndpointChanged: { + resetModel(); + root.getPage(); + } + + onSortKeyChanged: { + resetModel(); + root.getPage(); + } + + onSearchFilterChanged: { + resetModel(); + root.getPage(); + } + + onTagsFilterChanged: { + resetModel(); + root.getPage(); + } property bool initialResultReceived: false; property bool requestPending: false; property bool noMoreDataToRetrieve: false; - property int nextPageToRetrieve: 1; property var pagesAlreadyAdded: new Array(); + + // Redefining members and methods so that the parent of this Item + // can use PSFListModel as they would a regular ListModel + property alias model: finalModel; + property alias count: finalModel.count; + function clear() { finalModel.clear(); } + function get(index) { return finalModel.get(index); } + // Used while processing page data and sorting ListModel { id: tempModel; } + // This is the model that the parent of this Item will actually see + ListModel { + id: finalModel; + } + function processResult(status, retrievedResult) { root.initialResultReceived = true; root.requestPending = false; if (status === 'success') { - var currentPage = parseInt(result.current_page); + var currentPage = parseInt(retrievedResult.current_page); if (retrievedResult.length === 0) { root.noMoreDataToRetrieve = true; console.log("No more data to retrieve from backend endpoint.") - } else if (root.nextPageToRetrieve === 1) { + } + /* + See FIXME below... + + else if (root.currentPageToRetrieve === 1) { var sameItemCount = 0; tempModel.clear(); tempModel.append(retrievedResult); for (var i = 0; i < tempModel.count; i++) { - if (!root.get(i)) { + if (!finalModel.get(i)) { sameItemCount = -1; break; } - // Gotta think of another way to determine if the data we just got is the same + // Gotta think of a generic way to determine if the data we just got is the same // as the data that we already have in the model. - /* else if (tempModel.get(i).transaction_type === root.get(i).transaction_type && - tempModel.get(i).text === root.get(i).text) { + else if (tempModel.get(i).transaction_type === finalModel.get(i).transaction_type && + tempModel.get(i).text === finalModel.get(i).text) { sameItemCount++; - }*/ + } } if (sameItemCount !== tempModel.count) { - root.clear(); + finalModel.clear(); for (var i = 0; i < tempModel.count; i++) { - root.append(tempModel.get(i)); + finalModel.append(tempModel.get(i)); } } - } else { + } + */ + else { + // FIXME! Reconsider this logic, because it means that auto-refreshing the first page of results + // (like we do in WalletHome for Recent Activity) _won't_ catch brand new data elements! + // See the commented code above for how I did this for WalletHome specifically. if (root.pagesAlreadyAdded.indexOf(currentPage) !== -1) { console.log("Page " + currentPage + " of paginated data has already been added to the list."); } else { @@ -81,18 +179,18 @@ ListModel { var insertionIndex = 0; // If there's nothing in the model right now, we don't need to modify insertionIndex. - if (root.count !== 0) { + if (finalModel.count !== 0) { var currentIteratorPage; // Search through the whole model and look for the insertion point. // The insertion point is found when the result page from the server is less than // the page that the current item came from, OR when we've reached the end of the whole model. - for (var i = 0; i < root.count; i++) { - currentIteratorPage = root.get(i).resultIsFromPage; + for (var i = 0; i < finalModel.count; i++) { + currentIteratorPage = finalModel.get(i).resultIsFromPage; if (currentPage < currentIteratorPage) { insertionIndex = i; break; - } else if (i === root.count - 1) { + } else if (i === finalModel.count - 1) { insertionIndex = i + 1; break; } @@ -101,16 +199,23 @@ ListModel { // Go through the results we just got back from the server, setting the "resultIsFromPage" // property of those results and adding them to the main model. - // NOTE that this wouldn't be necessary if we did this step on the server. + // NOTE that this wouldn't be necessary if we did this step (or a similar step) on the server. for (var i = 0; i < tempModel.count; i++) { tempModel.setProperty(i, "resultIsFromPage", currentPage); - root.insert(i + insertionIndex, tempModel.get(i)) + finalModel.insert(i + insertionIndex, tempModel.get(i)) } } } } } + // Used when sorting model data on the CLIENT + // Right now, there is no sorting done on the client for + // any users of PSFListModel, but that could very easily change. + property string sortColumnName: ""; + property bool isSortingDescending: true; + property bool valuesAreNumerical: false; + function swap(a, b) { if (a < b) { move(a, b, 1); diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index f791ea25bc..0abdba1214 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -260,9 +260,9 @@ void Ledger::historyFailure(QNetworkReply& reply) { failResponse("history", reply); } -void Ledger::history(const QStringList& keys, const int& pageNumber) { +void Ledger::history(const QStringList& keys, const int& pageNumber, const int& itemsPerPage) { QJsonObject params; - params["per_page"] = 100; + params["per_page"] = itemsPerPage; params["page"] = pageNumber; keysQuery("history", "historySuccess", "historyFailure", params); } diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index abc97bfe72..1365e39b21 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -29,7 +29,7 @@ public: bool receiveAt(const QString& hfc_key, const QString& signing_key); void balance(const QStringList& keys); void inventory(const QStringList& keys); - void history(const QStringList& keys, const int& pageNumber); + void history(const QStringList& keys, const int& pageNumber, const int& itemsPerPage); void account(); void updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings = false, const bool controlledFailure = false); void certificateInfo(const QString& certificateId); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 722f29ba2f..9a5b0519a0 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -114,12 +114,12 @@ void QmlCommerce::inventory() { } } -void QmlCommerce::history(const int& pageNumber) { +void QmlCommerce::history(const int& pageNumber, const int& itemsPerPage) { auto ledger = DependencyManager::get(); auto wallet = DependencyManager::get(); QStringList cachedPublicKeys = wallet->listPublicKeys(); if (!cachedPublicKeys.isEmpty()) { - ledger->history(cachedPublicKeys, pageNumber); + ledger->history(cachedPublicKeys, pageNumber, itemsPerPage); } } diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index 27e97fe7db..5f33ab094c 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -74,7 +74,7 @@ protected: Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false); Q_INVOKABLE void balance(); Q_INVOKABLE void inventory(); - Q_INVOKABLE void history(const int& pageNumber); + Q_INVOKABLE void history(const int& pageNumber, const int& itemsPerPage = 100); Q_INVOKABLE void generateKeyPair(); Q_INVOKABLE void account(); From 0021af871457278b845116d13f047089d51e6a6d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 16 May 2018 12:28:52 -0700 Subject: [PATCH 057/380] Merge in in-progress changes from old commerce_paginationAndFiltering branch --- .../qml/hifi/commerce/checkout/Checkout.qml | 23 ++----------------- .../qml/hifi/commerce/purchases/Purchases.qml | 21 ++++------------- interface/src/commerce/Ledger.cpp | 9 ++++++-- interface/src/commerce/Ledger.h | 2 +- interface/src/commerce/QmlCommerce.cpp | 4 ++-- interface/src/commerce/QmlCommerce.h | 2 +- scripts/system/html/js/marketplacesInject.js | 12 ++++++---- 7 files changed, 25 insertions(+), 48 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index f25282c738..16c1b55930 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -42,7 +42,7 @@ Rectangle { property bool alreadyOwned: false; property int itemPrice: -1; property bool isCertified; - property string itemType; + property string itemType: "unknown"; property var itemTypesArray: ["entity", "wearable", "contentSet", "app", "avatar", "unknown"]; property var itemTypesText: ["entity", "wearable", "content set", "app", "avatar", "item"]; property var buttonTextNormal: ["REZ", "WEAR", "REPLACE CONTENT SET", "INSTALL", "WEAR", "REZ"]; @@ -98,9 +98,6 @@ Rectangle { } else { root.certificateId = result.data.certificate_id; root.itemHref = result.data.download_url; - if (result.data.categories.indexOf("Wearables") > -1) { - root.itemType = "wearable"; - } root.activeView = "checkoutSuccess"; UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned); } @@ -170,9 +167,6 @@ Rectangle { root.activeView = "checkoutFailure"; } else { root.itemHref = result.data.download_url; - if (result.data.categories.indexOf("Wearables") > -1) { - root.itemType = "wearable"; - } root.activeView = "checkoutSuccess"; } } @@ -186,20 +180,6 @@ Rectangle { itemPreviewImage.source = "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/" + itemId + "/thumbnail/hifi-mp-" + itemId + ".jpg"; } - onItemHrefChanged: { - if (root.itemHref.indexOf(".fst") > -1) { - root.itemType = "avatar"; - } else if (root.itemHref.indexOf('.json.gz') > -1 || root.itemHref.indexOf('.content.zip') > -1) { - root.itemType = "contentSet"; - } else if (root.itemHref.indexOf('.app.json') > -1) { - root.itemType = "app"; - } else if (root.itemHref.indexOf('.json') > -1) { - root.itemType = "entity"; // "wearable" type handled later - } else { - root.itemType = "unknown"; - } - } - onItemTypeChanged: { if (root.itemType === "entity" || root.itemType === "wearable" || root.itemType === "contentSet" || root.itemType === "avatar" || root.itemType === "app") { @@ -1102,6 +1082,7 @@ Rectangle { root.referrer = message.params.referrer; root.itemAuthor = message.params.itemAuthor; root.itemEdition = message.params.itemEdition || -1; + root.itemType = message.params.itemType || "unknown"; refreshBuyUI(); break; default: diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 8fe1ebe6c9..e32b31c1ea 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -614,7 +614,7 @@ Rectangle { wornEntityID: model.wornEntityID; upgradeUrl: model.upgrade_url; upgradeTitle: model.upgrade_title; - itemType: model.itemType; + itemType: model.item_type; isShowingMyItems: root.isShowingMyItems; valid: model.valid; anchors.topMargin: 10; @@ -996,7 +996,8 @@ Rectangle { for (var i = 0; i < purchasesModel.count; i++) { if (purchasesModel.get(i).title.toLowerCase().indexOf(filterBar.text.toLowerCase()) !== -1) { - if (purchasesModel.get(i).status !== "confirmed" && !root.isShowingMyItems) { + if (purchasesModel.get(i).status !== "confirmed" && !root.isShowingMyItems && + purchasesModel.get(i).edition_number !== "0") { tempPurchasesModel.insert(0, purchasesModel.get(i)); } else if ((root.isShowingMyItems && purchasesModel.get(i).edition_number === "0") || (!root.isShowingMyItems && purchasesModel.get(i).edition_number !== "0")) { @@ -1010,27 +1011,13 @@ Rectangle { for (var i = 0; i < tempPurchasesModel.count; i++) { currentRootFileUrl = tempPurchasesModel.get(i).root_file_url; currentCategories = tempPurchasesModel.get(i).categories; + currentItemType = tempPurchasesModel.get(i).item_type; - if (currentRootFileUrl.indexOf(".fst") > -1) { - currentItemType = "avatar"; - } else if (currentCategories.indexOf("Wearables") > -1) { - currentItemType = "wearable"; - } else if (currentRootFileUrl.endsWith('.json.gz') || currentRootFileUrl.endsWith('.content.zip')) { - currentItemType = "contentSet"; - } else if (currentRootFileUrl.endsWith('.app.json')) { - currentItemType = "app"; - } else if (currentRootFileUrl.endsWith('.json')) { - currentItemType = "entity"; - } else { - currentItemType = "unknown"; - } if (filterBar.primaryFilter_displayName !== "" && ((filterBar.primaryFilter_displayName === "Updatable" && tempPurchasesModel.get(i).upgrade_url === "") || (filterBar.primaryFilter_displayName !== "Updatable" && filterBar.primaryFilter_filterName.toLowerCase() !== currentItemType.toLowerCase()))) { tempPurchasesModel.remove(i); i--; - } else { - tempPurchasesModel.setProperty(i, 'itemType', currentItemType); } } diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 0abdba1214..5bd8c77d04 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -134,8 +134,13 @@ void Ledger::balance(const QStringList& keys) { keysQuery("balance", "balanceSuccess", "balanceFailure"); } -void Ledger::inventory(const QStringList& keys) { - keysQuery("inventory", "inventorySuccess", "inventoryFailure"); +void Ledger::inventory(const QString& editionFilter, const QString& typeFilter, const int& page, const int& perPage) { + QJsonObject params; + params["edition_filter"] = editionFilter; + params["type_filter"] = typeFilter; + params["page"] = page; + params["per_page"] = perPage; + keysQuery("inventory", "inventorySuccess", "inventoryFailure", params); } QString hfcString(const QJsonValue& sentValue, const QJsonValue& receivedValue) { diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index 1365e39b21..9733658357 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -28,7 +28,7 @@ public: void buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const bool controlled_failure = false); bool receiveAt(const QString& hfc_key, const QString& signing_key); void balance(const QStringList& keys); - void inventory(const QStringList& keys); + void inventory(const QString& editionFilter, const QString& typeFilter, const int& page, const int& perPage); void history(const QStringList& keys, const int& pageNumber, const int& itemsPerPage); void account(); void updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings = false, const bool controlledFailure = false); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 9a5b0519a0..dba8cd03c7 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -105,12 +105,12 @@ void QmlCommerce::balance() { } } -void QmlCommerce::inventory() { +void QmlCommerce::inventory(const QString& editionFilter, const QString& typeFilter, const int& page, const int& perPage) { auto ledger = DependencyManager::get(); auto wallet = DependencyManager::get(); QStringList cachedPublicKeys = wallet->listPublicKeys(); if (!cachedPublicKeys.isEmpty()) { - ledger->inventory(cachedPublicKeys); + ledger->inventory(editionFilter, typeFilter, page, perPage); } } diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index 5f33ab094c..3a08b4a19b 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -73,7 +73,7 @@ protected: Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false); Q_INVOKABLE void balance(); - Q_INVOKABLE void inventory(); + Q_INVOKABLE void inventory(const QString& editionFilter = QString(), const QString& typeFilter = QString(), const int& page = 1, const int& perPage = 20); Q_INVOKABLE void history(const int& pageNumber, const int& itemsPerPage = 100); Q_INVOKABLE void generateKeyPair(); Q_INVOKABLE void account(); diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 864c7d92b4..799a974fd6 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -250,7 +250,7 @@ }); } - function buyButtonClicked(id, name, author, price, href, referrer, edition) { + function buyButtonClicked(id, name, author, price, href, referrer, edition, type) { EventBridge.emitWebEvent(JSON.stringify({ type: "CHECKOUT", itemId: id, @@ -259,7 +259,8 @@ itemHref: href, referrer: referrer, itemAuthor: author, - itemEdition: edition + itemEdition: edition, + itemType: type.trim() })); } @@ -328,7 +329,8 @@ $(this).closest('.grid-item').find('.item-cost').text(), $(this).attr('data-href'), "mainPage", - -1); + -1, + $(this).closest('.grid-item').find('.item-type').text()); }); } @@ -419,6 +421,7 @@ } var cost = $('.item-cost').text(); + var type = $('.item-type').text(); var isUpdating = window.location.href.indexOf('edition=') > -1; var urlParams = new URLSearchParams(window.location.search); if (isUpdating) { @@ -438,7 +441,8 @@ cost, href, "itemPage", - urlParams.get('edition')); + urlParams.get('edition'), + type); } }); maybeAddPurchasesButton(); From 97bb0147348ae9bf8e0e18d8887095955c44945f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 16 May 2018 13:20:23 -0700 Subject: [PATCH 058/380] Almost working for Purchases! --- .../qml/hifi/commerce/purchases/Purchases.qml | 254 +++++++----------- .../qml/hifi/commerce/wallet/WalletHome.qml | 4 +- .../qml/hifi/models/PSFListModel.qml | 8 + 3 files changed, 106 insertions(+), 160 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index e32b31c1ea..9f5dec7ef3 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -16,6 +16,7 @@ import QtQuick 2.5 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls +import "../../models" as HifiModels import "../wallet" as HifiWallet import "../common" as HifiCommerceCommon import "../inspectionCertificate" as HifiInspectionCertificate @@ -34,7 +35,6 @@ Rectangle { property bool punctuationMode: false; property bool isShowingMyItems: false; property bool isDebuggingFirstUseTutorial: false; - property int pendingItemCount: 0; property string installedApps; property bool keyboardRaised: false; property int numUpdatesAvailable: 0; @@ -64,7 +64,10 @@ Rectangle { } else if (!Settings.getValue("isFirstUseOfPurchases", true) && root.activeView === "initialize") { root.activeView = "purchasesMain"; root.installedApps = Commerce.getInstalledApps(); - Commerce.inventory(); + purchasesModel.initialResultReceived = false; + purchasesModel.currentPageToRetrieve = 1; + purchasesModel.noMoreDataToRetrieve = false; + purchasesModel.getPage(); Commerce.getAvailableUpdates(); } } else { @@ -81,39 +84,7 @@ Rectangle { } onInventoryResult: { - purchasesReceived = true; - - if (result.status !== 'success') { - console.log("Failed to get purchases", result.message); - } else if (!purchasesContentsList.dragging) { // Don't modify the view if the user's scrolling - var inventoryResult = processInventoryResult(result.data.assets); - - var currentIndex = purchasesContentsList.currentIndex === -1 ? 0 : purchasesContentsList.currentIndex; - purchasesModel.clear(); - purchasesModel.append(inventoryResult); - - root.pendingItemCount = 0; - for (var i = 0; i < purchasesModel.count; i++) { - if (purchasesModel.get(i).status === "pending") { - root.pendingItemCount++; - } - } - - if (previousPurchasesModel.count !== 0) { - checkIfAnyItemStatusChanged(); - } else { - // Fill statusChanged default value - // Not doing this results in the default being true... - for (var i = 0; i < purchasesModel.count; i++) { - purchasesModel.setProperty(i, "statusChanged", false); - } - } - previousPurchasesModel.append(inventoryResult); - - buildFilteredPurchasesModel(); - - purchasesContentsList.positionViewAtIndex(currentIndex, ListView.Beginning); - } + purchasesModel.pageRetrieved(result); } onAvailableUpdatesResult: { @@ -134,6 +105,11 @@ Rectangle { } } + onIsShowingMyItemsChanged: { + purchasesModel.resetModel(); + + } + Timer { id: notSetUpTimer; interval: 200; @@ -184,7 +160,10 @@ Rectangle { onSendSignalToParent: { if (msg.method === 'sendAssetHome_back' || msg.method === 'closeSendAsset') { root.activeView = "purchasesMain"; - Commerce.inventory(); + purchasesModel.initialResultReceived = false; + purchasesModel.currentPageToRetrieve = 1; + purchasesModel.noMoreDataToRetrieve = false; + purchasesModel.getPage(); Commerce.getAvailableUpdates(); } else { sendToScript(msg); @@ -451,7 +430,10 @@ Rectangle { Settings.setValue("isFirstUseOfPurchases", false); root.activeView = "purchasesMain"; root.installedApps = Commerce.getInstalledApps(); - Commerce.inventory(); + purchasesModel.initialResultReceived = false; + purchasesModel.currentPageToRetrieve = 1; + purchasesModel.noMoreDataToRetrieve = false; + purchasesModel.getPage(); Commerce.getAvailableUpdates(); break; } @@ -548,14 +530,12 @@ Rectangle { } onPrimaryFilter_displayNameChanged: { - buildFilteredPurchasesModel(); - purchasesContentsList.positionViewAtIndex(0, ListView.Beginning) + purchasesModel.tagsFilter = filterBar.primaryFilter_filterName.toLowerCase(); filterBar.previousPrimaryFilter = filterBar.primaryFilter_displayName; } onTextChanged: { - buildFilteredPurchasesModel(); - purchasesContentsList.positionViewAtIndex(0, ListView.Beginning) + purchasesModel.searchFilter = filterBar.text; filterBar.previousText = filterBar.text; } } @@ -574,24 +554,58 @@ Rectangle { anchors.topMargin: 16; } - ListModel { + HifiModels.PSFListModel { id: purchasesModel; - } - ListModel { - id: previousPurchasesModel; - } - HifiCommerceCommon.SortableListModel { - id: tempPurchasesModel; - } - HifiCommerceCommon.SortableListModel { - id: filteredPurchasesModel; + + itemsPerPage: 3; + getPage: function() { + Commerce.inventory( + root.isShowingMyItems ? "proofs" : "purchased", + filterBar.primaryFilter_filterName.toLowerCase(), + purchasesModel.currentPageToRetrieve, + purchasesModel.itemsPerPage + ); + } + pageRetrieved: function(result) { + purchasesReceived = true; + + var processedInventory = processInventoryResult(result.data.assets); + + if (purchasesModel.processResult(result.status, processedInventory)) { + var currentId; + for (var i = 0; i < purchasesModel.count; i++) { + currentId = purchasesModel.get(i).id; + purchasesModel.setProperty(i, 'cardBackVisible', false); + purchasesModel.setProperty(i, 'isInstalled', ((root.installedApps).indexOf(currentId) > -1)); + purchasesModel.setProperty(i, 'wornEntityID', ''); + } + + // Client-side filter of "Updatable" items + // FIXME - this MUST be serverside (what if we don't have the + // page containing an updatable item on the client?) + if (filterBar.primaryFilter_displayName === "Updatable") { + for (var i = 0; i < purchasesModel.count; i++) { + if (purchasesModel.get(i).upgrade_url === "") { + purchasesModel.remove(i); + i--; + } + } + } + + sendToScript({ method: 'purchases_updateWearables' }); + // FIXME: This ALSO *MUST* be serverside (what if we don't have + // all instances of the item on the client yet?) + //populateDisplayedItemCounts(); + sortByDate(); + } + } } ListView { id: purchasesContentsList; - visible: (root.isShowingMyItems && filteredPurchasesModel.count !== 0) || (!root.isShowingMyItems && filteredPurchasesModel.count !== 0); + visible: purchasesModel.count !== 0; clip: true; - model: filteredPurchasesModel; + model: purchasesModel.model; snapMode: ListView.SnapToItem; // Anchors anchors.top: separator.bottom; @@ -608,9 +622,9 @@ Rectangle { itemEdition: model.edition_number; numberSold: model.number_sold; limitedRun: model.limited_run; - displayedItemCount: model.displayedItemCount; - cardBackVisible: model.cardBackVisible; - isInstalled: model.isInstalled; + displayedItemCount: model.displayedItemCount || 0; + cardBackVisible: model.cardBackVisible || false; + isInstalled: model.isInstalled || false; wornEntityID: model.wornEntityID; upgradeUrl: model.upgrade_url; upgradeTitle: model.upgrade_title; @@ -706,11 +720,11 @@ Rectangle { } else if (msg.method === "setFilterText") { filterBar.text = msg.filterText; } else if (msg.method === "flipCard") { - for (var i = 0; i < filteredPurchasesModel.count; i++) { + for (var i = 0; i < purchasesModel.count; i++) { if (i !== index || msg.closeAll) { - filteredPurchasesModel.setProperty(i, "cardBackVisible", false); + purchasesModel.setProperty(i, "cardBackVisible", false); } else { - filteredPurchasesModel.setProperty(i, "cardBackVisible", true); + purchasesModel.setProperty(i, "cardBackVisible", true); } } } else if (msg.method === "updateItemClicked") { @@ -761,7 +775,7 @@ Rectangle { lightboxPopup.button2text = "CONFIRM"; lightboxPopup.button2method = function() { Entities.deleteEntity(msg.wornEntityID); - filteredPurchasesModel.setProperty(index, 'wornEntityID', ''); + purchasesModel.setProperty(index, 'wornEntityID', ''); root.activeView = "giftAsset"; lightboxPopup.visible = false; }; @@ -773,6 +787,14 @@ Rectangle { } } } + + + onAtYEndChanged: { + if (purchasesContentsList.atYEnd) { + console.log("User scrolled to the bottom of 'Purchases'."); + purchasesModel.getNextPage(); + } + } } Rectangle { @@ -968,8 +990,8 @@ Rectangle { function populateDisplayedItemCounts() { var itemCountDictionary = {}; var currentItemId; - for (var i = 0; i < filteredPurchasesModel.count; i++) { - currentItemId = filteredPurchasesModel.get(i).id; + for (var i = 0; i < purchasesModel.count; i++) { + currentItemId = purchasesModel.get(i).id; if (itemCountDictionary[currentItemId] === undefined) { itemCountDictionary[currentItemId] = 1; } else { @@ -977,109 +999,25 @@ Rectangle { } } - for (var i = 0; i < filteredPurchasesModel.count; i++) { - filteredPurchasesModel.setProperty(i, "displayedItemCount", itemCountDictionary[filteredPurchasesModel.get(i).id]); + for (var i = 0; i < purchasesModel.count; i++) { + purchasesModel.setProperty(i, "displayedItemCount", itemCountDictionary[purchasesModel.get(i).id]); } } function sortByDate() { - filteredPurchasesModel.sortColumnName = "purchase_date"; - filteredPurchasesModel.isSortingDescending = true; - filteredPurchasesModel.valuesAreNumerical = true; - filteredPurchasesModel.quickSort(); - } - - function buildFilteredPurchasesModel() { - var sameItemCount = 0; - - tempPurchasesModel.clear(); - - for (var i = 0; i < purchasesModel.count; i++) { - if (purchasesModel.get(i).title.toLowerCase().indexOf(filterBar.text.toLowerCase()) !== -1) { - if (purchasesModel.get(i).status !== "confirmed" && !root.isShowingMyItems && - purchasesModel.get(i).edition_number !== "0") { - tempPurchasesModel.insert(0, purchasesModel.get(i)); - } else if ((root.isShowingMyItems && purchasesModel.get(i).edition_number === "0") || - (!root.isShowingMyItems && purchasesModel.get(i).edition_number !== "0")) { - tempPurchasesModel.append(purchasesModel.get(i)); - } - } - } - - // primaryFilter filtering and adding of itemType property to model - var currentItemType, currentRootFileUrl, currentCategories; - for (var i = 0; i < tempPurchasesModel.count; i++) { - currentRootFileUrl = tempPurchasesModel.get(i).root_file_url; - currentCategories = tempPurchasesModel.get(i).categories; - currentItemType = tempPurchasesModel.get(i).item_type; - - if (filterBar.primaryFilter_displayName !== "" && - ((filterBar.primaryFilter_displayName === "Updatable" && tempPurchasesModel.get(i).upgrade_url === "") || - (filterBar.primaryFilter_displayName !== "Updatable" && filterBar.primaryFilter_filterName.toLowerCase() !== currentItemType.toLowerCase()))) { - tempPurchasesModel.remove(i); - i--; - } - } - - for (var i = 0; i < tempPurchasesModel.count; i++) { - if (!filteredPurchasesModel.get(i)) { - sameItemCount = -1; - break; - } else if (tempPurchasesModel.get(i).itemId === filteredPurchasesModel.get(i).itemId && - tempPurchasesModel.get(i).edition_number === filteredPurchasesModel.get(i).edition_number && - tempPurchasesModel.get(i).status === filteredPurchasesModel.get(i).status) { - sameItemCount++; - } - } - - if (sameItemCount !== tempPurchasesModel.count || - filterBar.text !== filterBar.previousText || - filterBar.primaryFilter !== filterBar.previousPrimaryFilter) { - filteredPurchasesModel.clear(); - var currentId; - for (var i = 0; i < tempPurchasesModel.count; i++) { - currentId = tempPurchasesModel.get(i).id; - filteredPurchasesModel.append(tempPurchasesModel.get(i)); - filteredPurchasesModel.setProperty(i, 'cardBackVisible', false); - filteredPurchasesModel.setProperty(i, 'isInstalled', ((root.installedApps).indexOf(currentId) > -1)); - filteredPurchasesModel.setProperty(i, 'wornEntityID', ''); - } - - sendToScript({ method: 'purchases_updateWearables' }); - populateDisplayedItemCounts(); - sortByDate(); - } - } - - function checkIfAnyItemStatusChanged() { - var currentPurchasesModelId, currentPurchasesModelEdition, currentPurchasesModelStatus; - var previousPurchasesModelStatus; - for (var i = 0; i < purchasesModel.count; i++) { - currentPurchasesModelId = purchasesModel.get(i).id; - currentPurchasesModelEdition = purchasesModel.get(i).edition_number; - currentPurchasesModelStatus = purchasesModel.get(i).status; - - for (var j = 0; j < previousPurchasesModel.count; j++) { - previousPurchasesModelStatus = previousPurchasesModel.get(j).status; - if (currentPurchasesModelId === previousPurchasesModel.get(j).id && - currentPurchasesModelEdition === previousPurchasesModel.get(j).edition_number && - currentPurchasesModelStatus !== previousPurchasesModelStatus) { - - purchasesModel.setProperty(i, "statusChanged", true); - } else { - purchasesModel.setProperty(i, "statusChanged", false); - } - } - } + purchasesModel.sortColumnName = "purchase_date"; + purchasesModel.isSortingDescending = true; + purchasesModel.valuesAreNumerical = true; + purchasesModel.quickSort(); } function updateCurrentlyWornWearables(wearables) { - for (var i = 0; i < filteredPurchasesModel.count; i++) { + for (var i = 0; i < purchasesModel.count; i++) { for (var j = 0; j < wearables.length; j++) { - if (filteredPurchasesModel.get(i).itemType === "wearable" && - wearables[j].entityCertID === filteredPurchasesModel.get(i).certificate_id && - wearables[j].entityEdition.toString() === filteredPurchasesModel.get(i).edition_number) { - filteredPurchasesModel.setProperty(i, 'wornEntityID', wearables[j].entityID); + if (purchasesModel.get(i).itemType === "wearable" && + wearables[j].entityCertID === purchasesModel.get(i).certificate_id && + wearables[j].entityEdition.toString() === purchasesModel.get(i).edition_number) { + purchasesModel.setProperty(i, 'wornEntityID', wearables[j].entityID); break; } } @@ -1136,7 +1074,7 @@ Rectangle { switch (message.method) { case 'updatePurchases': referrerURL = message.referrerURL || ""; - titleBarContainer.referrerURL = message.referrerURL; + titleBarContainer.referrerURL = message.referrerURL || ""; filterBar.text = message.filterText ? message.filterText : ""; break; case 'inspectionCertificate_setCertificateId': diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index ac3afd3cf2..b41d04f718 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -34,7 +34,6 @@ Item { transactionHistoryModel.initialResultReceived = false; transactionHistoryModel.currentPageToRetrieve = 1; transactionHistoryModel.noMoreDataToRetrieve = false; - transactionHistoryModel.requestPending = true; transactionHistoryModel.getPage(); Commerce.getAvailableUpdates(); } else { @@ -153,7 +152,6 @@ Item { onTriggered: { if (transactionHistory.atYBeginning) { console.log("Refreshing 1st Page of Recent Activity..."); - transactionHistoryModel.requestPending = true; Commerce.balance(); transactionHistoryModel.currentPageToRetrieve = 1; transactionHistoryModel.getPage(); @@ -221,8 +219,10 @@ Item { HifiModels.PSFListModel { id: transactionHistoryModel; + listModelName: "transaction history"; itemsPerPage: 100; getPage: function() { + transactionHistoryModel.requestPending = true; Commerce.history(transactionHistoryModel.currentPageToRetrieve, transactionHistoryModel.itemsPerPage); } pageRetrieved: function(result) { diff --git a/interface/resources/qml/hifi/models/PSFListModel.qml b/interface/resources/qml/hifi/models/PSFListModel.qml index ee639a4f71..41134ddfdb 100644 --- a/interface/resources/qml/hifi/models/PSFListModel.qml +++ b/interface/resources/qml/hifi/models/PSFListModel.qml @@ -111,6 +111,9 @@ Item { property alias count: finalModel.count; function clear() { finalModel.clear(); } function get(index) { return finalModel.get(index); } + function remove(index) { return finalModel.remove(index); } + function setProperty(index, prop, value) { return finalModel.setProperty(index, prop, value); } + function move(from, to, n) { return finalModel.move(from, to, n); } // Used while processing page data and sorting ListModel { @@ -206,7 +209,12 @@ Item { } } } + return true; + } else { + console.log("Failed to get page result for " + root.listModelName); } + + return false; } // Used when sorting model data on the CLIENT From bc590f556accecdf3faf66ee1d1a7e2d5cd981d3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 16 May 2018 13:32:53 -0700 Subject: [PATCH 059/380] Get first page --- .../qml/hifi/commerce/purchases/Purchases.qml | 20 +++++++------------ .../qml/hifi/commerce/wallet/WalletHome.qml | 5 +---- .../qml/hifi/models/PSFListModel.qml | 17 ++++++++++++---- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 9f5dec7ef3..93400349a2 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -64,10 +64,7 @@ Rectangle { } else if (!Settings.getValue("isFirstUseOfPurchases", true) && root.activeView === "initialize") { root.activeView = "purchasesMain"; root.installedApps = Commerce.getInstalledApps(); - purchasesModel.initialResultReceived = false; - purchasesModel.currentPageToRetrieve = 1; - purchasesModel.noMoreDataToRetrieve = false; - purchasesModel.getPage(); + purchasesModel.getFirstPage(); Commerce.getAvailableUpdates(); } } else { @@ -160,10 +157,7 @@ Rectangle { onSendSignalToParent: { if (msg.method === 'sendAssetHome_back' || msg.method === 'closeSendAsset') { root.activeView = "purchasesMain"; - purchasesModel.initialResultReceived = false; - purchasesModel.currentPageToRetrieve = 1; - purchasesModel.noMoreDataToRetrieve = false; - purchasesModel.getPage(); + purchasesModel.getFirstPage(); Commerce.getAvailableUpdates(); } else { sendToScript(msg); @@ -430,10 +424,7 @@ Rectangle { Settings.setValue("isFirstUseOfPurchases", false); root.activeView = "purchasesMain"; root.installedApps = Commerce.getInstalledApps(); - purchasesModel.initialResultReceived = false; - purchasesModel.currentPageToRetrieve = 1; - purchasesModel.noMoreDataToRetrieve = false; - purchasesModel.getPage(); + purchasesModel.getFirstPage(); Commerce.getAvailableUpdates(); break; } @@ -596,7 +587,10 @@ Rectangle { // FIXME: This ALSO *MUST* be serverside (what if we don't have // all instances of the item on the client yet?) //populateDisplayedItemCounts(); - sortByDate(); + + // FIXME: Sorting by date should be done serverside (we should always get + // the most recent purchases on the 1st page) + //sortByDate(); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index b41d04f718..76a963f63f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -31,10 +31,7 @@ Item { if (visible) { transactionHistoryModel.clear(); Commerce.balance(); - transactionHistoryModel.initialResultReceived = false; - transactionHistoryModel.currentPageToRetrieve = 1; - transactionHistoryModel.noMoreDataToRetrieve = false; - transactionHistoryModel.getPage(); + transactionHistoryModel.getFirstPage(); Commerce.getAvailableUpdates(); } else { refreshTimer.stop(); diff --git a/interface/resources/qml/hifi/models/PSFListModel.qml b/interface/resources/qml/hifi/models/PSFListModel.qml index 41134ddfdb..f3b14fedd7 100644 --- a/interface/resources/qml/hifi/models/PSFListModel.qml +++ b/interface/resources/qml/hifi/models/PSFListModel.qml @@ -71,6 +71,15 @@ Item { console.log("Fetching Page " + root.currentPageToRetrieve + " of " + root.listModelName + "..."); } } + + // A helper function used to get the first page from the server. + // It can be custom-defined by this item's Parent. + property var getFirstPage: function() { + root.initialResultReceived = false; + root.currentPageToRetrieve = 1; + root.noMoreDataToRetrieve = false; + root.getPage(); + } // Resets both internal `ListModel`s and resets the page to retrieve to "1". function resetModel() { @@ -82,22 +91,22 @@ Item { onEndpointChanged: { resetModel(); - root.getPage(); + root.getFirstPage(); } onSortKeyChanged: { resetModel(); - root.getPage(); + root.getFirstPage(); } onSearchFilterChanged: { resetModel(); - root.getPage(); + root.getFirstPage(); } onTagsFilterChanged: { resetModel(); - root.getPage(); + root.getFirstPage(); } property bool initialResultReceived: false; From 86a8672c5a7a230ece2a79341299cb2dab186334 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Thu, 17 May 2018 10:17:22 -0700 Subject: [PATCH 060/380] Initialize Qt/openssl before RSA keygen to prevent collision --- libraries/networking/src/RSAKeypairGenerator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/RSAKeypairGenerator.cpp b/libraries/networking/src/RSAKeypairGenerator.cpp index 8ca8b81ea3..dcd4e7fd3c 100644 --- a/libraries/networking/src/RSAKeypairGenerator.cpp +++ b/libraries/networking/src/RSAKeypairGenerator.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include "NetworkLogging.h" @@ -25,7 +26,8 @@ RSAKeypairGenerator::RSAKeypairGenerator(QObject* parent) : QObject(parent) { - + // Ensure openssl/Qt config is set up. + QSslConfiguration::defaultConfiguration(); } void RSAKeypairGenerator::generateKeypair() { From 3730cbe36c829fa46a2bd83d340e5e2f21bf5d4c Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 17 May 2018 10:28:48 -0700 Subject: [PATCH 061/380] reconstruct cloneIDs lists on start, read/write locks on clone ID functions, fix removing last cloneable --- libraries/entities/src/EntityItem.cpp | 36 ++++++++++++++++++++------- libraries/entities/src/EntityItem.h | 3 ++- libraries/entities/src/EntityTree.cpp | 18 +++++++++++++- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1e95e999b1..e6aa572330 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3096,18 +3096,36 @@ void EntityItem::setCloneOriginID(const QUuid& value) { } bool EntityItem::addCloneID(const QUuid& cloneID) { - if (!_cloneIDs.contains(cloneID)) { - _cloneIDs.append(cloneID); - return true; - } + withWriteLock([&] { + if (!_cloneIDs.contains(cloneID)) { + _cloneIDs.append(cloneID); + return true; + } + }); return false; } bool EntityItem::removeCloneID(const QUuid& cloneID) { - int index = _cloneIDs.indexOf(cloneID); - if (index > 0) { - _cloneIDs.removeAt(index); - return true; - } + withWriteLock([&] { + int index = _cloneIDs.indexOf(cloneID); + if (index >= 0) { + _cloneIDs.removeAt(index); + return true; + } + }); return false; } + +const QList EntityItem::getCloneIDs() const { + QList result; + withReadLock([&] { + result = _cloneIDs; + }); + return result; +} + +void EntityItem::setCloneIDs(const QList& cloneIDs) { + withWriteLock([&] { + _cloneIDs = cloneIDs; + }); +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index f314cd1418..cc8cefb17b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -509,7 +509,8 @@ public: bool addCloneID(const QUuid& cloneID); bool removeCloneID(const QUuid& cloneID); - const QList& getCloneIDs() const { return _cloneIDs; } + const QList getCloneIDs() const; + void setCloneIDs(const QList& cloneIDs); signals: void requestRenderUpdate(); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b2daed4e72..c87f6d771a 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -631,7 +631,7 @@ void EntityTree::cleanupCloneIDs(const EntityItemID& entityID) { EntityItemPointer entity = findEntityByEntityItemID(entityID); if (entity) { // remove clone ID from it's clone origin's clone ID list if clone origin exists - const QUuid cloneOriginID = entity->getCloneOriginID(); + const QUuid& cloneOriginID = entity->getCloneOriginID(); if (!cloneOriginID.isNull()) { EntityItemPointer cloneOrigin = findEntityByID(cloneOriginID); if (cloneOrigin) { @@ -2385,6 +2385,8 @@ bool EntityTree::readFromMap(QVariantMap& map) { return false; } + QMap> cloneIDs; + bool success = true; foreach (QVariant entityVariant, entitiesQList) { // QVariantMap --> QScriptValue --> EntityItemProperties --> Entity @@ -2477,6 +2479,20 @@ bool EntityTree::readFromMap(QVariantMap& map) { qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); success = false; } + + const QUuid& cloneOriginID = entity->getCloneOriginID(); + if (!cloneOriginID.isNull()) { + cloneIDs[cloneOriginID].push_back(entity->getEntityItemID()); + } + } + + for (auto iter = cloneIDs.begin(); iter != cloneIDs.end(); ++iter) { + const QUuid& entityID = iter.key(); + const QList& cloneIDs = iter.value(); + EntityItemPointer entity = findEntityByID(entityID); + if (entity) { + entity->setCloneIDs(cloneIDs); + } } return success; From 42d84924274def80ade80cafeb5b7d84aaa3ec44 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 17 May 2018 11:17:04 -0700 Subject: [PATCH 062/380] no clock skew --- libraries/entities/src/EntityEditPacketSender.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index c2323b0a20..9ca102d016 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -34,7 +34,7 @@ void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer Date: Thu, 17 May 2018 11:25:20 -0700 Subject: [PATCH 063/380] Add JSDoc header to new clone function in Entity API --- libraries/entities/src/EntityScriptingInterface.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 883990418a..febc33ffde 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -224,6 +224,14 @@ public slots: Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const QString& textures, const QString& shapeType, bool dynamic, bool collisionless, const glm::vec3& position, const glm::vec3& gravity); + /**jsdoc + * Request a clone of an entity. Only entities that have been marked as 'cloneable' will be able to be cloned using this method. + * A cloned entity has most of the properties of the orignal entity, and can be requested from clients that do not have rez permissions. + * The client requests a clone from the entity server, which returns back the entityID of a valid clone if the operation was allowed. + * @function Entities.cloneEntity + * @param {Uuid} entityIDToClone - the ID of the entity to clone + * @returns {Entities.EntityID} The ID of the newly created clone + */ Q_INVOKABLE QUuid cloneEntity(QUuid entityIDToClone); /**jsdoc From fe92cf0c4788bc2942253d9ade93849d344cf7b2 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Thu, 17 May 2018 13:34:38 -0700 Subject: [PATCH 064/380] Move fix up a level to bit a little more general --- libraries/networking/src/AccountManager.cpp | 3 +++ libraries/networking/src/RSAKeypairGenerator.cpp | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 049129b2ba..1f6932094c 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -729,6 +729,9 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI return; } + // Ensure openssl/Qt config is set up. + QSslConfiguration::defaultConfiguration(); + // make sure we don't already have an outbound keypair generation request if (!_isWaitingForKeypairResponse) { _isWaitingForKeypairResponse = true; diff --git a/libraries/networking/src/RSAKeypairGenerator.cpp b/libraries/networking/src/RSAKeypairGenerator.cpp index dcd4e7fd3c..222b04b47c 100644 --- a/libraries/networking/src/RSAKeypairGenerator.cpp +++ b/libraries/networking/src/RSAKeypairGenerator.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include "NetworkLogging.h" @@ -26,8 +25,7 @@ RSAKeypairGenerator::RSAKeypairGenerator(QObject* parent) : QObject(parent) { - // Ensure openssl/Qt config is set up. - QSslConfiguration::defaultConfiguration(); + } void RSAKeypairGenerator::generateKeypair() { From b8ce07744da6d0c2c8a963644172529038cd0024 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 17 May 2018 14:50:14 -0700 Subject: [PATCH 065/380] initialize prop defaults, no bool returns --- libraries/entities/src/EntityItem.cpp | 8 ++------ libraries/entities/src/EntityItem.h | 14 +++++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e6aa572330..667ca9296d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3095,25 +3095,21 @@ void EntityItem::setCloneOriginID(const QUuid& value) { }); } -bool EntityItem::addCloneID(const QUuid& cloneID) { +void EntityItem::addCloneID(const QUuid& cloneID) { withWriteLock([&] { if (!_cloneIDs.contains(cloneID)) { _cloneIDs.append(cloneID); - return true; } }); - return false; } -bool EntityItem::removeCloneID(const QUuid& cloneID) { +void EntityItem::removeCloneID(const QUuid& cloneID) { withWriteLock([&] { int index = _cloneIDs.indexOf(cloneID); if (index >= 0) { _cloneIDs.removeAt(index); - return true; } }); - return false; } const QList EntityItem::getCloneIDs() const { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index cc8cefb17b..9b1230c843 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -507,8 +507,8 @@ public: void setSimulationOwnershipExpiry(uint64_t expiry) { _simulationOwnershipExpiry = expiry; } uint64_t getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } - bool addCloneID(const QUuid& cloneID); - bool removeCloneID(const QUuid& cloneID); + void addCloneID(const QUuid& cloneID); + void removeCloneID(const QUuid& cloneID); const QList getCloneIDs() const; void setCloneIDs(const QList& cloneIDs); @@ -666,11 +666,11 @@ protected: bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera - bool _cloneable; - float _cloneLifetime; - float _cloneLimit; - bool _cloneDynamic; - bool _cloneAvatarEntity; + bool _cloneable { ENTITY_ITEM_CLONEABLE }; + float _cloneLifetime { ENTITY_ITEM_CLONE_LIFETIME }; + float _cloneLimit { ENTITY_ITEM_CLONE_LIMIT }; + bool _cloneDynamic { ENTITY_ITEM_CLONE_DYNAMIC }; + bool _cloneAvatarEntity { ENTITY_ITEM_CLONE_AVATAR_ENTITY }; QUuid _cloneOriginID; QList _cloneIDs; From 30855f94eb3baed58067ad7d1af8bba1086d9726 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 17 May 2018 16:02:58 -0700 Subject: [PATCH 066/380] set last edited to 0 to ensure server update --- libraries/entities/src/EntityScriptingInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f47a353ae8..905474fd68 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -333,6 +333,7 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); properties.convertToCloneProperties(entityIDToClone); + properties.setLastEdited(0); // to ensure we take the properties from the server-created entity bool success = addLocalEntityCopy(properties, newEntityID); if (success) { getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); From 4e14eb37e304d1216545eb5ba44ccb7187b5bac3 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 17 May 2018 16:34:19 -0700 Subject: [PATCH 067/380] update comment --- libraries/entities/src/EntityScriptingInterface.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 905474fd68..ca64b3b09d 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -333,7 +333,9 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); properties.convertToCloneProperties(entityIDToClone); - properties.setLastEdited(0); // to ensure we take the properties from the server-created entity + // setLastEdited timestamp to 0 to ensure this entity gets updated with the properties + // from the server-created entity, don't change this unless you know what you are doing + properties.setLastEdited(0); bool success = addLocalEntityCopy(properties, newEntityID); if (success) { getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); From aa18aaa7b19e2969633de95b5f55a0e7eb2ef2cc Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 17 May 2018 18:06:46 -0700 Subject: [PATCH 068/380] Maybe --- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/avatar/MyAvatar.h | 4 ++-- .../src/avatars-renderer/Avatar.cpp | 14 ++++++++++++++ .../avatars-renderer/src/avatars-renderer/Avatar.h | 4 ++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 193e974484..8817ea3d05 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1127,8 +1127,8 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) { } void MyAvatar::setEnableMeshVisible(bool isEnabled) { - // TODO: This should tell the main MetaRenderItem of the Avatar to be hidden to control vsisiblity since the model is culled by the MetaRI. _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1, true); + Avatar::setEnableMeshVisible(isEnabled); } void MyAvatar::setEnableInverseKinematics(bool isEnabled) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 154e2e4d09..5e78d508fe 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1159,7 +1159,7 @@ public slots: * @function MyAvatar.getEnableMeshVisible * @returns {boolean} true if your avatar's mesh is visible, otherwise false. */ - bool getEnableMeshVisible() const { return _skeletonModel->isVisible(); } + bool getEnableMeshVisible() const override { return _skeletonModel->isVisible(); } /**jsdoc * Set whether or not your avatar mesh is visible. @@ -1171,7 +1171,7 @@ public slots: * MyAvatar.setEnableMeshVisible(true); * }, 10000); */ - void setEnableMeshVisible(bool isEnabled); + void setEnableMeshVisible(bool isEnabled) override; /**jsdoc * @function MyAvatar.setEnableInverseKinematics diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 38828a5163..858318746c 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -765,6 +765,20 @@ void Avatar::render(RenderArgs* renderArgs) { } } + +void Avatar::setEnableMeshVisible(bool isEnabled) { + render::Transaction transaction; + if (render::Item::isValidID(_renderItemID)) { + transaction.updateItem>(_renderItemID, [](render::Payload& p) { + }); + } + qApp->getMain3DScene()->enqueueTransaction(transaction); +} + +bool Avatar::getEnableMeshVisible() const { + return true; +} + void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { bool canTryFade{ false }; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 01114b5f6d..06bc1b174c 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -356,6 +356,10 @@ public: virtual void setAvatarEntityDataChanged(bool value) override; + // Show hide the model representation of the avatar + virtual void setEnableMeshVisible(bool isEnabled); + virtual bool getEnableMeshVisible() const; + void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override; void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override; From 545ada0abb608a577362a36d0550bce1260dc83f Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 18 May 2018 10:28:52 -0700 Subject: [PATCH 069/380] Connect signal to keyGen thread for it to quit when owner destructed --- libraries/networking/src/AccountManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 1f6932094c..a975a86ada 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -761,6 +761,7 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI this, &AccountManager::handleKeypairGenerationError); connect(keypairGenerator, &QObject::destroyed, generateThread, &QThread::quit); + connect(this, &QObject::destroyed, generateThread, &QThread::quit); connect(generateThread, &QThread::finished, generateThread, &QThread::deleteLater); keypairGenerator->moveToThread(generateThread); From 12b91a2ab720e8eb5c8c73822b01220003996e96 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 16 May 2018 18:06:12 -0700 Subject: [PATCH 070/380] compress skyboxes --- android/build.gradle | 6 ++--- cmake/macros/TargetEtc2Comp.cmake | 2 +- libraries/gpu/src/gpu/Texture.cpp | 14 +++++++++++- libraries/image/src/image/Image.cpp | 34 ++++++++++++++++++++++++----- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 71d48e28d4..c771c776b5 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,7 +14,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.0' + classpath 'com.android.tools.build:gradle:3.0.1' } } @@ -126,8 +126,8 @@ def packages = [ ], polyvox: [ file: 'polyvox_armv8-libcpp.tgz', - versionId: 'UmHp.EOFiepdXnv2YxwNXNO3J6nVsBkE', - checksum: '5c918288741ee754c16aeb12bb46b9e1', + versionId: 'A2kbKiNhpIenGq23bKRRzg7IMAI5BI92', + checksum: 'dba88b3a098747af4bb169e9eb9af57e', sharedLibFolder: 'lib', includeLibs: ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'], ], diff --git a/cmake/macros/TargetEtc2Comp.cmake b/cmake/macros/TargetEtc2Comp.cmake index 8dfae175a9..44152a58d2 100644 --- a/cmake/macros/TargetEtc2Comp.cmake +++ b/cmake/macros/TargetEtc2Comp.cmake @@ -14,7 +14,7 @@ macro(TARGET_ETC2COMP) select_library_configurations(ETC2COMP) else() add_dependency_external_projects(etc2comp) - find_package(ETC2COMP REQUIRED) + find_package(Etc2Comp REQUIRED) endif() target_include_directories(${TARGET_NAME} PRIVATE ${ETC2COMP_INCLUDE_DIRS}) diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index ed9505766b..a92243f808 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -684,9 +684,9 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector< PROFILE_RANGE(render_gpu, "sphericalHarmonicsFromTexture"); +#ifndef USE_GLES auto mipFormat = cubeTexture.getStoredMipFormat(); std::function unpackFunc; - switch (mipFormat.getSemantic()) { case gpu::R11G11B10: unpackFunc = glm::unpackF2x11_1x10; @@ -698,6 +698,7 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector< assert(false); break; } +#endif const uint sqOrder = order*order; @@ -732,7 +733,11 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector< for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) { PROFILE_RANGE(render_gpu, "ProcessFace"); +#ifndef USE_GLES auto data = reinterpret_cast( cubeTexture.accessStoredMipFace(0, face)->readData() ); +#else + auto data = cubeTexture.accessStoredMipFace(0, face)->readData(); +#endif if (data == nullptr) { continue; } @@ -816,8 +821,15 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector< glm::vec3 color{ 0.0f, 0.0f, 0.0f }; for (int i = 0; i < stride; ++i) { for (int j = 0; j < stride; ++j) { +#ifndef USE_GLES int k = (int)(x + i - halfStride + (y + j - halfStride) * width); color += unpackFunc(data[k]); +#else + const int NUM_COMPONENTS_PER_PIXEL = 4; + int k = NUM_COMPONENTS_PER_PIXEL * (int)(x + i - halfStride + (y + j - halfStride) * width); + // BGRA -> RGBA + color += glm::pow(glm::vec3(data[k + 2], data[k + 1], data[k]) / 255.0f, glm::vec3(2.2f)); +#endif } } diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 2fc22b4eac..63a4725f64 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -84,7 +84,13 @@ const QStringList getSupportedFormats() { return stringFormats; } + +// On GLES, we don't use HDR skyboxes +#ifndef USE_GLES QImage::Format QIMAGE_HDR_FORMAT = QImage::Format_RGB30; +#else +QImage::Format QIMAGE_HDR_FORMAT = QImage::Format_RGB32; +#endif TextureUsage::TextureLoader TextureUsage::getTextureLoaderForType(Type type, const QVariantMap& options) { switch (type) { @@ -557,7 +563,7 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic #if CPU_MIPMAPS PROFILE_RANGE(resource_parse, "generateMips"); +#ifndef USE_GLES if (image.format() == QIMAGE_HDR_FORMAT) { generateHDRMips(texture, std::move(image), abortProcessing, face); } else { generateLDRMips(texture, std::move(image), abortProcessing, face); } +#else + generateLDRMips(texture, std::move(image), abortProcessing, face); +#endif #else texture->setAutoGenerateMips(true); #endif @@ -1354,18 +1364,25 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI QImage image = processSourceImage(std::move(localCopy), true); if (image.format() != QIMAGE_HDR_FORMAT) { +#ifndef USE_GLES image = convertToHDRFormat(std::move(image), HDR_FORMAT); +#else + image = image.convertToFormat(QImage::Format_RGB32); +#endif } gpu::Element formatMip; gpu::Element formatGPU; if (isCubeTexturesCompressionEnabled()) { - formatMip = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; } else { - formatMip = HDR_FORMAT; +#ifdef USE_GLES + formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGB; +#else formatGPU = HDR_FORMAT; +#endif } + formatMip = formatGPU; // Find the layout of the cubemap in the 2D image // Use the original image size since processSourceImage may have altered the size / aspect ratio @@ -1412,9 +1429,16 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI // Generate irradiance while we are at it if (generateIrradiance) { PROFILE_RANGE(resource_parse, "generateIrradiance"); - auto irradianceTexture = gpu::Texture::createCube(HDR_FORMAT, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)); + gpu::Element irradianceFormat; + // TODO: we could locally compress the irradiance texture on Android, but we don't need to +#ifndef USE_GLES + irradianceFormat = HDR_FORMAT; +#else + irradianceFormat = gpu::Element::COLOR_SRGBA_32; +#endif + auto irradianceTexture = gpu::Texture::createCube(irradianceFormat, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)); irradianceTexture->setSource(srcImageName); - irradianceTexture->setStoredMipFormat(HDR_FORMAT); + irradianceTexture->setStoredMipFormat(irradianceFormat); for (uint8 face = 0; face < faces.size(); ++face) { irradianceTexture->assignStoredMipFace(0, face, faces[face].byteCount(), faces[face].constBits()); } From 29b11b910124640c39e59131de2e2443d904368b Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Fri, 18 May 2018 17:12:41 -0700 Subject: [PATCH 071/380] some fixes to server cloneables --- libraries/entities/src/EntityItem.cpp | 6 +++--- libraries/entities/src/EntityItem.h | 16 ++++++++-------- libraries/entities/src/EntityItemProperties.cpp | 10 +++++----- libraries/entities/src/EntityItemProperties.h | 12 ++++++------ .../entities/src/EntityItemPropertiesDefaults.h | 12 ++++++------ .../entities/src/EntityScriptingInterface.cpp | 17 ++++++++++++----- libraries/entities/src/EntityTree.cpp | 9 +++++---- 7 files changed, 45 insertions(+), 37 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 667ca9296d..9bad6f2519 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3112,15 +3112,15 @@ void EntityItem::removeCloneID(const QUuid& cloneID) { }); } -const QList EntityItem::getCloneIDs() const { - QList result; +const QVector EntityItem::getCloneIDs() const { + QVector result; withReadLock([&] { result = _cloneIDs; }); return result; } -void EntityItem::setCloneIDs(const QList& cloneIDs) { +void EntityItem::setCloneIDs(const QVector& cloneIDs) { withWriteLock([&] { _cloneIDs = cloneIDs; }); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 9b1230c843..42c4605e44 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -509,8 +509,8 @@ public: void addCloneID(const QUuid& cloneID); void removeCloneID(const QUuid& cloneID); - const QList getCloneIDs() const; - void setCloneIDs(const QList& cloneIDs); + const QVector getCloneIDs() const; + void setCloneIDs(const QVector& cloneIDs); signals: void requestRenderUpdate(); @@ -666,13 +666,13 @@ protected: bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera - bool _cloneable { ENTITY_ITEM_CLONEABLE }; - float _cloneLifetime { ENTITY_ITEM_CLONE_LIFETIME }; - float _cloneLimit { ENTITY_ITEM_CLONE_LIMIT }; - bool _cloneDynamic { ENTITY_ITEM_CLONE_DYNAMIC }; - bool _cloneAvatarEntity { ENTITY_ITEM_CLONE_AVATAR_ENTITY }; + bool _cloneable { ENTITY_ITEM_DEFAULT_CLONEABLE }; + float _cloneLifetime { ENTITY_ITEM_DEFAULT_CLONE_LIFETIME }; + float _cloneLimit { ENTITY_ITEM_DEFAULT_CLONE_LIMIT }; + bool _cloneDynamic { ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC }; + bool _cloneAvatarEntity { ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY }; QUuid _cloneOriginID; - QList _cloneIDs; + QVector _cloneIDs; private: std::unordered_map _materials; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 5a2f3a8fc5..39449c7cd1 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -3657,9 +3657,9 @@ void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityID setLifetime(getCloneLifetime()); setDynamic(getCloneDynamic()); setClientOnly(getCloneAvatarEntity()); - setCloneable(ENTITY_ITEM_CLONEABLE); - setCloneLifetime(ENTITY_ITEM_CLONE_LIFETIME); - setCloneLimit(ENTITY_ITEM_CLONE_LIMIT); - setCloneDynamic(ENTITY_ITEM_CLONE_DYNAMIC); - setCloneAvatarEntity(ENTITY_ITEM_CLONE_AVATAR_ENTITY); + setCloneable(ENTITY_ITEM_DEFAULT_CLONEABLE); + setCloneLifetime(ENTITY_ITEM_DEFAULT_CLONE_LIFETIME); + setCloneLimit(ENTITY_ITEM_DEFAULT_CLONE_LIMIT); + setCloneDynamic(ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC); + setCloneAvatarEntity(ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index a34058c010..d00a21435c 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -272,12 +272,12 @@ public: DEFINE_PROPERTY_REF(PROP_SERVER_SCRIPTS, ServerScripts, serverScripts, QString, ENTITY_ITEM_DEFAULT_SERVER_SCRIPTS); DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS); - DEFINE_PROPERTY(PROP_CLONEABLE, Cloneable, cloneable, bool, ENTITY_ITEM_CLONEABLE); - DEFINE_PROPERTY(PROP_CLONE_LIFETIME, CloneLifetime, cloneLifetime, float, ENTITY_ITEM_CLONE_LIFETIME); - DEFINE_PROPERTY(PROP_CLONE_LIMIT, CloneLimit, cloneLimit, float, ENTITY_ITEM_CLONE_LIMIT); - DEFINE_PROPERTY(PROP_CLONE_DYNAMIC, CloneDynamic, cloneDynamic, bool, ENTITY_ITEM_CLONE_DYNAMIC); - DEFINE_PROPERTY(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool, ENTITY_ITEM_CLONE_AVATAR_ENTITY); - DEFINE_PROPERTY(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid, ENTITY_ITEM_CLONE_ORIGIN_ID); + DEFINE_PROPERTY(PROP_CLONEABLE, Cloneable, cloneable, bool, ENTITY_ITEM_DEFAULT_CLONEABLE); + DEFINE_PROPERTY(PROP_CLONE_LIFETIME, CloneLifetime, cloneLifetime, float, ENTITY_ITEM_DEFAULT_CLONE_LIFETIME); + DEFINE_PROPERTY(PROP_CLONE_LIMIT, CloneLimit, cloneLimit, float, ENTITY_ITEM_DEFAULT_CLONE_LIMIT); + DEFINE_PROPERTY(PROP_CLONE_DYNAMIC, CloneDynamic, cloneDynamic, bool, ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC); + DEFINE_PROPERTY(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool, ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY); + DEFINE_PROPERTY(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid, ENTITY_ITEM_DEFAULT_CLONE_ORIGIN_ID); static QString getComponentModeString(uint32_t mode); static QString getComponentModeAsString(uint32_t mode); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 1a31bddebe..0fd926e677 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -97,11 +97,11 @@ const QUuid ENTITY_ITEM_DEFAULT_LAST_EDITED_BY = QUuid(); const bool ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS = false; -const bool ENTITY_ITEM_CLONEABLE = false; -const float ENTITY_ITEM_CLONE_LIFETIME = 300.0f; -const int ENTITY_ITEM_CLONE_LIMIT = 0; -const bool ENTITY_ITEM_CLONE_DYNAMIC = false; -const bool ENTITY_ITEM_CLONE_AVATAR_ENTITY = false; -const QUuid ENTITY_ITEM_CLONE_ORIGIN_ID = QUuid(); +const bool ENTITY_ITEM_DEFAULT_CLONEABLE = false; +const float ENTITY_ITEM_DEFAULT_CLONE_LIFETIME = 300.0f; +const int ENTITY_ITEM_DEFAULT_CLONE_LIMIT = 0; +const bool ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC = false; +const bool ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY = false; +const QUuid ENTITY_ITEM_DEFAULT_CLONE_ORIGIN_ID = QUuid(); #endif // hifi_EntityItemPropertiesDefaults_h diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f47a353ae8..ace4670fef 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -332,13 +332,20 @@ QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QStrin QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { EntityItemID newEntityID; EntityItemProperties properties = getEntityProperties(entityIDToClone); + bool cloneAvatarEntity = properties.getCloneAvatarEntity(); properties.convertToCloneProperties(entityIDToClone); - bool success = addLocalEntityCopy(properties, newEntityID); - if (success) { - getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); - return newEntityID; + + if (cloneAvatarEntity) { + return addEntity(properties, true); } else { - return QUuid(); + bool success = addLocalEntityCopy(properties, newEntityID); + if (success) { + getEntityPacketSender()->queueCloneEntityMessage(entityIDToClone, newEntityID); + return newEntityID; + } + else { + return QUuid(); + } } } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index c87f6d771a..a36ee4be9d 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -639,7 +639,7 @@ void EntityTree::cleanupCloneIDs(const EntityItemID& entityID) { } } // clear the clone origin ID on any clones that this entity had - const QList& cloneIDs = entity->getCloneIDs(); + const QVector& cloneIDs = entity->getCloneIDs(); foreach(const QUuid& cloneChildID, cloneIDs) { EntityItemPointer cloneChild = findEntityByEntityItemID(cloneChildID); if (cloneChild) { @@ -1627,7 +1627,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } else if (isClone && !isCloneable) { failedAdd = true; qCDebug(entities) << "User attempted to clone non-cloneable entity from entity ID:" << entityIDToClone; - } else if (isClone && entityToClone && entityToClone->getCloneIDs().size() >= cloneLimit) { + } else if (isClone && entityToClone && entityToClone->getCloneIDs().size() >= cloneLimit && cloneLimit != 0) { failedAdd = true; qCDebug(entities) << "User attempted to clone entity ID:" << entityIDToClone << " which reached it's cloneable limit."; } else { @@ -2039,6 +2039,7 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons if (shouldEraseEntity(entityID, sourceNode)) { entityItemIDsToDelete << entityItemID; + cleanupCloneIDs(entityItemID); } } @@ -2385,7 +2386,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { return false; } - QMap> cloneIDs; + QMap> cloneIDs; bool success = true; foreach (QVariant entityVariant, entitiesQList) { @@ -2488,7 +2489,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { for (auto iter = cloneIDs.begin(); iter != cloneIDs.end(); ++iter) { const QUuid& entityID = iter.key(); - const QList& cloneIDs = iter.value(); + const QVector& cloneIDs = iter.value(); EntityItemPointer entity = findEntityByID(entityID); if (entity) { entity->setCloneIDs(cloneIDs); From 36a08fdd8415a4de327f019e49c1fb108a86b30a Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 18 May 2018 17:41:28 -0700 Subject: [PATCH 072/380] Friday night end of the day, last compilation.... almost --- interface/src/avatar/MyAvatar.cpp | 5 ++- interface/src/avatar/MyAvatar.h | 2 +- .../src/avatars-renderer/Avatar.cpp | 20 ++++++---- .../src/avatars-renderer/Avatar.h | 3 ++ libraries/render/src/render/CullTask.cpp | 38 +++++++++---------- 5 files changed, 40 insertions(+), 28 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8817ea3d05..c698bb3c1b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1126,8 +1126,11 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) { _enableDebugDrawIKChains = isEnabled; } +bool MyAvatar::getEnableMeshVisible() const { + return Avatar::getEnableMeshVisible(); +} + void MyAvatar::setEnableMeshVisible(bool isEnabled) { - _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1, true); Avatar::setEnableMeshVisible(isEnabled); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 5e78d508fe..4070d3372c 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1159,7 +1159,7 @@ public slots: * @function MyAvatar.getEnableMeshVisible * @returns {boolean} true if your avatar's mesh is visible, otherwise false. */ - bool getEnableMeshVisible() const override { return _skeletonModel->isVisible(); } + bool getEnableMeshVisible() const override; /**jsdoc * Set whether or not your avatar mesh is visible. diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 858318746c..a3b5a731bb 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -55,7 +55,9 @@ namespace render { ItemKey::Builder keyBuilder = ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1).withMetaCullGroup(); auto avatarPtr = static_pointer_cast(avatar); auto model = avatarPtr->getSkeletonModel(); - if (model && !model->isVisible()) { + //if (model && !model->isVisible()) { + + if (!avatarPtr->getEnableMeshVisible() && model) { keyBuilder.withInvisible(); } return keyBuilder.build(); @@ -767,16 +769,14 @@ void Avatar::render(RenderArgs* renderArgs) { void Avatar::setEnableMeshVisible(bool isEnabled) { - render::Transaction transaction; - if (render::Item::isValidID(_renderItemID)) { - transaction.updateItem>(_renderItemID, [](render::Payload& p) { - }); + if (_isMeshEnableVisible != isEnabled) { + _isMeshEnableVisible = isEnabled; + _needMeshVisibleSwitch = true; } - qApp->getMain3DScene()->enqueueTransaction(transaction); } bool Avatar::getEnableMeshVisible() const { - return true; + return _isMeshEnableVisible; } void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { @@ -801,6 +801,12 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { } } + if (_needMeshVisibleSwitch) { + // _skeletonModel->setVisibleInScene(_isMeshEnableVisible, scene, render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1, true); + updateRenderItem(transaction); + _needMeshVisibleSwitch = false; + } + if (_mustFadeIn && canTryFade) { // Do it now to be sure all the sub items are ready and the fade is sent to them too fade(transaction, render::Transition::USER_ENTER_DOMAIN); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 06bc1b174c..f7e89653b5 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -536,6 +536,9 @@ protected: std::mutex _materialsLock; void processMaterials(); + + bool _isMeshEnableVisible{ true }; + bool _needMeshVisibleSwitch{ true }; }; #endif // hifi_Avatar_h diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index b5819f114f..ce6755b893 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -368,9 +368,9 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input RenderArgs* args = renderContext->args; const auto& inShapes = inputs.get0(); - const auto& cullFilter = inputs.get1(); - const auto& boundsFilter = inputs.get2(); - const auto& antiFrustum = inputs.get3(); + const auto& cullFilter = inputs.get1(); + const auto& boundsFilter = inputs.get2(); + const auto& antiFrustum = inputs.get3(); auto& outShapes = outputs.edit0(); auto& outBounds = outputs.edit1(); @@ -380,7 +380,7 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) { auto& details = args->_details.edit(_detailType); Test test(_cullFunctor, args, details, antiFrustum); - auto scene = args->_scene; + auto scene = args->_scene; for (auto& inItems : inShapes) { auto key = inItems.first; @@ -395,26 +395,26 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input if (antiFrustum == nullptr) { for (auto& item : inItems.second) { if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) { - const auto shapeKey = scene->getItem(item.id).getKey(); - if (cullFilter.test(shapeKey)) { - outItems->second.emplace_back(item); - } - if (boundsFilter.test(shapeKey)) { - outBounds += item.bound; - } + const auto shapeKey = scene->getItem(item.id).getKey(); + if (cullFilter.test(shapeKey)) { + outItems->second.emplace_back(item); + } + if (boundsFilter.test(shapeKey)) { + outBounds += item.bound; + } } } } else { for (auto& item : inItems.second) { if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) { - const auto shapeKey = scene->getItem(item.id).getKey(); - if (cullFilter.test(shapeKey)) { - outItems->second.emplace_back(item); - } - if (boundsFilter.test(shapeKey)) { - outBounds += item.bound; - } - } + const auto shapeKey = scene->getItem(item.id).getKey(); + if (cullFilter.test(shapeKey)) { + outItems->second.emplace_back(item); + } + if (boundsFilter.test(shapeKey)) { + outBounds += item.bound; + } + } } } details._rendered += (int)outItems->second.size(); From 6c8d68afc61ccc917f019664f7bed1b1f6a9d2ff Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Fri, 18 May 2018 18:18:42 -0700 Subject: [PATCH 073/380] add extra cleanup in delete messages and simulation, as a fall back --- libraries/entities/src/EntitySimulation.cpp | 1 + libraries/entities/src/EntityTree.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index d034ddedbe..ba088cb7fd 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -65,6 +65,7 @@ void EntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { removeEntityInternal(entity); if (entity->getElement()) { _deadEntities.insert(entity); + _entityTree->cleanupCloneIDs(entity->getEntityItemID()); } } } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a36ee4be9d..b698ac6eb8 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1990,6 +1990,7 @@ int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePo if (shouldEraseEntity(entityID, sourceNode)) { entityItemIDsToDelete << entityItemID; + cleanupCloneIDs(entityItemID); } } deleteEntities(entityItemIDsToDelete, true, true); From 1130f9998d8e6e8b92d8ec709d3ad2e1ba01c159 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Sat, 19 May 2018 10:42:55 -0700 Subject: [PATCH 074/380] Minor fix allows import GLTF from Substance Painter --- libraries/fbx/src/GLTFReader.cpp | 2 +- libraries/fbx/src/GLTFReader.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/fbx/src/GLTFReader.cpp b/libraries/fbx/src/GLTFReader.cpp index f322c2319e..1fa4b3873e 100644 --- a/libraries/fbx/src/GLTFReader.cpp +++ b/libraries/fbx/src/GLTFReader.cpp @@ -1174,7 +1174,7 @@ bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int byteL break; } case GLTFAccessorComponentType::UNSIGNED_INT: { - readArray(bin, byteOffset, byteLength, outarray, accessorType); + readArray(bin, byteOffset, byteLength, outarray, accessorType); break; } case GLTFAccessorComponentType::UNSIGNED_SHORT: { diff --git a/libraries/fbx/src/GLTFReader.h b/libraries/fbx/src/GLTFReader.h index 3554594768..28c1d8282f 100644 --- a/libraries/fbx/src/GLTFReader.h +++ b/libraries/fbx/src/GLTFReader.h @@ -190,7 +190,7 @@ namespace GLTFBufferViewTarget { struct GLTFBufferView { int buffer; //required int byteLength; //required - int byteOffset; + int byteOffset { 0 }; int target; QMap defined; void dump() { @@ -470,7 +470,7 @@ namespace GLTFAccessorComponentType { } struct GLTFAccessor { int bufferView; - int byteOffset; + int byteOffset { 0 }; int componentType; //required int count; //required int type; //required From 6d4f70427921ef9d94509d3a2d820a464b695067 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 21 May 2018 09:32:10 +1200 Subject: [PATCH 075/380] Regularize some JSDoc usage --- interface/src/Application.cpp | 2 +- interface/src/FancyCamera.h | 2 +- interface/src/avatar/MyAvatar.h | 2 +- .../src/raypick/PickScriptingInterface.h | 33 ++++++++++--------- .../src/raypick/PointerScriptingInterface.cpp | 6 ++-- .../scripting/WindowScriptingInterface.cpp | 2 +- .../src/scripting/WindowScriptingInterface.h | 2 +- interface/src/ui/overlays/Overlays.h | 2 +- .../src/avatars-renderer/Avatar.h | 2 +- libraries/avatars/src/AvatarData.cpp | 2 +- .../controllers/src/controllers/Actions.cpp | 2 +- .../controllers/src/controllers/InputDevice.h | 2 +- .../src/controllers/StandardController.cpp | 2 +- .../entities/src/AnimationPropertyGroup.cpp | 2 +- .../entities/src/EntityItemProperties.cpp | 2 +- .../src/input-plugins/KeyboardMouseDevice.cpp | 2 +- libraries/networking/src/AddressManager.h | 2 +- libraries/networking/src/DomainHandler.h | 2 +- .../src/AssetScriptingInterface.h | 8 ++--- libraries/script-engine/src/Quat.h | 2 +- .../src/SceneScriptingInterface.h | 6 ++-- libraries/script-engine/src/ScriptUUID.h | 2 +- libraries/shared/src/shared/Camera.h | 13 ++++---- libraries/ui/src/QmlFragmentClass.h | 2 +- .../ui/src/ui/TabletScriptingInterface.h | 2 +- .../oculus/src/OculusControllerManager.cpp | 2 +- plugins/openvr/src/ViveControllerManager.cpp | 2 +- 27 files changed, 56 insertions(+), 54 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 467c8c9a2c..266c085d99 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -715,7 +715,7 @@ private: * NavigationFocusednumbernumberNot used. * * - * @typedef Controller.Hardware-Application + * @typedef {object} Controller.Hardware-Application */ static const QString STATE_IN_HMD = "InHMD"; diff --git a/interface/src/FancyCamera.h b/interface/src/FancyCamera.h index bee21bad22..4ca073fb4f 100644 --- a/interface/src/FancyCamera.h +++ b/interface/src/FancyCamera.h @@ -25,7 +25,7 @@ class FancyCamera : public Camera { // FIXME: JSDoc 3.5.5 doesn't augment @property definitions. The following definition is repeated in Camera.h. /**jsdoc - * @property cameraEntity {Uuid} The ID of the entity that the camera position and orientation follow when the camera is in + * @property {Uuid} cameraEntity The ID of the entity that the camera position and orientation follow when the camera is in * entity mode. */ Q_PROPERTY(QUuid cameraEntity READ getCameraEntity WRITE setCameraEntity) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fa6a675d99..fe6ba71c13 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -121,7 +121,7 @@ class MyAvatar : public Avatar { * while flying. * @property {number} hmdRollControlDeadZone=8 - The amount of HMD roll, in degrees, required before your avatar turns if * hmdRollControlEnabled is enabled. - * @property hmdRollControlRate {number} If hmdRollControlEnabled is true, this value determines the maximum turn rate of + * @property {number} hmdRollControlRate If hmdRollControlEnabled is true, this value determines the maximum turn rate of * your avatar when rolling your HMD in degrees per second. * @property {number} userHeight=1.75 - The height of the user in sensor space. * @property {number} userEyeHeight=1.65 - The estimated height of the user's eyes in sensor space. Read-only. diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index a39aa3a4a1..5ef5d27d74 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -22,21 +22,22 @@ * @hifi-interface * @hifi-client-entity * - * @property PICK_NOTHING {number} A filter flag. Don't intersect with anything. Read-only. - * @property PICK_ENTITIES {number} A filter flag. Include entities when intersecting. Read-only. - * @property PICK_OVERLAYS {number} A filter flag. Include overlays when intersecting. Read-only. - * @property PICK_AVATARS {number} A filter flag. Include avatars when intersecting. Read-only. - * @property PICK_HUD {number} A filter flag. Include the HUD sphere when intersecting in HMD mode. Read-only. - * @property PICK_COARSE {number} A filter flag. Pick against coarse meshes, instead of exact meshes. Read-only. - * @property PICK_INCLUDE_INVISIBLE {number} A filter flag. Include invisible objects when intersecting. Read-only. - * @property PICK_INCLUDE_NONCOLLIDABLE {number} A filter flag. Include non-collidable objects when intersecting. + * @property {number} PICK_NOTHING A filter flag. Don't intersect with anything. Read-only. + * @property {number} PICK_ENTITIES A filter flag. Include entities when intersecting. Read-only. + * @property {number} PICK_OVERLAYS A filter flag. Include overlays when intersecting. Read-only. + * @property {number} PICK_AVATARS A filter flag. Include avatars when intersecting. Read-only. + * @property {number} PICK_HUD A filter flag. Include the HUD sphere when intersecting in HMD mode. Read-only. + * @property {number} PICK_COARSE A filter flag. Pick against coarse meshes, instead of exact meshes. Read-only. + * @property {number} PICK_INCLUDE_INVISIBLE A filter flag. Include invisible objects when intersecting. Read-only. + * @property {number} PICK_INCLUDE_NONCOLLIDABLE A filter flag. Include non-collidable objects when intersecting. * Read-only. - * @property PICK_ALL_INTERSECTIONS {number} Read-only. - * @property INTERSECTED_NONE {number} An intersection type. Intersected nothing with the given filter flags. Read-only. - * @property INTERSECTED_ENTITY {number} An intersection type. Intersected an entity. Read-only. - * @property INTERSECTED_OVERLAY {number} An intersection type. Intersected an overlay. Read-only. - * @property INTERSECTED_AVATAR {number} An intersection type. Intersected an avatar. Read-only. - * @property INTERSECTED_HUD {number} An intersection type. Intersected the HUD sphere. Read-only. + * @property {number} PICK_ALL_INTERSECTIONS Read-only. + * @property {number} INTERSECTED_NONE An intersection type. Intersected nothing with the given filter flags. + * Read-only. + * @property {number} INTERSECTED_ENTITY An intersection type. Intersected an entity. Read-only. + * @property {number} INTERSECTED_OVERLAY An intersection type. Intersected an overlay. Read-only. + * @property {number} INTERSECTED_AVATAR An intersection type. Intersected an avatar. Read-only. + * @property {number} INTERSECTED_HUD An intersection type. Intersected the HUD sphere. Read-only. * @property {number} perFrameTimeBudget - The max number of usec to spend per frame updating Pick results. Read-only. */ @@ -99,7 +100,7 @@ public: /**jsdoc * An intersection result for a Ray Pick. * - * @typedef {Object} RayPickResult + * @typedef {object} RayPickResult * @property {number} type The intersection type. * @property {boolean} intersects If there was a valid intersection (type != INTERSECTED_NONE) * @property {Uuid} objectID The ID of the intersected object. Uuid.NULL for the HUD or invalid intersections. @@ -113,7 +114,7 @@ public: /**jsdoc * An intersection result for a Stylus Pick. * - * @typedef {Object} StylusPickResult + * @typedef {object} StylusPickResult * @property {number} type The intersection type. * @property {boolean} intersects If there was a valid intersection (type != INTERSECTED_NONE) * @property {Uuid} objectID The ID of the intersected object. Uuid.NULL for the HUD or invalid intersections. diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index b7ac899c8d..4e953a5cb8 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -68,14 +68,14 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties) * A set of properties used to define the visual aspect of a Ray Pointer in the case that the Pointer is not intersecting something. Same as a {@link Pointers.RayPointerRenderState}, * but with an additional distance field. * - * @typedef {Object} Pointers.DefaultRayPointerRenderState + * @typedef {object} Pointers.DefaultRayPointerRenderState * @augments Pointers.RayPointerRenderState * @property {number} distance The distance at which to render the end of this Ray Pointer, if one is defined. */ /**jsdoc * A set of properties used to define the visual aspect of a Ray Pointer in the case that the Pointer is intersecting something. * - * @typedef {Object} Pointers.RayPointerRenderState + * @typedef {object} Pointers.RayPointerRenderState * @property {string} name The name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState} * @property {Overlays.OverlayProperties} [start] All of the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a type field). * An overlay to represent the beginning of the Ray Pointer, if desired. @@ -87,7 +87,7 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties) /**jsdoc * A trigger mechanism for Ray Pointers. * - * @typedef {Object} Pointers.Trigger + * @typedef {object} Pointers.Trigger * @property {Controller.Standard|Controller.Actions|function} action This can be a built-in Controller action, like Controller.Standard.LTClick, or a function that evaluates to >= 1.0 when you want to trigger button. * @property {string} button Which button to trigger. "Primary", "Secondary", "Tertiary", and "Focus" are currently supported. Only "Primary" will trigger clicks on web surfaces. If "Focus" is triggered, * it will try to set the entity or overlay focus to the object at which the Pointer is aimed. Buttons besides the first three will still trigger events, but event.button will be "None". diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 6f6e83842c..af9b5c8a46 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -522,7 +522,7 @@ int WindowScriptingInterface::openMessageBox(QString title, QString text, int bu * RestoreDefaults 0x8000000 "Restore Defaults" * * - * @typedef Window.MessageBoxButton + * @typedef {number} Window.MessageBoxButton */ int WindowScriptingInterface::createMessageBox(QString title, QString text, int buttons, int defaultButton) { auto messageBox = DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, title, text, diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 1d06f33ec0..d280d797d6 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -470,7 +470,7 @@ public slots: * * * - * @typedef Window.DisplayTexture + * @typedef {string} Window.DisplayTexture */ bool setDisplayTexture(const QString& name); diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 3ff782da99..d100b228ed 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -53,7 +53,7 @@ const OverlayID UNKNOWN_OVERLAY_ID = OverlayID(); * @property {number} distance - The distance from the {@link PickRay} origin to the intersection point. * @property {Vec3} surfaceNormal - The normal of the overlay surface at the intersection point. * @property {Vec3} intersection - The position of the intersection point. - * @property {Object} extraInfo Additional intersection details, if available. + * @property {object} extraInfo Additional intersection details, if available. */ class RayToOverlayIntersectionResult { public: diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 01114b5f6d..0f48e03e55 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -292,7 +292,7 @@ public: */ /**jsdoc * Information about a single joint in an Avatar's skeleton hierarchy. - * @typedef MyAvatar.SkeletonJoint + * @typedef {object} MyAvatar.SkeletonJoint * @property {string} name - Joint name. * @property {number} index - Joint index. * @property {number} parentIndex - Index of this joint's parent (-1 if no parent). diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 7a28686f8c..48ef1fb881 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2363,7 +2363,7 @@ glm::vec3 AvatarData::getAbsoluteJointTranslationInObjectFrame(int index) const } /**jsdoc - * @typedef AttachmentData + * @typedef {object} AttachmentData * @property {string} modelUrl * @property {string} jointName * @property {Vec3} translation diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp index 978b0888ba..6923ef4b98 100644 --- a/libraries/controllers/src/controllers/Actions.cpp +++ b/libraries/controllers/src/controllers/Actions.cpp @@ -307,7 +307,7 @@ namespace controller { * action. * * - * @typedef Controller.Actions + * @typedef {object} Controller.Actions */ // Device functions Input::NamedVector ActionsDevice::getAvailableInputs() const { diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h index 30a58eb2f0..1e626e6a3c 100644 --- a/libraries/controllers/src/controllers/InputDevice.h +++ b/libraries/controllers/src/controllers/InputDevice.h @@ -79,7 +79,7 @@ enum Hand { * {@link Controller.Hardware-Vive}. * * - * @typedef Controller.Hardware + * @typedef {object} Controller.Hardware * @example List all the currently available Controller.Hardware properties. * function printProperties(string, item) { * print(string); diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp index 471943400d..e1733d2524 100644 --- a/libraries/controllers/src/controllers/StandardController.cpp +++ b/libraries/controllers/src/controllers/StandardController.cpp @@ -231,7 +231,7 @@ void StandardController::focusOutEvent() { * * * - * @typedef Controller.Standard + * @typedef {object} Controller.Standard */ Input::NamedVector StandardController::getAvailableInputs() const { static Input::NamedVector availableInputs { diff --git a/libraries/entities/src/AnimationPropertyGroup.cpp b/libraries/entities/src/AnimationPropertyGroup.cpp index 43c6b7a6a5..2db85eb7ac 100644 --- a/libraries/entities/src/AnimationPropertyGroup.cpp +++ b/libraries/entities/src/AnimationPropertyGroup.cpp @@ -46,7 +46,7 @@ bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b /**jsdoc * The AnimationProperties are used to configure an animation. - * @typedef Entities.AnimationProperties + * @typedef {object} Entities.AnimationProperties * @property {string} url="" - The URL of the FBX file that has the animation. * @property {number} fps=30 - The speed in frames/s that the animation is played at. * @property {number} firstFrame=0 - The first frame to play in the animation. diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 4d7c114176..0def76f1bb 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1391,7 +1391,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool /**jsdoc * The axis-aligned bounding box of an entity. - * @typedef Entities.BoundingBox + * @typedef {object} Entities.BoundingBox * @property {Vec3} brn - The bottom right near (minimum axes values) corner of the AA box. * @property {Vec3} tfl - The top far left (maximum axes values) corner of the AA box. * @property {Vec3} center - The center of the AA box. diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index 8ecf527a14..650c9675a7 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -279,7 +279,7 @@ controller::Input KeyboardMouseDevice::InputDevice::makeInput(KeyboardMouseDevic * moved down. The data value is how far the average position of all touch points moved. * * - * @typedef Controller.Hardware-Keyboard + * @typedef {object} Controller.Hardware-Keyboard * @todo Currently, the mouse wheel in an ordinary mouse generates left/right wheel events instead of up/down. */ controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInputs() const { diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 7832b26c96..a12a18fa6a 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -138,7 +138,7 @@ public: * * * - * @typedef location.LookupTrigger + * @typedef {number} location.LookupTrigger */ enum LookupTrigger { UserInput, diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 08908dbaf6..4d98391104 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -137,7 +137,7 @@ public: * * * - * @typedef Window.ConnectionRefusedReason + * @typedef {number} Window.ConnectionRefusedReason */ enum class ConnectionRefusedReason : uint8_t { Unknown, diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 7f7a3a68b0..72d6901fb5 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -121,7 +121,7 @@ public: /**jsdoc * A set of properties that can be passed to {@link Assets.getAsset}. - * @typedef {Object} Assets.GetOptions + * @typedef {object} Assets.GetOptions * @property {string} [url] an "atp:" style URL, hash, or relative mapped path to fetch * @property {string} [responseType=text] the desired reponse type (text | arraybuffer | json) * @property {boolean} [decompress=false] whether to attempt gunzip decompression on the fetched data @@ -137,7 +137,7 @@ public: /**jsdoc * Result value returned by {@link Assets.getAsset}. - * @typedef {Object} Assets~getAssetResult + * @typedef {object} Assets~getAssetResult * @property {string} [url] the resolved "atp:" style URL for the fetched asset * @property {string} [hash] the resolved hash for the fetched asset * @property {string|ArrayBuffer|Object} [response] response data (possibly converted per .responseType value) @@ -159,7 +159,7 @@ public: /**jsdoc * A set of properties that can be passed to {@link Assets.putAsset}. - * @typedef {Object} Assets.PutOptions + * @typedef {object} Assets.PutOptions * @property {ArrayBuffer|string} [data] byte buffer or string value representing the new asset's content * @property {string} [path=null] ATP path mapping to automatically create (upon successful upload to hash) * @property {boolean} [compress=false] whether to gzip compress data before uploading @@ -174,7 +174,7 @@ public: /**jsdoc * Result value returned by {@link Assets.putAsset}. - * @typedef {Object} Assets~putAssetResult + * @typedef {object} Assets~putAssetResult * @property {string} [url] the resolved "atp:" style URL for the uploaded asset (based on .path if specified, otherwise on the resulting ATP hash) * @property {string} [path] the uploaded asset's resulting ATP path (or undefined if no path mapping was assigned) * @property {string} [hash] the uploaded asset's resulting ATP hash diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 1ccdfdbf31..76b7ac45e3 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -43,7 +43,7 @@ * @hifi-server-entity * @hifi-assignment-client * - * @property IDENTITY {Quat} { x: 0, y: 0, z: 0, w: 1 } : The identity rotation, i.e., no rotation. + * @property {Quat} IDENTITY - { x: 0, y: 0, z: 0, w: 1 } : The identity rotation, i.e., no rotation. * Read-only. * @example Print the IDENTITY value. * print(JSON.stringify(Quat.IDENTITY)); // { x: 0, y: 0, z: 0, w: 1 } diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index fdfbc6f6c0..da42cf2df3 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -21,7 +21,7 @@ namespace SceneScripting { /**jsdoc - * @typedef Scene.Stage.Location + * @typedef {object} Scene.Stage.Location * @property {number} longitude * @property {number} latitude * @property {number} altitude @@ -49,7 +49,7 @@ namespace SceneScripting { using LocationPointer = std::unique_ptr; /**jsdoc - * @typedef Scene.Stage.Time + * @typedef {object} Scene.Stage.Time * @property {number} hour * @property {number} day */ @@ -73,7 +73,7 @@ namespace SceneScripting { using TimePointer = std::unique_ptr